Merge branch 'upstream/development' into LYN-8514_AutomatedReviewServerLogChecks

This commit is contained in:
Gene Walters
2021-12-06 11:30:12 -08:00
959 changed files with 15035 additions and 10763 deletions
+124
View File
@@ -0,0 +1,124 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import os, traceback, binascii, sys, json, pathlib, logging
import azlmbr.math
import azlmbr.bus
from scene_helpers import *
#
# SceneAPI Processor
#
def update_manifest(scene):
import uuid
import azlmbr.scene as sceneApi
import azlmbr.scene.graph
from scene_api import scene_data as sceneData
graph = sceneData.SceneGraph(scene.graph)
# Get a list of all the mesh nodes, as well as all the nodes
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
mesh_name_list.sort(key=lambda node: str.casefold(node.get_path()))
scene_manifest = sceneData.SceneManifest()
clean_filename = scene.sourceFilename.replace('.', '_')
# Compute the filename of the scene file
source_basepath = scene.watchFolder
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
source_filename_only = os.path.basename(clean_filename)
created_entities = []
previous_entity_id = azlmbr.entity.InvalidEntityId
first_mesh = True
# Make a list of mesh node paths
mesh_path_list = list(map(lambda node: node.get_path(), mesh_name_list))
# Assume the first mesh is the main mesh
main_mesh = mesh_name_list[0]
mesh_path = main_mesh.get_path()
# Create a unique mesh group name using the filename + node name
mesh_group_name = '{}_{}'.format(source_filename_only, main_mesh.get_name())
# Remove forbidden filename characters from the name since this will become a file on disk later
mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
# Add the MeshGroup to the manifest and give it a unique ID
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
# Set our current node as the only node that is included in this MeshGroup
scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
# Explicitly remove all other nodes to prevent implicit inclusions
for node in mesh_path_list:
if node != mesh_path:
scene_manifest.mesh_group_unselect_node(mesh_group, node)
# Create a LOD rule
lod_rule = scene_manifest.mesh_group_add_lod_rule(mesh_group)
# Loop all the mesh nodes after the first
for x in mesh_path_list[1:]:
# Add a new LOD level
lod = scene_manifest.lod_rule_add_lod(lod_rule)
# Select the current mesh for this LOD level
scene_manifest.lod_select_node(lod, x)
# Unselect every other mesh for this LOD level
for y in mesh_path_list:
if y != x:
scene_manifest.lod_unselect_node(lod, y)
# Create an editor entity
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
# Add an EditorMeshComponent to the entity
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
# The assetHint will be converted to an AssetId later during prefab loading
json_update = json.dumps({
"Controller": { "Configuration": { "ModelAsset": {
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
});
# Apply the JSON above to the component we created
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
if not result:
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
create_prefab(scene_manifest, source_filename_only, [entity_id])
# Convert the manifest to a JSON string and return it
new_manifest = scene_manifest.export()
return new_manifest
sceneJobHandler = None
def on_update_manifest(args):
try:
scene = args[0]
return update_manifest(scene)
except RuntimeError as err:
print (f'ERROR - {err}')
log_exception_traceback()
except:
log_exception_traceback()
global sceneJobHandler
sceneJobHandler = None
# try to create SceneAPI handler for processing
try:
import azlmbr.scene as sceneApi
if (sceneJobHandler == None):
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
sceneJobHandler.connect()
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
except:
sceneJobHandler = None
@@ -0,0 +1,95 @@
"""
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 traceback, logging, json
from typing import Tuple, List
import azlmbr.bus
from scene_api import scene_data as sceneData
from scene_api.scene_data import SceneGraphName
def log_exception_traceback():
"""
Outputs an exception stacktrace.
"""
data = traceback.format_exc()
logger = logging.getLogger('python')
logger.error(data)
def sanitize_name_for_disk(name: str):
"""
Removes illegal filename characters from a string.
:param name: String to clean.
:return: Name with illegal characters removed.
"""
return "".join(char for char in name if char not in "|<>:\"/?*\\")
def get_mesh_node_names(scene_graph: sceneData.SceneGraph) -> Tuple[List[SceneGraphName], List[str]]:
"""
Returns a tuple of all the mesh nodes as well as all the node paths
:param scene_graph: Scene graph to search
:return: Tuple of [Mesh Nodes, All Node Paths]
"""
import azlmbr.scene as sceneApi
import azlmbr.scene.graph
mesh_data_list = []
node = scene_graph.get_root()
children = []
paths = []
while node.IsValid():
# store children to process after siblings
if scene_graph.has_node_child(node):
children.append(scene_graph.get_node_child(node))
node_name = sceneData.SceneGraphName(scene_graph.get_node_name(node))
paths.append(node_name.get_path())
# store any node that has mesh data content
node_content = scene_graph.get_node_content(node)
if node_content.CastWithTypeName('MeshData'):
if scene_graph.is_node_end_point(node) is False:
if len(node_name.get_path()):
mesh_data_list.append(sceneData.SceneGraphName(scene_graph.get_node_name(node)))
# advance to next node
if scene_graph.has_node_sibling(node):
node = scene_graph.get_node_sibling(node)
elif children:
node = children.pop()
else:
node = azlmbr.scene.graph.NodeIndex()
return mesh_data_list, paths
def create_prefab(scene_manifest: sceneData.SceneManifest, prefab_name: str, entities: list) -> None:
prefab_filename = prefab_name + ".prefab"
created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", entities,
prefab_filename)
if created_template_id is None or created_template_id == azlmbr.prefab.InvalidTemplateId:
raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
# Convert the prefab to a JSON string
output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
if output is not None and output.IsSuccess():
json_string = output.GetValue()
uuid = azlmbr.math.Uuid_CreateRandom().ToString()
json_result = json.loads(json_string)
# Add a PrefabGroup to the manifest and store the JSON on it
scene_manifest.add_prefab_group(prefab_name, uuid, json_result)
else:
raise RuntimeError(
"SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
@@ -5,55 +5,17 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import os, traceback, binascii, sys, json, pathlib, logging
import azlmbr.math
import azlmbr.bus
import azlmbr.math
from scene_api.scene_data import PrimitiveShape, DecompositionMode
from scene_helpers import *
#
# SceneAPI Processor
#
def log_exception_traceback():
data = traceback.format_exc()
logger = logging.getLogger('python')
logger.error(data)
def get_mesh_node_names(sceneGraph):
import azlmbr.scene as sceneApi
import azlmbr.scene.graph
from scene_api import scene_data as sceneData
meshDataList = []
node = sceneGraph.get_root()
children = []
paths = []
while node.IsValid():
# store children to process after siblings
if sceneGraph.has_node_child(node):
children.append(sceneGraph.get_node_child(node))
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
paths.append(nodeName.get_path())
# store any node that has mesh data content
nodeContent = sceneGraph.get_node_content(node)
if nodeContent.CastWithTypeName('MeshData'):
if sceneGraph.is_node_end_point(node) is False:
if (len(nodeName.get_path())):
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
# advance to next node
if sceneGraph.has_node_sibling(node):
node = sceneGraph.get_node_sibling(node)
elif children:
node = children.pop()
else:
node = azlmbr.scene.graph.NodeIndex()
return meshDataList, paths
def add_material_component(entity_id):
# Create an override AZ::Render::EditorMaterialComponent
editor_material_component = azlmbr.entity.EntityUtilityBus(
@@ -64,24 +26,53 @@ def add_material_component(entity_id):
# this fills out the material asset to a known product AZMaterial asset relative path
json_update = json.dumps({
"Controller": { "Configuration": { "materials": [
{
"Key": {},
"Value": { "MaterialAsset":{
"assetHint": "materials/basic_grey.azmaterial"
}}
}]
}}
});
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_material_component, json_update)
"Controller": {"Configuration": {"materials": [
{
"Key": {},
"Value": {"MaterialAsset": {
"assetHint": "materials/basic_grey.azmaterial"
}}
}]
}}
})
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
editor_material_component, json_update)
if not result:
raise RuntimeError("UpdateComponentForEntity for editor_material_component failed")
def add_physx_meshes(scene_manifest: sceneData.SceneManifest, source_file_name: str, mesh_name_list: List, all_node_paths: List[str]):
first_mesh = mesh_name_list[0].get_path()
# Add a Box Primitive PhysX mesh with a comment
physx_box = scene_manifest.add_physx_primitive_mesh_group(source_file_name + "_box", PrimitiveShape.BOX, 0.0, None)
scene_manifest.physx_mesh_group_add_comment(physx_box, "This is a box primitive")
# Select the first mesh, unselect every other node
scene_manifest.physx_mesh_group_add_selected_node(physx_box, first_mesh)
for node in all_node_paths:
if node != first_mesh:
scene_manifest.physx_mesh_group_add_unselected_node(physx_box, node)
# Add a Convex Mesh PhysX mesh with a comment
convex_mesh = scene_manifest.add_physx_convex_mesh_group(source_file_name + "_convex", 0.08, .0004,
True, True, True, True, True, 24, True, "Glass")
scene_manifest.physx_mesh_group_add_comment(convex_mesh, "This is a convex mesh")
# Select/Unselect nodes using lists
all_except_first_mesh = [x for x in all_node_paths if x != first_mesh]
scene_manifest.physx_mesh_group_add_selected_unselected_nodes(convex_mesh, [first_mesh], all_except_first_mesh)
# Configure mesh decomposition for this mesh
scene_manifest.physx_mesh_group_decompose_meshes(convex_mesh, 512, 32, .002, 100100, DecompositionMode.TETRAHEDRON,
0.06, 0.055, 0.00015, 3, 3, True, False)
# Add a Triangle mesh
triangle = scene_manifest.add_physx_triangle_mesh_group(source_file_name + "_triangle", False, True, True, True, True, True)
scene_manifest.physx_mesh_group_add_selected_unselected_nodes(triangle, [first_mesh], all_except_first_mesh)
def update_manifest(scene):
import json
import uuid, os
import azlmbr.scene as sceneApi
import azlmbr.scene.graph
from scene_api import scene_data as sceneData
@@ -89,9 +80,9 @@ def update_manifest(scene):
# Get a list of all the mesh nodes, as well as all the nodes
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
scene_manifest = sceneData.SceneManifest()
clean_filename = scene.sourceFilename.replace('.', '_')
# Compute the filename of the scene file
source_basepath = scene.watchFolder
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
@@ -101,6 +92,8 @@ def update_manifest(scene):
previous_entity_id = azlmbr.entity.InvalidEntityId
first_mesh = True
add_physx_meshes(scene_manifest, source_filename_only, mesh_name_list, all_node_paths)
# Loop every mesh node in the scene
for activeMeshIndex in range(len(mesh_name_list)):
mesh_name = mesh_name_list[activeMeshIndex]
@@ -108,7 +101,7 @@ def update_manifest(scene):
# Create a unique mesh group name using the filename + node name
mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name())
# Remove forbidden filename characters from the name since this will become a file on disk later
mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
mesh_group_name = sanitize_name_for_disk(mesh_group_name)
# Add the MeshGroup to the manifest and give it a unique ID
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
@@ -129,37 +122,61 @@ def update_manifest(scene):
# Create an editor entity
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
# Add an EditorMeshComponent to the entity
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
# The assetHint will be converted to an AssetId later during prefab loading
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
entity_id, "AZ::Render::EditorMeshComponent")
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just
# created + the azmodel extension The MeshGroup we created will be output as a product in the asset's path
# named mesh_group_name.azmodel The assetHint will be converted to an AssetId later during prefab loading
json_update = json.dumps({
"Controller": { "Configuration": { "ModelAsset": {
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
});
"Controller": {"Configuration": {"ModelAsset": {
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel"}}}
})
# Apply the JSON above to the component we created
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
editor_mesh_component, json_update)
if not result:
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
# Add a physics component referencing the triangle mesh we made for the first node
if previous_entity_id is None:
physx_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
entity_id, "{FD429282-A075-4966-857F-D0BBF186CFE6} EditorColliderComponent")
json_update = json.dumps({
"ShapeConfiguration": {
"PhysicsAsset": {
"Asset": {
"assetHint": os.path.join(source_relative_path, source_filename_only + "_triangle.pxmesh")
}
}
}
})
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, physx_mesh_component, json_update)
if not result:
raise RuntimeError("UpdateComponentForEntity failed for PhysX mesh component")
# an example of adding a material component to override the default material
if previous_entity_id is not None and first_mesh:
first_mesh = False
add_material_component(entity_id)
# Get the transform component
transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
# Set this entity to be a child of the last entity we created
# This is just an example of how to do parenting and isn't necessarily useful to parent everything like this
if previous_entity_id is not None:
transform_json = json.dumps({
"Parent Entity" : previous_entity_id.to_json()
});
"Parent Entity": previous_entity_id.to_json()
})
# Apply the JSON update
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json)
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
transform_component, transform_json)
if not result:
raise RuntimeError("UpdateComponentForEntity failed for Transform component")
@@ -171,37 +188,23 @@ def update_manifest(scene):
created_entities.append(entity_id)
# Create a prefab with all our entities
prefab_filename = source_filename_only + ".prefab"
created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename)
if created_template_id == azlmbr.prefab.InvalidTemplateId:
raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
# Convert the prefab to a JSON string
output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
if output.IsSuccess():
jsonString = output.GetValue()
uuid = azlmbr.math.Uuid_CreateRandom().ToString()
jsonResult = json.loads(jsonString)
# Add a PrefabGroup to the manifest and store the JSON on it
scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult)
else:
raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
create_prefab(scene_manifest, source_filename_only, created_entities)
# Convert the manifest to a JSON string and return it
new_manifest = scene_manifest.export()
return new_manifest
sceneJobHandler = None
def on_update_manifest(args):
try:
scene = args[0]
return update_manifest(scene)
except RuntimeError as err:
print (f'ERROR - {err}')
print(f'ERROR - {err}')
log_exception_traceback()
except:
log_exception_traceback()
@@ -209,10 +212,12 @@ def on_update_manifest(args):
global sceneJobHandler
sceneJobHandler = None
# try to create SceneAPI handler for processing
try:
import azlmbr.scene as sceneApi
if (sceneJobHandler == None):
if sceneJobHandler is None:
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
sceneJobHandler.connect()
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
@@ -12,6 +12,7 @@ import pytest
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
from Atom.atom_utils.atom_constants import LIGHT_TYPES
logger = logging.getLogger(__name__)
@@ -159,3 +160,17 @@ class TestMaterialEditorBasicTests(object):
enable_prefab_system=False,
)
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
enable_prefab_system = False
@pytest.mark.test_case_id("C36529666")
class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module
@pytest.mark.test_case_id("C36525660")
class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module
@@ -18,6 +18,13 @@ LIGHT_TYPES = {
'simple_spot': 7,
}
# Qualiity Level settings for Diffuse Global Illumination level component
GLOBAL_ILLUMINATION_QUALITY = {
'Low': 0,
'Medium': 1,
'High': 2,
}
class AtomComponentProperties:
"""
@@ -116,6 +123,21 @@ class AtomComponentProperties:
}
return properties[property]
@staticmethod
def diffuse_global_illumination(property: str = 'name') -> str:
"""
Diffuse Global Illumination level component properties.
Controls global settings for Diffuse Probe Grid components.
- 'Quality Level' from atom_constants.py GLOBAL_ILLUMINATION_QUALITY
:param property: From the last element of the property tree path. Default 'name' for component name string.
:return: Full property path OR component name if no property specified.
"""
properties = {
'name': 'Diffuse Global Illumination',
'Quality Level': 'Controller|Configuration|Quality Level'
}
return properties[property]
@staticmethod
def diffuse_probe_grid(property: str = 'name') -> str:
"""
@@ -148,12 +170,17 @@ class AtomComponentProperties:
@staticmethod
def display_mapper(property: str = 'name') -> str:
"""
Display Mapper component properties.
Display Mapper level component properties.
- 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT
- 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
an Asset.id value corresponding to a lighting asset file.
:param property: From the last element of the property tree path. Default 'name' for component name string.
:return: Full property path OR component name if no property specified.
"""
properties = {
'name': 'Display Mapper',
'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT',
'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
}
return properties[property]
@@ -390,7 +417,7 @@ class AtomComponentProperties:
'name': 'PostFX Shape Weight Modifier',
'requires': [AtomComponentProperties.postfx_layer()],
'shapes': ['Axis Aligned Box Shape', 'Box Shape', 'Capsule Shape', 'Compound Shape', 'Cylinder Shape',
'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Vegetation Reference Shape'],
'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Shape Reference'],
}
return properties[property]
@@ -0,0 +1,109 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
class Tests:
creation_undo = (
"UNDO Level component addition success",
"UNDO Level component addition failed")
creation_redo = (
"REDO Level component addition success",
"REDO Level component addition failed")
diffuse_global_illumination_component = (
"Level has a Diffuse Global Illumination component",
"Level failed to find Diffuse Global Illumination component")
diffuse_global_illumination_quality = (
"Quality Level set",
"Quality Level could not be set")
enter_game_mode = (
"Entered game mode",
"Failed to enter game mode")
exit_game_mode = (
"Exited game mode",
"Couldn't exit game mode")
def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity():
"""
Summary:
Tests the Diffuse Global Illumination level component can be added to the level entity and is stable.
Test setup:
- Wait for Editor idle loop.
- Open the "Base" level.
Expected Behavior:
The component can be added, used in game mode, and has accurate required components.
Creation and deletion undo/redo should also work.
Test Steps:
1) Add Diffuse Global Illumination level component to the level entity.
2) UNDO the level component addition.
3) REDO the level component addition.
4) Set Quality Level property to Low
5) Enter/Exit game mode.
6) Look for errors and asserts.
:return: None
"""
import azlmbr.legacy.general as general
from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
from editor_python_test_tools.utils import Report, Tracer, TestHelper
from Atom.atom_utils.atom_constants import AtomComponentProperties, GLOBAL_ILLUMINATION_QUALITY
with Tracer() as error_tracer:
# Test setup begins.
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
TestHelper.init_idle()
TestHelper.open_level("", "Base")
# Test steps begin.
# 1. Add Diffuse Global Illumination level component to the level entity.
diffuse_global_illumination_component = EditorLevelEntity.add_component(
AtomComponentProperties.diffuse_global_illumination())
Report.critical_result(
Tests.diffuse_global_illumination_component,
EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
# 2. UNDO the level component addition.
# -> UNDO component addition.
general.undo()
general.idle_wait_frames(1)
Report.result(Tests.creation_undo,
not EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
# 3. REDO the level component addition.
# -> REDO component addition.
general.redo()
general.idle_wait_frames(1)
Report.result(Tests.creation_redo,
EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
# 4. Set Quality Level property to Low
diffuse_global_illumination_component.set_component_property_value(
AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low']))
quality = diffuse_global_illumination_component.get_component_property_value(
AtomComponentProperties.diffuse_global_illumination('Quality Level'))
Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low'])
# 5. Enter/Exit game mode.
TestHelper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
TestHelper.exit_game_mode(Tests.exit_game_mode)
# 6. Look for errors and asserts.
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
for error_info in error_tracer.errors:
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
for assert_info in error_tracer.asserts:
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity)
@@ -0,0 +1,124 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
class Tests:
creation_undo = (
"UNDO level component addition success",
"UNDO level component addition failed")
creation_redo = (
"REDO Level component addition success",
"REDO Level component addition failed")
display_mapper_component = (
"Level has a Display Mapper component",
"Level failed to find Display Mapper component")
ldr_color_grading_lut = (
"LDR color Grading LUT asset set",
"LDR color Grading LUT asset could not be set")
enable_ldr_color_grading_lut = (
"Enable LDR color grading LUT set",
"Enable LDR color grading LUT could not be set")
enter_game_mode = (
"Entered game mode",
"Failed to enter game mode")
exit_game_mode = (
"Exited game mode",
"Couldn't exit game mode")
def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
"""
Summary:
Tests the Display Mapper level component can be added to the level entity and has the expected functionality.
Test setup:
- Wait for Editor idle loop.
- Open the "Base" level.
Expected Behavior:
The component can be added, used in game mode, and has accurate required components.
Creation and deletion undo/redo should also work.
Test Steps:
1) Add Display Mapper level component to the level entity.
2) UNDO the level component addition.
3) REDO the level component addition.
4) Set LDR color Grading LUT asset.
5) Set Enable LDR color grading LUT property True
6) Enter/Exit game mode.
7) Look for errors and asserts.
:return: None
"""
import os
import azlmbr.legacy.general as general
from editor_python_test_tools.asset_utils import Asset
from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
from editor_python_test_tools.utils import Report, Tracer, TestHelper
from Atom.atom_utils.atom_constants import AtomComponentProperties
with Tracer() as error_tracer:
# Test setup begins.
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
TestHelper.init_idle()
TestHelper.open_level("", "Base")
# Test steps begin.
# 1. Add Display Mapper level component to the level entity.
display_mapper_component = EditorLevelEntity.add_component(AtomComponentProperties.display_mapper())
Report.critical_result(
Tests.display_mapper_component,
EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
# 2. UNDO the level component addition.
# -> UNDO component addition.
general.undo()
general.idle_wait_frames(1)
Report.result(Tests.creation_undo, not EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
# 3. REDO the level component addition.
# -> REDO component addition.
general.redo()
general.idle_wait_frames(1)
Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
# 4. Set LDR color Grading LUT asset.
display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
display_mapper_component.set_component_property_value(
AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
Report.result(
Tests.ldr_color_grading_lut,
display_mapper_component.get_component_property_value(
AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
# 5. Set Enable LDR color grading LUT property True
display_mapper_component.set_component_property_value(
AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
Report.result(
Test.enable_ldr_color_grading_lut,
display_mapper_component.get_component_property_value(
AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
# 6. Enter/Exit game mode.
TestHelper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
TestHelper.exit_game_mode(Tests.exit_game_mode)
# 7. Look for errors and asserts.
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
for error_info in error_tracer.errors:
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
for assert_info in error_tracer.asserts:
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AtomEditorComponentsLevel_DisplayMapper_AddedToEntity)
@@ -5,16 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
class Tests:
camera_creation = (
"Camera Entity successfully created",
"Camera Entity failed to be created")
camera_component_added = (
"Camera component was added to entity",
"Camera component failed to be added to entity")
camera_component_check = (
"Entity has a Camera component",
"Entity failed to find Camera component")
creation_undo = (
"UNDO Entity creation success",
"UNDO Entity creation failed")
@@ -39,6 +31,12 @@ class Tests:
is_hidden = (
"Entity is hidden",
"Entity was not hidden")
ldr_color_grading_lut = (
"LDR color Grading LUT asset set",
"LDR color Grading LUT asset could not be set")
enable_ldr_color_grading_lut = (
"Enable LDR color grading LUT set",
"Enable LDR color grading LUT could not be set")
entity_deleted = (
"Entity deleted",
"Entity was not deleted")
@@ -68,19 +66,23 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
2) Add Display Mapper component to Display Mapper entity.
3) UNDO the entity creation and component addition.
4) REDO the entity creation and component addition.
5) Enter/Exit game mode.
6) Test IsHidden.
7) Test IsVisible.
8) Delete Display Mapper entity.
9) UNDO deletion.
10) REDO deletion.
11) Look for errors and asserts.
5) Set LDR color Grading LUT asset.
6) Set Enable LDR color grading LUT property True
7) Enter/Exit game mode.
8) Test IsHidden.
9) Test IsVisible.
10) Delete Display Mapper entity.
11) UNDO deletion.
12) REDO deletion.
13) Look for errors and asserts.
:return: None
"""
import os
import azlmbr.legacy.general as general
from editor_python_test_tools.asset_utils import Asset
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import Report, Tracer, TestHelper
from Atom.atom_utils.atom_constants import AtomComponentProperties
@@ -97,7 +99,7 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
Report.critical_result(Tests.display_mapper_creation, display_mapper_entity.exists())
# 2. Add Display Mapper component to Display Mapper entity.
display_mapper_entity.add_component(AtomComponentProperties.display_mapper())
display_mapper_component = display_mapper_entity.add_component(AtomComponentProperties.display_mapper())
Report.critical_result(
Tests.display_mapper_component,
display_mapper_entity.has_component(AtomComponentProperties.display_mapper()))
@@ -126,33 +128,51 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
general.idle_wait_frames(1)
Report.result(Tests.creation_redo, display_mapper_entity.exists())
# 5. Enter/Exit game mode.
# 5. Set LDR color Grading LUT asset.
display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
display_mapper_component.set_component_property_value(
AtomComponentProperties.display_mapper("LDR color Grading LUT"), display_mapper_asset.id)
Report.result(
Tests.ldr_color_grading_lut,
display_mapper_component.get_component_property_value(
AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id)
# 6. Set Enable LDR color grading LUT property True
display_mapper_component.set_component_property_value(
AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
Report.result(
Tests.enable_ldr_color_grading_lut,
display_mapper_component.get_component_property_value(
AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
# 7. Enter/Exit game mode.
TestHelper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
TestHelper.exit_game_mode(Tests.exit_game_mode)
# 6. Test IsHidden.
# 8. Test IsHidden.
display_mapper_entity.set_visibility_state(False)
Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
# 7. Test IsVisible.
# 9. Test IsVisible.
display_mapper_entity.set_visibility_state(True)
general.idle_wait_frames(1)
Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
# 8. Delete Display Mapper entity.
# 10. Delete Display Mapper entity.
display_mapper_entity.delete()
Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
# 9. UNDO deletion.
# 11. UNDO deletion.
general.undo()
Report.result(Tests.deletion_undo, display_mapper_entity.exists())
# 10. REDO deletion.
# 12. REDO deletion.
general.redo()
Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
# 11. Look for errors and asserts.
# 13. Look for errors and asserts.
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
for error_info in error_tracer.errors:
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
@@ -107,7 +107,6 @@ class EditorComponent:
return type_ids
def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
"""
Converts a vector3-like element into a azlmbr.math.Vector3
@@ -120,6 +119,7 @@ def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
else:
raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
class EditorEntity:
"""
Entity class is used to create and interact with Editor Entities.
@@ -470,3 +470,99 @@ class EditorEntity:
assert self.id.isValid(), "A valid entity id is required to focus on its owning prefab."
focus_prefab_result = azlmbr.prefab.PrefabFocusPublicRequestBus(bus.Broadcast, "FocusOnOwningPrefab", self.id)
assert focus_prefab_result.IsSuccess(), f"Prefab operation 'FocusOnOwningPrefab' failed. Error: {focus_prefab_result.GetError()}"
class EditorLevelEntity:
"""
EditorLevel class used to add and fetch level components.
Level entity is a special entity that you do not create/destroy independently of larger systems of level creation.
This collects a number of staticmethods that do not rely on entityId since Level entity is found internally by
EditorLevelComponentAPIBus requests.
"""
@staticmethod
def get_type_ids(component_names: list) -> list:
"""
Used to get type ids of given components list for EntityType Level
:param: component_names: List of components to get type ids
:return: List of type ids of given components.
"""
type_ids = editor.EditorComponentAPIBus(
bus.Broadcast, "FindComponentTypeIdsByEntityType", component_names, azlmbr.entity.EntityType().Level
)
return type_ids
@staticmethod
def add_component(component_name: str) -> EditorComponent:
"""
Used to add new component to Level.
:param component_name: String of component name to add.
:return: Component object of newly added component.
"""
component = EditorLevelEntity.add_components([component_name])[0]
return component
@staticmethod
def add_components(component_names: list) -> List[EditorComponent]:
"""
Used to add multiple components
:param: component_names: List of components to add to level
:return: List of newly added components to the level
"""
components = []
type_ids = EditorLevelEntity.get_type_ids(component_names)
for type_id in type_ids:
new_comp = EditorComponent()
new_comp.type_id = type_id
add_component_outcome = editor.EditorLevelComponentAPIBus(
bus.Broadcast, "AddComponentsOfType", [type_id]
)
assert (
add_component_outcome.IsSuccess()
), f"Failure: Could not add component: '{new_comp.get_component_name()}' to level"
new_comp.id = add_component_outcome.GetValue()[0]
components.append(new_comp)
return components
@staticmethod
def get_components_of_type(component_names: list) -> List[EditorComponent]:
"""
Used to get components of type component_name that already exists on the level
:param component_names: List of names of components to check
:return: List of Level Component objects of given component name
"""
component_list = []
type_ids = EditorLevelEntity.get_type_ids(component_names)
for type_id in type_ids:
component = EditorComponent()
component.type_id = type_id
get_component_of_type_outcome = editor.EditorLevelComponentAPIBus(
bus.Broadcast, "GetComponentOfType", type_id
)
assert (
get_component_of_type_outcome.IsSuccess()
), f"Failure: Level does not have component:'{component.get_component_name()}'"
component.id = get_component_of_type_outcome.GetValue()
component_list.append(component)
return component_list
@staticmethod
def has_component(component_name: str) -> bool:
"""
Used to verify if the level has the specified component
:param component_name: Name of component to check for
:return: True, if level has specified component. Else, False
"""
type_ids = EditorLevelEntity.get_type_ids([component_name])
return editor.EditorLevelComponentAPIBus(bus.Broadcast, "HasComponentOfType", type_ids[0])
@staticmethod
def count_components_of_type(component_name: str) -> int:
"""
Used to get a count of the specified level component attached to the level
:param component_name: Name of component to check for
:return: integer count of occurences of level component attached to level or zero if none are present
"""
type_ids = EditorLevelEntity.get_type_ids([component_name])
return editor.EditorLevelComponentAPIBus(bus.Broadcast, "CountComponentsOfType", type_ids[0])
@@ -34,6 +34,38 @@ class TestHelper:
# JIRA: SPEC-2880
# general.idle_wait_frames(1)
@staticmethod
def create_level(level_name: str) -> bool:
"""
:param level_name: The name of the level to be created
:return: True if ECreateLevelResult returns 0, False otherwise with logging to report reason
"""
Report.info(f"Creating level {level_name}")
# Use these hardcoded values to pass expected values for old terrain system until new create_level API is
# available
heightmap_resolution = 1024
heightmap_meters_per_pixel = 1
terrain_texture_resolution = 4096
use_terrain = False
result = general.create_level_no_prompt(level_name, heightmap_resolution, heightmap_meters_per_pixel,
terrain_texture_resolution, use_terrain)
# Result codes are ECreateLevelResult defined in CryEdit.h
if result == 1:
Report.info(f"{level_name} level already exists")
elif result == 2:
Report.info("Failed to create directory")
elif result == 3:
Report.info("Directory length is too long")
elif result != 0:
Report.info("Unknown error, failed to create level")
else:
Report.info(f"{level_name} level created successfully")
return result == 0
@staticmethod
def open_level(directory : str, level : str):
# type: (str, str) -> None
@@ -98,38 +98,32 @@ class FileManagement:
"""
file_map = FileManagement._load_file_map()
backup_path = FileManagement.backup_folder_path
backup_file_name = "{}.bak".format(file_name)
backup_file = os.path.join(backup_path, backup_file_name)
# If backup directory DNE, make one
if not os.path.exists(backup_path):
os.mkdir(backup_path)
# If "traditional" backup file exists, delete it (myFile.txt.bak)
if os.path.exists(backup_file):
fs.delete([backup_file], True, False)
# Find my next storage name (myFile_1.txt.bak)
backup_storage_file_name = FileManagement._next_available_name(backup_file_name, file_map)
if backup_storage_file_name is None:
# Find my next storage name (myFile_1.txt)
backup_file_name = FileManagement._next_available_name(file_name, file_map)
if backup_file_name is None:
# If _next_available_name returns None, we have backed up MAX_BACKUPS of files name [file_name]
raise Exception(
"FileManagement class ran out of backups per name. Max: {}".format(FileManagement.MAX_BACKUPS)
)
backup_storage_file = os.path.join(backup_path, backup_storage_file_name)
# If this backup file already exists, delete it.
backup_storage_file = "{}.bak".format(os.path.normpath(os.path.join(backup_path, backup_file_name)))
if os.path.exists(backup_storage_file):
# This file should not exists, but if it does it's about to get clobbered!
fs.unlock_file(backup_storage_file)
# Create "traditional" backup file (myFile.txt.bak)
fs.create_backup(os.path.join(file_path, file_name), backup_path)
# Copy "traditional" backup file into storage backup (myFile_1.txt.bak)
FileManagement._copy_file(backup_file_name, backup_path, backup_storage_file_name, backup_path)
fs.lock_file(backup_storage_file)
# Delete "traditional" back up file
fs.unlock_file(backup_file)
fs.delete([backup_file], True, False)
fs.delete([backup_storage_file], True, False)
# Create backup file (myFile_1.txt.bak)
original_file = os.path.normpath(os.path.join(file_path, file_name))
fs.create_backup(original_file, backup_path, backup_file_name)
# Update file map with new file
file_map[os.path.join(file_path, file_name)] = backup_storage_file_name
file_map[original_file] = backup_file_name
FileManagement._save_file_map(file_map)
# Unlock original file to get it ready to be edited by the test
fs.unlock_file(os.path.join(file_path, file_name))
fs.unlock_file(original_file)
@staticmethod
def _restore_file(file_name, file_path):
@@ -143,20 +137,15 @@ class FileManagement:
"""
file_map = FileManagement._load_file_map()
backup_path = FileManagement.backup_folder_path
src_file = os.path.join(file_path, file_name)
src_file = os.path.normpath(os.path.join(file_path, file_name))
if src_file in file_map:
backup_file = os.path.join(backup_path, file_map[src_file])
if os.path.exists(backup_file):
fs.unlock_file(backup_file)
fs.unlock_file(src_file)
# Make temporary copy of backed up file to restore from
temp_file = "{}.bak".format(file_name)
FileManagement._copy_file(file_map[src_file], backup_path, temp_file, backup_path)
fs.restore_backup(src_file, backup_path)
fs.lock_file(src_file)
# Delete backup file
fs.delete([os.path.join(backup_path, temp_file)], True, False)
backup_file_name = file_map[src_file]
backup_file = "{}.bak".format(os.path.join(backup_path, backup_file_name))
fs.unlock_file(src_file)
if fs.restore_backup(src_file, backup_path, backup_file_name):
fs.delete([backup_file], True, False)
# Remove from file map
del file_map[src_file]
FileManagement._save_file_map(file_map)
@@ -24,6 +24,7 @@ def CreatePrefab_WithSingleEntity():
# Creates a prefab from the new entity
Prefab.create_prefab(car_prefab_entities, CAR_PREFAB_FILE_NAME)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(CreatePrefab_WithSingleEntity)
@@ -0,0 +1,144 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
class HeightTests:
single_gradient_height_correct = (
"Successfully retrieved height for gradient1.",
"Failed to retrieve height for gradient1."
)
double_gradient_height_correct = (
"Successfully retrieved height when two gradients exist.",
"Failed to retrieve height when two gradients exist."
)
triple_gradient_height_correct = (
"Successfully retrieved height when three gradients exist.",
"Failed to retrieve height when three gradients exist."
)
terrain_data_changed_call_count_correct = (
"OnTerrainDataChanged called expected number of times.",
"OnTerrainDataChanged call count incorrect."
)
def TerrainHeightGradientList_AddRemoveGradientWorks():
"""
Summary:
Test aspects of the TerrainHeightGradientList through the BehaviorContext and the Property Tree.
:return: None
"""
import os
import math as sys_math
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.math as math
import azlmbr.terrain as terrain
import azlmbr.editor as editor
import azlmbr.vegetation as vegetation
import azlmbr.entity as EntityId
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
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_entity_utils import EditorEntity
terrain_changed_call_count = 0
expected_terrain_changed_calls = 0
aabb_component_name = "Axis Aligned Box Shape"
gradientlist_component_name = "Terrain Height Gradient List"
layerspawner_component_name = "Terrain Layer Spawner"
gradient_value_path = "Configuration|Value"
def create_entity_at(entity_name, components_to_add, x, y, z):
entity = hydra.Entity(entity_name)
entity.create_entity(math.Vector3(x, y, z), components_to_add)
return entity
def on_terrain_changed(args):
nonlocal terrain_changed_call_count
terrain_changed_call_count += 1
def set_component_path_val(entity, component, path, value):
entity.get_set_test(component, path, value)
def set_gradients_check_height(main_entity, gradient_list, expected_height, test_results):
nonlocal expected_terrain_changed_calls
test_tolerance = 0.01
gradient_list_path = "Configuration|Gradient Entities"
set_component_path_val(main_entity, 1, gradient_list_path, gradient_list)
expected_terrain_changed_calls += 1
# Wait until the terrain data has been updated.
helper.wait_for_condition(lambda: terrain_changed_call_count == expected_terrain_changed_calls, 2.0)
# Get the height at the origin.
height = terrain.TerrainDataRequestBus(bus.Broadcast, "GetHeightFromFloats", 0.0, 0.0, 0)
Report.result(test_results, sys_math.isclose(height, expected_height, abs_tol=test_tolerance))
helper.init_idle()
# Open a level.
helper.open_level("Physics", "Base")
helper.wait_for_condition(lambda: general.get_current_level_name() == "Base", 2.0)
general.idle_wait_frames(1)
# Add a terrain world component
world_component = hydra.add_level_component("Terrain World")
aabb_height = 1024.0
box_dimensions = math.Vector3(1.0, 1.0, aabb_height);
# Create a main entity with a LayerSpawner, AAbb and HeightGradientList.
main_entity = create_entity_at("entity2", [layerspawner_component_name, gradientlist_component_name, aabb_component_name], 0.0, 0.0, aabb_height/2.0)
# Create three gradient entities.
gradient_entity1 = create_entity_at("Constant Gradient1", ["Constant Gradient"], 0.0, 0.0, 0.0);
gradient_entity2 = create_entity_at("Constant Gradient2", ["Constant Gradient"], 0.0, 0.0, 0.0);
gradient_entity3 = create_entity_at("Constant Gradient3", ["Constant Gradient"], 0.0, 0.0, 0.0);
# Give everything a chance to finish initializing.
general.idle_wait_frames(1)
# Set the gradients to different values.
gradient_values = [0.5, 0.8, 0.3]
set_component_path_val(gradient_entity1, 0, gradient_value_path, gradient_values[0])
set_component_path_val(gradient_entity2, 0, gradient_value_path, gradient_values[1])
set_component_path_val(gradient_entity3, 0, gradient_value_path, gradient_values[2])
# Give the TerrainSystem time to tick.
general.idle_wait_frames(1)
# Set the dimensions of the Aabb.
set_component_path_val(main_entity, 2, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions)
# Set up a handler to wait for notifications from the TerrainSystem.
handler = azlmbr.terrain.TerrainDataNotificationBusHandler()
handler.connect()
handler.add_callback("OnTerrainDataChanged", on_terrain_changed)
# Add a gradient to GradientList, then check the height returned from the TerrainSystem is correct.
set_gradients_check_height(main_entity, [gradient_entity1.id], aabb_height * gradient_values[0], HeightTests.single_gradient_height_correct)
# Add gradient2 and check height at the origin, this should have changed to match the second gradient value.
set_gradients_check_height(main_entity, [gradient_entity1.id, gradient_entity2.id], aabb_height * gradient_values[1], HeightTests.double_gradient_height_correct)
# Add gradient3, the height should still be the second value, as that was the highest.
set_gradients_check_height(main_entity, [gradient_entity1.id, gradient_entity2.id, gradient_entity3.id], aabb_height * gradient_values[1], HeightTests.triple_gradient_height_correct)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(TerrainHeightGradientList_AddRemoveGradientWorks)
@@ -72,7 +72,7 @@ def Terrain_SupportsPhysics():
# 2) Create 2 test entities, one parent at 512.0, 512.0, 50.0 and one child at the default position and add the required components
entity1_components_to_add = ["Axis Aligned Box Shape", "Terrain Layer Spawner", "Terrain Height Gradient List", "Terrain Physics Heightfield Collider", "PhysX Heightfield Collider"]
entity2_components_to_add = ["Vegetation Reference Shape", "Gradient Transform Modifier", "FastNoise Gradient"]
entity2_components_to_add = ["Shape Reference", "Gradient Transform Modifier", "FastNoise Gradient"]
ball_components_to_add = ["Sphere Shape", "PhysX Collider", "PhysX Rigid Body"]
terrain_spawner_entity = hydra.Entity("TestEntity1")
terrain_spawner_entity.create_entity(azmath.Vector3(512.0, 512.0, 50.0), entity1_components_to_add)
@@ -27,3 +27,6 @@ class TestAutomation(EditorTestSuite):
class test_Terrain_SupportsPhysics(EditorSharedTest):
from .EditorScripts import Terrain_SupportsPhysics as test_module
class test_TerrainHeightGradientList_AddRemoveGradientWorks(EditorSharedTest):
from .EditorScripts import TerrainHeightGradientList_AddRemoveGradientWorks as test_module
@@ -15,6 +15,7 @@ import logging
# Import LyTestTools
import ly_test_tools.o3de.asset_processor as asset_processor_commands
import ly_test_tools.o3de.asset_processor_utils
logger = logging.getLogger(__name__)
@@ -36,5 +37,8 @@ def asset_processor(request: pytest.fixture, workspace: pytest.fixture) -> asset
ap.stop()
request.addfinalizer(teardown)
for n in ly_test_tools.o3de.asset_processor_utils.processList:
assert not ly_test_tools.o3de.asset_processor_utils.check_ap_running(n), f"{n} process did not shutdown correctly."
return ap
@@ -8,6 +8,8 @@ General Asset Processor Batch Tests
"""
# Import builtin libraries
from os import listdir
import pytest
import logging
import os
@@ -724,3 +726,11 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
assert error_line_found, "The error could not be found in the newest run of the AP Batch log."
@pytest.mark.assetpipeline
def test_AssetProcessor_Log_On_Failure(self, asset_processor, ap_setup_fixture, workspace):
asset_processor.prepare_test_environment(ap_setup_fixture["tests_dir"], "test_AP_Logs")
result, output = asset_processor.batch_process(expect_failure=True, capture_output=True)
assert result == False, f'AssetProcessorBatch should have failed because there is a bad asset, output was {output}'
jobLogs = listdir(workspace.paths.ap_job_logs() + "/test_AP_Logs")
assert not len(jobLogs) == 0, 'No job logs where output during failure.'
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c6b33c6137d6bd8c696f180c30a23089c95c1af398a630b4b13e080bec3254d
size 18220
@@ -8,7 +8,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
import os
import logging
import subprocess
import sys
import pytest
import time
@@ -128,7 +128,8 @@ class TestAutomationBase:
errors.append(TestRunError("FAILED TEST", error_str))
if return_code and return_code != TestAutomationBase.TEST_FAIL_RETCODE: # Crashed
crash_info = "-- No crash log available --"
crash_log = os.path.join(workspace.paths.project_log(), 'error.log')
crash_log = workspace.paths.crash_log()
try:
waiter.wait_for(lambda: os.path.exists(crash_log), timeout=TestAutomationBase.WAIT_FOR_CRASH_LOG)
except AssertionError:
@@ -72,9 +72,9 @@ def DynamicSliceInstanceSpawner_Embedded_E2E():
# 1) Create a new, temporary level
lvl_name = "tmp_level"
helper.init_idle()
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
level_created = helper.create_level(lvl_name)
general.idle_wait(1.0)
Report.critical_result(Tests.level_created, level_created == 0)
Report.critical_result(Tests.level_created, level_created)
general.set_current_view_position(512.0, 480.0, 38.0)
# 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
@@ -73,9 +73,9 @@ def DynamicSliceInstanceSpawner_External_E2E():
# 1) Create a new, temporary level
lvl_name = "tmp_level"
helper.init_idle()
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
level_created = helper.create_level(lvl_name)
general.idle_wait(1.0)
Report.critical_result(Tests.level_created, level_created == 0)
Report.critical_result(Tests.level_created, level_created)
general.set_current_view_position(512.0, 480.0, 38.0)
# 2) Create a new entity with required vegetation area components and switch the Vegetation Asset List Source
@@ -76,9 +76,9 @@ def LayerBlender_E2E_Editor():
# 1) Create a new, temporary level
lvl_name = "tmp_level"
helper.init_idle()
level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
level_created = helper.create_level(lvl_name)
general.idle_wait(1.0)
Report.critical_result(Tests.level_created, level_created == 0)
Report.critical_result(Tests.level_created, level_created)
general.set_current_view_position(500.49, 498.69, 46.66)
general.set_current_view_rotation(-42.05, 0.00, -36.33)
@@ -78,7 +78,7 @@ def LayerSpawner_InheritBehaviorFlag():
# Create Vegetation area and assign a valid asset
veg_1 = hydra.Entity("veg_1")
veg_1.create_entity(
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"]
)
set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice"))
veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
@@ -86,7 +86,7 @@ def LayerSpawner_InheritBehaviorFlag():
# Create second vegetation area and assign a valid asset
veg_2 = hydra.Entity("veg_2")
veg_2.create_entity(
position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"]
)
set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice"))
veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
@@ -9,7 +9,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
def LayerSpawner_InstancesPlantInAllSupportedShapes():
"""
Summary:
The level is loaded and vegetation area is created. Then the Vegetation Reference Shape
The level is loaded and vegetation area is created. Then the Shape Reference
component of vegetation area is pinned with entities of different shape components to check
if the vegetation plants in different shaped areas.
@@ -67,7 +67,7 @@ def LayerSpawner_InstancesPlantInAllSupportedShapes():
10.0, 10.0, 10.0,
asset_path)
vegetation.remove_component("Box Shape")
vegetation.add_component("Vegetation Reference Shape")
vegetation.add_component("Shape Reference")
# Create surface for planting on
dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
@@ -18,6 +18,17 @@ from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, E
class TestAutomation(EditorTestSuite):
enable_prefab_system = False
# Helpers for test asset cleanup
def cleanup_test_level(self, workspace):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
True, True)
def cleanup_test_slices(self, workspace):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices",
"TestSlice_1.slice")], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices",
"TestSlice_2.slice")], True, True)
class test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(EditorParallelTest):
from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module
@@ -37,10 +48,7 @@ class TestAutomation(EditorTestSuite):
class test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(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", "slices",
"TestSlice_1.slice")], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices",
"TestSlice_2.slice")], True, True)
TestAutomation.cleanup_test_slices(self, workspace)
from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest):
@@ -148,29 +156,32 @@ class TestAutomation(EditorTestSuite):
class test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(EditorParallelTest):
from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module
@pytest.mark.xfail(reason="Intermittently fails to create level")
class test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(EditorSingleTest):
from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module
# Custom teardown to remove test level 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)
# Custom setup/teardown to remove test level created during test
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
TestAutomation.cleanup_test_level(self, workspace)
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
TestAutomation.cleanup_test_level(self, workspace)
@pytest.mark.xfail(reason="Intermittently fails to create level")
class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
# Custom teardown to remove test level 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)
# Custom setup/teardown to remove test level created during test
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
TestAutomation.cleanup_test_level(self, workspace)
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
TestAutomation.cleanup_test_level(self, workspace)
@pytest.mark.xfail(reason="Intermittently fails to create level")
class test_LayerBlender_E2E_Editor(EditorSingleTest):
from .EditorScripts import LayerBlender_E2E_Editor as test_module
# Custom teardown to remove test level created during test
# Custom setup/teardown to remove test level created during test
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
TestAutomation.cleanup_test_level(self, workspace)
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)
TestAutomation.cleanup_test_level(self, workspace)
@@ -96,7 +96,7 @@ def AreaNodes_DependentComponentsAdded():
'SpawnerAreaNode': [
'Vegetation Layer Spawner',
'Vegetation Asset List',
'Vegetation Reference Shape'
'Shape Reference'
],
'MeshBlockerAreaNode': [
'Vegetation Layer Blocker (Mesh)',
@@ -104,7 +104,7 @@ def AreaNodes_DependentComponentsAdded():
],
'BlockerAreaNode': [
'Vegetation Layer Blocker',
'Vegetation Reference Shape'
'Shape Reference'
]
}
@@ -82,7 +82,7 @@ def Edit_DisabledNodeDuplication():
nodes = {
'SpawnerAreaNode': 'Vegetation Asset List',
'MeshBlockerAreaNode': 'Mesh',
'BlockerAreaNode': 'Vegetation Reference Shape',
'BlockerAreaNode': 'Shape Reference',
'FastNoiseGradientNode': 'Gradient Transform Modifier',
'ImageGradientNode': 'Gradient Transform Modifier',
'PerlinNoiseGradientNode': 'Gradient Transform Modifier',
@@ -104,7 +104,7 @@ def GradientNodes_DependentComponentsAdded():
# we will be checking for
commonComponents = [
'Gradient Transform Modifier',
'Vegetation Reference Shape'
'Shape Reference'
]
componentNames = []
for name in gradients:
@@ -114,7 +114,7 @@ def GradientNodes_DependentComponentsAdded():
# Create nodes for the gradients that have additional required dependencies and check if
# the Entity created by adding the node has the appropriate Component and required
# Gradient Transform Modifier and Vegetation Reference Shape components added automatically to it
# Gradient Transform Modifier and Shape Reference components added automatically to it
newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId)
x = 10.0
y = 10.0
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7e169277bca473325281d5fe043cffc9196bd3ef46f6bffbea6e0b5e3b7194a1
size 62700
@@ -0,0 +1,8 @@
{
"values": [
{
"$type": "ScriptProcessorRule",
"scriptFilename": "Editor/Scripts/auto_lod.py"
}
]
}
@@ -10,6 +10,8 @@
#include "EditorPreferencesPageViewportManipulator.h"
#include <AzToolsFramework/Viewport/ViewportSettings.h>
// Editor
#include "EditorViewportSettings.h"
#include "Settings.h"
@@ -19,7 +21,17 @@ void CEditorPreferencesPage_ViewportManipulator::Reflect(AZ::SerializeContext& s
serialize.Class<Manipulators>()
->Version(1)
->Field("LineBoundWidth", &Manipulators::m_manipulatorLineBoundWidth)
->Field("CircleBoundWidth", &Manipulators::m_manipulatorCircleBoundWidth);
->Field("CircleBoundWidth", &Manipulators::m_manipulatorCircleBoundWidth)
->Field("LinearManipulatorAxisLength", &Manipulators::m_linearManipulatorAxisLength)
->Field("PlanarManipulatorAxisLength", &Manipulators::m_planarManipulatorAxisLength)
->Field("SurfaceManipulatorRadius", &Manipulators::m_surfaceManipulatorRadius)
->Field("SurfaceManipulatorOpacity", &Manipulators::m_surfaceManipulatorOpacity)
->Field("LinearManipulatorConeLength", &Manipulators::m_linearManipulatorConeLength)
->Field("LinearManipulatorConeRadius", &Manipulators::m_linearManipulatorConeRadius)
->Field("ScaleManipulatorBoxHalfExtent", &Manipulators::m_scaleManipulatorBoxHalfExtent)
->Field("RotationManipulatorRadius", &Manipulators::m_rotationManipulatorRadius)
->Field("ManipulatorViewBaseScale", &Manipulators::m_manipulatorViewBaseScale)
->Field("FlipManipulatorAxesTowardsView", &Manipulators::m_flipManipulatorAxesTowardsView);
serialize.Class<CEditorPreferencesPage_ViewportManipulator>()->Version(2)->Field(
"Manipulators", &CEditorPreferencesPage_ViewportManipulator::m_manipulators);
@@ -36,7 +48,55 @@ void CEditorPreferencesPage_ViewportManipulator::Reflect(AZ::SerializeContext& s
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_manipulatorCircleBoundWidth, "Circle Bound Width",
"Manipulator Circle Bound Width")
->Attribute(AZ::Edit::Attributes::Min, 0.001f)
->Attribute(AZ::Edit::Attributes::Max, 2.0f);
->Attribute(AZ::Edit::Attributes::Max, 2.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_linearManipulatorAxisLength, "Linear Manipulator Axis Length",
"Length of default Linear Manipulator (for Translation and Scale Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.1f)
->Attribute(AZ::Edit::Attributes::Max, 5.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_planarManipulatorAxisLength, "Planar Manipulator Axis Length",
"Length of default Planar Manipulator (for Translation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.1f)
->Attribute(AZ::Edit::Attributes::Max, 5.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_surfaceManipulatorRadius, "Surface Manipulator Radius",
"Radius of default Surface Manipulator (for Translation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.05f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_surfaceManipulatorOpacity, "Surface Manipulator Opacity",
"Opacity of default Surface Manipulator (for Translation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_linearManipulatorConeLength, "Linear Manipulator Cone Length",
"Length of cone for default Linear Manipulator (for Translation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.05f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_linearManipulatorConeRadius, "Linear Manipulator Cone Radius",
"Radius of cone for default Linear Manipulator (for Translation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.05f)
->Attribute(AZ::Edit::Attributes::Max, 0.5f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_scaleManipulatorBoxHalfExtent, "Scale Manipulator Box Half Extent",
"Half extent of box for default Scale Manipulator")
->Attribute(AZ::Edit::Attributes::Min, 0.05f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_rotationManipulatorRadius, "Rotation Manipulator Radius",
"Radius of default Angular Manipulators (for Rotation Manipulators)")
->Attribute(AZ::Edit::Attributes::Min, 0.5f)
->Attribute(AZ::Edit::Attributes::Max, 5.0f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &Manipulators::m_manipulatorViewBaseScale, "Manipulator View Base Scale",
"The base scale to apply to all Manipulator Views (default is 1.0)")
->Attribute(AZ::Edit::Attributes::Min, 0.5f)
->Attribute(AZ::Edit::Attributes::Max, 2.0f)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &Manipulators::m_flipManipulatorAxesTowardsView, "Flip Manipulator Axes Towards View",
"Determines whether Planar and Linear Manipulators should switch to face the view (camera) in the Editor");
editContext
->Class<CEditorPreferencesPage_ViewportManipulator>("Manipulator Viewport Preferences", "Manipulator Viewport Preferences")
@@ -82,10 +142,32 @@ void CEditorPreferencesPage_ViewportManipulator::OnApply()
{
SandboxEditor::SetManipulatorLineBoundWidth(m_manipulators.m_manipulatorLineBoundWidth);
SandboxEditor::SetManipulatorCircleBoundWidth(m_manipulators.m_manipulatorCircleBoundWidth);
AzToolsFramework::SetLinearManipulatorAxisLength(m_manipulators.m_linearManipulatorAxisLength);
AzToolsFramework::SetPlanarManipulatorAxisLength(m_manipulators.m_planarManipulatorAxisLength);
AzToolsFramework::SetSurfaceManipulatorRadius(m_manipulators.m_surfaceManipulatorRadius);
AzToolsFramework::SetSurfaceManipulatorOpacity(m_manipulators.m_surfaceManipulatorOpacity);
AzToolsFramework::SetLinearManipulatorConeLength(m_manipulators.m_linearManipulatorConeLength);
AzToolsFramework::SetLinearManipulatorConeRadius(m_manipulators.m_linearManipulatorConeRadius);
AzToolsFramework::SetScaleManipulatorBoxHalfExtent(m_manipulators.m_scaleManipulatorBoxHalfExtent);
AzToolsFramework::SetRotationManipulatorRadius(m_manipulators.m_rotationManipulatorRadius);
AzToolsFramework::SetFlipManipulatorAxesTowardsView(m_manipulators.m_flipManipulatorAxesTowardsView);
AzToolsFramework::SetManipulatorViewBaseScale(m_manipulators.m_manipulatorViewBaseScale);
}
void CEditorPreferencesPage_ViewportManipulator::InitializeSettings()
{
m_manipulators.m_manipulatorLineBoundWidth = SandboxEditor::ManipulatorLineBoundWidth();
m_manipulators.m_manipulatorCircleBoundWidth = SandboxEditor::ManipulatorCircleBoundWidth();
m_manipulators.m_linearManipulatorAxisLength = AzToolsFramework::LinearManipulatorAxisLength();
m_manipulators.m_planarManipulatorAxisLength = AzToolsFramework::PlanarManipulatorAxisLength();
m_manipulators.m_surfaceManipulatorRadius = AzToolsFramework::SurfaceManipulatorRadius();
m_manipulators.m_surfaceManipulatorOpacity = AzToolsFramework::SurfaceManipulatorOpacity();
m_manipulators.m_linearManipulatorConeLength = AzToolsFramework::LinearManipulatorConeLength();
m_manipulators.m_linearManipulatorConeRadius = AzToolsFramework::LinearManipulatorConeRadius();
m_manipulators.m_scaleManipulatorBoxHalfExtent = AzToolsFramework::ScaleManipulatorBoxHalfExtent();
m_manipulators.m_rotationManipulatorRadius = AzToolsFramework::RotationManipulatorRadius();
m_manipulators.m_flipManipulatorAxesTowardsView = AzToolsFramework::FlipManipulatorAxesTowardsView();
m_manipulators.m_manipulatorViewBaseScale = AzToolsFramework::ManipulatorViewBaseScale();
}
@@ -41,6 +41,16 @@ private:
float m_manipulatorLineBoundWidth = 0.0f;
float m_manipulatorCircleBoundWidth = 0.0f;
float m_linearManipulatorAxisLength = 0.0f;
float m_planarManipulatorAxisLength = 0.0f;
float m_surfaceManipulatorRadius = 0.0f;
float m_surfaceManipulatorOpacity = 0.0f;
float m_linearManipulatorConeLength = 0.0f;
float m_linearManipulatorConeRadius = 0.0f;
float m_scaleManipulatorBoxHalfExtent = 0.0f;
float m_rotationManipulatorRadius = 0.0f;
float m_manipulatorViewBaseScale = 0.0f;
bool m_flipManipulatorAxesTowardsView = false;
};
Manipulators m_manipulators;
+93 -107
View File
@@ -12,6 +12,7 @@
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/string/string_view.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
namespace SandboxEditor
{
@@ -57,31 +58,6 @@ namespace SandboxEditor
constexpr AZStd::string_view CameraDefaultStartingPositionY = "/Amazon/Preferences/Editor/Camera/DefaultStartingPosition/y";
constexpr AZStd::string_view CameraDefaultStartingPositionZ = "/Amazon/Preferences/Editor/Camera/DefaultStartingPosition/z";
template<typename T>
void SetRegistry(const AZStd::string_view setting, T&& value)
{
if (auto* registry = AZ::SettingsRegistry::Get())
{
registry->Set(setting, AZStd::forward<T>(value));
}
}
template<typename T>
AZStd::remove_cvref_t<T> GetRegistry(const AZStd::string_view setting, T&& defaultValue)
{
AZStd::remove_cvref_t<T> value = AZStd::forward<T>(defaultValue);
if (const auto* registry = AZ::SettingsRegistry::Get())
{
T potentialValue;
if (registry->Get(potentialValue, setting))
{
value = AZStd::move(potentialValue);
}
}
return value;
}
struct EditorViewportSettingsCallbacksImpl : public EditorViewportSettingsCallbacks
{
EditorViewportSettingsCallbacksImpl()
@@ -118,399 +94,409 @@ namespace SandboxEditor
AZ::Vector3 CameraDefaultEditorPosition()
{
return AZ::Vector3(
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionX, 0.0)),
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionY, -10.0)),
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionZ, 4.0)));
aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraDefaultStartingPositionX, 0.0)),
aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraDefaultStartingPositionY, -10.0)),
aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraDefaultStartingPositionZ, 4.0)));
}
void SetCameraDefaultEditorPosition(const AZ::Vector3& defaultCameraPosition)
{
SetRegistry(CameraDefaultStartingPositionX, defaultCameraPosition.GetX());
SetRegistry(CameraDefaultStartingPositionY, defaultCameraPosition.GetY());
SetRegistry(CameraDefaultStartingPositionZ, defaultCameraPosition.GetZ());
AzToolsFramework::SetRegistry(CameraDefaultStartingPositionX, defaultCameraPosition.GetX());
AzToolsFramework::SetRegistry(CameraDefaultStartingPositionY, defaultCameraPosition.GetY());
AzToolsFramework::SetRegistry(CameraDefaultStartingPositionZ, defaultCameraPosition.GetZ());
}
AZ::u64 MaxItemsShownInAssetBrowserSearch()
{
return GetRegistry(AssetBrowserMaxItemsShownInSearchSetting, aznumeric_cast<AZ::u64>(50));
return AzToolsFramework::GetRegistry(AssetBrowserMaxItemsShownInSearchSetting, aznumeric_cast<AZ::u64>(50));
}
void SetMaxItemsShownInAssetBrowserSearch(const AZ::u64 numberOfItemsShown)
{
SetRegistry(AssetBrowserMaxItemsShownInSearchSetting, numberOfItemsShown);
AzToolsFramework::SetRegistry(AssetBrowserMaxItemsShownInSearchSetting, numberOfItemsShown);
}
bool GridSnappingEnabled()
{
return GetRegistry(GridSnappingSetting, false);
return AzToolsFramework::GetRegistry(GridSnappingSetting, false);
}
void SetGridSnapping(const bool enabled)
{
SetRegistry(GridSnappingSetting, enabled);
AzToolsFramework::SetRegistry(GridSnappingSetting, enabled);
}
float GridSnappingSize()
{
return aznumeric_cast<float>(GetRegistry(GridSizeSetting, 0.1));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(GridSizeSetting, 0.1));
}
void SetGridSnappingSize(const float size)
{
SetRegistry(GridSizeSetting, size);
AzToolsFramework::SetRegistry(GridSizeSetting, size);
}
bool AngleSnappingEnabled()
{
return GetRegistry(AngleSnappingSetting, false);
return AzToolsFramework::GetRegistry(AngleSnappingSetting, false);
}
void SetAngleSnapping(const bool enabled)
{
SetRegistry(AngleSnappingSetting, enabled);
AzToolsFramework::SetRegistry(AngleSnappingSetting, enabled);
}
float AngleSnappingSize()
{
return aznumeric_cast<float>(GetRegistry(AngleSizeSetting, 5.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(AngleSizeSetting, 5.0));
}
void SetAngleSnappingSize(const float size)
{
SetRegistry(AngleSizeSetting, size);
AzToolsFramework::SetRegistry(AngleSizeSetting, size);
}
bool ShowingGrid()
{
return GetRegistry(ShowGridSetting, false);
return AzToolsFramework::GetRegistry(ShowGridSetting, false);
}
void SetShowingGrid(const bool showing)
{
SetRegistry(ShowGridSetting, showing);
AzToolsFramework::SetRegistry(ShowGridSetting, showing);
}
bool StickySelectEnabled()
{
return GetRegistry(StickySelectSetting, false);
return AzToolsFramework::GetRegistry(StickySelectSetting, false);
}
void SetStickySelectEnabled(const bool enabled)
{
SetRegistry(StickySelectSetting, enabled);
AzToolsFramework::SetRegistry(StickySelectSetting, enabled);
}
float ManipulatorLineBoundWidth()
{
return aznumeric_cast<float>(GetRegistry(ManipulatorLineBoundWidthSetting, 0.1));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(ManipulatorLineBoundWidthSetting, 0.1));
}
void SetManipulatorLineBoundWidth(const float lineBoundWidth)
{
SetRegistry(ManipulatorLineBoundWidthSetting, lineBoundWidth);
AzToolsFramework::SetRegistry(ManipulatorLineBoundWidthSetting, lineBoundWidth);
}
float ManipulatorCircleBoundWidth()
{
return aznumeric_cast<float>(GetRegistry(ManipulatorCircleBoundWidthSetting, 0.1));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(ManipulatorCircleBoundWidthSetting, 0.1));
}
void SetManipulatorCircleBoundWidth(const float circleBoundWidth)
{
SetRegistry(ManipulatorCircleBoundWidthSetting, circleBoundWidth);
AzToolsFramework::SetRegistry(ManipulatorCircleBoundWidthSetting, circleBoundWidth);
}
float CameraTranslateSpeed()
{
return aznumeric_cast<float>(GetRegistry(CameraTranslateSpeedSetting, 10.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraTranslateSpeedSetting, 10.0));
}
void SetCameraTranslateSpeed(const float speed)
{
SetRegistry(CameraTranslateSpeedSetting, speed);
AzToolsFramework::SetRegistry(CameraTranslateSpeedSetting, speed);
}
float CameraBoostMultiplier()
{
return aznumeric_cast<float>(GetRegistry(CameraBoostMultiplierSetting, 3.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraBoostMultiplierSetting, 3.0));
}
void SetCameraBoostMultiplier(const float multiplier)
{
SetRegistry(CameraBoostMultiplierSetting, multiplier);
AzToolsFramework::SetRegistry(CameraBoostMultiplierSetting, multiplier);
}
float CameraRotateSpeed()
{
return aznumeric_cast<float>(GetRegistry(CameraRotateSpeedSetting, 0.005));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraRotateSpeedSetting, 0.005));
}
void SetCameraRotateSpeed(const float speed)
{
SetRegistry(CameraRotateSpeedSetting, speed);
AzToolsFramework::SetRegistry(CameraRotateSpeedSetting, speed);
}
float CameraScrollSpeed()
{
return aznumeric_cast<float>(GetRegistry(CameraScrollSpeedSetting, 0.02));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraScrollSpeedSetting, 0.02));
}
void SetCameraScrollSpeed(const float speed)
{
SetRegistry(CameraScrollSpeedSetting, speed);
AzToolsFramework::SetRegistry(CameraScrollSpeedSetting, speed);
}
float CameraDollyMotionSpeed()
{
return aznumeric_cast<float>(GetRegistry(CameraDollyMotionSpeedSetting, 0.01));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraDollyMotionSpeedSetting, 0.01));
}
void SetCameraDollyMotionSpeed(const float speed)
{
SetRegistry(CameraDollyMotionSpeedSetting, speed);
AzToolsFramework::SetRegistry(CameraDollyMotionSpeedSetting, speed);
}
bool CameraOrbitYawRotationInverted()
{
return GetRegistry(CameraOrbitYawRotationInvertedSetting, false);
return AzToolsFramework::GetRegistry(CameraOrbitYawRotationInvertedSetting, false);
}
void SetCameraOrbitYawRotationInverted(const bool inverted)
{
SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted);
AzToolsFramework::SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted);
}
bool CameraPanInvertedX()
{
return GetRegistry(CameraPanInvertedXSetting, true);
return AzToolsFramework::GetRegistry(CameraPanInvertedXSetting, true);
}
void SetCameraPanInvertedX(const bool inverted)
{
SetRegistry(CameraPanInvertedXSetting, inverted);
AzToolsFramework::SetRegistry(CameraPanInvertedXSetting, inverted);
}
bool CameraPanInvertedY()
{
return GetRegistry(CameraPanInvertedYSetting, true);
return AzToolsFramework::GetRegistry(CameraPanInvertedYSetting, true);
}
void SetCameraPanInvertedY(const bool inverted)
{
SetRegistry(CameraPanInvertedYSetting, inverted);
AzToolsFramework::SetRegistry(CameraPanInvertedYSetting, inverted);
}
float CameraPanSpeed()
{
return aznumeric_cast<float>(GetRegistry(CameraPanSpeedSetting, 0.01));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraPanSpeedSetting, 0.01));
}
void SetCameraPanSpeed(float speed)
{
SetRegistry(CameraPanSpeedSetting, speed);
AzToolsFramework::SetRegistry(CameraPanSpeedSetting, speed);
}
float CameraRotateSmoothness()
{
return aznumeric_cast<float>(GetRegistry(CameraRotateSmoothnessSetting, 5.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraRotateSmoothnessSetting, 5.0));
}
void SetCameraRotateSmoothness(const float smoothness)
{
SetRegistry(CameraRotateSmoothnessSetting, smoothness);
AzToolsFramework::SetRegistry(CameraRotateSmoothnessSetting, smoothness);
}
float CameraTranslateSmoothness()
{
return aznumeric_cast<float>(GetRegistry(CameraTranslateSmoothnessSetting, 5.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraTranslateSmoothnessSetting, 5.0));
}
void SetCameraTranslateSmoothness(const float smoothness)
{
SetRegistry(CameraTranslateSmoothnessSetting, smoothness);
AzToolsFramework::SetRegistry(CameraTranslateSmoothnessSetting, smoothness);
}
bool CameraRotateSmoothingEnabled()
{
return GetRegistry(CameraRotateSmoothingSetting, true);
return AzToolsFramework::GetRegistry(CameraRotateSmoothingSetting, true);
}
void SetCameraRotateSmoothingEnabled(const bool enabled)
{
SetRegistry(CameraRotateSmoothingSetting, enabled);
AzToolsFramework::SetRegistry(CameraRotateSmoothingSetting, enabled);
}
bool CameraTranslateSmoothingEnabled()
{
return GetRegistry(CameraTranslateSmoothingSetting, true);
return AzToolsFramework::GetRegistry(CameraTranslateSmoothingSetting, true);
}
void SetCameraTranslateSmoothingEnabled(const bool enabled)
{
SetRegistry(CameraTranslateSmoothingSetting, enabled);
AzToolsFramework::SetRegistry(CameraTranslateSmoothingSetting, enabled);
}
bool CameraCaptureCursorForLook()
{
return GetRegistry(CameraCaptureCursorLookSetting, true);
return AzToolsFramework::GetRegistry(CameraCaptureCursorLookSetting, true);
}
void SetCameraCaptureCursorForLook(const bool capture)
{
SetRegistry(CameraCaptureCursorLookSetting, capture);
AzToolsFramework::SetRegistry(CameraCaptureCursorLookSetting, capture);
}
float CameraDefaultOrbitDistance()
{
return aznumeric_cast<float>(GetRegistry(CameraDefaultOrbitDistanceSetting, 20.0));
return aznumeric_cast<float>(AzToolsFramework::GetRegistry(CameraDefaultOrbitDistanceSetting, 20.0));
}
void SetCameraDefaultOrbitDistance(const float distance)
{
SetRegistry(CameraDefaultOrbitDistanceSetting, distance);
AzToolsFramework::SetRegistry(CameraDefaultOrbitDistanceSetting, distance);
}
AzFramework::InputChannelId CameraTranslateForwardChannelId()
{
return AzFramework::InputChannelId(
GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str());
AzToolsFramework::GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str());
}
void SetCameraTranslateForwardChannelId(AZStd::string_view cameraTranslateForwardId)
{
SetRegistry(CameraTranslateForwardIdSetting, cameraTranslateForwardId);
AzToolsFramework::SetRegistry(CameraTranslateForwardIdSetting, cameraTranslateForwardId);
}
AzFramework::InputChannelId CameraTranslateBackwardChannelId()
{
return AzFramework::InputChannelId(
GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str());
AzToolsFramework::GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str());
}
void SetCameraTranslateBackwardChannelId(AZStd::string_view cameraTranslateBackwardId)
{
SetRegistry(CameraTranslateBackwardIdSetting, cameraTranslateBackwardId);
AzToolsFramework::SetRegistry(CameraTranslateBackwardIdSetting, cameraTranslateBackwardId);
}
AzFramework::InputChannelId CameraTranslateLeftChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str());
}
void SetCameraTranslateLeftChannelId(AZStd::string_view cameraTranslateLeftId)
{
SetRegistry(CameraTranslateLeftIdSetting, cameraTranslateLeftId);
AzToolsFramework::SetRegistry(CameraTranslateLeftIdSetting, cameraTranslateLeftId);
}
AzFramework::InputChannelId CameraTranslateRightChannelId()
{
return AzFramework::InputChannelId(
GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str());
AzToolsFramework::GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str());
}
void SetCameraTranslateRightChannelId(AZStd::string_view cameraTranslateRightId)
{
SetRegistry(CameraTranslateRightIdSetting, cameraTranslateRightId);
AzToolsFramework::SetRegistry(CameraTranslateRightIdSetting, cameraTranslateRightId);
}
AzFramework::InputChannelId CameraTranslateUpChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str());
}
void SetCameraTranslateUpChannelId(AZStd::string_view cameraTranslateUpId)
{
SetRegistry(CameraTranslateUpIdSetting, cameraTranslateUpId);
AzToolsFramework::SetRegistry(CameraTranslateUpIdSetting, cameraTranslateUpId);
}
AzFramework::InputChannelId CameraTranslateDownChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str());
}
void SetCameraTranslateDownChannelId(AZStd::string_view cameraTranslateDownId)
{
SetRegistry(CameraTranslateDownIdSetting, cameraTranslateDownId);
AzToolsFramework::SetRegistry(CameraTranslateDownIdSetting, cameraTranslateDownId);
}
AzFramework::InputChannelId CameraTranslateBoostChannelId()
{
return AzFramework::InputChannelId(
GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str());
AzToolsFramework::GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str());
}
void SetCameraTranslateBoostChannelId(AZStd::string_view cameraTranslateBoostId)
{
SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId);
AzToolsFramework::SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId);
}
AzFramework::InputChannelId CameraOrbitChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
}
void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId)
{
SetRegistry(CameraOrbitIdSetting, cameraOrbitId);
AzToolsFramework::SetRegistry(CameraOrbitIdSetting, cameraOrbitId);
}
AzFramework::InputChannelId CameraFreeLookChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraFreeLookIdSetting, AZStd::string("mouse_button_right")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraFreeLookIdSetting, AZStd::string("mouse_button_right")).c_str());
}
void SetCameraFreeLookChannelId(AZStd::string_view cameraFreeLookId)
{
SetRegistry(CameraFreeLookIdSetting, cameraFreeLookId);
AzToolsFramework::SetRegistry(CameraFreeLookIdSetting, cameraFreeLookId);
}
AzFramework::InputChannelId CameraFreePanChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraFreePanIdSetting, AZStd::string("mouse_button_middle")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraFreePanIdSetting, AZStd::string("mouse_button_middle")).c_str());
}
void SetCameraFreePanChannelId(AZStd::string_view cameraFreePanId)
{
SetRegistry(CameraFreePanIdSetting, cameraFreePanId);
AzToolsFramework::SetRegistry(CameraFreePanIdSetting, cameraFreePanId);
}
AzFramework::InputChannelId CameraOrbitLookChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str());
}
void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId)
{
SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId);
AzToolsFramework::SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId);
}
AzFramework::InputChannelId CameraOrbitDollyChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
}
void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId)
{
SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId);
AzToolsFramework::SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId);
}
AzFramework::InputChannelId CameraOrbitPanChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
}
void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId)
{
SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId);
AzToolsFramework::SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId);
}
AzFramework::InputChannelId CameraFocusChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraFocusIdSetting, AZStd::string("keyboard_key_alphanumeric_X")).c_str());
return AzFramework::InputChannelId(
AzToolsFramework::GetRegistry(CameraFocusIdSetting, AZStd::string("keyboard_key_alphanumeric_X")).c_str());
}
void SetCameraFocusChannelId(AZStd::string_view cameraFocusId)
{
SetRegistry(CameraFocusIdSetting, cameraFocusId);
AzToolsFramework::SetRegistry(CameraFocusIdSetting, cameraFocusId);
}
} // namespace SandboxEditor
-8
View File
@@ -35,7 +35,6 @@
// CryCommon
#include <CryCommon/INavigationSystem.h>
#include <CryCommon/LyShine/ILyShine.h>
#include <CryCommon/MainThreadRenderRequestBus.h>
// Editor
@@ -595,13 +594,6 @@ void CGameEngine::SwitchToInEditor()
// Enable accelerators.
GetIEditor()->EnableAcceleratos(true);
// reset UI system
if (gEnv->pLyShine)
{
gEnv->pLyShine->Reset();
}
// [Anton] - order changed, see comments for CGameEngine::SetSimulationMode
//! Send event to switch out of game.
GetIEditor()->GetObjectManager()->SendEvent(EVENT_OUTOFGAME);
@@ -13,7 +13,6 @@ set(FILES
EditorCommonAPI.h
ActionOutput.h
ActionOutput.cpp
UiEditorDLLBus.h
DockTitleBarWidget.cpp
DockTitleBarWidget.h
SaveUtilities/AsyncSaveRunner.h
+5 -6
View File
@@ -75,17 +75,16 @@ void CImageEx::ReverseUpDown()
}
uint32* pPixData = GetData();
uint32* pReversePix = new uint32[GetWidth() * GetHeight()];
for (int i = GetHeight() - 1, i2 = 0; i >= 0; i--, i2++)
const int height = GetHeight();
const int width = GetWidth();
for (int i = 0; i < height / 2; i++)
{
for (int k = 0; k < GetWidth(); k++)
for (int j = 0; j < width; j++)
{
pReversePix[i2 * GetWidth() + k] = pPixData[i * GetWidth() + k];
AZStd::swap(pPixData[i * width + j], pPixData[(height - 1 - i) * width + j]);
}
}
Attach(pReversePix, GetWidth(), GetHeight());
}
void CImageEx::FillAlpha(unsigned char value)
@@ -486,9 +486,11 @@ namespace AZ
// Merge Command Line arguments
constexpr bool executeRegDumpCommands = false;
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
// Skip over merging the User Registry in non-debug and profile configurations
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(*m_settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {});
#endif
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry);
@@ -23,7 +23,7 @@ namespace AZ::SettingsRegistryConsoleUtils
inline constexpr const char* SettingsRegistryRemove = "sr_regremove";
inline constexpr const char* SettingsRegistryDump = "sr_regdump";
inline constexpr const char* SettingsRegistryDumpAll = "sr_regdumpall";
inline constexpr const char* SettingsRegistryMergeFile = "sr_regset-file";
inline constexpr const char* SettingsRegistryMergeFile = "sr_regset_file";
// RAII structure which owns the instances of the Settings Registry Console commands
// registered with an AZ Console
@@ -53,7 +53,7 @@ namespace AZ::SettingsRegistryConsoleUtils
//! "sr_regdumpall" accepts 0 arguments and dumps the entire settings registry
//! NOTE: this might result in a large amount of output to the console
//!
//! "sr_regset-file" accepts 1 or 2 arguments - <file-path> [<anchor json path>]
//! "sr_regset_file" accepts 1 or 2 arguments - <file-path> [<anchor json path>]
//! Merges the json formatted file <file path> into the settings registry underneath the root anchor ""
//! or <anchor json path> if supplied
[[nodiscard]] ConsoleFunctorHandle RegisterAzConsoleCommands(SettingsRegistryInterface& registry, AZ::IConsole& azConsole);
@@ -914,11 +914,11 @@ namespace UnitTest
m_testAssetManager->SetParallelDependentLoadingEnabled(true);
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_LoadTest_SameAsset_DifferentFilters)
#else
TEST_F(AssetJobsFloodTest, LoadTest_SameAsset_DifferentFilters)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
@@ -1263,11 +1263,11 @@ namespace UnitTest
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadDependencies_NoLoadNotLoaded)
#else
TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadDependencies_NoLoadNotLoaded)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
// Setup has already created/destroyed assets
@@ -1304,11 +1304,11 @@ namespace UnitTest
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadContainerDependencies_LoadAllLoadsNoLoad)
#else
TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadContainerDependencies_LoadAllLoadsNoLoad)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
// Setup has already created/destroyed assets
@@ -1343,11 +1343,11 @@ namespace UnitTest
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed)
#else
TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
// Setup has already created/destroyed assets
@@ -12,13 +12,57 @@
namespace AzFramework::Terrain
{
// Create a handler that can be accessed from Python scripts to receive terrain change notifications.
class TerrainDataNotificationHandler final
: public AzFramework::Terrain::TerrainDataNotificationBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(
TerrainDataNotificationHandler,
"{A83EF103-295A-4653-8279-F30FBF3F9037}",
AZ::SystemAllocator,
OnTerrainDataCreateBegin,
OnTerrainDataCreateEnd,
OnTerrainDataDestroyBegin,
OnTerrainDataDestroyEnd,
OnTerrainDataChanged);
void OnTerrainDataCreateBegin() override
{
Call(FN_OnTerrainDataCreateBegin);
}
void OnTerrainDataCreateEnd() override
{
Call(FN_OnTerrainDataCreateEnd);
}
void OnTerrainDataDestroyBegin() override
{
Call(FN_OnTerrainDataDestroyBegin);
}
void OnTerrainDataDestroyEnd() override
{
Call(FN_OnTerrainDataDestroyEnd);
}
void OnTerrainDataChanged(
const AZ::Aabb& dirtyRegion, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask dataChangedMask) override
{
Call(FN_OnTerrainDataChanged, dirtyRegion, dataChangedMask);
}
};
void TerrainDataRequests::Reflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AzFramework::Terrain::TerrainDataRequestBus>("TerrainDataRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Terrain")
->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeight)
->Attribute(AZ::Script::Attributes::Module, "terrain")
->Event("GetNormal", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetNormal)
->Event("GetMaxSurfaceWeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeight)
->Event("GetMaxSurfaceWeightFromVector2",
@@ -34,8 +78,24 @@ namespace AzFramework::Terrain
->Event("GetTerrainAabb", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb)
->Event("GetTerrainHeightQueryResolution",
&AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainHeightQueryResolution)
->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightVal)
->Event("GetHeightFromVector2", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightValFromVector2)
->Event("GetHeightFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightValFromFloats)
;
behaviorContext->EBus<AzFramework::Terrain::TerrainDataNotificationBus>("TerrainDataNotificationBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Terrain")
->Attribute(AZ::Script::Attributes::Module, "terrain")
->Event("OnTerrainDataCreateBegin", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataCreateBegin)
->Event("OnTerrainDataCreateEnd", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataCreateEnd)
->Event("OnTerrainDataDestroyBegin", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataDestroyBegin)
->Event("OnTerrainDataDestroyEnd", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataDestroyEnd)
->Event("OnTerrainDataChanged", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataChanged)
->Handler<AzFramework::Terrain::TerrainDataNotificationHandler>()
;
}
//TerrainDataNotificationHandler::Reflect(context);
}
} // namespace AzFramework::Terrain
@@ -144,13 +144,31 @@ namespace AzFramework
return result;
}
SurfaceData::SurfacePoint BehaviorContextGetSurfacePointFromVector2(
const AZ::Vector2& inPosition,
Sampler sampleFilter = Sampler::DEFAULT) const
const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT) const
{
SurfaceData::SurfacePoint result;
GetSurfacePointFromVector2(inPosition, result, sampleFilter);
return result;
}
// Functions without the optional bool* parameter that can be used from Python tests.
float GetHeightVal(AZ::Vector3 position, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeight(position, sampler, &terrainExists);
}
float GetHeightValFromVector2(AZ::Vector2 position, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeightFromVector2(position, sampler, &terrainExists);
}
float GetHeightValFromFloats(float x, float y, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeightFromFloats(x, y, sampler, &terrainExists);
}
};
using TerrainDataRequestBus = AZ::EBus<TerrainDataRequests>;
@@ -13,6 +13,13 @@
namespace UnitTest
{
//! Null implementation of DebugDisplayRequests for dummy draw calls.
class NullDebugDisplayRequests : public AzFramework::DebugDisplayRequests
{
public:
virtual ~NullDebugDisplayRequests() = default;
};
//! Minimal implementation of DebugDisplayRequests to support testing shapes.
//! Stores a list of points based on received draw calls to delineate the exterior of the object requested to be drawn.
class TestDebugDisplayRequests : public AzFramework::DebugDisplayRequests
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
+127 -48
View File
@@ -29,6 +29,13 @@ namespace InputUnitTests
////////////////////////////////////////////////////////////////////////////////////////////////
class InputTest : public ScopedAllocatorSetupFixture
{
public:
InputTest() : ScopedAllocatorSetupFixture()
{
// Many input tests are only valid if the GamePad device is supported on this platform.
m_gamepadSupported = InputDeviceGamepad::GetMaxSupportedGamepads() > 0;
}
protected:
////////////////////////////////////////////////////////////////////////////////////////////
void SetUp() override
@@ -46,6 +53,7 @@ namespace InputUnitTests
////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<InputSystemComponent> m_inputSystemComponent;
bool m_gamepadSupported;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -78,12 +86,17 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_ActivateDeactivate_Successfull)
#else
TEST_F(InputTest, InputContext_ActivateDeactivate_Successfull)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_ActivateDeactivate_Successfull";
#else
SUCCEED() << "Skipping test InputContext_ActivateDeactivate_Successfull";
#endif
return;
}
// Create an input context (they are inactive by default).
InputContext inputContext("TestInputContext");
@@ -148,12 +161,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_AddRemoveInputMapping_Successfull)
#else
TEST_F(InputTest, InputContext_AddRemoveInputMapping_Successfull)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_AddRemoveInputMapping_Successfull";
#else
SUCCEED() << "Skipping test InputContext_AddRemoveInputMapping_Successfull";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -256,12 +275,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_ConsumeProcessedInput_Consumed)
#else
TEST_F(InputTest, InputContext_ConsumeProcessedInput_Consumed)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_ConsumeProcessedInput_Consumed";
#else
SUCCEED() << "Skipping test InputContext_ConsumeProcessedInput_Consumed";
#endif
return;
}
InputContext::InitData initData;
// Create a high priority input context that consumes input processed by any of its mappings.
@@ -340,12 +365,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_FilteredInput_Mapped)
#else
TEST_F(InputTest, InputContext_FilteredInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_FilteredInput_Mapped";
#else
SUCCEED() << "Skipping test InputContext_FilteredInput_Mapped";
#endif
return;
}
// Create an input context that initially only listens for keyboard input.
InputContext::InitData initData;
initData.autoActivate = true;
@@ -413,12 +444,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_AddRemoveSourceInput_Successful)
#else
TEST_F(InputTest, InputMappingOr_AddRemoveSourceInput_Successful)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_AddRemoveSourceInput_Successful";
#else
SUCCEED() << "Skipping test InputMappingOr_AddRemoveSourceInput_Successful";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -491,12 +528,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_SingleSourceInput_Mapped)
#else
TEST_F(InputTest, InputMappingOr_SingleSourceInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_SingleSourceInput_Mapped";
#else
SUCCEED() << "Skipping test InputMappingOr_SingleSourceInput_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -558,12 +601,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_MultipleSourceInputs_Mapped)
#else
TEST_F(InputTest, InputMappingOr_MultipleSourceInputs_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_MultipleSourceInputs_Mapped";
#else
SUCCEED() << "Skipping test InputMappingOr_MultipleSourceInputs_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -650,12 +699,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_AddRemoveSourceInput_Successful)
#else
TEST_F(InputTest, InputMappingAnd_AddRemoveSourceInput_Successful)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_AddRemoveSourceInput_Successful";
#else
SUCCEED() << "Skipping test InputMappingAnd_AddRemoveSourceInput_Successful";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -728,12 +783,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_SingleSourceInput_Mapped)
#else
TEST_F(InputTest, InputMappingAnd_SingleSourceInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_SingleSourceInput_Mapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_SingleSourceInput_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -795,12 +856,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputs_Mapped)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputs_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputs_Mapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputs_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -909,12 +976,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -969,12 +1042,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -29,7 +29,8 @@ namespace UnitTest
void SetUpEditorFixtureImpl() override
{
ToolsApplicationFixtureT::SetUpEditorFixtureImpl();
m_viewportManipulatorInteraction = AZStd::make_unique<IndirectCallManipulatorViewportInteraction>();
m_viewportManipulatorInteraction =
AZStd::make_unique<IndirectCallManipulatorViewportInteraction>(ToolsApplicationFixtureT::CreateDebugDisplayRequests());
m_actionDispatcher = AZStd::make_unique<ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction);
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
@@ -17,11 +17,10 @@ namespace AzManipulatorTestFramework
class ViewportInteraction;
//! Implementation of manipulator viewport interaction that manipulates the manager directly.
class DirectCallManipulatorViewportInteraction
: public ManipulatorViewportInteraction
class DirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction
{
public:
DirectCallManipulatorViewportInteraction();
explicit DirectCallManipulatorViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests);
~DirectCallManipulatorViewportInteraction();
// ManipulatorViewportInteractionInterface ...
@@ -21,7 +21,7 @@ namespace AzManipulatorTestFramework
class IndirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction
{
public:
IndirectCallManipulatorViewportInteraction();
explicit IndirectCallManipulatorViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests);
~IndirectCallManipulatorViewportInteraction();
// ManipulatorViewportInteractionInterface ...
@@ -11,10 +11,13 @@
#include <AzFramework/Visibility/EntityVisibilityQuery.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
namespace AzFramework
{
class DebugDisplayRequests;
}
namespace AzManipulatorTestFramework
{
class NullDebugDisplayRequests;
//! Implementation of the viewport interaction model to handle viewport interaction requests.
class ViewportInteraction
: public ViewportInteractionInterface
@@ -23,7 +26,7 @@ namespace AzManipulatorTestFramework
, private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler
{
public:
ViewportInteraction();
explicit ViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests);
~ViewportInteraction();
// ViewportInteractionInterface overrides ...
@@ -63,7 +66,7 @@ namespace AzManipulatorTestFramework
static constexpr AzFramework::ViewportId m_viewportId = 1234; //!< Arbitrary viewport id for manipulator tests.
AzFramework::EntityVisibilityQuery m_entityVisibilityQuery;
AZStd::unique_ptr<NullDebugDisplayRequests> m_nullDebugDisplayRequests;
AZStd::shared_ptr<AzFramework::DebugDisplayRequests> m_debugDisplayRequests;
AzFramework::CameraState m_cameraState;
bool m_gridSnapping = false;
bool m_angularSnapping = false;
@@ -118,10 +118,11 @@ namespace AzManipulatorTestFramework
return m_manipulatorManager->Interacting();
}
DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction()
DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction(
AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests)
: m_customManager(
AZStd::make_unique<CustomManipulatorManager>(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))))
, m_viewportInteraction(AZStd::make_unique<ViewportInteraction>())
, m_viewportInteraction(AZStd::make_unique<ViewportInteraction>(AZStd::move(debugDisplayRequests)))
, m_manipulatorManager(AZStd::make_unique<DirectCallManipulatorManager>(m_viewportInteraction.get(), m_customManager))
{
}
@@ -76,8 +76,9 @@ namespace AzManipulatorTestFramework
return manipulatorInteracting;
}
IndirectCallManipulatorViewportInteraction::IndirectCallManipulatorViewportInteraction()
: m_viewportInteraction(AZStd::make_unique<ViewportInteraction>())
IndirectCallManipulatorViewportInteraction::IndirectCallManipulatorViewportInteraction(
AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests)
: m_viewportInteraction(AZStd::make_unique<ViewportInteraction>(AZStd::move(debugDisplayRequests)))
, m_manipulatorManager(AZStd::make_unique<IndirectCallManipulatorManager>(*m_viewportInteraction))
{
}
@@ -13,15 +13,8 @@
namespace AzManipulatorTestFramework
{
// Null debug display for dummy draw calls
class NullDebugDisplayRequests : public AzFramework::DebugDisplayRequests
{
public:
virtual ~NullDebugDisplayRequests() = default;
};
ViewportInteraction::ViewportInteraction()
: m_nullDebugDisplayRequests(AZStd::make_unique<NullDebugDisplayRequests>())
ViewportInteraction::ViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests)
: m_debugDisplayRequests(AZStd::move(debugDisplayRequests))
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId);
AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(m_viewportId);
@@ -102,7 +95,7 @@ namespace AzManipulatorTestFramework
AzFramework::DebugDisplayRequests& ViewportInteraction::GetDebugDisplay()
{
return *m_nullDebugDisplayRequests;
return *m_debugDisplayRequests;
}
void ViewportInteraction::SetGridSnapping(const bool enabled)
@@ -26,7 +26,8 @@ namespace UnitTest
{
public:
GridSnappingFixture()
: m_viewportManipulatorInteraction(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>())
: m_viewportManipulatorInteraction(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>(
AZStd::make_shared<NullDebugDisplayRequests>()))
, m_actionDispatcher(
AZStd::make_unique<AzManipulatorTestFramework::ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction))
{
@@ -15,7 +15,8 @@ namespace UnitTest
{
public:
AValidViewportInteraction()
: m_viewportInteraction(AZStd::make_unique<AzManipulatorTestFramework::ViewportInteraction>())
: m_viewportInteraction(
AZStd::make_unique<AzManipulatorTestFramework::ViewportInteraction>(AZStd::make_shared<NullDebugDisplayRequests>()))
{
}
@@ -75,9 +75,11 @@ namespace UnitTest
void SetUpEditorFixtureImpl() override
{
m_directState =
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>());
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>(
AZStd::make_shared<NullDebugDisplayRequests>()));
m_busState =
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction>());
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction>(
AZStd::make_shared<NullDebugDisplayRequests>()));
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
@@ -53,7 +53,6 @@ static void OptimizedSetParent(QWidget* widget, QWidget* parent)
namespace AzQtComponents
{
static const FancyDockingDropZoneConstants g_FancyDockingConstants;
// Constant for the threshold in pixels for snapping to edges while dragging for docking
static const int g_snapThresholdInPixels = 15;
@@ -155,7 +154,7 @@ namespace AzQtComponents
// Timer for updating our hovered drop zone opacity
QObject::connect(m_dropZoneHoverFadeInTimer, &QTimer::timeout, this, &FancyDocking::onDropZoneHoverFadeInUpdate);
m_dropZoneHoverFadeInTimer->setInterval(g_FancyDockingConstants.dropZoneHoverFadeUpdateIntervalMS);
m_dropZoneHoverFadeInTimer->setInterval(FancyDockingDropZoneConstants::dropZoneHoverFadeUpdateIntervalMS);
QIcon dragIcon = QIcon(QStringLiteral(":/Cursors/Grabbing.svg"));
m_dragCursor = QCursor(dragIcon.pixmap(16), 5, 2);
}
@@ -333,13 +332,13 @@ namespace AzQtComponents
*/
void FancyDocking::onDropZoneHoverFadeInUpdate()
{
const qreal dropZoneHoverOpacity = g_FancyDockingConstants.dropZoneHoverFadeIncrement + m_dropZoneState.dropZoneHoverOpacity();
const qreal dropZoneHoverOpacity = FancyDockingDropZoneConstants::dropZoneHoverFadeIncrement + m_dropZoneState.dropZoneHoverOpacity();
// Once we've reached the full drop zone opacity, cut it off in case we
// went over and stop the timer
if (dropZoneHoverOpacity >= g_FancyDockingConstants.dropZoneOpacity)
if (dropZoneHoverOpacity >= FancyDockingDropZoneConstants::dropZoneOpacity)
{
m_dropZoneState.setDropZoneHoverOpacity(g_FancyDockingConstants.dropZoneOpacity);
m_dropZoneState.setDropZoneHoverOpacity(FancyDockingDropZoneConstants::dropZoneOpacity);
m_dropZoneHoverFadeInTimer->stop();
}
else
@@ -792,12 +791,12 @@ namespace AzQtComponents
QPoint mainWindowTopLeft = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.topLeft()));
QPoint mainWindowTopRight = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.topRight()));
QPoint mainWindowBottomLeft = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.bottomLeft()));
QSize absoluteLeftRightSize(g_FancyDockingConstants.absoluteDropZoneSizeInPixels, mainWindowRect.height());
QSize absoluteLeftRightSize(FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels, mainWindowRect.height());
QRect absoluteLeftDropZone(mainWindowTopLeft, absoluteLeftRightSize);
QRect absoluteRightDropZone(mainWindowTopRight - QPoint(g_FancyDockingConstants.absoluteDropZoneSizeInPixels, 0), absoluteLeftRightSize);
QSize absoluteTopBottomSize(mainWindowRect.width(), g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
QRect absoluteRightDropZone(mainWindowTopRight - QPoint(FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels, 0), absoluteLeftRightSize);
QSize absoluteTopBottomSize(mainWindowRect.width(), FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
QRect absoluteTopDropZone(mainWindowTopLeft, absoluteTopBottomSize);
QRect absoluteBottomDropZone(mainWindowBottomLeft - QPoint(0, g_FancyDockingConstants.absoluteDropZoneSizeInPixels), absoluteTopBottomSize);
QRect absoluteBottomDropZone(mainWindowBottomLeft - QPoint(0, FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels), absoluteTopBottomSize);
// If the drop target is a main window, then we will only show the absolute
// drop zone if the cursor is in that zone already
@@ -986,16 +985,16 @@ namespace AzQtComponents
switch (m_dropZoneState.absoluteDropZoneArea())
{
case Qt::LeftDockWidgetArea:
dockRect.setX(dockRect.x() + g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setX(dockRect.x() + FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::RightDockWidgetArea:
dockRect.setWidth(dockRect.width() - g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setWidth(dockRect.width() - FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::TopDockWidgetArea:
dockRect.setY(dockRect.y() + g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setY(dockRect.y() + FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::BottomDockWidgetArea:
dockRect.setHeight(dockRect.height() - g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setHeight(dockRect.height() - FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
}
@@ -1034,15 +1033,15 @@ namespace AzQtComponents
// Set the drop zone width/height to the default, but if the dock widget
// width and/or height is below the threshold, then switch to scaling them
// down accordingly
int dropZoneWidth = g_FancyDockingConstants.dropZoneSizeInPixels;
if (dockWidth < g_FancyDockingConstants.minDockSizeBeforeDropZoneScalingInPixels)
int dropZoneWidth = FancyDockingDropZoneConstants::dropZoneSizeInPixels;
if (dockWidth < FancyDockingDropZoneConstants::minDockSizeBeforeDropZoneScalingInPixels)
{
dropZoneWidth = aznumeric_cast<int>(dockWidth * g_FancyDockingConstants.dropZoneScaleFactor);
dropZoneWidth = aznumeric_cast<int>(dockWidth * FancyDockingDropZoneConstants::dropZoneScaleFactor);
}
int dropZoneHeight = g_FancyDockingConstants.dropZoneSizeInPixels;
if (dockHeight < g_FancyDockingConstants.minDockSizeBeforeDropZoneScalingInPixels)
int dropZoneHeight = FancyDockingDropZoneConstants::dropZoneSizeInPixels;
if (dockHeight < FancyDockingDropZoneConstants::minDockSizeBeforeDropZoneScalingInPixels)
{
dropZoneHeight = aznumeric_cast<int>(dockHeight * g_FancyDockingConstants.dropZoneScaleFactor);
dropZoneHeight = aznumeric_cast<int>(dockHeight * FancyDockingDropZoneConstants::dropZoneScaleFactor);
}
// Calculate the inner corners to be used when constructing the drop zone polygons
@@ -1078,7 +1077,7 @@ namespace AzQtComponents
int innerDropZoneWidth = m_dropZoneState.innerDropZoneRect().width();
int innerDropZoneHeight = m_dropZoneState.innerDropZoneRect().height();
int centerDropZoneDiameter = (innerDropZoneWidth < innerDropZoneHeight) ? innerDropZoneWidth : innerDropZoneHeight;
centerDropZoneDiameter = aznumeric_cast<int>(centerDropZoneDiameter * g_FancyDockingConstants.centerTabDropZoneScale);
centerDropZoneDiameter = aznumeric_cast<int>(centerDropZoneDiameter * FancyDockingDropZoneConstants::centerTabDropZoneScale);
// Setup our center tab drop zone
const QSize centerDropZoneSize(centerDropZoneDiameter, centerDropZoneDiameter);
@@ -1986,7 +1985,7 @@ namespace AzQtComponents
// hasn't faded in all the way yet, then ignore the drop zone area
// which will make the widget floating
bool modifiedKeyPressed = FancyDockingDropZoneWidget::CheckModifierKey();
if (modifiedKeyPressed || m_dropZoneState.dropZoneHoverOpacity() != g_FancyDockingConstants.dropZoneOpacity)
if (modifiedKeyPressed || m_dropZoneState.dropZoneHoverOpacity() != FancyDockingDropZoneConstants::dropZoneOpacity)
{
area = Qt::NoDockWidgetArea;
}
@@ -3026,7 +3025,7 @@ namespace AzQtComponents
{
bool modifiedKeyPressed = FancyDockingDropZoneWidget::CheckModifierKey();
m_ghostWidget->setWindowOpacity(modifiedKeyPressed ? 1.0f : g_FancyDockingConstants.draggingDockWidgetOpacity);
m_ghostWidget->setWindowOpacity(modifiedKeyPressed ? 1.0f : FancyDockingDropZoneConstants::draggingDockWidgetOpacity);
m_ghostWidget->setPixmap(m_state.dockWidgetScreenGrab.screenGrab, m_state.placeholder(), m_state.placeholderScreen());
}
}
@@ -19,26 +19,6 @@
namespace AzQtComponents
{
static const FancyDockingDropZoneConstants g_Constants;
FancyDockingDropZoneConstants::FancyDockingDropZoneConstants()
{
draggingDockWidgetOpacity = 0.6;
dropZoneOpacity = 0.4;
dropZoneSizeInPixels = 40;
minDockSizeBeforeDropZoneScalingInPixels = dropZoneSizeInPixels * 3;
dropZoneScaleFactor = 0.25;
centerTabDropZoneScale = 0.5;
centerTabIconScale = 0.5;
dropZoneColor = QColor(155, 155, 155);
dropZoneBorderColor = Qt::black;
dropZoneBorderInPixels = 1;
absoluteDropZoneSizeInPixels = 25;
dockingTargetDelayMS = 110;
dropZoneHoverFadeUpdateIntervalMS = 20;
dropZoneHoverFadeIncrement = dropZoneOpacity / (dockingTargetDelayMS / dropZoneHoverFadeUpdateIntervalMS);
centerDropZoneIconPath = QString(":/stylesheet/img/UI20/docking/tabs_icon.svg");
}
FancyDockingDropZoneWidget::FancyDockingDropZoneWidget(QMainWindow* mainWindow, QWidget* coordinatesRelativeTo, QScreen* screen, FancyDockingDropZoneState* dropZoneState)
// NOTE: this will not work with multiple monitors if this widget has a parent. The floating drop zone
@@ -154,7 +134,7 @@ namespace AzQtComponents
// Draw all of the normal drop zones if they exist (if a dock widget is hovered over)
painter.setPen(Qt::NoPen);
painter.setOpacity(g_Constants.dropZoneOpacity);
painter.setOpacity(FancyDockingDropZoneConstants::dropZoneOpacity);
auto dropZones = m_dropZoneState->dropZones();
for (auto it = dropZones.cbegin(); it != dropZones.cend(); ++it)
{
@@ -189,7 +169,7 @@ namespace AzQtComponents
// Otherwise, set the normal color
else
{
painter.setBrush(g_Constants.dropZoneColor);
painter.setBrush(FancyDockingDropZoneConstants::dropZoneColor);
}
// negate the window position to offset everything by that much
@@ -214,8 +194,8 @@ namespace AzQtComponents
// Scale the tabs icon based on the drop zone size and our specified offset
// Doing this through QIcon to make sure that SVG is rendered already in desired resolution
const QSize& dropZoneSize = dropZoneRect.size();
const QSize requestedIconSize = dropZoneSize * g_Constants.centerTabIconScale;
const QIcon dropZoneIcon = QIcon(g_Constants.centerDropZoneIconPath);
const QSize requestedIconSize = dropZoneSize * FancyDockingDropZoneConstants::centerTabIconScale;
const QIcon dropZoneIcon = QIcon(FancyDockingDropZoneConstants::centerDropZoneIconPath);
const QPixmap dropZonePixmap = dropZoneIcon.pixmap(requestedIconSize);
const QSize receivedIconSize = dropZoneIcon.actualSize(requestedIconSize);
@@ -264,7 +244,7 @@ namespace AzQtComponents
}
else
{
painter.setBrush(g_Constants.dropZoneColor);
painter.setBrush(FancyDockingDropZoneConstants::dropZoneColor);
}
painter.drawRect(absoluteDropZoneRect);
@@ -313,8 +293,8 @@ namespace AzQtComponents
const QPoint innerBottomRight = innerDropZoneRect.bottomRight();
// Draw the lines using the appropriate pen
QPen dropZoneBorderPen(g_Constants.dropZoneBorderColor);
dropZoneBorderPen.setWidth(g_Constants.dropZoneBorderInPixels);
QPen dropZoneBorderPen(FancyDockingDropZoneConstants::dropZoneBorderColor);
dropZoneBorderPen.setWidth(FancyDockingDropZoneConstants::dropZoneBorderInPixels);
painter.setPen(dropZoneBorderPen);
painter.setOpacity(1);
painter.drawLine(topLeft, innerTopLeft);
@@ -28,63 +28,58 @@ class QPainter;
namespace AzQtComponents
{
struct AZ_QT_COMPONENTS_API FancyDockingDropZoneConstants
namespace FancyDockingDropZoneConstants
{
// Constant for the opacity of the screen grab for the dock widget being dragged
qreal draggingDockWidgetOpacity;
static constexpr qreal draggingDockWidgetOpacity = 0.6;
// Constant for the opacity of the normal drop zones
qreal dropZoneOpacity;
static constexpr qreal dropZoneOpacity = 0.4;
// Constant for the default drop zone size (in pixels)
int dropZoneSizeInPixels;
static constexpr int dropZoneSizeInPixels = 40;
// Constant for the dock width/height size (in pixels) before we need to start
// scaling down the drop zone sizes, or else they will overlap with the center
// tab icon or each other
int minDockSizeBeforeDropZoneScalingInPixels;
static constexpr int minDockSizeBeforeDropZoneScalingInPixels = dropZoneSizeInPixels * 3;
// Constant for the factor by which we must scale down the drop zone sizes once
// the dock width/height size is too small
qreal dropZoneScaleFactor;
static constexpr qreal dropZoneScaleFactor = 0.25;
// Constant for the percentage to scale down the inner drop zone rectangle for the center tab drop zone
qreal centerTabDropZoneScale;
static constexpr qreal centerTabDropZoneScale = 0.5;
// Constant for the percentage to scale down the center tab drop zone for the center tab icon
qreal centerTabIconScale;
static constexpr qreal centerTabIconScale = 0.5;
// Constant for the drop zone hotspot default color
QColor dropZoneColor;
static const QColor dropZoneColor = QColor(155, 155, 155);
// Constant for the drop zone border color
QColor dropZoneBorderColor;
static const QColor dropZoneBorderColor = Qt::black;
// Constant for the border width in pixels separating the drop zones
int dropZoneBorderInPixels;
static constexpr int dropZoneBorderInPixels = 1;
// Constant for the border width in pixels separating the drop zones
int absoluteDropZoneSizeInPixels;
static constexpr int absoluteDropZoneSizeInPixels = 25;
// Constant for the delay (in milliseconds) before a drop zone becomes active
// once it is hovered over
int dockingTargetDelayMS;
static constexpr int dockingTargetDelayMS = 110;
// Constant for the rate at which we will update (fade in) the drop zone opacity
// when hovered over (in milliseconds)
int dropZoneHoverFadeUpdateIntervalMS;
static constexpr int dropZoneHoverFadeUpdateIntervalMS = 20;
// Constant for the incremental opacity increase for the hovered drop zone
// that will fade in to the full drop zone opacity in the desired time
qreal dropZoneHoverFadeIncrement;
static constexpr qreal dropZoneHoverFadeIncrement = dropZoneOpacity / (dockingTargetDelayMS / dropZoneHoverFadeUpdateIntervalMS);
// Constant for the path to the center drop zone tabs icon
QString centerDropZoneIconPath;
FancyDockingDropZoneConstants();
FancyDockingDropZoneConstants(const FancyDockingDropZoneConstants&) = delete;
FancyDockingDropZoneConstants& operator=(const FancyDockingDropZoneConstants&) = delete;
static const QString centerDropZoneIconPath = QStringLiteral(":/stylesheet/img/UI20/docking/tabs_icon.svg");
};
class FancyDockingDropZoneState
@@ -323,7 +323,7 @@ namespace AzQtComponents
saturation *= 2.0 - lightness;
}
double value = (lightness + saturation) / 2.0;
saturation = (2.0 * saturation) / (lightness + saturation);
saturation = qFuzzyIsNull(lightness + saturation) ? 0 : (2.0 * saturation) / (lightness + saturation);
m_hsv.saturation = AZ::GetClamp(saturation, 0.0, 1.0);
m_hsv.value = AZ::GetClamp(value, 0.0, 12.5);
@@ -341,11 +341,12 @@ namespace AzQtComponents
double saturation = m_hsv.saturation * m_hsv.value;
if (lightness <= 1.0)
{
saturation /= lightness;
saturation = (qFuzzyIsNull(lightness)) ? 0.0 : saturation / lightness;
}
else
{
saturation /= 2.0 - lightness;
double two_minus_lightness = 2.0 - lightness;
saturation = (qFuzzyIsNull(two_minus_lightness)) ? 0.0 : saturation / two_minus_lightness;
}
lightness /= 2.0;
@@ -164,11 +164,7 @@ namespace
}
}
#if AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST
TEST(AzQtComponents, DISABLED_ColorConversionsTestAllZeros)
#else
TEST(AzQtComponents, ColorConversionsTestAllZeros)
#endif // AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST
{
TestConversions({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 });
}
@@ -14,16 +14,14 @@
#define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000
#define AZ_TRAIT_DISABLE_FAILED_AP_CONNECTION_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ATOM_RPI_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST true
#define AZ_TRAIT_DISABLE_FAILED_FRAMEPROFILER_TEST true
#define AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_GRADIENT_SIGNAL_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_MULTIPLAYER_GRIDMATE_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_NATIVE_WINDOWS_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_PROCESS_LAUNCHER_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_TESTS true
@@ -30,6 +30,7 @@
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
@@ -268,6 +269,7 @@ namespace AzToolsFramework
azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
azrtti_typeid<FocusModeSystemComponent>(),
azrtti_typeid<ContainerEntitySystemComponent>(),
azrtti_typeid<ReadOnlyEntitySystemComponent>(),
azrtti_typeid<SliceMetadataEntityContextComponent>(),
azrtti_typeid<Prefab::PrefabSystemComponent>(),
azrtti_typeid<EditorEntityFixupComponent>(),
@@ -23,6 +23,7 @@
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySortComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditorComponent.h>
#include <AzToolsFramework/Render/EditorIntersectorComponent.h>
@@ -75,6 +76,7 @@ namespace AzToolsFramework
EditorEntityFixupComponent::CreateDescriptor(),
EntityUtilityComponent::CreateDescriptor(),
ContainerEntitySystemComponent::CreateDescriptor(),
ReadOnlyEntitySystemComponent::CreateDescriptor(),
FocusModeSystemComponent::CreateDescriptor(),
SliceMetadataEntityContextComponent::CreateDescriptor(),
SliceRequestComponent::CreateDescriptor(),
@@ -0,0 +1,63 @@
/*
* 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/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzFramework/Entity/EntityContext.h>
namespace AzToolsFramework
{
//! Used to notify changes of state for read-only entities.
class ReadOnlyEntityPublicNotifications
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status changes.
//! @param entityId The entity whose status has changed.
//! @param readOnly The read-only state the container was changed to.
virtual void OnReadOnlyEntityStatusChanged([[maybe_unused]] const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly) {}
protected:
~ReadOnlyEntityPublicNotifications() = default;
};
using ReadOnlyEntityPublicNotificationBus = AZ::EBus<ReadOnlyEntityPublicNotifications>;
//! Used by the ReadOnlyEntitySystemComponent to query the read-only state of entities as set by systems using the API.
class ReadOnlyEntityQueryRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status is queried.
//! Allows multiple systems to weigh in on the read-only status of an entity.
//! @param entityId The entity whose status has changed.
//! @param[out] isReadOnly The output of the query. Should only be changed to true, and left untouched if false.
virtual void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) = 0;
protected:
~ReadOnlyEntityQueryRequests() = default;
};
using ReadOnlyEntityQueryRequestBus = AZ::EBus<ReadOnlyEntityQueryRequests>;
} // namespace AzToolsFramework
@@ -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/Interface/Interface.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityContextBus.h>
namespace AzToolsFramework
{
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityPublicInterface
{
public:
AZ_RTTI(ReadOnlyEntityPublicInterface, "{921FE15B-6EBD-47F0-8238-BC63318DEDEA}");
//! Returns whether the entity id provided is registered as read-only.
virtual bool IsReadOnly(const AZ::EntityId& entityId) = 0;
};
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityQueryInterface
{
public:
AZ_RTTI(ReadOnlyEntityQueryInterface, "{2ACD63C5-1F3E-4DE8-880E-8115F857D329}");
//! Refreshes the cached read-only status for the entities provided.
//! @param entityIds The entityIds whose read-only state will be queried again.
virtual void RefreshReadOnlyState(const EntityIdList& entityIds) = 0;
//! Refreshes the cached read-only status for all entities.
//! Useful when disconnecting a handler at runtime.
virtual void RefreshReadOnlyStateForAllEntities() = 0;
};
} // namespace AzToolsFramework
@@ -0,0 +1,99 @@
/*
* 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 <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
void ReadOnlyEntitySystemComponent::Activate()
{
AZ::Interface<ReadOnlyEntityQueryInterface>::Register(this);
AZ::Interface<ReadOnlyEntityPublicInterface>::Register(this);
EditorEntityContextNotificationBus::Handler::BusConnect();
}
void ReadOnlyEntitySystemComponent::Deactivate()
{
EditorEntityContextNotificationBus::Handler::BusDisconnect();
AZ::Interface<ReadOnlyEntityPublicInterface>::Unregister(this);
AZ::Interface<ReadOnlyEntityQueryInterface>::Unregister(this);
}
void ReadOnlyEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ReadOnlyEntitySystemComponent, AZ::Component>()->Version(1);
}
}
void ReadOnlyEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("ReadOnlyEntityService"));
}
bool ReadOnlyEntitySystemComponent::IsReadOnly(const AZ::EntityId& entityId)
{
if (!m_readOnlystates.contains(entityId))
{
QueryReadOnlyStateForEntity(entityId);
}
return m_readOnlystates[entityId];
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyState(const EntityIdList& entityIds)
{
for (const AZ::EntityId& entityId : entityIds)
{
bool wasReadOnly = m_readOnlystates[entityId];
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyStateForAllEntities()
{
for (auto& elem : m_readOnlystates)
{
AZ::EntityId entityId = elem.first;
bool wasReadOnly = elem.second;
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::OnContextReset()
{
m_readOnlystates.clear();
}
void ReadOnlyEntitySystemComponent::QueryReadOnlyStateForEntity(const AZ::EntityId& entityId)
{
bool isReadOnly = false;
ReadOnlyEntityQueryRequestBus::Broadcast(
&ReadOnlyEntityQueryRequestBus::Events::IsReadOnly, entityId, isReadOnly);
m_readOnlystates[entityId] = isReadOnly;
}
} // namespace AzToolsFramework
@@ -0,0 +1,56 @@
/*
* 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/Component/Component.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
namespace AzToolsFramework
{
//! System Component to track read-only entity registration.
//! An entity registered as ReadOnly cannot be altered in the Editor.
class ReadOnlyEntitySystemComponent final
: public AZ::Component
, private ReadOnlyEntityPublicInterface
, private ReadOnlyEntityQueryInterface
, private EditorEntityContextNotificationBus::Handler
{
public:
AZ_COMPONENT(ReadOnlyEntitySystemComponent, "{B32EB03F-D88F-4B3A-9C16-071AF04DA646}");
ReadOnlyEntitySystemComponent() = default;
virtual ~ReadOnlyEntitySystemComponent() = default;
// AZ::Component overrides ...
void Activate() override;
void Deactivate() override;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
// ReadOnlyEntityPublicNotifications overrides ...
bool IsReadOnly(const AZ::EntityId& entityId) override;
// ReadOnlyEntityQueryInterface overrides ...
void RefreshReadOnlyState(const EntityIdList& entityIds) override;
void RefreshReadOnlyStateForAllEntities() override;
// EditorEntityContextNotificationBus overrides ...
void OnContextReset() override;
private:
void QueryReadOnlyStateForEntity(const AZ::EntityId& entityId);
AZStd::unordered_map<AZ::EntityId, bool> m_readOnlystates;
};
} // namespace AzToolsFramework
@@ -50,7 +50,7 @@ namespace AzToolsFramework
return false;
}
void TraceLogger::PrepareLogFile(const AZStd::string& logFileName)
void TraceLogger::OpenLogFile(const AZStd::string& logFileName, bool clearLogFile)
{
using namespace AzFramework;
@@ -73,7 +73,7 @@ namespace AzToolsFramework
AZStd::string logPath;
StringFunc::Path::Join(logDirectory.c_str(), logFileName.c_str(), logPath);
m_logFile.reset(aznew LogFile(logPath.c_str()));
m_logFile.reset(aznew LogFile(logPath.c_str(), clearLogFile));
if (m_logFile)
{
m_logFile->SetMachineReadable(false);
@@ -81,7 +81,7 @@ namespace AzToolsFramework
{
m_logFile->AppendLog(LogFile::SEV_NORMAL, message.window.c_str(), message.message.c_str());
}
m_startupLogSink = {};
m_startupLogSink.clear();
m_logFile->FlushLog();
}
}
@@ -23,7 +23,7 @@ namespace AzToolsFramework
~TraceLogger();
//! Open log file and dump log sink into it
void PrepareLogFile(const AZStd::string& logFileName);
void OpenLogFile(const AZStd::string& logFileName, bool clearLogFile);
//! Add filter to ignore messages for windows with matching names
void AddWindowFilter(const AZStd::string& filter);
@@ -55,7 +55,8 @@ namespace AzToolsFramework
AZStd::string window;
AZStd::string message;
};
AZStd::vector<LogMessage> m_startupLogSink;
AZStd::list<LogMessage> m_startupLogSink;
AZStd::unordered_set<AZStd::string> m_windowFilters;
AZStd::unordered_set<AZStd::string> m_messageFilters;
AZStd::unique_ptr<AzFramework::LogFile> m_logFile;
@@ -191,8 +191,8 @@ namespace AzToolsFramework
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
void AngularManipulator::SetAxis(const AZ::Vector3& axis)
@@ -14,7 +14,7 @@
namespace AzToolsFramework
{
AZ_CVAR(bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators");
AZ_CVAR(bool, ed_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators");
const AZ::Color BaseManipulator::s_defaultMouseOverColor = AZ::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
@@ -28,7 +28,7 @@ namespace AzFramework
namespace AzToolsFramework
{
AZ_CVAR_EXTERNED(bool, cl_manipulatorDrawDebug);
AZ_CVAR_EXTERNED(bool, ed_manipulatorDrawDebug);
namespace UndoSystem
{
@@ -116,8 +116,8 @@ namespace AzToolsFramework
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
@@ -207,7 +207,7 @@ namespace AzToolsFramework
? AZ::Transform::CreateFromQuaternionAndTranslation(m_visualOrientationOverride, GetLocalPosition())
: GetLocalTransform();
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
if (PerformingAction())
{
@@ -239,8 +239,8 @@ namespace AzToolsFramework
view->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
ManipulatorState{ ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
@@ -146,7 +146,7 @@ namespace AzToolsFramework
for (const auto& pair : m_manipulatorIdToPtrMap)
{
pair.second->Draw({ Interacting() }, debugDisplay, cameraState, mouseInteraction);
pair.second->Draw(ManipulatorManagerState{ Interacting() }, debugDisplay, cameraState, mouseInteraction);
}
RefreshMouseOverState(mouseInteraction.m_mousePick);
@@ -10,6 +10,15 @@
namespace AzToolsFramework
{
AZ::Transform ApplySpace(const AZ::Transform& localTransform, const AZ::Transform& space, const AZ::Vector3& nonUniformScale)
{
AZ::Transform result;
result.SetRotation(space.GetRotation() * localTransform.GetRotation());
result.SetTranslation(space.TransformPoint(nonUniformScale * localTransform.GetTranslation()));
result.SetUniformScale(space.GetUniformScale() * localTransform.GetUniformScale());
return result;
}
const AZ::Transform& ManipulatorSpace::GetSpace() const
{
return m_space;
@@ -32,11 +41,7 @@ namespace AzToolsFramework
AZ::Transform ManipulatorSpace::ApplySpace(const AZ::Transform& localTransform) const
{
AZ::Transform result;
result.SetRotation(m_space.GetRotation() * localTransform.GetRotation());
result.SetTranslation(m_space.TransformPoint(m_nonUniformScale * localTransform.GetTranslation()));
result.SetUniformScale(m_space.GetUniformScale() * localTransform.GetUniformScale());
return result;
return AzToolsFramework::ApplySpace(localTransform, m_space, m_nonUniformScale);
}
const AZ::Vector3& ManipulatorSpaceWithLocalPosition::GetLocalPosition() const
@@ -17,6 +17,8 @@ namespace AZ
namespace AzToolsFramework
{
AZ::Transform ApplySpace(const AZ::Transform& localTransform, const AZ::Transform& space, const AZ::Vector3& nonUniformScale);
//! Handles location for manipulators which have a global space but no local transformation.
class ManipulatorSpace
{
@@ -21,6 +21,7 @@
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
#include <AzToolsFramework/Manipulators/SplineSelectionManipulator.h>
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
AZ_CVAR(
@@ -30,6 +31,13 @@ AZ_CVAR(
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Display additional debug drawing for manipulator bounds");
AZ_CVAR(
float,
ed_planarManipulatorBoundScaleFactor,
1.75f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The scale factor to apply to the planar manipulator bounds");
namespace AzToolsFramework
{
@@ -78,7 +86,8 @@ namespace AzToolsFramework
{
// check if we actually needed to flip the axis, if so, write to shouldCorrect
// so we know and are able to draw it differently if we wish (e.g. hollow if flipped)
const bool correcting = ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState);
const bool correcting =
FlipManipulatorAxesTowardsView() && ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState);
// the corrected axis, if no flip was required, output == input
correctedAxis = correcting ? -axis : axis;
@@ -325,7 +334,8 @@ namespace AzToolsFramework
float ManipulatorView::ManipulatorViewScaleMultiplier(
const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const
{
return ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f;
const float screenScale = ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f;
return screenScale * ManipulatorViewBaseScale();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -342,47 +352,77 @@ namespace AzToolsFramework
const AZ::Vector3 axis1 = m_axis1;
const AZ::Vector3 axis2 = m_axis2;
CameraCorrectAxis(
axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
CameraCorrectAxis(
axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
// support partial application of CameraCorrectAxis to reduce redundant call site parameters
auto cameraCorrectAxisPartialFn =
[&manipulatorState, &managerState, &mouseInteraction, &cameraState](const AZ::Vector3& inAxis, AZ::Vector3& outAxis)
{
CameraCorrectAxis(
inAxis, outAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition,
cameraState);
};
const Picking::BoundShapeQuad quadBound = CalculateQuadBound(
manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
m_size *
ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState));
cameraCorrectAxisPartialFn(axis1, m_cameraCorrectedAxis1);
cameraCorrectAxisPartialFn(axis2, m_cameraCorrectedAxis2);
cameraCorrectAxisPartialFn(axis1 * axis1.Dot(m_offset), m_cameraCorrectedOffsetAxis1);
cameraCorrectAxisPartialFn(axis2 * axis2.Dot(m_offset), m_cameraCorrectedOffsetAxis2);
const AZ::Vector3 totalScale =
manipulatorState.m_nonUniformScale * AZ::Vector3(manipulatorState.m_worldFromLocal.GetUniformScale());
const auto cameraCorrectedVisualOffset = (m_cameraCorrectedOffsetAxis1 + m_cameraCorrectedOffsetAxis2) * totalScale.GetReciprocal();
const auto viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const Picking::BoundShapeQuad quadBoundVisual = CalculateQuadBound(
manipulatorState.m_localPosition + (cameraCorrectedVisualOffset * viewScale), manipulatorState, m_cameraCorrectedAxis1,
m_cameraCorrectedAxis2, m_size * viewScale);
debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver));
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_axis1Color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawLine(quadBound.m_corner4, quadBound.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner4, quadBoundVisual.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner1, quadBoundVisual.m_corner2);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_axis2Color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawLine(quadBound.m_corner2, quadBound.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner4, quadBoundVisual.m_corner1);
debugDisplay.DrawLine(quadBoundVisual.m_corner2, quadBoundVisual.m_corner3);
if (manipulatorState.m_mouseOver)
{
debugDisplay.SetColor(Vector3ToVector4(m_mouseOverColor.GetAsVector3(), 0.5f));
debugDisplay.CullOff();
debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4);
debugDisplay.DrawQuad(
quadBoundVisual.m_corner1, quadBoundVisual.m_corner2, quadBoundVisual.m_corner3, quadBoundVisual.m_corner4);
debugDisplay.CullOn();
}
RefreshBoundInternal(managerId, manipulatorId, quadBound);
// total size of bounds to use for mouse intersection
const float hitSize = m_size * ed_planarManipulatorBoundScaleFactor;
// size of edge bounds (the 'margin/border' outside the visual representation)
const float edgeSize = (hitSize - m_size) * 0.5f;
const AZ::Vector3 edgeOffset =
((m_cameraCorrectedAxis1 * edgeSize + m_cameraCorrectedAxis2 * edgeSize) * totalScale.GetReciprocal());
const auto cameraCorrectedHitOffset = cameraCorrectedVisualOffset - edgeOffset;
const Picking::BoundShapeQuad quadBoundHit = CalculateQuadBound(
manipulatorState.m_localPosition + (cameraCorrectedHitOffset * viewScale), manipulatorState, m_cameraCorrectedAxis1,
m_cameraCorrectedAxis2, hitSize * viewScale);
if (ed_manipulatorDisplayBoundDebug)
{
debugDisplay.DrawQuad(quadBoundHit.m_corner1, quadBoundHit.m_corner2, quadBoundHit.m_corner3, quadBoundHit.m_corner4);
}
RefreshBoundInternal(managerId, manipulatorId, quadBoundHit);
}
void ManipulatorViewQuadBillboard::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
[[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const Picking::BoundShapeQuad quadBound = CalculateQuadBoundBillboard(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
@@ -442,7 +482,7 @@ namespace AzToolsFramework
void ManipulatorViewLineSelect::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -570,7 +610,7 @@ namespace AzToolsFramework
void ManipulatorViewSphere::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -599,12 +639,12 @@ namespace AzToolsFramework
void ManipulatorViewCircle::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
[[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
@@ -665,7 +705,7 @@ namespace AzToolsFramework
void ManipulatorViewSplineSelect::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -698,12 +738,18 @@ namespace AzToolsFramework
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const float size)
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Vector3& offset,
const float size)
{
AZStd::unique_ptr<ManipulatorViewQuad> viewQuad = AZStd::make_unique<ManipulatorViewQuad>();
viewQuad->m_axis1 = planarManipulator.GetAxis1();
viewQuad->m_axis2 = planarManipulator.GetAxis2();
viewQuad->m_axis1 = axis1;
viewQuad->m_axis2 = axis2;
viewQuad->m_size = size;
viewQuad->m_offset = offset;
viewQuad->m_axis1Color = axis1Color;
viewQuad->m_axis2Color = axis2Color;
return viewQuad;
@@ -54,7 +54,7 @@ namespace AzToolsFramework
AZ_RTTI(ManipulatorView, "{7529E3E9-39B3-4D15-899A-FA13770113B2}")
ManipulatorView();
ManipulatorView(bool screenSizeFixed);
explicit ManipulatorView(bool screenSizeFixed);
virtual ~ManipulatorView();
ManipulatorView(ManipulatorView&&) = default;
ManipulatorView& operator=(ManipulatorView&&) = default;
@@ -117,13 +117,16 @@ namespace AzToolsFramework
AZ::Vector3 m_axis1 = AZ::Vector3(1.0f, 0.0f, 0.0f);
AZ::Vector3 m_axis2 = AZ::Vector3(0.0f, 1.0f, 0.0f);
AZ::Vector3 m_offset = AZ::Vector3::CreateZero();
AZ::Color m_axis1Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
AZ::Color m_axis2Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
float m_size = 0.06f; //!< size to render and do mouse ray intersection tests against.
private:
AZ::Vector3 m_cameraCorrectedAxis1;
AZ::Vector3 m_cameraCorrectedAxis2;
AZ::Vector3 m_cameraCorrectedAxis1; //!< First axis of quad (should be orthogonal to second axis).
AZ::Vector3 m_cameraCorrectedAxis2; //!< Second axis of quad (should be orthogonal to first axis).
AZ::Vector3 m_cameraCorrectedOffsetAxis1; //!< Offset along first axis (parallel with first axis).
AZ::Vector3 m_cameraCorrectedOffsetAxis2; //!< Offset along second axis (parallel with second axis).
};
//! A screen aligned quad, centered at the position of the manipulator, display filled.
@@ -379,7 +382,12 @@ namespace AzToolsFramework
// Helpers to create various manipulator views.
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, float size);
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Vector3& offset,
float size);
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(const AZ::Color& color, float size);
@@ -132,7 +132,7 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
const AZ::Transform combined = TransformUniformScale(GetSpace()) * GetLocalTransform();
for (const auto& fixed : m_fixedAxes)
@@ -145,8 +145,8 @@ namespace AzToolsFramework
{
view->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() },
debugDisplay, cameraState, mouseInteraction);
}
}
@@ -171,7 +171,7 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
if (PerformingAction())
{
@@ -202,8 +202,8 @@ namespace AzToolsFramework
{
view->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() },
debugDisplay, cameraState, mouseInteraction);
}
}
@@ -9,6 +9,7 @@
#include "ScaleManipulators.h"
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
@@ -120,25 +121,25 @@ namespace AzToolsFramework
void ScaleManipulators::ConfigureView(
const float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color)
{
const float boxSize = 0.1f;
const float boxHalfExtent = ScaleManipulatorBoxHalfExtent();
const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex)
{
const auto lineLength = axisLength - boxSize;
const auto lineLength = axisLength - (2.0f * boxHalfExtent);
ManipulatorViews views;
views.emplace_back(
CreateManipulatorViewLine(*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, m_lineBoundWidth));
views.emplace_back(CreateManipulatorViewLine(
*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, m_lineBoundWidth));
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), colors[manipulatorIndex],
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * lineLength, AZ::Vector3(boxSize)));
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (lineLength + boxHalfExtent), AZ::Vector3(boxHalfExtent)));
m_axisScaleManipulators[manipulatorIndex]->SetViews(AZStd::move(views));
}
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxSize)));
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxHalfExtent)));
m_uniformScaleManipulator->SetViews(AZStd::move(views));
}
@@ -90,8 +90,8 @@ namespace AzToolsFramework
{
view->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
@@ -94,8 +94,8 @@ namespace AzToolsFramework
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() },
debugDisplay, cameraState, mouseInteraction);
}
}
@@ -166,8 +166,8 @@ namespace AzToolsFramework
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
void SurfaceManipulator::InvalidateImpl()
@@ -10,18 +10,30 @@
#include <AzCore/Math/VectorConversions.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
static const float SurfaceManipulatorTransparency = 0.75f;
static const float LinearManipulatorAxisLength = 2.0f;
static const float SurfaceManipulatorRadius = 0.1f;
static const AZ::Color LinearManipulatorXAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorYAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorZAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
static const AZ::Color SurfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
static TranslationManipulatorsViewCreateInfo DefaultTranslationManipulatorViewCreateInfo()
{
TranslationManipulatorsViewCreateInfo createInfo;
createInfo.axis1Color = LinearManipulatorXAxisColor;
createInfo.axis2Color = LinearManipulatorYAxisColor;
createInfo.axis3Color = LinearManipulatorZAxisColor;
createInfo.surfaceColor = SurfaceManipulatorColor;
createInfo.linearAxisLength = LinearManipulatorAxisLength();
createInfo.linearConeLength = LinearManipulatorConeLength();
createInfo.linearConeRadius = LinearManipulatorConeRadius();
createInfo.planarAxisLength = PlanarManipulatorAxisLength();
createInfo.surfaceRadius = SurfaceManipulatorRadius();
return createInfo;
}
TranslationManipulators::TranslationManipulators(
const Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
: m_dimensions(dimensions)
@@ -234,15 +246,32 @@ namespace AzToolsFramework
}
}
void TranslationManipulators::ConfigureView2d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo)
{
ConfigureLinearView(
translationManipulatorViewCreateInfo.linearAxisLength, translationManipulatorViewCreateInfo.linearConeLength,
translationManipulatorViewCreateInfo.linearConeRadius, translationManipulatorViewCreateInfo.axis1Color,
translationManipulatorViewCreateInfo.axis2Color, translationManipulatorViewCreateInfo.axis3Color);
ConfigurePlanarView(
translationManipulatorViewCreateInfo.planarAxisLength, translationManipulatorViewCreateInfo.linearAxisLength,
translationManipulatorViewCreateInfo.linearConeLength, translationManipulatorViewCreateInfo.axis1Color,
translationManipulatorViewCreateInfo.axis2Color, translationManipulatorViewCreateInfo.axis3Color);
}
void TranslationManipulators::ConfigureView3d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo)
{
ConfigureView2d(translationManipulatorViewCreateInfo);
ConfigureSurfaceView(translationManipulatorViewCreateInfo.surfaceRadius, translationManipulatorViewCreateInfo.surfaceColor);
}
void TranslationManipulators::ConfigureLinearView(
const float axisLength,
const float coneLength,
const float coneRadius,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Color& axis3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/)
{
const float coneLength = 0.28f;
const float coneRadius = 0.07f;
const AZ::Color axesColor[] = { axis1Color, axis2Color, axis3Color };
const auto configureLinearView = [lineBoundWidth = m_lineBoundWidth, coneLength, axisLength,
@@ -251,7 +280,7 @@ namespace AzToolsFramework
const auto lineLength = axisLength - coneLength;
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewLine(*linearManipulator, color, lineLength, lineBoundWidth));
views.emplace_back(CreateManipulatorViewLine(*linearManipulator, color, axisLength, lineBoundWidth));
views.emplace_back(
CreateManipulatorViewCone(*linearManipulator, color, linearManipulator->GetAxis() * lineLength, coneLength, coneRadius));
linearManipulator->SetViews(AZStd::move(views));
@@ -264,19 +293,21 @@ namespace AzToolsFramework
}
void TranslationManipulators::ConfigurePlanarView(
const float planarAxisLength,
const float linearAxisLength,
const float linearConeLength,
const AZ::Color& plane1Color,
const AZ::Color& plane2Color /*= AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)*/,
const AZ::Color& plane3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/)
{
const float planeSize = 0.6f;
const AZ::Color planesColor[] = { plane1Color, plane2Color, plane3Color };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_planarManipulators.size(); ++manipulatorIndex)
{
const AZStd::shared_ptr<ManipulatorViewQuad> manipulatorView = CreateManipulatorViewQuad(
*m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], planesColor[(manipulatorIndex + 1) % 3], planeSize);
m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ manipulatorView });
const auto& planarManipulator = *m_planarManipulators[manipulatorIndex];
m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ CreateManipulatorViewQuadForPlanarTranslationManipulator(
planarManipulator.GetAxis1(), planarManipulator.GetAxis2(), planesColor[manipulatorIndex],
planesColor[(manipulatorIndex + 1) % 3], linearAxisLength, linearConeLength, planarAxisLength) });
}
}
@@ -286,12 +317,11 @@ namespace AzToolsFramework
{
m_surfaceManipulator->SetView(CreateManipulatorViewSphere(
color, radius,
[](const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, bool mouseOver,
[]([[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction, bool mouseOver,
const AZ::Color& defaultColor) -> AZ::Color
{
const AZ::Color color[2] = {
defaultColor,
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorTransparency)
defaultColor, Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorOpacity())
};
return color[mouseOver];
@@ -325,16 +355,25 @@ namespace AzToolsFramework
void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureLinearView(
LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius, SurfaceManipulatorColor);
translationManipulators->ConfigureView3d(DefaultTranslationManipulatorViewCreateInfo());
}
void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY());
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor);
translationManipulators->ConfigureLinearView(LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
translationManipulators->ConfigureView2d(DefaultTranslationManipulatorViewCreateInfo());
}
AZStd::shared_ptr<ManipulatorViewQuad> CreateManipulatorViewQuadForPlanarTranslationManipulator(
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const float linearAxisLength,
const float linearConeLength,
const float planarAxisLength)
{
const AZ::Vector3 offset = (axis1 + axis2) * (((linearAxisLength - linearConeLength) * 0.5f) - (planarAxisLength * 0.5f));
return CreateManipulatorViewQuad(axis1, axis2, axis1Color, axis2Color, offset, planarAxisLength);
}
} // namespace AzToolsFramework
@@ -15,6 +15,20 @@
namespace AzToolsFramework
{
//! Parameters to configure the appearance of the TranslationManipulators view(s).
struct TranslationManipulatorsViewCreateInfo
{
float linearAxisLength;
float linearConeLength;
float linearConeRadius;
float planarAxisLength;
float surfaceRadius;
AZ::Color axis1Color;
AZ::Color axis2Color;
AZ::Color axis3Color;
AZ::Color surfaceColor;
};
//! TranslationManipulators is an aggregation of 3 linear manipulators, 3 planar manipulators
//! and one surface manipulator who share the same transform.
class TranslationManipulators : public Manipulators
@@ -23,6 +37,9 @@ namespace AzToolsFramework
AZ_RTTI(TranslationManipulators, "{D5E49EA2-30E0-42BC-A51D-6A7F87818260}")
AZ_CLASS_ALLOCATOR(TranslationManipulators, AZ::SystemAllocator, 0)
TranslationManipulators(TranslationManipulators&&) = delete;
TranslationManipulators& operator=(TranslationManipulators&&) = delete;
//! How many dimensions does this translation manipulator have.
enum class Dimensions
{
@@ -52,25 +69,31 @@ namespace AzToolsFramework
void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3 = AZ::Vector3::CreateAxisZ());
void ConfigureView2d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo);
void ConfigureView3d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo);
//! Sets the bound width to use for the line/axis of a linear manipulator.
void SetLineBoundWidth(float lineBoundWidth);
private:
void ConfigurePlanarView(
float planeSize,
float linearAxisLength,
float linearConeLength,
const AZ::Color& plane1Color,
const AZ::Color& plane2Color = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f),
const AZ::Color& plane3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f));
void ConfigureLinearView(
float axisLength,
float coneLength,
float coneRadius,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f));
void ConfigureSurfaceView(float radius, const AZ::Color& color);
//! Sets the bound width to use for the line/axis of a linear manipulator.
void SetLineBoundWidth(float lineBoundWidth);
private:
AZ_DISABLE_COPY_MOVE(TranslationManipulators)
// Manipulators
void ProcessManipulators(const AZStd::function<void(BaseManipulator*)>&) override;
@@ -130,4 +153,12 @@ namespace AzToolsFramework
void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators);
void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators);
AZStd::shared_ptr<ManipulatorViewQuad> CreateManipulatorViewQuadForPlanarTranslationManipulator(
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
float linearAxisLength,
float linearConeLength,
float planarAxisLength);
} // namespace AzToolsFramework
@@ -521,21 +521,18 @@ namespace AzToolsFramework
nestedInstanceLink.has_value(),
"A valid link was not found for one of the instances provided as input for the CreatePrefab operation.");
PrefabDomReference nestedInstanceLinkDom = nestedInstanceLink->get().GetLinkDom();
AZ_Assert(
nestedInstanceLinkDom.has_value(),
"A valid DOM was not found for the link corresponding to one of the instances provided as input for the "
"CreatePrefab operation.");
PrefabDomValueReference nestedInstanceLinkPatches =
PrefabDomUtils::FindPrefabDomValue(nestedInstanceLinkDom->get(), PrefabDomUtils::PatchesName);
AZ_Assert(
nestedInstanceLinkPatches.has_value(),
"A valid DOM for patches was not found for the link corresponding to one of the instances provided as input for the "
"CreatePrefab operation.");
PrefabDom patchesCopyForUndoSupport;
patchesCopyForUndoSupport.CopyFrom(nestedInstanceLinkPatches->get(), patchesCopyForUndoSupport.GetAllocator());
PrefabDomReference nestedInstanceLinkDom = nestedInstanceLink->get().GetLinkDom();
if (nestedInstanceLinkDom.has_value())
{
PrefabDomValueReference nestedInstanceLinkPatches =
PrefabDomUtils::FindPrefabDomValue(nestedInstanceLinkDom->get(), PrefabDomUtils::PatchesName);
if (nestedInstanceLinkPatches.has_value())
{
patchesCopyForUndoSupport.CopyFrom(nestedInstanceLinkPatches->get(), patchesCopyForUndoSupport.GetAllocator());
}
}
PrefabUndoHelpers::RemoveLink(
sourceInstance->GetTemplateId(), targetTemplateId, sourceInstance->GetInstanceAlias(), sourceInstance->GetLinkId(),
AZStd::move(patchesCopyForUndoSupport), undoBatch);
@@ -8,10 +8,12 @@
#include <API/ToolsApplicationAPI.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
#include <Prefab/PrefabSystemComponentInterface.h>
#include <Prefab/PrefabSystemScriptingHandler.h>
#include <AzCore/Component/Entity.h>
#include <Prefab/EditorPrefabComponent.h>
#include <ToolsComponents/TransformComponent.h>
@@ -72,6 +74,9 @@ namespace AzToolsFramework::Prefab
entities, commonRoot, &topLevelEntities);
auto containerEntity = AZStd::make_unique<AZ::Entity>();
containerEntity->CreateComponent<Components::TransformComponent>();
containerEntity->CreateComponent<Components::EditorLockComponent>();
containerEntity->CreateComponent<Components::EditorVisibilityComponent>();
containerEntity->CreateComponent<Prefab::EditorPrefabComponent>();
for (AZ::Entity* entity : topLevelEntities)
@@ -565,9 +565,7 @@ namespace AzToolsFramework
EditorRequestBus::BroadcastResult(position, &EditorRequestBus::Events::GetWorldPositionAtViewportCenter);
}
// Instantiating from context menu always puts the instance at the root level
auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabFilePath, parentId, position);
if (!createPrefabOutcome.IsSuccess())
{
WarnUserOfError("Prefab Instantiation Error",createPrefabOutcome.GetError());
@@ -594,15 +592,13 @@ namespace AzToolsFramework
}
else
{
// otherwise return since it needs to be inside an authored prefab
return;
EditorRequestBus::BroadcastResult(position, &EditorRequestBus::Events::GetWorldPositionAtViewportCenter);
}
// Instantiating from context menu always puts the instance at the root level
auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabAssetPath, parentId, position);
if (!createPrefabOutcome.IsSuccess())
{
WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError());
WarnUserOfError("Procedural Prefab Instantiation Error", createPrefabOutcome.GetError());
}
}
}
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/Slice/SliceDataFlagsCommand.h>
@@ -497,6 +498,9 @@ namespace AzToolsFramework
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
AZ_Assert(m_prefabPublicInterface != nullptr, "EntityPropertyEditor requires a PrefabPublicInterface instance on Initialize.");
m_readOnlyEntityPublicInterface = AZ::Interface<ReadOnlyEntityPublicInterface>::Get();
AZ_Assert(m_readOnlyEntityPublicInterface != nullptr, "EntityPropertyEditor requires a ReadOnlyEntityPublicInterface instance on Initialize.");
setObjectName("EntityPropertyEditor");
setAcceptDrops(true);
@@ -535,10 +539,6 @@ namespace AzToolsFramework
model->setItem(row, 0, m_comboItems[row]);
}
m_gui->m_statusComboBox->setModel(model);
m_gui->m_statusComboBox->setStyleSheet("QComboBox {border: 0px; border-radius:3px; background-color:#555555; color:white}"
"QComboBox:on {background-color:#e9e9e9; color:black; border:0px}"
"QComboBox::down-arrow:on {image: url(:/stylesheet/img/dropdowns/black_down_arrow.png)}"
"QComboBox::drop-down {border-radius: 3p}");
AzQtComponents::ComboBox::addCustomCheckStateStyle(m_gui->m_statusComboBox);
EnableEditor(true);
m_sceneIsNew = true;
@@ -565,6 +565,12 @@ namespace AzToolsFramework
AZ::EntitySystemBus::Handler::BusConnect();
EntityPropertyEditorRequestBus::Handler::BusConnect();
EditorWindowUIRequestBus::Handler::BusConnect();
AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(
editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityPublicNotificationBus::Handler::BusConnect(editorEntityContextId);
m_spacer = nullptr;
m_emptyIcon = QIcon();
@@ -614,6 +620,7 @@ namespace AzToolsFramework
{
qApp->removeEventFilter(this);
ReadOnlyEntityPublicNotificationBus::Handler::BusDisconnect();
EditorWindowUIRequestBus::Handler::BusDisconnect();
EntityPropertyEditorRequestBus::Handler::BusDisconnect();
ToolsApplicationEvents::Bus::Handler::BusDisconnect();
@@ -973,7 +980,7 @@ namespace AzToolsFramework
m_gui->m_entityDetailsLabel->setVisible(false);
// If we're in edit mode, make the name field editable.
m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled());
m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled() || m_selectionContainsReadOnlyEntity);
// get the name of the entity.
auto entity = GetSelectedEntityById(entityId);
@@ -1062,6 +1069,12 @@ namespace AzToolsFramework
bool EntityPropertyEditor::CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const
{
if (m_selectionContainsReadOnlyEntity)
{
// Can't add components if there is a read only entity in the selection
return false;
}
if (selectionEntityTypeInfo == SelectionEntityTypeInfo::Mixed ||
selectionEntityTypeInfo == SelectionEntityTypeInfo::None)
{
@@ -1126,6 +1139,17 @@ namespace AzToolsFramework
m_selectedEntityIds.clear();
GetSelectedEntities(m_selectedEntityIds);
// Check if any of the selected entities are marked as read only
m_selectionContainsReadOnlyEntity = false;
for (const auto& entityId : m_selectedEntityIds)
{
if (m_readOnlyEntityPublicInterface->IsReadOnly(entityId))
{
m_selectionContainsReadOnlyEntity = true;
break;
}
}
SourceControlFileInfo scFileInfo;
ToolsApplicationRequests::Bus::BroadcastResult(scFileInfo, &ToolsApplicationRequests::GetSceneSourceControlInfo);
@@ -1681,6 +1705,12 @@ namespace AzToolsFramework
componentEditor->UpdateExpandability();
componentEditor->InvalidateAll(!componentInFilter ? m_filterString.c_str() : nullptr);
// If we are in read only mode, then show the components as disabled
if (m_selectionContainsReadOnlyEntity)
{
componentEditor->mockDisabledState(true);
}
if (!componentEditor->GetPropertyEditor()->HasFilteredOutNodes() || componentEditor->GetPropertyEditor()->HasVisibleNodes())
{
for (AZ::Component* componentInstance : componentInstances)
@@ -3077,6 +3107,7 @@ namespace AzToolsFramework
}
}
m_gui->m_statusComboBox->setDisabled(m_selectionContainsReadOnlyEntity);
m_gui->m_statusComboBox->setVisible(!m_isSystemEntityEditor && !m_isLevelEntityEditor);
m_gui->m_statusComboBox->style()->unpolish(m_gui->m_statusComboBox);
m_gui->m_statusComboBox->style()->polish(m_gui->m_statusComboBox);
@@ -3304,7 +3335,8 @@ namespace AzToolsFramework
const auto& componentsToEdit = GetSelectedComponents();
const bool hasComponents = !m_selectedEntityIds.empty() && !componentsToEdit.empty();
const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit);
// Don't allow components to be removed/cut/enabled/disabled if read only
const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit) && !m_selectionContainsReadOnlyEntity;
const bool allowCopy = hasComponents && AreComponentsCopyable(componentsToEdit);
m_actionToDeleteComponents->setEnabled(allowRemove);
@@ -3366,6 +3398,12 @@ namespace AzToolsFramework
return false;
}
if (m_selectionContainsReadOnlyEntity)
{
// Can't paste components if there is a read only entity in the selection
return false;
}
// Grab component data from clipboard, if exists
const QMimeData* mimeData = ComponentMimeData::GetComponentMimeDataFromClipboard();
@@ -5727,6 +5765,14 @@ namespace AzToolsFramework
SaveComponentEditorState();
}
void EntityPropertyEditor::OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly)
{
if (IsEntitySelected(entityId))
{
UpdateContents();
}
}
void EntityPropertyEditor::OnEditorModeActivated(
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
{
@@ -29,6 +29,7 @@
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
#include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
#include <AzToolsFramework/ToolsComponents/EditorInspectorComponentBus.h>
#include <AzQtComponents/Components/O3DEStylesheet.h>
@@ -62,6 +63,7 @@ namespace AzToolsFramework
class ComponentPaletteWidget;
class ComponentModeCollectionInterface;
struct SourceControlFileInfo;
class ReadOnlyEntityPublicInterface;
namespace AssetBrowser
{
@@ -116,6 +118,7 @@ namespace AzToolsFramework
, public AZ::EntitySystemBus::Handler
, public AZ::TickBus::Handler
, private EditorWindowUIRequestBus::Handler
, private ReadOnlyEntityPublicNotificationBus::Handler
{
Q_OBJECT;
public:
@@ -253,6 +256,9 @@ namespace AzToolsFramework
// EditorWindowRequestBus overrides
void SetEditorUiEnabled(bool enable) override;
// ReadOnlyEntityPublicNotificationBus overrides ...
void OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, bool readOnly) override;
bool IsEntitySelected(const AZ::EntityId& id) const;
bool IsSingleEntitySelected(const AZ::EntityId& id) const;
@@ -623,6 +629,9 @@ namespace AzToolsFramework
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
bool m_prefabsAreEnabled = false;
ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr;
bool m_selectionContainsReadOnlyEntity = false;
// Reordering row widgets within the RPE.
static constexpr float MoveFadeSeconds = 0.5f;
@@ -191,7 +191,7 @@
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(51, 51, 51)</string>
<string notr="true">QWidget#m_darkBox { background-color:rgb(51, 51, 51) }</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
@@ -444,6 +444,9 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(51, 51, 51)</string>
</property>
</widget>
</item>
<item>
@@ -15,12 +15,14 @@
#include <AzCore/Slice/SliceComponent.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzTest/AzTest.h>
#include <AZTestShared/Math/MathTestHelpers.h>
#include <AZTestShared/Utils/Utils.h>
#include <AzFramework/UnitTest/TestDebugDisplayRequests.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
@@ -235,6 +237,13 @@ namespace UnitTest
return toolsApp;
}
//! It is possible to override this in classes deriving from ToolsApplicationFixture to provide alternate
//! implementations of the DebugDisplayRequests interface (e.g. TestDebugDisplayRequests).
virtual AZStd::shared_ptr<AzFramework::DebugDisplayRequests> CreateDebugDisplayRequests()
{
return AZStd::make_shared<NullDebugDisplayRequests>();
}
protected:
TestEditorActions m_editorActions;
ToolsApplicationMessageHandler m_messageHandler; // used to suppress trace messages in test output
@@ -0,0 +1,123 @@
/*
* 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 <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
constexpr AZStd::string_view FlipManipulatorAxesTowardsViewSetting = "/Amazon/Preferences/Editor/Manipulator/FlipManipulatorAxesTowardsView";
constexpr AZStd::string_view LinearManipulatorAxisLengthSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorAxisLength";
constexpr AZStd::string_view PlanarManipulatorAxisLengthSetting = "/Amazon/Preferences/Editor/Manipulator/PlanarManipulatorAxisLength";
constexpr AZStd::string_view SurfaceManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/SurfaceManipulatorRadius";
constexpr AZStd::string_view SurfaceManipulatorOpacitySetting = "/Amazon/Preferences/Editor/Manipulator/SurfaceManipulatorOpacity";
constexpr AZStd::string_view LinearManipulatorConeLengthSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorConeLength";
constexpr AZStd::string_view LinearManipulatorConeRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorConeRadius";
constexpr AZStd::string_view ScaleManipulatorBoxHalfExtentSetting = "/Amazon/Preferences/Editor/Manipulator/ScaleManipulatorBoxHalfExtent";
constexpr AZStd::string_view RotationManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/RotationManipulatorRadius";
constexpr AZStd::string_view ManipulatorViewBaseScaleSetting = "/Amazon/Preferences/Editor/Manipulator/ViewBaseScale";
bool FlipManipulatorAxesTowardsView()
{
return GetRegistry(FlipManipulatorAxesTowardsViewSetting, true);
}
void SetFlipManipulatorAxesTowardsView(const bool enabled)
{
SetRegistry(FlipManipulatorAxesTowardsViewSetting, enabled);
}
float LinearManipulatorAxisLength()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorAxisLengthSetting, 2.0));
}
void SetLinearManipulatorAxisLength(const float length)
{
SetRegistry(LinearManipulatorAxisLengthSetting, length);
}
float PlanarManipulatorAxisLength()
{
return aznumeric_cast<float>(GetRegistry(PlanarManipulatorAxisLengthSetting, 0.6));
}
void SetPlanarManipulatorAxisLength(const float length)
{
SetRegistry(PlanarManipulatorAxisLengthSetting, length);
}
float SurfaceManipulatorRadius()
{
return aznumeric_cast<float>(GetRegistry(SurfaceManipulatorRadiusSetting, 0.1));
}
void SetSurfaceManipulatorRadius(const float radius)
{
SetRegistry(SurfaceManipulatorRadiusSetting, radius);
}
float SurfaceManipulatorOpacity()
{
return aznumeric_cast<float>(GetRegistry(SurfaceManipulatorOpacitySetting, 0.75));
}
void SetSurfaceManipulatorOpacity(const float opacity)
{
SetRegistry(SurfaceManipulatorOpacitySetting, opacity);
}
float LinearManipulatorConeLength()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorConeLengthSetting, 0.28));
}
void SetLinearManipulatorConeLength(const float length)
{
SetRegistry(LinearManipulatorConeLengthSetting, length);
}
float LinearManipulatorConeRadius()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorConeRadiusSetting, 0.1));
}
void SetLinearManipulatorConeRadius(const float radius)
{
SetRegistry(LinearManipulatorConeRadiusSetting, radius);
}
float ScaleManipulatorBoxHalfExtent()
{
return aznumeric_cast<float>(GetRegistry(ScaleManipulatorBoxHalfExtentSetting, 0.1));
}
void SetScaleManipulatorBoxHalfExtent(const float size)
{
SetRegistry(ScaleManipulatorBoxHalfExtentSetting, size);
}
float RotationManipulatorRadius()
{
return aznumeric_cast<float>(GetRegistry(RotationManipulatorRadiusSetting, 2.0));
}
void SetRotationManipulatorRadius(const float radius)
{
SetRegistry(RotationManipulatorRadiusSetting, radius);
}
float ManipulatorViewBaseScale()
{
return aznumeric_cast<float>(GetRegistry(ManipulatorViewBaseScaleSetting, 1.0));
}
void SetManipulatorViewBaseScale(const float scale)
{
SetRegistry(ManipulatorViewBaseScaleSetting, scale);
}
} // namespace AzToolsFramework
@@ -0,0 +1,69 @@
/*
* 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/Settings/SettingsRegistry.h>
namespace AzToolsFramework
{
template<typename T>
void SetRegistry(const AZStd::string_view setting, T&& value)
{
if (auto* registry = AZ::SettingsRegistry::Get())
{
registry->Set(setting, AZStd::forward<T>(value));
}
}
template<typename T>
AZStd::remove_cvref_t<T> GetRegistry(const AZStd::string_view setting, T&& defaultValue)
{
AZStd::remove_cvref_t<T> value = AZStd::forward<T>(defaultValue);
if (const auto* registry = AZ::SettingsRegistry::Get())
{
T potentialValue;
if (registry->Get(potentialValue, setting))
{
value = AZStd::move(potentialValue);
}
}
return value;
}
bool FlipManipulatorAxesTowardsView();
void SetFlipManipulatorAxesTowardsView(bool enabled);
float LinearManipulatorAxisLength();
void SetLinearManipulatorAxisLength(float length);
float PlanarManipulatorAxisLength();
void SetPlanarManipulatorAxisLength(float length);
float SurfaceManipulatorRadius();
void SetSurfaceManipulatorRadius(float radius);
float SurfaceManipulatorOpacity();
void SetSurfaceManipulatorOpacity(float opacity);
float LinearManipulatorConeLength();
void SetLinearManipulatorConeLength(float length);
float LinearManipulatorConeRadius();
void SetLinearManipulatorConeRadius(float radius);
float ScaleManipulatorBoxHalfExtent();
void SetScaleManipulatorBoxHalfExtent(float halfExtent);
float RotationManipulatorRadius();
void SetRotationManipulatorRadius(float radius);
float ManipulatorViewBaseScale();
void SetManipulatorViewBaseScale(float scale);
} // namespace AzToolsFramework
@@ -33,6 +33,7 @@
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Viewport/ActionBus.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <Entity/EditorEntityContextBus.h>
@@ -1376,7 +1377,7 @@ namespace AzToolsFramework
// view
rotationManipulators->SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
rotationManipulators->ConfigureView(
2.0f, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
RotationManipulatorRadius(), AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
AzFramework::ViewportColors::ZAxisColor);
struct SharedRotationState
@@ -1535,7 +1536,8 @@ namespace AzToolsFramework
RecalculateAverageManipulatorTransform(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame));
scaleManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
scaleManipulators->ConfigureView(2.0f, AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
scaleManipulators->ConfigureView(
LinearManipulatorAxisLength(), AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
struct SharedScaleState
{
@@ -159,6 +159,10 @@ set(FILES
Entity/SliceEditorEntityOwnershipServiceBus.h
Entity/EntityUtilityComponent.h
Entity/EntityUtilityComponent.cpp
Entity/ReadOnly/ReadOnlyEntityInterface.h
Entity/ReadOnly/ReadOnlyEntityBus.h
Entity/ReadOnly/ReadOnlyEntitySystemComponent.cpp
Entity/ReadOnly/ReadOnlyEntitySystemComponent.h
Fingerprinting/TypeFingerprinter.h
Fingerprinting/TypeFingerprinter.cpp
FocusMode/FocusModeInterface.h
@@ -502,6 +506,8 @@ set(FILES
Viewport/ViewportMessages.cpp
Viewport/ViewportTypes.h
Viewport/ViewportTypes.cpp
Viewport/ViewportSettings.h
Viewport/ViewportSettings.cpp
ViewportUi/Button.h
ViewportUi/Button.cpp
ViewportUi/ButtonGroup.h
@@ -0,0 +1,125 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Tests/Entity/ReadOnly/ReadOnlyEntityFixture.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzToolsFramework
{
void ReadOnlyEntityFixture::SetUpEditorFixtureImpl()
{
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
m_readOnlyEntityPublicInterface = AZ::Interface<ReadOnlyEntityPublicInterface>::Get();
ASSERT_TRUE(m_readOnlyEntityPublicInterface != nullptr);
GenerateTestHierarchy();
}
void ReadOnlyEntityFixture::TearDownEditorFixtureImpl()
{
}
void ReadOnlyEntityFixture::GenerateTestHierarchy()
{
/*
* Root
* |_ Child
* |_ GrandChild1
* |_ GrandChild2
*/
m_entityMap[RootEntityName] = CreateEditorEntity(RootEntityName, AZ::EntityId());
m_entityMap[ChildEntityName] = CreateEditorEntity(ChildEntityName, m_entityMap[RootEntityName]);
m_entityMap[GrandChild1EntityName] = CreateEditorEntity(GrandChild1EntityName, m_entityMap[ChildEntityName]);
m_entityMap[GrandChild2EntityName] = CreateEditorEntity(GrandChild2EntityName, m_entityMap[ChildEntityName]);
}
AZ::EntityId ReadOnlyEntityFixture::CreateEditorEntity(const char* name, AZ::EntityId parentId)
{
AZ::Entity* entity = nullptr;
UnitTest::CreateDefaultEditorEntity(name, &entity);
// Parent
AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
return entity->GetId();
}
ReadOnlyHandlerAlwaysTrue::ReadOnlyHandlerAlwaysTrue()
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerAlwaysTrue::~ReadOnlyHandlerAlwaysTrue()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
void ReadOnlyHandlerAlwaysTrue::IsReadOnly([[maybe_unused]] const AZ::EntityId& entityId, bool& isReadOnly)
{
isReadOnly = true;
}
ReadOnlyHandlerAlwaysFalse::ReadOnlyHandlerAlwaysFalse()
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerAlwaysFalse::~ReadOnlyHandlerAlwaysFalse()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
ReadOnlyHandlerEntityId::ReadOnlyHandlerEntityId(AZ::EntityId entityId)
: m_entityId(entityId)
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerEntityId::~ReadOnlyHandlerEntityId()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
void ReadOnlyHandlerEntityId::IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly)
{
if (entityId == m_entityId)
{
isReadOnly = true;
}
}
}

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