Merge branch 'development' into terrain/sphrose/physics_collider_materials_LYN-6431
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "ContainerEntity",
|
||||
"Name": "PinkFlower",
|
||||
"Components": {
|
||||
"Component_[10444337162843472597]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 10444337162843472597
|
||||
},
|
||||
"Component_[14431042590323756177]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 14431042590323756177,
|
||||
"ChildEntityOrderEntryArray": [
|
||||
{
|
||||
"EntityId": "Entity_[491002114939]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[14577735453176806353]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 14577735453176806353
|
||||
},
|
||||
"Component_[15674021346798629563]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 15674021346798629563
|
||||
},
|
||||
"Component_[16784074985702513600]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 16784074985702513600,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[3351614541100572773]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 3351614541100572773
|
||||
},
|
||||
"Component_[3600658560328167663]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 3600658560328167663
|
||||
},
|
||||
"Component_[6155673728651558934]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 6155673728651558934
|
||||
},
|
||||
"Component_[8458684662170321289]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 8458684662170321289
|
||||
},
|
||||
"Component_[8705192117416252351]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 8705192117416252351
|
||||
},
|
||||
"Component_[8801280051488695852]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 8801280051488695852
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[491002114939]": {
|
||||
"Id": "Entity_[491002114939]",
|
||||
"Name": "PinkFlower",
|
||||
"Components": {
|
||||
"Component_[11083205340162142682]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 11083205340162142682
|
||||
},
|
||||
"Component_[11327363779873517]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 11327363779873517
|
||||
},
|
||||
"Component_[12717389211269537921]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 12717389211269537921
|
||||
},
|
||||
"Component_[12826285685970138542]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 12826285685970138542,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{549F4C4D-A7D9-5F2A-A6BD-F24C8BC43BBF}",
|
||||
"subId": 280086017
|
||||
},
|
||||
"assetHint": "assets/objects/foliage/grass_flower_pink.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[14101419970865342875]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 14101419970865342875
|
||||
},
|
||||
"Component_[14770464075286403207]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 14770464075286403207
|
||||
},
|
||||
"Component_[15205142653091190082]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 15205142653091190082,
|
||||
"Parent Entity": "ContainerEntity"
|
||||
},
|
||||
"Component_[15510898811147803772]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 15510898811147803772,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 15205142653091190082
|
||||
},
|
||||
{
|
||||
"ComponentId": 12826285685970138542,
|
||||
"SortIndex": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[15988401742428977134]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 15988401742428977134
|
||||
},
|
||||
"Component_[4300550837037679336]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 4300550837037679336
|
||||
},
|
||||
"Component_[996914988793716659]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 996914988793716659
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:27f87510ae07771dbad3e430e31502b1d1d13dee868f143b7f1de2a7febc8eb9
|
||||
size 7046400
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"values": [
|
||||
{
|
||||
"$type": "ScriptProcessorRule",
|
||||
"scriptFilename": "Assets/TestAnim/scene_export_actor.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
#
|
||||
# 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, sys, uuid, os, json
|
||||
|
||||
#
|
||||
# Example for exporting ActorGroup scene rules
|
||||
#
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def get_node_names(sceneGraph, nodeTypeName, testEndPoint = False, validList = None):
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
node = sceneGraph.get_root()
|
||||
nodeList = []
|
||||
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 = scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
paths.append(nodeName.get_path())
|
||||
|
||||
include = True
|
||||
|
||||
if (validList is not None):
|
||||
include = False # if a valid list filter provided, assume to not include node name
|
||||
name_parts = nodeName.get_path().split('.')
|
||||
for valid in validList:
|
||||
if (valid in name_parts[-1]):
|
||||
include = True
|
||||
break
|
||||
|
||||
# store any node that has provides specifc data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if include and nodeContent.CastWithTypeName(nodeTypeName):
|
||||
if testEndPoint is not None:
|
||||
include = sceneGraph.is_node_end_point(node) is testEndPoint
|
||||
if include:
|
||||
if (len(nodeName.get_path())):
|
||||
nodeList.append(scene_api.scene_data.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 nodeList, paths
|
||||
|
||||
def generate_mesh_group(scene, sceneManifest, meshDataList, paths):
|
||||
# Compute the name of the scene file
|
||||
clean_filename = scene.sourceFilename.replace('.', '_')
|
||||
mesh_group_name = os.path.basename(clean_filename)
|
||||
|
||||
# make the mesh group
|
||||
mesh_group = sceneManifest.add_mesh_group(mesh_group_name)
|
||||
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, clean_filename)) + '}'
|
||||
|
||||
# add all nodes to this mesh group
|
||||
for activeMeshIndex in range(len(meshDataList)):
|
||||
mesh_name = meshDataList[activeMeshIndex]
|
||||
mesh_path = mesh_name.get_path()
|
||||
sceneManifest.mesh_group_select_node(mesh_group, mesh_path)
|
||||
|
||||
def create_shape_configuration(nodeName):
|
||||
import scene_api.physics_data
|
||||
|
||||
if(nodeName in ['_foot_','_wrist_']):
|
||||
shapeConfiguration = scene_api.physics_data.BoxShapeConfiguration()
|
||||
shapeConfiguration.scale = [1.1, 1.1, 1.1]
|
||||
shapeConfiguration.dimensions = [2.1, 3.1, 4.1]
|
||||
return shapeConfiguration
|
||||
else:
|
||||
shapeConfiguration = scene_api.physics_data.CapsuleShapeConfiguration()
|
||||
shapeConfiguration.scale = [1.0, 1.0, 1.0]
|
||||
shapeConfiguration.height = 1.0
|
||||
shapeConfiguration.radius = 1.0
|
||||
return shapeConfiguration
|
||||
|
||||
def create_collider_configuration(nodeName):
|
||||
import scene_api.physics_data
|
||||
|
||||
colliderConfiguration = scene_api.physics_data.ColliderConfiguration()
|
||||
colliderConfiguration.Position = [0.1, 0.1, 0.2]
|
||||
colliderConfiguration.Rotation = [45.0, 35.0, 25.0]
|
||||
return colliderConfiguration
|
||||
|
||||
def generate_physics_nodes(actorPhysicsSetupRule, nodeNameList):
|
||||
import scene_api.physics_data
|
||||
|
||||
hitDetectionConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
simulatedObjectColliderConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
clothConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
ragdollConfig = scene_api.physics_data.RagdollConfiguration()
|
||||
|
||||
for nodeName in nodeNameList:
|
||||
shapeConfiguration = create_shape_configuration(nodeName)
|
||||
colliderConfiguration = create_collider_configuration(nodeName)
|
||||
hitDetectionConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
simulatedObjectColliderConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
clothConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
#
|
||||
ragdollNode = scene_api.physics_data.RagdollNodeConfiguration()
|
||||
ragdollNode.JointConfig.Name = nodeName
|
||||
ragdollConfig.add_ragdoll_node_configuration(ragdollNode)
|
||||
ragdollConfig.colliders.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
|
||||
actorPhysicsSetupRule.set_simulated_object_collider_config(simulatedObjectColliderConfig)
|
||||
actorPhysicsSetupRule.set_hit_detection_config(hitDetectionConfig)
|
||||
actorPhysicsSetupRule.set_cloth_config(clothConfig)
|
||||
actorPhysicsSetupRule.set_ragdoll_config(ragdollConfig)
|
||||
|
||||
def generate_actor_group(scene, sceneManifest, meshDataList, paths):
|
||||
import scene_api.scene_data
|
||||
import scene_api.physics_data
|
||||
import scene_api.actor_group
|
||||
|
||||
# fetch bone data
|
||||
validNames = ['_neck_','_pelvis_','_leg_','_knee_','_spine_','_arm_','_clavicle_','_head_','_elbow_','_wrist_']
|
||||
graph = scene_api.scene_data.SceneGraph(scene.graph)
|
||||
nodeList, allNodePaths = get_node_names(graph, 'BoneData', validList = validNames)
|
||||
|
||||
nodeNameList = []
|
||||
for activeMeshIndex, nodeName in enumerate(nodeList):
|
||||
nodeNameList.append(nodeName.get_name())
|
||||
|
||||
# add comment
|
||||
commentRule = scene_api.actor_group.CommentRule()
|
||||
commentRule.text = str(nodeNameList)
|
||||
|
||||
# ActorPhysicsSetupRule
|
||||
actorPhysicsSetupRule = scene_api.actor_group.ActorPhysicsSetupRule()
|
||||
generate_physics_nodes(actorPhysicsSetupRule, nodeNameList)
|
||||
|
||||
# add scale of the Actor rule
|
||||
actorScaleRule = scene_api.actor_group.ActorScaleRule()
|
||||
actorScaleRule.scaleFactor = 2.0
|
||||
|
||||
# add coordinate system rule
|
||||
coordinateSystemRule = scene_api.actor_group.CoordinateSystemRule()
|
||||
coordinateSystemRule.useAdvancedData = False
|
||||
|
||||
# add morph target rule
|
||||
morphTargetRule = scene_api.actor_group.MorphTargetRule()
|
||||
morphTargetRule.targets.select_targets([nodeNameList[0]], nodeNameList)
|
||||
|
||||
# add skeleton optimization rule
|
||||
skeletonOptimizationRule = scene_api.actor_group.SkeletonOptimizationRule()
|
||||
skeletonOptimizationRule.autoSkeletonLOD = True
|
||||
skeletonOptimizationRule.criticalBonesList.select_targets([nodeNameList[0:2]], nodeNameList)
|
||||
|
||||
# add LOD rule
|
||||
lodRule = scene_api.actor_group.LodRule()
|
||||
lodRule0 = lodRule.add_lod_level(0)
|
||||
lodRule0.select_targets([nodeNameList[1:4]], nodeNameList)
|
||||
|
||||
actorGroup = scene_api.actor_group.ActorGroup()
|
||||
actorGroup.name = os.path.basename(scene.sourceFilename)
|
||||
actorGroup.add_rule(actorScaleRule)
|
||||
actorGroup.add_rule(coordinateSystemRule)
|
||||
actorGroup.add_rule(skeletonOptimizationRule)
|
||||
actorGroup.add_rule(morphTargetRule)
|
||||
actorGroup.add_rule(lodRule)
|
||||
actorGroup.add_rule(actorPhysicsSetupRule)
|
||||
actorGroup.add_rule(commentRule)
|
||||
sceneManifest.manifest['values'].append(actorGroup.to_dict())
|
||||
|
||||
def update_manifest(scene):
|
||||
import json, uuid, os
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
graph = scene_api.scene_data.SceneGraph(scene.graph)
|
||||
mesh_name_list, all_node_paths = get_node_names(graph, 'MeshData')
|
||||
scene_manifest = scene_api.scene_data.SceneManifest()
|
||||
generate_actor_group(scene, scene_manifest, mesh_name_list, all_node_paths)
|
||||
generate_mesh_group(scene, scene_manifest, mesh_name_list, all_node_paths)
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
return scene_manifest.export()
|
||||
|
||||
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.disconnect()
|
||||
sceneJobHandler = None
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene
|
||||
|
||||
sceneJobHandler = azlmbr.scene.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -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]
|
||||
|
||||
|
||||
+109
@@ -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)
|
||||
+124
@@ -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)
|
||||
+44
-24
@@ -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}")
|
||||
|
||||
+97
-1
@@ -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])
|
||||
|
||||
+32
@@ -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)
|
||||
|
||||
@@ -12,7 +12,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
NAME AutomatedTesting::PrefabTests
|
||||
TEST_SUITE main
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AZ::AssetProcessor
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
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 pytest
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.SUITE_main
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomationNoAutoTestMode(EditorTestSuite):
|
||||
|
||||
# Enable only -BatchMode for these tests. Some tests cannot run in -autotest_mode due to UI interactions
|
||||
global_extra_cmdline_args = ["-BatchMode"]
|
||||
|
||||
class test_CreatePrefab_UnderAnEntity(EditorSharedTest):
|
||||
from .tests.create_prefab import CreatePrefab_UnderAnEntity as test_module
|
||||
|
||||
class test_CreatePrefab_UnderAnotherPrefab(EditorSharedTest):
|
||||
from .tests.create_prefab import CreatePrefab_UnderAnotherPrefab as test_module
|
||||
|
||||
class test_DeleteEntity_UnderAnotherPrefab(EditorSharedTest):
|
||||
from .tests.delete_entity import DeleteEntity_UnderAnotherPrefab as test_module
|
||||
|
||||
class test_DeleteEntity_UnderLevelPrefab(EditorSharedTest):
|
||||
from .tests.delete_entity import DeleteEntity_UnderLevelPrefab as test_module
|
||||
|
||||
class test_ReparentPrefab_UnderAnotherPrefab(EditorSharedTest):
|
||||
from .tests.reparent_prefab import ReparentPrefab_UnderAnotherPrefab as test_module
|
||||
|
||||
class test_DetachPrefab_UnderAnotherPrefab(EditorSharedTest):
|
||||
from .tests.detach_prefab import DetachPrefab_UnderAnotherPrefab as test_module
|
||||
|
||||
class test_OpenLevel_ContainingTwoEntities(EditorSharedTest):
|
||||
from .tests.open_level import OpenLevel_ContainingTwoEntities as test_module
|
||||
|
||||
class test_CreatePrefab_WithSingleEntity(EditorSharedTest):
|
||||
from .tests.create_prefab import CreatePrefab_WithSingleEntity as test_module
|
||||
|
||||
class test_InstantiatePrefab_ContainingASingleEntity(EditorSharedTest):
|
||||
from .tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module
|
||||
|
||||
class test_DeletePrefab_ContainingASingleEntity(EditorSharedTest):
|
||||
from .tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module
|
||||
|
||||
class test_DuplicatePrefab_ContainingASingleEntity(EditorSharedTest):
|
||||
from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module
|
||||
+1
@@ -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)
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
def DetachPrefab_UnderAnotherPrefab():
|
||||
|
||||
CAR_PREFAB_FILE_NAME = 'car_prefab'
|
||||
WHEEL_PREFAB_FILE_NAME = 'wheel_prefab'
|
||||
CAR_PREFAB_FILE_NAME = 'car_prefab2'
|
||||
WHEEL_PREFAB_FILE_NAME = 'wheel_prefab2'
|
||||
|
||||
import editor_python_test_tools.pyside_utils as pyside_utils
|
||||
|
||||
|
||||
+144
@@ -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)
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
"""
|
||||
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 VegetationTests:
|
||||
vegetation_on_gradient_1 = (
|
||||
"Vegetation detected at correct position on Gradient1",
|
||||
"Vegetation not detected at correct position on Gradient1"
|
||||
)
|
||||
vegetation_on_gradient_2 = (
|
||||
"Vegetation detected at correct position on Gradient2",
|
||||
"Vegetation not detected at correct position on Gradient2"
|
||||
)
|
||||
unfiltered_vegetation_count_correct = (
|
||||
"Unfiltered vegetation spawn count correct",
|
||||
"Unfiltered vegetation spawn count incorrect"
|
||||
)
|
||||
|
||||
testTag2_excluded_vegetation_count_correct = (
|
||||
"TestTag2 filtered vegetation count correct",
|
||||
"TestTag2 filtered vegetation count incorrect"
|
||||
)
|
||||
testTag2_excluded_vegetation_z_correct = (
|
||||
"TestTag2 filtered vegetation spawned in correct position",
|
||||
"TestTag2 filtered vegetation failed to spawn in correct position"
|
||||
)
|
||||
|
||||
testTag3_excluded_vegetation_count_correct = (
|
||||
"TestTag3 filtered vegetation count correct",
|
||||
"TestTag3 filtered vegetation count incorrect"
|
||||
)
|
||||
testTag3_excluded_vegetation_z_correct = (
|
||||
"TestTag3 filtered vegetation spawned in correct position",
|
||||
"TestTag3 filtered vegetation failed to spawn in correct position"
|
||||
)
|
||||
|
||||
cleared_exclusion_vegetation_count_correct = (
|
||||
"Cleared filter vegetation count correct",
|
||||
"Cleared filter vegetation count incorrect"
|
||||
)
|
||||
|
||||
def TerrainSystem_VegetationSpawnsOnTerrainSurfaces():
|
||||
"""
|
||||
Summary:
|
||||
Load an empty level,
|
||||
Create two entities with constant gradient components with different values.
|
||||
Create two entities with TerrainLayerSpawners
|
||||
Create an entity to spawn vegetation
|
||||
Ensure that vegetation spawns at the correct heights
|
||||
Add a VegetationSurfaceMaskFilter and ensure it responds correctly to surface changes.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import math as sys_math
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.vegetation as vegetation
|
||||
import azlmbr.terrain as terrain
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.surface_data as surface_data
|
||||
|
||||
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
|
||||
|
||||
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 FindHighestAndLowestZValuesInArea(aabb):
|
||||
vegetation_items = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', aabb)
|
||||
|
||||
lowest_z = min([item.position.z for item in vegetation_items])
|
||||
highest_z = max([item.position.z for item in vegetation_items])
|
||||
|
||||
return highest_z, lowest_z
|
||||
|
||||
helper.init_idle()
|
||||
|
||||
# Open an empty level.
|
||||
helper.open_level("Physics", "Base")
|
||||
helper.wait_for_condition(lambda: general.get_current_level_name() == "Base", 2.0)
|
||||
|
||||
general.idle_wait_frames(1)
|
||||
|
||||
box_height = 20.0
|
||||
box_y_position = 10.0
|
||||
box_dimensions = math.Vector3(20.0, 20.0, box_height)
|
||||
|
||||
# Add Terrain Rendering
|
||||
hydra.add_level_component("Terrain World")
|
||||
hydra.add_level_component("Terrain World Renderer")
|
||||
|
||||
# Create two terrain entities at adjoining positions
|
||||
terrain_entity_1 = create_entity_at("Terrain1", ["Terrain Layer Spawner", "Axis Aligned Box Shape", "Terrain Height Gradient List", "Terrain Surface Gradient List"], 0.0, box_y_position, box_height/2.0)
|
||||
terrain_entity_1.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions)
|
||||
|
||||
terrain_entity_2 = create_entity_at("Terrain2", ["Terrain Layer Spawner", "Axis Aligned Box Shape", "Terrain Height Gradient List", "Terrain Surface Gradient List"], 20.0, box_y_position, box_height/2.0)
|
||||
terrain_entity_2.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions)
|
||||
|
||||
# Create two gradient entities.
|
||||
gradient_value_1 = 0.25
|
||||
gradient_value_2 = 0.5
|
||||
|
||||
gradient_entity_1 = create_entity_at("Gradient1", ["Constant Gradient"], 0.0, 0.0, 0.0)
|
||||
gradient_entity_1.get_set_test(0, "Configuration|Value", gradient_value_1)
|
||||
|
||||
gradient_entity_2 = create_entity_at("Gradient2", ["Constant Gradient"], 0.0, 0.0, 0.0)
|
||||
gradient_entity_2.get_set_test(0, "Configuration|Value", gradient_value_2)
|
||||
|
||||
mapping = terrain.TerrainSurfaceGradientMapping()
|
||||
mapping.gradientEntityId = gradient_entity_1.id
|
||||
pte = hydra.get_property_tree(terrain_entity_1.components[3])
|
||||
pte.add_container_item("Configuration|Gradient to Surface Mappings", 0, mapping)
|
||||
|
||||
mapping = terrain.TerrainSurfaceGradientMapping()
|
||||
mapping.gradientEntityId = gradient_entity_2.id
|
||||
pte = hydra.get_property_tree(terrain_entity_2.components[3])
|
||||
pte.add_container_item("Configuration|Gradient to Surface Mappings", 0, mapping)
|
||||
|
||||
# create a vegetation entity that overlaps both terrain entities.
|
||||
vegetation_entity = create_entity_at("Vegetation", ["Vegetation Layer Spawner", "Axis Aligned Box Shape", "Vegetation Asset List", "Vegetation Surface Mask Filter"], 10.0, box_y_position, box_height/2.0)
|
||||
vegetation_entity.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions)
|
||||
|
||||
# Set the vegetation area to a PrefabInstanceSpawner with a specific prefab asset selected.
|
||||
prefab_spawner = vegetation.PrefabInstanceSpawner()
|
||||
prefab_spawner.SetPrefabAssetPath(os.path.join("Prefabs", "PinkFlower.spawnable"))
|
||||
descriptor = hydra.get_component_property_value(vegetation_entity.components[2], 'Configuration|Embedded Assets|[0]')
|
||||
descriptor.spawner = prefab_spawner
|
||||
vegetation_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
|
||||
# Assign gradients to layer spawners.
|
||||
terrain_entity_1.get_set_test(2, "Configuration|Gradient Entities", [gradient_entity_1.id])
|
||||
terrain_entity_2.get_set_test(2, "Configuration|Gradient Entities", [gradient_entity_2.id])
|
||||
|
||||
# Move view so that the entities are visible.
|
||||
general.set_current_view_position(17.0, -66.0, 41.0)
|
||||
general.set_current_view_rotation(-15, 0, 0)
|
||||
|
||||
# Expected item counts under conditions to be tested.
|
||||
# By default, vegetation spawns at a density of 20 items per 16 meters,
|
||||
# so in a 20m square, there should be around 25 ^ 2 items depending on whether area edges are included.
|
||||
# In this case there are 26 ^ 2 items.
|
||||
expected_surface_tag_excluded_item_count = 338
|
||||
expected_no_exclusions_item_count = 676
|
||||
|
||||
# Wait for the vegetation to spawn
|
||||
helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_no_exclusions_item_count, 5.0)
|
||||
|
||||
# Check the spawn count is correct.
|
||||
item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id)
|
||||
Report.result(VegetationTests.unfiltered_vegetation_count_correct, item_count == expected_no_exclusions_item_count)
|
||||
|
||||
test_aabb = math.Aabb_CreateFromMinMax(math.Vector3(-10.0, -10.0, 0.0), math.Vector3(30.0, 10.0, box_height))
|
||||
|
||||
# Find the z positions of the items with the lowest and highest x values, this will avoid the overlap area where z values are blended between the surface heights.
|
||||
highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb)
|
||||
|
||||
# Check that the z values are as expected.
|
||||
Report.result(VegetationTests.vegetation_on_gradient_1, sys_math.isclose(lowest_z, box_height * gradient_value_1, abs_tol=0.01))
|
||||
Report.result(VegetationTests.vegetation_on_gradient_2, sys_math.isclose(highest_z, box_height * gradient_value_2, abs_tol=0.01))
|
||||
|
||||
# Assign SurfaceTags to the SurfaceGradientLists
|
||||
terrain_entity_1.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag2"))
|
||||
terrain_entity_2.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag3"))
|
||||
|
||||
# Give the VegetationSurfaceFilter an exclusion list, set it to exclude test_tag2 which should remove all the lower items which are in terrain_entity_1.
|
||||
vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags", [surface_data.SurfaceTag()])
|
||||
vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("test_tag2"))
|
||||
|
||||
# Wait for the vegetation to respawn and check z values.
|
||||
helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_surface_tag_excluded_item_count, 5.0)
|
||||
|
||||
item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id)
|
||||
Report.result(VegetationTests.testTag2_excluded_vegetation_count_correct, item_count == expected_surface_tag_excluded_item_count)
|
||||
|
||||
highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb)
|
||||
|
||||
Report.result(VegetationTests.testTag2_excluded_vegetation_z_correct, lowest_z > box_height * gradient_value_1)
|
||||
|
||||
# Clear the filter and ensure vegetation respawns.
|
||||
vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("invalid"))
|
||||
helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_no_exclusions_item_count, 5.0)
|
||||
|
||||
item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id)
|
||||
Report.result(VegetationTests.cleared_exclusion_vegetation_count_correct, item_count == expected_no_exclusions_item_count)
|
||||
|
||||
# Exclude test_tag3 to exclude the higher items in terrain_entity_2 and recheck.
|
||||
vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("test_tag3"))
|
||||
|
||||
helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_surface_tag_excluded_item_count, 5.0)
|
||||
|
||||
item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id)
|
||||
Report.result(VegetationTests.testTag3_excluded_vegetation_count_correct, item_count == expected_surface_tag_excluded_item_count)
|
||||
|
||||
highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb)
|
||||
|
||||
Report.result(VegetationTests.testTag3_excluded_vegetation_z_correct, highest_z < box_height * gradient_value_2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(TerrainSystem_VegetationSpawnsOnTerrainSurfaces)
|
||||
@@ -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,10 @@ 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
|
||||
|
||||
class test_TerrainSystem_VegetationSpawnsOnTerrainSurfaces(EditorSharedTest):
|
||||
from .EditorScripts import TerrainSystem_VegetationSpawnsOnTerrainSurfaces 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
|
||||
|
||||
+10
@@ -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.'
|
||||
|
||||
+3
@@ -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:
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+2
-2
@@ -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'
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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',
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -325,13 +325,13 @@ namespace AZ
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
AZ_Assert(m_assetData, "Asset is not loaded");
|
||||
AZ_Assert(m_assetData, "Asset %s (%s) is not loaded", m_assetId.ToString<AZStd::string>().c_str(), m_assetHint.c_str());
|
||||
return *Get();
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
AZ_Assert(m_assetData, "Asset is not loaded");
|
||||
AZ_Assert(m_assetData, "Asset %s (%s) is not loaded", m_assetId.ToString<AZStd::string>().c_str(), m_assetHint.c_str());
|
||||
return Get();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
#include <Streamer/IStreamerMock.h>
|
||||
#include <Tests/Asset/BaseAssetManagerTest.h>
|
||||
@@ -131,8 +132,8 @@ namespace UnitTest
|
||||
* This will test the aspect of the system where ObjectStreams and asset jobs loading dependent
|
||||
* assets will do the work in their own thread.
|
||||
*/
|
||||
class AssetJobsFloodTest
|
||||
: public BaseAssetManagerTest
|
||||
|
||||
class AssetJobsFloodTest : public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
TestAssetManager* m_testAssetManager{ nullptr };
|
||||
@@ -183,15 +184,14 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
SetupTest();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TearDownTest();
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
|
||||
void SetupAssets()
|
||||
@@ -257,9 +257,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -273,11 +273,11 @@ namespace UnitTest
|
||||
noLoadAsset.m_asset = m_testAssetManager->CreateAsset<AssetWithSerializedData>(MyAsset2Id, AssetLoadBehavior::NoLoad);
|
||||
EXPECT_EQ(m_assetHandlerAndCatalog->m_numCreations, 4);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DelayLoadAsset.txt", AZ::DataStream::ST_XML, &delayedAsset, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "NoLoadAsset.txt", AZ::DataStream::ST_XML, &noLoadAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DelayLoadAsset.txt", &delayedAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("NoLoadAsset.txt", &noLoadAsset, m_serializeContext));
|
||||
|
||||
AssetWithQueueAndPreLoadReferences preLoadRoot;
|
||||
AssetWithQueueAndPreLoadReferences preLoadA;
|
||||
@@ -297,16 +297,16 @@ namespace UnitTest
|
||||
preLoadBrokenA.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(PreloadBrokenDepBId, AssetLoadBehavior::PreLoad);
|
||||
preLoadBrokenB.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(PreloadAssetNoDataId, AssetLoadBehavior::PreLoad);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadRoot.txt", AZ::DataStream::ST_XML, &preLoadRoot, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadA.txt", AZ::DataStream::ST_XML, &preLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadB.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadC.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadA.txt", AZ::DataStream::ST_XML, &queueLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadB.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadC.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadBrokenA.txt", AZ::DataStream::ST_XML, &preLoadBrokenA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadBrokenB.txt", AZ::DataStream::ST_XML, &preLoadBrokenB, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadNoData.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadRoot.txt", &preLoadRoot, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadA.txt", &preLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadB.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadC.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadA.txt", &queueLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadB.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadC.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadBrokenA.txt", &preLoadBrokenA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadBrokenB.txt", &preLoadBrokenB, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadNoData.txt", &noRefs, m_serializeContext));
|
||||
|
||||
AssetWithQueueAndPreLoadReferences circularA;
|
||||
AssetWithQueueAndPreLoadReferences circularB;
|
||||
@@ -318,43 +318,15 @@ namespace UnitTest
|
||||
circularC.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(CircularBId, AssetLoadBehavior::PreLoad);
|
||||
circularD.m_preLoad = circularC.m_preLoad;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularA.txt", AZ::DataStream::ST_XML, &circularA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularB.txt", AZ::DataStream::ST_XML, &circularB, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularC.txt", AZ::DataStream::ST_XML, &circularC, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularD.txt", AZ::DataStream::ST_XML, &circularD, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularA.txt", &circularA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularB.txt", &circularB, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularC.txt", &circularC, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularD.txt", &circularD, m_serializeContext));
|
||||
|
||||
m_assetHandlerAndCatalog->m_numCreations = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TearDownTest()
|
||||
{
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset4.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset5.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset6.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset1.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset2.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset3.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "DelayLoadAsset.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "NoLoadAsset.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadRoot.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadBrokenA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadBrokenB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadNoData.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularD.txt");
|
||||
}
|
||||
|
||||
void CheckFinishedCreationsAndDestructions()
|
||||
{
|
||||
// Make sure asset jobs have finished before validating the number of destroyed assets, because it's possible that the asset job
|
||||
@@ -367,7 +339,7 @@ namespace UnitTest
|
||||
};
|
||||
|
||||
static constexpr AZStd::chrono::seconds MaxDispatchTimeoutSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds * 12;
|
||||
|
||||
|
||||
template <typename Pred>
|
||||
bool DispatchEventsUntilCondition(AZ::Data::AssetManager& assetManager, Pred&& conditionPredicate,
|
||||
AZStd::chrono::seconds logIntervalSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds,
|
||||
@@ -608,7 +580,7 @@ namespace UnitTest
|
||||
AZ::Data::AssetData::AssetStatus expected_base_status = AZ::Data::AssetData::AssetStatus::Ready;
|
||||
EXPECT_EQ(baseStatus, expected_base_status);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(AssetJobsFloodTest, RapidAcquireAndRelease)
|
||||
{
|
||||
auto assetUuids = {
|
||||
@@ -641,7 +613,7 @@ namespace UnitTest
|
||||
{
|
||||
Asset<AssetWithAssetReference> asset1 =
|
||||
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
|
||||
|
||||
if (checkLoaded)
|
||||
{
|
||||
asset1.BlockUntilLoadComplete();
|
||||
@@ -714,8 +686,8 @@ namespace UnitTest
|
||||
|
||||
AssetWithSerializedData ap;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "a.txt", AZ::DataStream::ST_XML, &ap, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "b.txt", AZ::DataStream::ST_XML, &ap, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("a.txt", &ap, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("b.txt", &ap, m_serializeContext));
|
||||
}
|
||||
|
||||
auto& assetManager = AssetManager::Instance();
|
||||
@@ -778,7 +750,7 @@ namespace UnitTest
|
||||
* Verify that loads without using the Asset Container still work correctly
|
||||
*/
|
||||
class AssetContainerDisableTest
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -797,7 +769,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
SetupTest();
|
||||
|
||||
}
|
||||
@@ -807,7 +779,7 @@ namespace UnitTest
|
||||
AssetManager::Instance().UnregisterHandler(m_assetHandlerAndCatalog);
|
||||
delete m_assetHandlerAndCatalog;
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
|
||||
void SetupAssets()
|
||||
@@ -849,9 +821,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -862,9 +834,9 @@ namespace UnitTest
|
||||
assetWithPreload3.m_asset = m_testAssetManager->CreateAsset<AssetWithSerializedData>(MyAsset6Id, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_EQ(m_assetHandlerAndCatalog->m_numCreations, 3);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, m_serializeContext));
|
||||
|
||||
m_assetHandlerAndCatalog->m_numCreations = 0;
|
||||
}
|
||||
@@ -942,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();
|
||||
|
||||
@@ -1291,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
|
||||
@@ -1332,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
|
||||
@@ -1371,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
|
||||
@@ -2014,11 +1986,12 @@ namespace UnitTest
|
||||
CheckFinishedCreationsAndDestructions();
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run multiple threads that get and release assets simultaneously to test AssetManager's thread safety
|
||||
*/
|
||||
class AssetJobsMultithreadedTest
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -2028,6 +2001,7 @@ namespace UnitTest
|
||||
static inline const AZ::Uuid MyAsset5Id{ "{D9CDAB04-D206-431E-BDC0-1DD615D56197}" };
|
||||
static inline const AZ::Uuid MyAsset6Id{ "{B2F139C3-5032-4B52-ADCA-D52A8F88E043}" };
|
||||
|
||||
|
||||
// Initialize the Job Manager with 2 threads for the Asset Manager to use.
|
||||
size_t GetNumJobManagerThreads() const override { return 2; }
|
||||
|
||||
@@ -2078,9 +2052,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, &context));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -2089,9 +2063,9 @@ namespace UnitTest
|
||||
assetWithPreload2.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset5Id, AssetLoadBehavior::PreLoad);
|
||||
assetWithPreload3.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset6Id, AssetLoadBehavior::PreLoad);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, &context));
|
||||
|
||||
EXPECT_TRUE(assetHandlerAndCatalog->m_numCreations == 3);
|
||||
assetHandlerAndCatalog->m_numCreations = 0;
|
||||
@@ -2191,22 +2165,22 @@ namespace UnitTest
|
||||
// A will be saved to disk with MyAsset1Id
|
||||
AssetWithAssetReference a;
|
||||
a.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset2Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &a, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &a, &context));
|
||||
AssetWithAssetReference b;
|
||||
b.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset3Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &b, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &b, &context));
|
||||
AssetWithAssetReference c;
|
||||
c.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset4Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &c, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &c, &context));
|
||||
AssetWithAssetReference d;
|
||||
d.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset5Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &d, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &d, &context));
|
||||
AssetWithAssetReference e;
|
||||
e.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset6Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &e, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &e, &context));
|
||||
AssetWithAssetReference f;
|
||||
f.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset1Id); // refer back to asset1
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &f, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &f, &context));
|
||||
|
||||
EXPECT_TRUE(assetHandlerAndCatalog->m_numCreations == 6);
|
||||
assetHandlerAndCatalog->m_numCreations = 0;
|
||||
@@ -2347,26 +2321,26 @@ namespace UnitTest
|
||||
// AssetD is MYASSETD
|
||||
AssetWithSerializedData d;
|
||||
d.m_data = 42;
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &d, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &d, &context));
|
||||
|
||||
// AssetC is MYASSETC
|
||||
AssetWithAssetReference c;
|
||||
c.m_asset = db.CreateAsset<AssetWithSerializedData>(AssetId(MyAssetDId)); // point at D
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &c, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &c, &context));
|
||||
|
||||
// AssetB is MYASSETB
|
||||
AssetWithAssetReference b;
|
||||
b.m_asset = db.CreateAsset<AssetWithAssetReference>(AssetId(MyAssetCId)); // point at C
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &b, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &b, &context));
|
||||
|
||||
// AssetA will be written to disk as MYASSETA
|
||||
AssetWithAssetReference a;
|
||||
a.m_asset = db.CreateAsset<AssetWithAssetReference>(AssetId(MyAssetBId)); // point at B
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &a, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &a, &context));
|
||||
}
|
||||
|
||||
const size_t numThreads = 4;
|
||||
AZStd::atomic_int threadCount(numThreads);
|
||||
constexpr size_t NumThreads = 4;
|
||||
AZStd::atomic_int threadCount(NumThreads);
|
||||
AZStd::condition_variable cv;
|
||||
AZStd::vector<AZStd::thread> threads;
|
||||
AZStd::atomic_bool keepDispatching(true);
|
||||
@@ -2381,7 +2355,7 @@ namespace UnitTest
|
||||
|
||||
AZStd::thread dispatchThread(dispatch);
|
||||
|
||||
for (size_t threadIdx = 0; threadIdx < numThreads; ++threadIdx)
|
||||
for (size_t threadIdx = 0; threadIdx < NumThreads; ++threadIdx)
|
||||
{
|
||||
threads.emplace_back([&threadCount, &db, &cv]()
|
||||
{
|
||||
@@ -2569,7 +2543,6 @@ namespace UnitTest
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsMultithreadedTest, DISABLED_ParallelDeepAssetReferences)
|
||||
#else
|
||||
// temporarily disabled until sporadic failures can be root caused
|
||||
TEST_F(AssetJobsMultithreadedTest, ParallelDeepAssetReferences)
|
||||
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
@@ -2577,7 +2550,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
class AssetManagerTests
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
protected:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -2592,7 +2565,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
|
||||
m_console = AZStd::make_unique<AZ::Console>();
|
||||
AZ::Interface<AZ::IConsole>::Register(m_console.get());
|
||||
@@ -2631,7 +2604,7 @@ namespace UnitTest
|
||||
AssetManager::Destroy();
|
||||
AZ::Interface<AZ::IConsole>::Unregister(m_console.get());
|
||||
m_console = nullptr;
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2982,7 +2955,7 @@ namespace UnitTest
|
||||
* the middle of loading. The tests help ensure that assets can't get stuck in perpetual loading states.
|
||||
**/
|
||||
class AssetManagerClearAssetReferenceTests
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
protected:
|
||||
static inline const AZ::Uuid RootAssetId{ "{AB13F568-C676-41FE-A7E9-341F71A78104}" };
|
||||
@@ -3001,7 +2974,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
|
||||
// create the database
|
||||
AssetManager::Descriptor desc;
|
||||
@@ -3039,21 +3012,18 @@ namespace UnitTest
|
||||
|
||||
// Create and save the dependent asset first, so that we can get a reference to it.
|
||||
AssetWithSerializedData dependentBlockingAsset;
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DependentPreloadBlockingAsset.txt",
|
||||
AZ::DataStream::ST_XML, &dependentBlockingAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DependentPreloadBlockingAsset.txt", &dependentBlockingAsset, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference dependentAsset;
|
||||
dependentAsset.m_asset = AssetManager::Instance().CreateAsset<AssetWithAssetReference>(
|
||||
NestedDependentPreloadBlockingAssetId, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DependentPreloadAsset.txt",
|
||||
AZ::DataStream::ST_XML, &dependentAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DependentPreloadAsset.txt", &dependentAsset, m_serializeContext));
|
||||
|
||||
// Create and save the top-level asset.
|
||||
AssetWithAssetReference rootAsset;
|
||||
rootAsset.m_asset = AssetManager::Instance().CreateAsset<AssetWithAssetReference>(
|
||||
DependentPreloadAssetId, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "RootAsset.txt",
|
||||
AZ::DataStream::ST_XML, &rootAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("RootAsset.txt", &rootAsset, m_serializeContext));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -3065,7 +3035,7 @@ namespace UnitTest
|
||||
delete m_assetHandlerAndCatalog;
|
||||
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -165,4 +165,254 @@ namespace UnitTest
|
||||
|
||||
EXPECT_FALSE(AssetManager::Instance().HasActiveJobsOrStreamerRequests());
|
||||
}
|
||||
|
||||
MemoryStreamerWrapper::MemoryStreamerWrapper()
|
||||
{
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
||||
ON_CALL(m_mockStreamer, SuspendProcessing()).WillByDefault([this]()
|
||||
{
|
||||
m_suspended = true;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, ResumeProcessing()).WillByDefault([this]()
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
m_suspended = false;
|
||||
|
||||
while (!m_processingQueue.empty())
|
||||
{
|
||||
FileRequestHandle requestHandle = m_processingQueue.front();
|
||||
m_processingQueue.pop();
|
||||
|
||||
const auto& onCompleteCallback = GetReadRequest(requestHandle)->m_callback;
|
||||
|
||||
if (onCompleteCallback)
|
||||
{
|
||||
onCompleteCallback(requestHandle);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, Read(_, ::testing::An<IStreamerTypes::RequestMemoryAllocator&>(), _, _, _, _))
|
||||
.WillByDefault(
|
||||
[this](
|
||||
[[maybe_unused]] AZStd::string_view relativePath, IStreamerTypes::RequestMemoryAllocator& allocator, size_t size,
|
||||
AZStd::chrono::microseconds deadline, IStreamerTypes::Priority priority, [[maybe_unused]] size_t offset)
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
ReadRequest request;
|
||||
|
||||
// Save off the requested deadline and priority
|
||||
request.m_deadline = deadline;
|
||||
request.m_priority = priority;
|
||||
request.m_data = allocator.Allocate(size, size, 8);
|
||||
|
||||
const auto* virtualFile = FindFile(relativePath);
|
||||
|
||||
AZ_Assert(
|
||||
virtualFile->size() == size, "Streamer read request size did not match size of saved file: %d vs %d (%.*s)",
|
||||
virtualFile->size(), size,
|
||||
relativePath.size(), relativePath.data());
|
||||
AZ_Assert(size > 0, "Size is zero %.*s", relativePath.size(), relativePath.data());
|
||||
|
||||
memcpy(request.m_data.m_address, virtualFile->data(), size);
|
||||
|
||||
// Create a real file request result and return it
|
||||
request.m_request = m_context.GetNewExternalRequest();
|
||||
|
||||
m_readRequests.push_back(request);
|
||||
|
||||
return request.m_request;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, SetRequestCompleteCallback(_, _))
|
||||
.WillByDefault([this](FileRequestPtr& request, AZ::IO::IStreamer::OnCompleteCallback callback) -> FileRequestPtr&
|
||||
{
|
||||
// Save off the callback just so that we can call it when the request is "done"
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(request);
|
||||
readRequest->m_callback = callback;
|
||||
|
||||
return request;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, QueueRequest(_))
|
||||
.WillByDefault([this](const auto& fileRequest)
|
||||
{
|
||||
if (!m_suspended)
|
||||
{
|
||||
decltype(ReadRequest::m_callback) onCompleteCallback;
|
||||
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(fileRequest);
|
||||
onCompleteCallback = readRequest->m_callback;
|
||||
|
||||
if (onCompleteCallback)
|
||||
{
|
||||
onCompleteCallback(fileRequest);
|
||||
|
||||
m_readRequests.erase(readRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
m_processingQueue.push(fileRequest);
|
||||
}
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, GetRequestStatus(_))
|
||||
.WillByDefault([]([[maybe_unused]] FileRequestHandle request)
|
||||
{
|
||||
// Return whatever request status has been set in this class
|
||||
return IO::IStreamerTypes::RequestStatus::Completed;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, GetReadRequestResult(_, _, _, _))
|
||||
.WillByDefault([this](
|
||||
[[maybe_unused]] FileRequestHandle request, void*& buffer, AZ::u64& numBytesRead,
|
||||
IStreamerTypes::ClaimMemory claimMemory)
|
||||
{
|
||||
// Make sure the requestor plans to free the data buffer we allocated.
|
||||
EXPECT_EQ(claimMemory, IStreamerTypes::ClaimMemory::Yes);
|
||||
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
ReadRequest* readRequest = GetReadRequest(request);
|
||||
|
||||
// Provide valid data buffer results.
|
||||
numBytesRead = readRequest->m_data.m_size;
|
||||
buffer = readRequest->m_data.m_address;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, RescheduleRequest(_, _, _))
|
||||
.WillByDefault([this](IO::FileRequestPtr target, AZStd::chrono::microseconds newDeadline, IO::IStreamerTypes::Priority newPriority)
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(target);
|
||||
|
||||
readRequest->m_deadline = newDeadline;
|
||||
readRequest->m_priority = newPriority;
|
||||
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
ReadRequest* MemoryStreamerWrapper::GetReadRequest(FileRequestHandle request)
|
||||
{
|
||||
auto itr = AZStd::find_if(
|
||||
m_readRequests.begin(), m_readRequests.end(),
|
||||
[request](const ReadRequest& searchItem) -> bool
|
||||
{
|
||||
return (searchItem.m_request == request);
|
||||
});
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
AZStd::vector<char>* MemoryStreamerWrapper::FindFile(AZStd::string_view path)
|
||||
{
|
||||
auto itr = m_virtualFiles.find(path);
|
||||
|
||||
if (itr == m_virtualFiles.end())
|
||||
{
|
||||
// Path didn't work as-is, does it have the test folder prefixed? If so try removing it
|
||||
if (AZ::StringFunc::StartsWith(path, GetTestFolderPath()))
|
||||
{
|
||||
AZStd::string_view pathWithoutFolder = path;
|
||||
|
||||
pathWithoutFolder = AZ::StringFunc::LStrip(pathWithoutFolder, GetTestFolderPath().c_str());
|
||||
itr = m_virtualFiles.find(pathWithoutFolder);
|
||||
}
|
||||
else // Path isn't prefixed, so try adding it
|
||||
{
|
||||
itr = m_virtualFiles.find(GetTestFolderPath().append(path));
|
||||
}
|
||||
}
|
||||
|
||||
if (itr != m_virtualFiles.end())
|
||||
{
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
// Currently no test expects a file not to exist so we assert to make it easy to quickly find where something went wrong
|
||||
// If we ever need to test for a non-existent file this assert should just be conditionally disabled for that specific test
|
||||
AZ_Assert(false, "Failed to find virtual file %*.s", path.size(), path.data())
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::SetUp()
|
||||
{
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
||||
BaseAssetManagerTest::SetUp();
|
||||
|
||||
ON_CALL(m_fileIO, Size(::testing::Matcher<const char*>(::testing::_), _))
|
||||
.WillByDefault(
|
||||
[this](const char* path, u64& size)
|
||||
{
|
||||
AZStd::scoped_lock lock(m_streamerWrapper->m_mutex);
|
||||
|
||||
const auto* file = m_streamerWrapper->FindFile(path);
|
||||
|
||||
if (file)
|
||||
{
|
||||
size = file->size();
|
||||
return ResultCode::Success;
|
||||
}
|
||||
|
||||
AZ_Error("DisklessAssetManagerBase", false, "Failed to find virtual file %.*s", path);
|
||||
|
||||
return ResultCode::Error;
|
||||
});
|
||||
|
||||
m_prevFileIO = IO::FileIOBase::GetInstance();
|
||||
IO::FileIOBase::SetInstance(nullptr);
|
||||
IO::FileIOBase::SetInstance(&m_fileIO);
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::TearDown()
|
||||
{
|
||||
IO::FileIOBase::SetInstance(nullptr);
|
||||
IO::FileIOBase::SetInstance(m_prevFileIO);
|
||||
|
||||
BaseAssetManagerTest::TearDown();
|
||||
}
|
||||
|
||||
IO::IStreamer* DisklessAssetManagerBase::CreateStreamer()
|
||||
{
|
||||
m_streamerWrapper = AZStd::make_unique<MemoryStreamerWrapper>();
|
||||
|
||||
return &(m_streamerWrapper->m_mockStreamer);
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::DestroyStreamer(IO::IStreamer*)
|
||||
{
|
||||
m_streamerWrapper = nullptr;
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string&)
|
||||
{
|
||||
AZStd::string assetFileName = GetTestFolderPath() + assetName;
|
||||
|
||||
AssetWithCustomData asset;
|
||||
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile(assetFileName, &asset, m_serializeContext));
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::DeleteAssetFromDisk(const AZStd::string&)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#include <Tests/Asset/TestAssetTypes.h>
|
||||
#include <Tests/SerializeContextFixture.h>
|
||||
#include <Tests/TestCatalog.h>
|
||||
|
||||
#include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
|
||||
#include <Streamer/IStreamerMock.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
@@ -58,7 +59,11 @@ namespace UnitTest
|
||||
|
||||
// Subclasses can optionally override the streamer creation and destruction
|
||||
virtual IO::IStreamer* CreateStreamer() { return aznew IO::Streamer(AZStd::thread_desc{}, StreamerComponent::CreateStreamerStack()); }
|
||||
virtual void DestroyStreamer(IO::IStreamer* streamer) { delete streamer; }
|
||||
virtual void DestroyStreamer(IO::IStreamer* streamer)
|
||||
{
|
||||
delete streamer;
|
||||
streamer = nullptr;
|
||||
}
|
||||
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
@@ -66,8 +71,8 @@ namespace UnitTest
|
||||
static void SuppressTraceOutput(bool suppress);
|
||||
|
||||
// Helper methods to create and destroy actual assets on the disk for true end-to-end asset loading.
|
||||
void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid);
|
||||
void DeleteAssetFromDisk(const AZStd::string& assetName);
|
||||
virtual void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid);
|
||||
virtual void DeleteAssetFromDisk(const AZStd::string& assetName);
|
||||
|
||||
void BlockUntilAssetJobsAreComplete();
|
||||
|
||||
@@ -82,4 +87,57 @@ namespace UnitTest
|
||||
AZStd::vector<AZStd::string> m_assetsWritten;
|
||||
};
|
||||
|
||||
|
||||
struct ReadRequest
|
||||
{
|
||||
AZStd::chrono::milliseconds m_deadline{};
|
||||
AZ::IO::IStreamerTypes::Priority m_priority{};
|
||||
IO::IStreamerTypes::RequestMemoryAllocatorResult m_data{ nullptr, 0, IO::IStreamerTypes::MemoryType::ReadWrite };
|
||||
AZ::IO::IStreamer::OnCompleteCallback m_callback;
|
||||
IO::FileRequestPtr m_request;
|
||||
};
|
||||
|
||||
struct MemoryStreamerWrapper
|
||||
{
|
||||
MemoryStreamerWrapper();
|
||||
~MemoryStreamerWrapper() = default;
|
||||
|
||||
ReadRequest* GetReadRequest(IO::FileRequestHandle request);
|
||||
|
||||
template<typename TObject>
|
||||
bool WriteMemoryFile(const AZStd::string& filePath, TObject* object, AZ::SerializeContext* context)
|
||||
{
|
||||
auto& buffer = m_virtualFiles[filePath];
|
||||
ByteContainerStream stream(&buffer);
|
||||
|
||||
return AZ::Utils::SaveObjectToStream(stream, DataStream::StreamType::ST_XML, object, context);
|
||||
}
|
||||
|
||||
AZStd::vector<char>* FindFile(AZStd::string_view path);
|
||||
|
||||
::testing::NiceMock<StreamerMock> m_mockStreamer;
|
||||
IO::StreamerContext m_context;
|
||||
AZStd::atomic_bool m_suspended{ false };
|
||||
|
||||
AZStd::recursive_mutex m_mutex;
|
||||
AZStd::queue<FileRequestHandle> m_processingQueue; // Keeps tracks of requests that have been queued while processing is suspended
|
||||
AZStd::vector<ReadRequest> m_readRequests;
|
||||
AZStd::unordered_map<AZStd::string, AZStd::vector<char>> m_virtualFiles;
|
||||
};
|
||||
|
||||
struct DisklessAssetManagerBase : BaseAssetManagerTest
|
||||
{
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
IO::IStreamer* CreateStreamer() override;
|
||||
void DestroyStreamer(IO::IStreamer*) override;
|
||||
|
||||
void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid) override;
|
||||
void DeleteAssetFromDisk(const AZStd::string& assetName) override;
|
||||
|
||||
AZStd::unique_ptr<MemoryStreamerWrapper> m_streamerWrapper;
|
||||
::testing::NiceMock<MockFileIOBase> m_fileIO;
|
||||
IO::FileIOBase* m_prevFileIO{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +167,8 @@ namespace UnitTest
|
||||
if (!info.m_streamName.empty())
|
||||
{
|
||||
AZStd::string fullName = GetTestFolderPath() + info.m_streamName;
|
||||
info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(fullName.c_str()));
|
||||
IO::FileIOBase* io = IO::FileIOBase::GetInstance();
|
||||
io->Size(fullName.c_str(), info.m_dataLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -187,8 +188,11 @@ namespace UnitTest
|
||||
|
||||
if (!info.m_streamName.empty())
|
||||
{
|
||||
IO::FileIOBase* io = AZ::IO::FileIOBase::GetInstance();
|
||||
|
||||
AZStd::string fullName = GetTestFolderPath() + info.m_streamName;
|
||||
info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(fullName.c_str()));
|
||||
|
||||
io->Size(fullName.c_str(), info.m_dataLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+7
-6
@@ -6,16 +6,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CommunicatorTracePrinter.h"
|
||||
#include "ProcessCommunicatorTracePrinter.h"
|
||||
|
||||
CommunicatorTracePrinter::CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window) :
|
||||
|
||||
ProcessCommunicatorTracePrinter::ProcessCommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window) :
|
||||
m_communicator(communicator),
|
||||
m_window(window)
|
||||
{
|
||||
m_stringBeingConcatenated.reserve(1024);
|
||||
}
|
||||
|
||||
CommunicatorTracePrinter::~CommunicatorTracePrinter()
|
||||
ProcessCommunicatorTracePrinter::~ProcessCommunicatorTracePrinter()
|
||||
{
|
||||
// flush stdout
|
||||
WriteCurrentString(false);
|
||||
@@ -24,7 +25,7 @@ CommunicatorTracePrinter::~CommunicatorTracePrinter()
|
||||
WriteCurrentString(true);
|
||||
}
|
||||
|
||||
void CommunicatorTracePrinter::Pump()
|
||||
void ProcessCommunicatorTracePrinter::Pump()
|
||||
{
|
||||
if (m_communicator->IsValid())
|
||||
{
|
||||
@@ -42,7 +43,7 @@ void CommunicatorTracePrinter::Pump()
|
||||
}
|
||||
}
|
||||
|
||||
void CommunicatorTracePrinter::ParseDataBuffer(AZ::u32 readSize, bool isFromStdErr)
|
||||
void ProcessCommunicatorTracePrinter::ParseDataBuffer(AZ::u32 readSize, bool isFromStdErr)
|
||||
{
|
||||
if (readSize > AZ_ARRAY_SIZE(m_streamBuffer))
|
||||
{
|
||||
@@ -67,7 +68,7 @@ void CommunicatorTracePrinter::ParseDataBuffer(AZ::u32 readSize, bool isFromStdE
|
||||
}
|
||||
}
|
||||
|
||||
void CommunicatorTracePrinter::WriteCurrentString(bool isFromStdErr)
|
||||
void ProcessCommunicatorTracePrinter::WriteCurrentString(bool isFromStdErr)
|
||||
{
|
||||
AZStd::string& bufferToUse = isFromStdErr ? m_errorStringBeingConcatenated : m_stringBeingConcatenated;
|
||||
|
||||
+7
-6
@@ -10,20 +10,21 @@
|
||||
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
//! CommunicatorTracePrinter listens to stderr and stdout of a running process and writes its output to the AZ_Trace system
|
||||
//! ProcessCommunicatorTracePrinter listens to stderr and stdout of a running process and writes its output to the AZ_Trace system
|
||||
//! Importantly, it does not do any blocking operations.
|
||||
class CommunicatorTracePrinter
|
||||
class ProcessCommunicatorTracePrinter
|
||||
{
|
||||
public:
|
||||
CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window);
|
||||
~CommunicatorTracePrinter();
|
||||
ProcessCommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window);
|
||||
~ProcessCommunicatorTracePrinter();
|
||||
|
||||
// call this periodically to drain the buffers and write them.
|
||||
//! Call this periodically to drain the buffers and write them.
|
||||
void Pump();
|
||||
|
||||
// drains the buffer into the string thats being built, then traces the string when it hits a newline.
|
||||
//! Drains the buffer into the string that's being built, then traces the string when it hits a newline.
|
||||
void ParseDataBuffer(AZ::u32 readSize, bool isFromStdErr);
|
||||
|
||||
//! Prints the current buffer to AZ_Error or AZ_TracePrintf so that it can be picked up by AZ::Debug::Trace
|
||||
void WriteCurrentString(bool isFromStdError);
|
||||
|
||||
private:
|
||||
@@ -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
|
||||
|
||||
@@ -277,6 +277,8 @@ set(FILES
|
||||
Process/ProcessWatcher.cpp
|
||||
Process/ProcessWatcher.h
|
||||
Process/ProcessCommon_fwd.h
|
||||
Process/ProcessCommunicatorTracePrinter.cpp
|
||||
Process/ProcessCommunicatorTracePrinter.h
|
||||
ProjectManager/ProjectManager.h
|
||||
ProjectManager/ProjectManager.cpp
|
||||
Render/GameIntersectorComponent.h
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
+2
-3
@@ -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 ...
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ namespace AzManipulatorTestFramework
|
||||
class IndirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction
|
||||
{
|
||||
public:
|
||||
IndirectCallManipulatorViewportInteraction();
|
||||
explicit IndirectCallManipulatorViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests);
|
||||
~IndirectCallManipulatorViewportInteraction();
|
||||
|
||||
// ManipulatorViewportInteractionInterface ...
|
||||
|
||||
+7
-4
@@ -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;
|
||||
|
||||
+3
-2
@@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
+3
-2
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+7
-27
@@ -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);
|
||||
|
||||
+16
-21
@@ -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
|
||||
|
||||
+4
-3
@@ -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;
|
||||
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.58087 1.8457C8.88135 1.8457 7.99903 2.19115 6.93392 2.88204L6.92893 2.87676C6.30965 3.2791 5.82426 3.79917 5.22899 4.43697L5.22899 4.43697C4.86895 4.82273 4.46872 5.25156 3.97436 5.72345L4.40762 6.13135C6.90029 8.44469 8.28286 9.60136 9.56289 9.60136C10.2624 9.60136 11.1447 9.25592 12.2098 8.56503L12.2148 8.57031C12.9369 8.10117 13.5717 7.47196 14.368 6.68268L14.3681 6.68264C14.6677 6.38563 14.9902 6.06596 15.3489 5.72362L14.9156 5.31571C12.4229 3.00237 10.8609 1.8457 9.58087 1.8457ZM7.6529 3.64381L7.65238 3.64325C8.14738 3.13093 8.82452 2.81518 9.57127 2.81518C11.0878 2.81518 12.3171 4.11733 12.3171 5.72362C12.3171 6.53856 12.0007 7.27522 11.4909 7.80326L11.4914 7.80381C10.9964 8.31614 10.3192 8.63189 9.57249 8.63189C8.05599 8.63189 6.82663 7.32973 6.82663 5.72345C6.82663 4.90851 7.14307 4.17185 7.6529 3.64381ZM9.56659 3.78466C9.05074 3.78466 8.58461 4.0095 8.25119 4.37149L8.25649 4.3771C7.93789 4.72586 7.74192 5.20047 7.74192 5.72345C7.74192 6.79431 8.56359 7.66241 9.57717 7.66241C10.093 7.66241 10.5592 7.43756 10.8926 7.07558L10.8873 7.06997C11.2059 6.72121 11.4018 6.24659 11.4018 5.72362C11.4018 4.65276 10.5802 3.78466 9.56659 3.78466ZM2.97474 1.99964H6.70318C6.07867 2.40803 5.53108 2.87237 5.07056 3.38303H2.97474C2.38778 3.38303 1.896 3.86007 1.896 4.44841V13.035C1.896 13.6233 2.37192 14.1003 2.97474 14.1003H11.5094C12.0964 14.1003 12.5881 13.6392 12.5881 13.035H12.6199V9.26317C13.1109 8.93674 13.5803 8.5478 14 8.10987V13.035C14 14.4025 12.8895 15.4996 11.5253 15.4996H2.97474C1.61046 15.4996 0.5 14.4025 0.5 13.035V4.44841C0.5 3.09681 1.61046 1.99964 2.97474 1.99964Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 4.60547C3 2.94862 4.34315 1.60547 6 1.60547C7.65685 1.60547 9 2.94862 9 4.60547V5.84076H10V6.60547C10 7.53544 10 8.00043 9.89778 8.38193C9.62038 9.4172 8.81173 10.2258 7.77646 10.5032C7.39496 10.6055 6.92997 10.6055 6 10.6055C5.07003 10.6055 4.60504 10.6055 4.22354 10.5032C3.18827 10.2258 2.37962 9.4172 2.10222 8.38193C2 8.00043 2 7.53544 2 6.60547V5.84076H3V4.60547ZM5.25 6.89953V9.54659H6.75V6.89953H5.25ZM6 2.66429C4.89543 2.66429 4 3.55972 4 4.66429V5.84076L8 5.84076V4.66429C8 3.55972 7.10457 2.66429 6 2.66429Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
@@ -7,7 +7,9 @@
|
||||
<file alias="prefab.svg">Entity/prefab.svg</file>
|
||||
<file alias="prefab_edit.svg">Entity/prefab_edit.svg</file>
|
||||
<file alias="prefab_edit_open.svg">Entity/prefab_edit_open.svg</file>
|
||||
<file alias="prefab_edit_open_readonly.svg">Entity/prefab_edit_open_readonly.svg</file>
|
||||
<file alias="prefab_edit_close.svg">Entity/prefab_edit_close.svg</file>
|
||||
<file alias="readonly.svg">Entity/readonly.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Level">
|
||||
<file alias="level.svg">Level/level.svg</file>
|
||||
|
||||
@@ -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
|
||||
+43
@@ -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
|
||||
+99
@@ -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
|
||||
+56
@@ -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);
|
||||
|
||||
// ReadOnlyEntityPublicInterface 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;
|
||||
|
||||
+2
-2
@@ -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
|
||||
{
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user