diff --git a/AutomatedTesting/CMakeLists.txt b/AutomatedTesting/CMakeLists.txt index 1c5382ba4b..9621c0accb 100644 --- a/AutomatedTesting/CMakeLists.txt +++ b/AutomatedTesting/CMakeLists.txt @@ -27,5 +27,4 @@ else() set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) - add_subdirectory(Gem) endif() \ No newline at end of file diff --git a/AutomatedTesting/Gem/CMakeLists.txt b/AutomatedTesting/Gem/CMakeLists.txt index 7a411544ec..e3d8a4087a 100644 --- a/AutomatedTesting/Gem/CMakeLists.txt +++ b/AutomatedTesting/Gem/CMakeLists.txt @@ -6,6 +6,9 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) -add_subdirectory(PythonTests) -add_subdirectory(PythonCoverage) +add_subdirectory(PythonTests) \ No newline at end of file diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt index 8808507765..1a88d6e69a 100644 --- a/AutomatedTesting/Gem/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AutomatedTesting ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} diff --git a/AutomatedTesting/Gem/PythonCoverage/CMakeLists.txt b/AutomatedTesting/Gem/PythonCoverage/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/AutomatedTesting/Gem/PythonCoverage/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonCoverage/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/AutomatedTesting/Gem/PythonCoverage/Code/CMakeLists.txt b/AutomatedTesting/Gem/PythonCoverage/Code/CMakeLists.txt index a865ccc49f..ea6db88c1c 100644 --- a/AutomatedTesting/Gem/PythonCoverage/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonCoverage/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(PAL_TRAIT_PYTHONCOVERAGE_SUPPORTED) diff --git a/AutomatedTesting/Gem/PythonCoverage/gem.json b/AutomatedTesting/Gem/PythonCoverage/gem.json index b99ce0daad..681696d78e 100644 --- a/AutomatedTesting/Gem/PythonCoverage/gem.json +++ b/AutomatedTesting/Gem/PythonCoverage/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "A tool for generating gem coverage for Python tests.", "canonical_tags": [ @@ -13,5 +14,8 @@ "PythonCoverage" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "", + "dependencies": [ + ] } diff --git a/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt index aea2562e0b..64effb5b4c 100644 --- a/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_BLAST Traits diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index 800f347359..26c03e78c2 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -10,7 +10,7 @@ # Automated Tests ################################################################################ -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index 72530325e0..c3398406ab 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -8,7 +8,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT # Built-in Imports from __future__ import annotations from typing import List, Tuple, Union - +from enum import Enum +import warnings # Open 3D Engine Imports import azlmbr @@ -21,14 +22,25 @@ import azlmbr.legacy.general as general from editor_python_test_tools.utils import Report +class EditorEntityType(Enum): + GAME = azlmbr.entity.EntityType().Game + LEVEL = azlmbr.entity.EntityType().Level + + class EditorComponent: """ EditorComponent class used to set and get the component property value using path EditorComponent object is returned from either of EditorEntity.add_component() or Entity.add_components() or EditorEntity.get_components_of_type() which also assigns self.id and self.type_id to the EditorComponent object. + self.type_id is the UUID for the component type as provided by an ebus call. """ + def __init__(self, type_id: uuid): + self.type_id = type_id + self.id = None + self.property_tree_editor = None + def get_component_name(self) -> str: """ Used to get name of component @@ -38,9 +50,9 @@ class EditorComponent: assert len(type_names) != 0, "Component object does not have type id" return type_names[0] - def get_property_tree(self): + def get_property_tree(self, force_get: bool = False): """ - Used to get the property tree object of component that has following functions associated with it: + Used to get and cache the property tree editor of component that has following functions associated with it: 1. prop_tree.is_container(path) 2. prop_tree.get_container_count(path) 3. prop_tree.reset_container(path) @@ -48,17 +60,161 @@ class EditorComponent: 5. prop_tree.remove_container_item(path, key) 6. prop_tree.update_container_item(path, key, value) 7. prop_tree.get_container_item(path, key) - :return: Property tree object of a component + :param force_get: Force a fresh property tree editor rather than the cached self.property_tree_editor + :return: Property tree editor of the component """ + if (not force_get) and (self.property_tree_editor is not None): + return self.property_tree_editor + build_prop_tree_outcome = editor.EditorComponentAPIBus( bus.Broadcast, "BuildComponentPropertyTreeEditor", self.id ) assert ( build_prop_tree_outcome.IsSuccess() - ), f"Failure: Could not build property tree of component: '{self.get_component_name()}'" + ), f"Failure: Could not build property tree editor of component: '{self.get_component_name()}'" prop_tree = build_prop_tree_outcome.GetValue() Report.info(prop_tree.build_paths_list()) - return prop_tree + self.property_tree_editor = prop_tree + return self.property_tree_editor + + def is_property_container(self, component_property_path: str) -> bool: + """ + Used to determine if a component property is a container. + Containers are a collection of same typed values that can expand/shrink to contain more or less. + There are two types of containers; indexed and associative. + Indexed containers use integer key and are something like a linked list + Associative containers utilize keys of the same type which could be any supported type. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :return: Boolean True if the property is a container False if it is not. + """ + if self.property_tree_editor is None: + self.get_property_tree() + result = self.property_tree_editor.is_container(component_property_path) + if not result: + Report.info(f"{self.get_component_name()}: '{component_property_path}' is not a container") + return result + + def get_container_count(self, component_property_path: str) -> int: + """ + Used to get the count of items in the container. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :return: Count of items in the container as unsigned integer + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + container_count_outcome = self.property_tree_editor.get_container_count(component_property_path) + assert ( + container_count_outcome.IsSuccess() + ), f"Failure: get_container_count did not return success for '{component_property_path}'" + return container_count_outcome.GetValue() + + def reset_container(self, component_property_path: str): + """ + Used to reset a container to empty + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :return: None + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + reset_outcome = self.property_tree_editor.reset_container(component_property_path) + assert ( + reset_outcome.IsSuccess() + ), f"Failure: could not reset_container on '{component_property_path}'" + + def append_container_item(self, component_property_path: str, value: any): + """ + Used to append a value to an indexed container item without providing an index key. + Append will fail on an associative container + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :param value: Value to be set + :return: None + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + append_outcome = self.property_tree_editor.append_container_item(component_property_path, value) + assert ( + append_outcome.IsSuccess() + ), f"Failure: could not append_container_item to '{component_property_path}'" + + def add_container_item(self, component_property_path: str, key: any, value: any): + """ + Used to add a container item at a specified key. + There are two types of containers; indexed and associative. + Indexed containers use integer key. + Associative containers utilize keys of the same type which could be any supported type. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :param key: Zero index integer key or any supported type for associative container + :param value: Value to be set + :return: None + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + add_outcome = self.property_tree_editor.add_container_item(component_property_path, key, value) + assert ( + add_outcome.IsSuccess() + ), f"Failure: could not add_container_item '{key}' to '{component_property_path}'" + + def get_container_item(self, component_property_path: str, key: any) -> any: + """ + Used to retrieve a container item value at the specified key. + There are two types of containers; indexed and associative. + Indexed containers use integer key. + Associative containers utilize keys of the same type which could be any supported type. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :param key: Zero index integer key or any supported type for associative container + :return: Value stored at the key specified + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + get_outcome = self.property_tree_editor.get_container_item(component_property_path, key) + assert ( + get_outcome.IsSuccess() + ), ( + f"Failure: could not get a value for {self.get_component_name()}: '{component_property_path}' [{key}]. " + f"Error returned by get_container_item: {get_outcome.GetError()}") + return get_outcome.GetValue() + + def remove_container_item(self, component_property_path: str, key: any): + """ + Used to remove a container item value at the specified key. + There are two types of containers; indexed and associative. + Indexed containers use integer key. + Associative containers utilize keys of the same type which could be any supported type. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :param key: Zero index integer key or any supported type for associative container + :return: None + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + remove_outcome = self.property_tree_editor.remove_container_item(component_property_path, key) + assert ( + remove_outcome.IsSuccess() + ), f"Failure: could not remove_container_item '{key}' from '{component_property_path}'" + + def update_container_item(self, component_property_path: str, key: any, value: any): + """ + Used to update a container item at a specified key. + There are two types of containers; indexed and associative. + Indexed containers use integer key. + Associative containers utilize keys of the same type which could be any supported type. + :param component_property_path: String of component property. (e.g. 'Settings|Visible') + :param key: Zero index integer key or any supported type for associative container + :param value: Value to be set + :return: None + """ + assert ( + self.is_property_container(component_property_path) + ), f"Failure: '{component_property_path}' is not a property container" + update_outcome = self.property_tree_editor.update_container_item(component_property_path, key, value) + assert ( + update_outcome.IsSuccess() + ), f"Failure: could not update '{key}' in '{component_property_path}'" def get_component_property_value(self, component_property_path: str): """ @@ -94,23 +250,36 @@ class EditorComponent: """ return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", self.id) + def set_enabled(self, new_state: bool): + """ + Used to set the component enabled state + :param new_state: Boolean enabled True, disabled False + :return: None + """ + if new_state: + editor.EditorComponentAPIBus(bus.Broadcast, "EnableComponents", [self.id]) + else: + editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [self.id]) + def disable_component(self): """ Used to disable the component using its id value. + Deprecation warning! Use set_enabled(False) instead as this method is in deprecation :return: None """ + warnings.warn("disable_component is deprecated, use set_enabled(False) instead.", DeprecationWarning) editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [self.id]) @staticmethod - def get_type_ids(component_names: list) -> list: + def get_type_ids(component_names: list, entity_type: EditorEntityType = EditorEntityType.GAME) -> list: """ Used to get type ids of given components list - :param: component_names: List of components to get type ids - :return: List of type ids of given components. + :param component_names: List of components to get type ids + :param entity_type: Entity_Type enum value Entity_Type.GAME is the default + :return: List of type ids of given components. Type id is a UUID as provided by the ebus call """ type_ids = editor.EditorComponentAPIBus( - bus.Broadcast, "FindComponentTypeIdsByEntityType", component_names, azlmbr.entity.EntityType().Game - ) + bus.Broadcast, "FindComponentTypeIdsByEntityType", component_names, entity_type.value) return type_ids @@ -131,7 +300,7 @@ class EditorEntity: """ Entity class is used to create and interact with Editor Entities. Example: To create Editor Entity, Use the code: - test_entity = Entity.create_editor_entity("TestEntity") + test_entity = EditorEntity.create_editor_entity("TestEntity") # This creates a python object with 'test_entity' linked to entity name "TestEntity" in Editor. # To add component, use: test_entity.add_component() @@ -276,10 +445,9 @@ class EditorEntity: :return: List of newly added components to the entity """ components = [] - type_ids = EditorComponent.get_type_ids(component_names) + type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.GAME) for type_id in type_ids: - new_comp = EditorComponent() - new_comp.type_id = type_id + new_comp = EditorComponent(type_id) add_component_outcome = editor.EditorComponentAPIBus( bus.Broadcast, "AddComponentsOfType", self.id, [type_id] ) @@ -291,6 +459,27 @@ class EditorEntity: self.components.append(new_comp) return components + def remove_component(self, component_name: str) -> None: + """ + Used to remove a component from Entity + :param component_name: String of component name to remove + :return: None + """ + self.remove_components([component_name]) + + def remove_components(self, component_names: list): + """ + Used to remove a list of components from Entity + :param component_names: List of component names to remove + :return: None + """ + type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.GAME) + for type_id in type_ids: + remove_outcome = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", self.id, [type_id]) + assert ( + remove_outcome.IsSuccess() + ), f"Failure: could not remove component from '{self.get_name()}'" + def get_components_of_type(self, component_names: list) -> List[EditorComponent]: """ Used to get components of type component_name that already exists on Entity @@ -298,10 +487,9 @@ class EditorEntity: :return: List of Entity Component objects of given component name """ component_list = [] - type_ids = EditorComponent.get_type_ids(component_names) + type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.GAME) for type_id in type_ids: - component = EditorComponent() - component.type_id = type_id + component = EditorComponent(type_id) get_component_of_type_outcome = editor.EditorComponentAPIBus( bus.Broadcast, "GetComponentOfType", self.id, type_id ) @@ -319,7 +507,7 @@ class EditorEntity: :param component_name: Name of component to check for :return: True, if entity has specified component. Else, False """ - type_ids = EditorComponent.get_type_ids([component_name]) + type_ids = EditorComponent.get_type_ids([component_name], EditorEntityType.GAME) return editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", self.id, type_ids[0]) def get_start_status(self) -> int: @@ -359,6 +547,21 @@ class EditorEntity: set_status = self.get_start_status() assert set_status == status_to_set, f"Failed to set start status of {desired_start_status} to {self.get_name}" + def is_locked(self) -> bool: + """ + Used to get the locked status of the entity + :return: Boolean True if locked False if not locked + """ + return editor.EditorEntityInfoRequestBus(bus.Event, "IsLocked", self.id) + + def set_lock_state(self, is_locked: bool) -> None: + """ + Sets the lock state on the object to locked or not locked. + :param is_locked: True for locking, False to unlock. + :return: None + """ + editor.EditorEntityAPIBus(bus.Event, "SetLockState", self.id, is_locked) + def delete(self) -> None: """ Used to delete the Entity. @@ -488,18 +691,6 @@ class EditorLevelEntity: 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: """ @@ -518,10 +709,9 @@ class EditorLevelEntity: :return: List of newly added components to the level """ components = [] - type_ids = EditorLevelEntity.get_type_ids(component_names) + type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.LEVEL) for type_id in type_ids: - new_comp = EditorComponent() - new_comp.type_id = type_id + new_comp = EditorComponent(type_id) add_component_outcome = editor.EditorLevelComponentAPIBus( bus.Broadcast, "AddComponentsOfType", [type_id] ) @@ -540,10 +730,9 @@ class EditorLevelEntity: :return: List of Level Component objects of given component name """ component_list = [] - type_ids = EditorLevelEntity.get_type_ids(component_names) + type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.LEVEL) for type_id in type_ids: - component = EditorComponent() - component.type_id = type_id + component = EditorComponent(type_id) get_component_of_type_outcome = editor.EditorLevelComponentAPIBus( bus.Broadcast, "GetComponentOfType", type_id ) @@ -562,7 +751,7 @@ class EditorLevelEntity: :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]) + type_ids = EditorComponent.get_type_ids([component_name], EditorEntityType.LEVEL) return editor.EditorLevelComponentAPIBus(bus.Broadcast, "HasComponentOfType", type_ids[0]) @staticmethod @@ -572,5 +761,5 @@ class EditorLevelEntity: :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]) + type_ids = EditorComponent.get_type_ids([component_name], EditorEntityType.LEVEL) return editor.EditorLevelComponentAPIBus(bus.Broadcast, "CountComponentsOfType", type_ids[0]) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SameCollisionGroupSameCustomLayerCollide.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SameCollisionGroupSameCustomLayerCollide.py index 2e40c0b557..8e8fccd725 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SameCollisionGroupSameCustomLayerCollide.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SameCollisionGroupSameCustomLayerCollide.py @@ -127,7 +127,7 @@ def Collider_SameCollisionGroupSameCustomLayerCollide(): # Main Script # 1) Load the level helper.init_idle() - helper.open_level("physics", "Collider_SameCollisionGroupSameCustomLayerCollide") + helper.open_level("Physics", "Collider_SameCollisionGroupSameCustomLayerCollide") # 2) Enter Game Mode helper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_MultipleForcesInSameComponentCombineForces.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_MultipleForcesInSameComponentCombineForces.py index 7307f3a2fb..e5f6e236cf 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_MultipleForcesInSameComponentCombineForces.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_MultipleForcesInSameComponentCombineForces.py @@ -162,7 +162,7 @@ def ForceRegion_MultipleForcesInSameComponentCombineForces(): helper.init_idle() # 1) Load Level - helper.open_level("physics", "ForceRegion_MultipleForcesInSameComponentCombineForces") + helper.open_level("Physics", "ForceRegion_MultipleForcesInSameComponentCombineForces") # 2) Enter Game Mode helper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_after.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_after.py index 1f8cfae498..41ccc8f2dd 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_after.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_after.py @@ -229,8 +229,8 @@ def Material_DefaultLibraryUpdatedAcrossLevels_after(): for test in test_list: # 1) Open the correct level is open helper.open_level( - "physics", - f"Material_DefaultLibraryUpdatedAcrossLevels\\{test.level}" + "Physics", + os.path.join("Material_DefaultLibraryUpdatedAcrossLevels", str(test.level)) ) # 2) Enter Game Mode diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_before.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_before.py index 15db5808e2..d86a016be1 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_before.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_DefaultLibraryUpdatedAcrossLevels_before.py @@ -189,7 +189,7 @@ def Material_DefaultLibraryUpdatedAcrossLevels_before(): # 1) Open the correct level is open helper.open_level( "Physics", - f"Material_DefaultLibraryUpdatedAcrossLevels\\{test.level}" + os.path.join("Material_DefaultLibraryUpdatedAcrossLevels", str(test.level)) ) # 2) Enter Game Mode diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_LibraryUpdatedAcrossLevels.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_LibraryUpdatedAcrossLevels.py index 0b647361f6..6eebfe60bc 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_LibraryUpdatedAcrossLevels.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/material/Material_LibraryUpdatedAcrossLevels.py @@ -252,10 +252,8 @@ def Material_LibraryUpdatedAcrossLevels(): for test in test_list: # 1) Open the correct level for the test helper.open_level( - "physics", - "Material_LibraryUpdatedAcrossLevels\\Material_LibraryUpdatedAcrossLevels_{}".format( - test.level_index - ), + "Physics", + os.path.join("Material_LibraryUpdatedAcrossLevels", str(test.level_index)) ) # 2) Open Game Mode diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/script_canvas/ScriptCanvas_SpawnEntityWithPhysComponents.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/script_canvas/ScriptCanvas_SpawnEntityWithPhysComponents.py index 5862b7586b..e6e29063d6 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/script_canvas/ScriptCanvas_SpawnEntityWithPhysComponents.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/script_canvas/ScriptCanvas_SpawnEntityWithPhysComponents.py @@ -106,7 +106,7 @@ def ScriptCanvas_SpawnEntityWithPhysComponents(): # Main Script helper.init_idle() # 1) Open Level - helper.open_level("physics", "ScriptCanvas_SpawnEntityWithPhysComponents") + helper.open_level("Physics", "ScriptCanvas_SpawnEntityWithPhysComponents") # 2) Enter Game Mode helper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt index 733e8edf29..d4554ee84b 100644 --- a/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_WHITEBOX Traits diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt index e37a5ed99b..5839093473 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt @@ -93,15 +93,19 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_pytest( - NAME AssetPipelineTests.AssetBundler - PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py + NAME AssetPipelineTests.AssetBuilder + PATH ${CMAKE_CURRENT_LIST_DIR}/asset_builder_tests.py EXCLUDE_TEST_RUN_TARGET_FROM_IDE TEST_SERIAL TEST_SUITE periodic RUNTIME_DEPENDENCIES AZ::AssetProcessor - AZ::AssetBundlerBatch ) + + set(SUPPORTED_PLATFORMS "Windows" "Mac") + if (NOT "${PAL_PLATFORM_NAME}" IN_LIST SUPPORTED_PLATFORMS) + return() + endif() ly_add_pytest( NAME AssetPipelineTests.BundleMode @@ -117,16 +121,16 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_pytest( - NAME AssetPipelineTests.AssetBuilder - PATH ${CMAKE_CURRENT_LIST_DIR}/asset_builder_tests.py + NAME AssetPipelineTests.AssetBundler + PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py EXCLUDE_TEST_RUN_TARGET_FROM_IDE TEST_SERIAL TEST_SUITE periodic RUNTIME_DEPENDENCIES AZ::AssetProcessor + AZ::AssetBundlerBatch ) - ly_add_pytest( NAME AssetPipelineTests.MissingDependency PATH ${CMAKE_CURRENT_LIST_DIR}/missing_dependency_tests.py @@ -136,5 +140,5 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES AZ::AssetProcessorBatch ) - + endif() diff --git a/AutomatedTesting/Gem/Sponza/gem.json b/AutomatedTesting/Gem/Sponza/gem.json index 68749cd5f4..f36b22a805 100644 --- a/AutomatedTesting/Gem/Sponza/gem.json +++ b/AutomatedTesting/Gem/Sponza/gem.json @@ -4,14 +4,19 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "A standard test scene for Global Illumination (forked from crytek sponza scene)", "canonical_tags": [ - "Gem" + "Gem", + "Asset" ], "user_tags": [ - "Assets" + "Sponza" ], + "icon_path": "preview.png", "requirements": "", - "dependencies": [] + "documentation_url": "", + "dependencies": [ + ] } diff --git a/AutomatedTesting/Gem/gem.json b/AutomatedTesting/Gem/gem.json index df197df09d..90a0c8cb01 100644 --- a/AutomatedTesting/Gem/gem.json +++ b/AutomatedTesting/Gem/gem.json @@ -3,13 +3,21 @@ "display_name": "AutomatedTesting", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", - "origin": "Amazon Web Services, Inc.", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "Project Gem for customizing the AutomatedTesting project functionality.", "canonical_tags": [ "Gem" ], - "user_tags": [], + "user_tags": [ + "AutomatedTesting" + ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "", + "dependencies": [], + "external_subdirectories": [ + "PythonCoverage" + ] } diff --git a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly index 9babf84ba4..18b503bab5 100644 --- a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly +++ b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60276c07b45a734e4f71d695278167ea61e884f8b513906168c9642078ad5954 -size 6045 +oid sha256:0d004c329a7c5044a8fe05b6dbbf9b19de29c60acec75f13fdbc344a55aab8c7 +size 6404 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/0.ly b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/0.ly new file mode 100644 index 0000000000..b908d29eab --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/0.ly @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e89946c224d2e765931e8ba8e33133ac24651af321a404016d9a9ea8c323db6c +size 8563 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/filelist.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/filelist.xml new file mode 100644 index 0000000000..bb94b733b3 --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/filelist.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/level.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/level.pak new file mode 100644 index 0000000000..614e41c4b2 --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/level.pak @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a46437ba86135567d87d43af0c4d499bf3cfe321721dbaf6e3cda8e49427ee1 +size 40212 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/tags.txt b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/tags.txt similarity index 100% rename from AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/tags.txt rename to AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/tags.txt diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/terraintexture.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/terraintexture.pak similarity index 100% rename from AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/terraintexture.pak rename to AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/0/terraintexture.pak diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/1.ly b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/1.ly new file mode 100644 index 0000000000..216426fc2a --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/1.ly @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95996da3902d885060e700c573d13144bab246b930dfeedaed6066c13c879b11 +size 8737 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/filelist.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/filelist.xml new file mode 100644 index 0000000000..5f5b4928fc --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/filelist.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/level.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/level.pak new file mode 100644 index 0000000000..d920770374 --- /dev/null +++ b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/level.pak @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:894dfd4ab92aa4d1d6003aebf82cf7ff854a8b3684e010234e073879f88b64e5 +size 40210 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/tags.txt b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/tags.txt similarity index 100% rename from AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/tags.txt rename to AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/tags.txt diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/terraintexture.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/terraintexture.pak similarity index 100% rename from AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/terraintexture.pak rename to AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/1/terraintexture.pak diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/C15425935_Material_LibraryUpdatedAcrossLevels_0.ly b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/C15425935_Material_LibraryUpdatedAcrossLevels_0.ly deleted file mode 100644 index a5953fc44b..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/C15425935_Material_LibraryUpdatedAcrossLevels_0.ly +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:969b77ee335d2a04524a27c765dd2f2bdee048661f3ff7be0766ba69d18d5842 -size 10409 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/filelist.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/filelist.xml deleted file mode 100644 index 9a78b1bfd5..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/filelist.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/level.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/level.pak deleted file mode 100644 index 8e6b3b29cb..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/level.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:547d7fdfcd959569b69d78eb6f63c7c19fc90840d69ca2d46eca8a3e82b8db75 -size 39337 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/Environment.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/Environment.xml deleted file mode 100644 index 4ba36f66ae..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/Environment.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/GameTokens.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/GameTokens.xml deleted file mode 100644 index 668a4583bd..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/GameTokens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TerrainTexture.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TerrainTexture.xml deleted file mode 100644 index f43df05b22..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TerrainTexture.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TimeOfDay.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TimeOfDay.xml deleted file mode 100644 index 456d609b8a..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/TimeOfDay.xml +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/VegetationMap.dat b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/VegetationMap.dat deleted file mode 100644 index dce5631cd0..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/leveldata/VegetationMap.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9 -size 63 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/terrain/terrain.pxheightfield b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/terrain/terrain.pxheightfield deleted file mode 100644 index 011356e521..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_0/terrain/terrain.pxheightfield +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19096597087688692a225c1955f73d22c46354995fca1df8dff107a90c2f17a2 -size 4202594 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/C15425935_Material_LibraryUpdatedAcrossLevels_1.ly b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/C15425935_Material_LibraryUpdatedAcrossLevels_1.ly deleted file mode 100644 index 9f48f08a1b..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/C15425935_Material_LibraryUpdatedAcrossLevels_1.ly +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:29f752c141514cb4b50aea07e6b63de5c8f43149ddac37722e9ddb8b5f4a667d -size 9495 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/filelist.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/filelist.xml deleted file mode 100644 index 9a78b1bfd5..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/filelist.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/level.pak b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/level.pak deleted file mode 100644 index 8e6b3b29cb..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/level.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:547d7fdfcd959569b69d78eb6f63c7c19fc90840d69ca2d46eca8a3e82b8db75 -size 39337 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/Environment.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/Environment.xml deleted file mode 100644 index 4ba36f66ae..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/Environment.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/GameTokens.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/GameTokens.xml deleted file mode 100644 index 668a4583bd..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/GameTokens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TerrainTexture.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TerrainTexture.xml deleted file mode 100644 index f43df05b22..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TerrainTexture.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TimeOfDay.xml b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TimeOfDay.xml deleted file mode 100644 index 456d609b8a..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/TimeOfDay.xml +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/VegetationMap.dat b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/VegetationMap.dat deleted file mode 100644 index dce5631cd0..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/leveldata/VegetationMap.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9 -size 63 diff --git a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/terrain/terrain.pxheightfield b/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/terrain/terrain.pxheightfield deleted file mode 100644 index 011356e521..0000000000 --- a/AutomatedTesting/Levels/Physics/Material_LibraryUpdatedAcrossLevels/C15425935_Material_LibraryUpdatedAcrossLevels_1/terrain/terrain.pxheightfield +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19096597087688692a225c1955f73d22c46354995fca1df8dff107a90c2f17a2 -size 4202594 diff --git a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly index d6052ffa7c..a4b28a9e96 100644 --- a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly +++ b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb97ada674d123c67d7a32eb65e81fa66472cf51f748054c4a4297649f2a0f40 -size 5568 +oid sha256:0f645243fb623258ed4b063c5a18ea414560496f97d7234782ca97884e0ed8f0 +size 5961 diff --git a/AutomatedTesting/project.json b/AutomatedTesting/project.json index fc14645d2b..5a4b303570 100644 --- a/AutomatedTesting/project.json +++ b/AutomatedTesting/project.json @@ -5,12 +5,15 @@ "modules": [], "project_id": "{D816AFAE-4BB7-4FEF-88F4-E2B786DCF29D}", "android_settings": { - "package_name": "com.lumberyard.yourgame", + "package_name": "org.o3de.automatedtesting", "version_number": 1, "version_name": "1.0.0", "orientation": "landscape" }, "engine": "o3de", "display_name": "AutomatedTesting", - "icon_path": "preview.png" -} + "icon_path": "preview.png", + "external_subdirectories": [ + "Gem" + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f61a9561e8..c81581fe0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,21 +49,56 @@ include(cmake/O3DEJson.cmake) # Subdirectory processing ################################################################################ -function(add_engine_json_external_subdirectories) - read_json_external_subdirs(external_subdis ${LY_ROOT_FOLDER}/engine.json) - foreach(external_subdir ${external_subdis}) - file(REAL_PATH ${external_subdir} real_external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER}) - list(APPEND engine_external_subdirs ${real_external_subdir}) - endforeach() +# this function is building up the LY_EXTERNAL_SUBDIRS global property +function(add_engine_gem_json_external_subdirectories gem_path) + set(gem_json_path ${gem_path}/gem.json) + if(EXISTS ${gem_json_path}) + read_json_external_subdirs(gem_external_subdirs ${gem_path}/gem.json) + foreach(gem_external_subdir ${gem_external_subdirs}) + file(REAL_PATH ${gem_external_subdir} real_external_subdir BASE_DIRECTORY ${gem_path}) + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${real_external_subdir}) + add_engine_gem_json_external_subdirectories(${real_external_subdir}) + endforeach() + endif() +endfunction() - set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${engine_external_subdirs}) +function(add_engine_json_external_subdirectories) + read_json_external_subdirs(engine_external_subdirs ${LY_ROOT_FOLDER}/engine.json) + foreach(engine_external_subdir ${engine_external_subdirs}) + file(REAL_PATH ${engine_external_subdir} real_external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER}) + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${real_external_subdir}) + add_engine_gem_json_external_subdirectories(${real_external_subdir}) + endforeach() +endfunction() + +function(add_subdirectory_on_externalsubdirs) + get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS) + list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs}) + # Loop over the additional external subdirectories and invoke add_subdirectory on them + foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) + # Hash the external_directory name and append it to the Binary Directory section of add_subdirectory + # This is to deal with potential situations where multiple external directories has the same last directory name + # For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory + file(REAL_PATH ${external_directory} full_directory_path) + string(SHA256 full_directory_hash ${full_directory_path}) + # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit + # when the external subdirectory contains relative paths of significant length + string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) + # Use the last directory as the suffix path to use for the Binary Directory + get_filename_component(directory_name ${external_directory} NAME) + add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash}) + endforeach() endfunction() # Add the projects first so the Launcher can find them include(cmake/Projects.cmake) if(NOT INSTALLED_ENGINE) - + # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra + # external subdirectories. This should go before adding the rest of the targets so the targets are availbe to the launcher. + add_engine_json_external_subdirectories() + add_subdirectory_on_externalsubdirs() + # Add the rest of the targets add_subdirectory(Assets) add_subdirectory(Code) @@ -73,31 +108,11 @@ if(NOT INSTALLED_ENGINE) add_subdirectory(Templates) add_subdirectory(Tools) - # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra - # external subdirectories - add_engine_json_external_subdirectories() else() ly_find_o3de_packages() + add_subdirectory_on_externalsubdirs() endif() -get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS) -list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs}) - -# Loop over the additional external subdirectories and invoke add_subdirectory on them -foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) - # Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory - # This is to deal with potential situations where multiple external directories has the same last directory name - # For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory - file(REAL_PATH ${external_directory} full_directory_path) - string(SHA256 full_directory_hash ${full_directory_path}) - # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit - # when the external subdirectory contains relative paths of significant length - string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) - # Use the last directory as the suffix path to use for the Binary Directory - get_filename_component(directory_name ${external_directory} NAME) - add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash}) -endforeach() - ################################################################################ # Post-processing ################################################################################ diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp index bcaaa02b67..a7faea36f6 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp @@ -17,6 +17,7 @@ #include #include #include +#include // AzQtComponents #include @@ -83,6 +84,9 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent) m_ui->m_assetBrowserTableViewWidget->setVisible(false); m_ui->m_toggleDisplayViewBtn->setVisible(false); m_ui->m_searchWidget->SetFilterInputInterval(AZStd::chrono::milliseconds(250)); + + m_assetBrowserModel->SetFilterModel(m_filterModel.data()); + if (ed_useNewAssetBrowserTableView) { m_ui->m_toggleDisplayViewBtn->setVisible(true); diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 3358b49dce..9d74f8e3a2 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -63,7 +63,7 @@ ly_add_target( set(pal_cmake_files "") foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(pal_cmake_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${enabled_platform}) + o3de_pal_dir(pal_cmake_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${enabled_platform} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) list(APPEND pal_cmake_files ${pal_cmake_dir}/editor_lib_${enabled_platform_lowercase}_files.cmake) endforeach() diff --git a/Code/Editor/EditorPreferencesPageViewportGeneral.cpp b/Code/Editor/EditorPreferencesPageViewportGeneral.cpp index 77560e24f8..f33cc3f725 100644 --- a/Code/Editor/EditorPreferencesPageViewportGeneral.cpp +++ b/Code/Editor/EditorPreferencesPageViewportGeneral.cpp @@ -41,8 +41,6 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria ->Field("ShowBBoxes", &Display::m_showBBoxes) ->Field("DrawEntityLabels", &Display::m_drawEntityLabels) ->Field("ShowTriggerBounds", &Display::m_showTriggerBounds) - ->Field("ShowIcons", &Display::m_showIcons) - ->Field("DistanceScaleIcons", &Display::m_distanceScaleIcons) ->Field("ShowFrozenHelpers", &Display::m_showFrozenHelpers) ->Field("FillSelectedShapes", &Display::m_fillSelectedShapes) ->Field("ShowGridGuide", &Display::m_showGridGuide) @@ -118,10 +116,6 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria AZ::Edit::UIHandlers::CheckBox, &Display::m_drawEntityLabels, "Always Draw Entity Labels", "Always Draw Entity Labels") ->DataElement( AZ::Edit::UIHandlers::CheckBox, &Display::m_showTriggerBounds, "Always Show Trigger Bounds", "Always Show Trigger Bounds") - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showIcons, "Show Object Icons", "Show Object Icons") - ->DataElement( - AZ::Edit::UIHandlers::CheckBox, &Display::m_distanceScaleIcons, "Scale Object Icons with Distance", - "Scale Object Icons with Distance") ->DataElement( AZ::Edit::UIHandlers::CheckBox, &Display::m_showFrozenHelpers, "Show Helpers of Frozen Objects", "Show Helpers of Frozen Objects") @@ -244,8 +238,6 @@ void CEditorPreferencesPage_ViewportGeneral::OnApply() } gSettings.viewports.bDrawEntityLabels = m_display.m_drawEntityLabels; gSettings.viewports.bShowTriggerBounds = m_display.m_showTriggerBounds; - gSettings.viewports.bShowIcons = m_display.m_showIcons; - gSettings.viewports.bDistanceScaleIcons = m_display.m_distanceScaleIcons; gSettings.viewports.nShowFrozenHelpers = m_display.m_showFrozenHelpers; gSettings.viewports.bFillSelectedShapes = m_display.m_fillSelectedShapes; gSettings.viewports.bShowGridGuide = m_display.m_showGridGuide; @@ -300,8 +292,6 @@ void CEditorPreferencesPage_ViewportGeneral::InitializeSettings() m_display.m_showBBoxes = (ds->GetRenderFlags() & RENDER_FLAG_BBOX) == RENDER_FLAG_BBOX; m_display.m_drawEntityLabels = gSettings.viewports.bDrawEntityLabels; m_display.m_showTriggerBounds = gSettings.viewports.bShowTriggerBounds; - m_display.m_showIcons = gSettings.viewports.bShowIcons; - m_display.m_distanceScaleIcons = gSettings.viewports.bDistanceScaleIcons; m_display.m_showFrozenHelpers = gSettings.viewports.nShowFrozenHelpers; m_display.m_fillSelectedShapes = gSettings.viewports.bFillSelectedShapes; m_display.m_showGridGuide = gSettings.viewports.bShowGridGuide; diff --git a/Code/Editor/EditorPreferencesPageViewportGeneral.h b/Code/Editor/EditorPreferencesPageViewportGeneral.h index be89cc6df4..2d2a207d6c 100644 --- a/Code/Editor/EditorPreferencesPageViewportGeneral.h +++ b/Code/Editor/EditorPreferencesPageViewportGeneral.h @@ -62,8 +62,6 @@ private: bool m_showBBoxes; bool m_drawEntityLabels; bool m_showTriggerBounds; - bool m_showIcons; - bool m_distanceScaleIcons; bool m_showFrozenHelpers; bool m_fillSelectedShapes; bool m_showGridGuide; diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 828812fb7e..a8180bcace 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -582,11 +582,11 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) case eNotify_OnCloseScene: m_renderViewport->SetScene(nullptr); - SetDefaultCamera(); break; case eNotify_OnEndSceneOpen: UpdateScene(); + SetDefaultCamera(); break; case eNotify_OnBeginNewScene: @@ -1027,8 +1027,6 @@ void EditorViewportWidget::OnTitleMenu(QMenu* menu) AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Safe Frame"), &gSettings.viewports.bShowSafeFrame); AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Construction Plane"), &gSettings.snap.constructPlaneDisplay); AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Trigger Bounds"), &gSettings.viewports.bShowTriggerBounds); - AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Icons"), &gSettings.viewports.bShowIcons, &gSettings.viewports.bShowSizeBasedIcons); - AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Size-based Icons"), &gSettings.viewports.bShowSizeBasedIcons, &gSettings.viewports.bShowIcons); AZ::ViewportHelpers::AddCheckbox(menu, tr("Show Helpers of Frozen Objects"), &gSettings.viewports.nShowFrozenHelpers); if (!m_predefinedAspectRatios.IsEmpty()) diff --git a/Code/Editor/Lib/Tests/test_DisplaySettingsPythonBindings.cpp b/Code/Editor/Lib/Tests/test_DisplaySettingsPythonBindings.cpp index fd65634d4e..b73cb039ea 100644 --- a/Code/Editor/Lib/Tests/test_DisplaySettingsPythonBindings.cpp +++ b/Code/Editor/Lib/Tests/test_DisplaySettingsPythonBindings.cpp @@ -35,6 +35,11 @@ namespace DisplaySettingsPythonBindingsUnitTests m_app.Start(appDesc); m_app.RegisterComponentDescriptor(AzToolsFramework::DisplaySettingsPythonFuncsHandler::CreateDescriptor()); + + // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // in the unit tests. + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } void TearDown() override diff --git a/Code/Editor/Objects/BaseObject.cpp b/Code/Editor/Objects/BaseObject.cpp index 86840789dd..c14547407b 100644 --- a/Code/Editor/Objects/BaseObject.cpp +++ b/Code/Editor/Objects/BaseObject.cpp @@ -36,12 +36,6 @@ // To use the Andrew's algorithm in order to make convex hull from the points, this header is needed. #include "Util/GeometryUtil.h" -namespace { - QColor kLinkColorParent = QColor(0, 255, 255); - QColor kLinkColorChild = QColor(0, 0, 255); - QColor kLinkColorGray = QColor(128, 128, 128); -} - extern CObjectManager* g_pObjectManager; ////////////////////////////////////////////////////////////////////////// @@ -761,72 +755,6 @@ void CBaseObject::SetModified(bool) { } -void CBaseObject::DrawDefault(DisplayContext& dc, const QColor& labelColor) -{ - Vec3 wp = GetWorldPos(); - - bool bDisplaySelectionHelper = false; - if (!CanBeDrawn(dc, bDisplaySelectionHelper)) - { - return; - } - - // Draw link between parent and child. - if (dc.flags & DISPLAY_LINKS) - { - if (GetParent()) - { - dc.DrawLine(GetParentAttachPointWorldTM().GetTranslation(), wp, IsFrozen() ? kLinkColorGray : kLinkColorParent, IsFrozen() ? kLinkColorGray : kLinkColorChild); - } - size_t nChildCount = GetChildCount(); - for (size_t i = 0; i < nChildCount; ++i) - { - const CBaseObject* pChild = GetChild(i); - dc.DrawLine(pChild->GetParentAttachPointWorldTM().GetTranslation(), pChild->GetWorldPos(), pChild->IsFrozen() ? kLinkColorGray : kLinkColorParent, pChild->IsFrozen() ? kLinkColorGray : kLinkColorChild); - } - } - - // Draw Bounding box - if (dc.flags & DISPLAY_BBOX) - { - AABB box; - GetBoundBox(box); - dc.SetColor(Vec3(1, 1, 1)); - dc.DrawWireBox(box.min, box.max); - } - - if (IsHighlighted()) - { - DrawHighlight(dc); - } - - if (IsSelected()) - { - DrawArea(dc); - - CSelectionGroup* pSelection = GetObjectManager()->GetSelection(); - - // If the number of selected object is over 2, the merged boundbox should be used to render the measurement axis. - if (!pSelection || (pSelection && pSelection->GetCount() == 1)) - { - DrawDimensions(dc); - } - } - - if (bDisplaySelectionHelper) - { - DrawSelectionHelper(dc, wp, labelColor, 1.0f); - } - else if (!(dc.flags & DISPLAY_HIDENAMES)) - { - DrawLabel(dc, wp, labelColor); - } - - SetDrawTextureIconProperties(dc, wp); - DrawTextureIcon(dc, wp); - DrawWarningIcons(dc, wp); -} - ////////////////////////////////////////////////////////////////////////// void CBaseObject::DrawDimensions(DisplayContext&, AABB*) { @@ -850,91 +778,6 @@ void CBaseObject::DrawSelectionHelper(DisplayContext& dc, const Vec3& pos, const dc.SetState(nPrevState); } -////////////////////////////////////////////////////////////////////////// -void CBaseObject::SetDrawTextureIconProperties(DisplayContext& dc, const Vec3& pos, float alpha, int texIconFlags) -{ - if (gSettings.viewports.bShowIcons || gSettings.viewports.bShowSizeBasedIcons) - { - if (IsHighlighted()) - { - dc.SetColor(QColor(255, 120, 0), 0.8f * alpha); - } - else if (IsSelected()) - { - dc.SetSelectedColor(alpha); - } - else if (IsFrozen()) - { - dc.SetFreezeColor(); - } - else - { - dc.SetColor(QColor(255, 255, 255), alpha); - } - - m_vDrawIconPos = pos; - - int nIconFlags = texIconFlags; - if (CheckFlags(OBJFLAG_SHOW_ICONONTOP)) - { - Vec3 objectPos = GetWorldPos(); - - AABB box; - GetBoundBox(box); - m_vDrawIconPos.z = (m_vDrawIconPos.z - objectPos.z) + box.max.z; - nIconFlags |= DisplayContext::TEXICON_ALIGN_BOTTOM; - } - m_nIconFlags = nIconFlags; - } -} - -////////////////////////////////////////////////////////////////////////// -void CBaseObject::DrawTextureIcon(DisplayContext& dc, [[maybe_unused]] const Vec3& pos, [[maybe_unused]] float alpha) -{ - if (m_nTextureIcon && (gSettings.viewports.bShowIcons || gSettings.viewports.bShowSizeBasedIcons)) - { - dc.DrawTextureLabel(GetTextureIconDrawPos(), OBJECT_TEXTURE_ICON_SIZEX, OBJECT_TEXTURE_ICON_SIZEY, GetTextureIcon(), GetTextureIconFlags()); - } -} - -////////////////////////////////////////////////////////////////////////// -void CBaseObject::DrawWarningIcons(DisplayContext& dc, const Vec3&) -{ - if (gSettings.viewports.bShowIcons || gSettings.viewports.bShowSizeBasedIcons) - { - const int warningIconSizeX = OBJECT_TEXTURE_ICON_SIZEX / 2; - const int warningIconSizeY = OBJECT_TEXTURE_ICON_SIZEY / 2; - - const int iconOffsetX = m_nTextureIcon ? (-OBJECT_TEXTURE_ICON_SIZEX / 2) : 0; - const int iconOffsetY = m_nTextureIcon ? (-OBJECT_TEXTURE_ICON_SIZEY / 2) : 0; - - if (gSettings.viewports.bShowScaleWarnings) - { - const EScaleWarningLevel scaleWarningLevel = GetScaleWarningLevel(); - - if (scaleWarningLevel != eScaleWarningLevel_None) - { - dc.SetColor(QColor(255, scaleWarningLevel == eScaleWarningLevel_RescaledNonUniform ? 50 : 255, 50), 1.0f); - dc.DrawTextureLabel(GetTextureIconDrawPos(), warningIconSizeX, warningIconSizeY, - GetIEditor()->GetIconManager()->GetIconTexture(eIcon_ScaleWarning), GetTextureIconFlags(), - -warningIconSizeX / 2, iconOffsetX - (warningIconSizeY / 2)); - } - } - - if (gSettings.viewports.bShowRotationWarnings) - { - const ERotationWarningLevel rotationWarningLevel = GetRotationWarningLevel(); - if (rotationWarningLevel != eRotationWarningLevel_None) - { - dc.SetColor(QColor(255, rotationWarningLevel == eRotationWarningLevel_RotatedNonRectangular ? 50 : 255, 50), 1.0f); - dc.DrawTextureLabel(GetTextureIconDrawPos(), warningIconSizeX, warningIconSizeY, - GetIEditor()->GetIconManager()->GetIconTexture(eIcon_RotationWarning), GetTextureIconFlags(), - warningIconSizeX / 2, iconOffsetY - (warningIconSizeY / 2)); - } - } - } -} - ////////////////////////////////////////////////////////////////////////// void CBaseObject::DrawLabel(DisplayContext& dc, const Vec3& pos, const QColor& lC, float alpha, float size) { diff --git a/Code/Editor/Objects/BaseObject.h b/Code/Editor/Objects/BaseObject.h index f78755e81d..fea248c7f7 100644 --- a/Code/Editor/Objects/BaseObject.h +++ b/Code/Editor/Objects/BaseObject.h @@ -398,9 +398,6 @@ public: // Interface to be implemented in plugins. ////////////////////////////////////////////////////////////////////////// - //! Draw object to specified viewport. - virtual void Display([[maybe_unused]] DisplayContext& disp) {} - //! Perform intersection testing of this object. //! Return true if was hit. virtual bool HitTest([[maybe_unused]] HitContext& hc) { return false; }; @@ -529,8 +526,6 @@ protected: void ResolveParent(CBaseObject* object); void SetColor(const QColor& color); - //! Draw default object items. - virtual void DrawDefault(DisplayContext& dc, const QColor& labelColor = QColor(255, 255, 255)); //! Draw object label. void DrawLabel(DisplayContext& dc, const Vec3& pos, const QColor& labelColor = QColor(255, 255, 255), float alpha = 1.0f, float size = 1.f); //! Draw 3D Axis at object position. @@ -539,10 +534,6 @@ protected: void DrawArea(DisplayContext& dc); //! Draw selection helper. void DrawSelectionHelper(DisplayContext& dc, const Vec3& pos, const QColor& labelColor = QColor(255, 255, 255), float alpha = 1.0f); - //! Draw helper icon. - virtual void DrawTextureIcon(DisplayContext& dc, const Vec3& pos, float alpha = 1.0f); - //! Draw warning icons - virtual void DrawWarningIcons(DisplayContext& dc, const Vec3& pos); //! Check if dimension's figures can be displayed before draw them. virtual void DrawDimensions(DisplayContext& dc, AABB* pMergedBoundBox = nullptr); @@ -575,7 +566,6 @@ protected: //! Only used by ObjectManager. bool IsPotentiallyVisible() const; - void SetDrawTextureIconProperties(DisplayContext& dc, const Vec3& pos, float alpha = 1.0f, int texIconFlags = 0); const Vec3& GetTextureIconDrawPos(){ return m_vDrawIconPos; }; int GetTextureIconFlags(){ return m_nIconFlags; }; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp index fbb700723b..a70c200417 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp @@ -723,97 +723,6 @@ CComponentEntityObject* CComponentEntityObject::FindObjectForEntity(AZ::EntityId return nullptr; } -void CComponentEntityObject::Display(DisplayContext& dc) -{ - if (!(dc.flags & DISPLAY_2D)) - { - m_entityIconVisible = false; - } - - bool displaySelectionHelper = false; - if (!CanBeDrawn(dc, displaySelectionHelper)) - { - return; - } - - DrawDefault(dc); - - bool showIcons = m_hasIcon; - if (showIcons) - { - SEditorSettings* editorSettings = GetIEditor()->GetEditorSettings(); - if (!editorSettings->viewports.bShowIcons && !editorSettings->viewports.bShowSizeBasedIcons) - { - showIcons = false; - } - } - - if (m_entityId.IsValid()) - { - // Draw link to parent if this or the parent object are selected. - { - AZ::EntityId parentId; - EBUS_EVENT_ID_RESULT(parentId, m_entityId, AZ::TransformBus, GetParentId); - if (parentId.IsValid()) - { - bool isParentVisible = false; - AzToolsFramework::EditorEntityInfoRequestBus::EventResult(isParentVisible, parentId, &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible); - - CComponentEntityObject* parentObject = CComponentEntityObject::FindObjectForEntity(parentId); - if (isParentVisible && (IsSelected() || (parentObject && parentObject->IsSelected()))) - { - const QColor kLinkColorParent(0, 255, 255); - const QColor kLinkColorChild(0, 0, 255); - - AZ::Vector3 parentTranslation; - EBUS_EVENT_ID_RESULT(parentTranslation, parentId, AZ::TransformBus, GetWorldTranslation); - dc.DrawLine(AZVec3ToLYVec3(parentTranslation), GetWorldTM().GetTranslation(), kLinkColorParent, kLinkColorChild); - } - } - } - - // Don't draw icons if we have an ancestor in the same location that has an icon - makes sure - // ancestor icons draw on top and are able to be selected over children. Also check if a descendant - // is selected at the same location. In cases of entity hierarchies where numerous ancestors have - // no position offset, we need this so the ancestors don't draw over us when we're selected - if (showIcons) - { - if ((dc.flags & DISPLAY_2D) || - IsSelected() || - IsAncestorIconDrawingAtSameLocation() || - IsDescendantSelectedAtSameLocation()) - { - showIcons = false; - } - } - - // Allow components to override in-editor visualization. - { - const AzFramework::DisplayContextRequestGuard displayContextGuard(dc); - - AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; - AzFramework::DebugDisplayRequestBus::Bind( - debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); - AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus."); - - AzFramework::DebugDisplayRequests* debugDisplay = - AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); - - AzFramework::EntityDebugDisplayEventBus::Event( - m_entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, - AzFramework::ViewportInfo{ dc.GetView()->asCViewport()->GetViewportId() }, - *debugDisplay); - } - } -} - -void CComponentEntityObject::DrawDefault(DisplayContext& dc, const QColor& labelColor) -{ - CEntityObject::DrawDefault(dc, labelColor); - - DrawAccent(dc); -} - bool CComponentEntityObject::IsIsolated() const { return m_isIsolated; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h index 7ccea8da84..62209965a5 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h @@ -55,7 +55,6 @@ public: bool SetRotation(const Quat& rotate, int flags) override; bool SetScale(const Vec3& scale, int flags) override; void InvalidateTM(int nWhyFlags) override; - void Display(DisplayContext& disp) override; bool HitTest(HitContext& hc) override; void GetLocalBounds(AABB& box) override; void GetBoundBox(AABB& box) override; @@ -69,7 +68,6 @@ public: void DetachThis(bool bKeepPos = true) override; XmlNodeRef Export(const QString& levelPath, XmlNodeRef& xmlNode) override; void DeleteEntity() override; - void DrawDefault(DisplayContext& dc, const QColor& labelColor = QColor(255, 255, 255)) override; bool IsIsolated() const override; bool IsSelected() const override; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp index 08d79adcf5..1c361b050d 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include "OutlinerDisplayOptionsMenu.h" #include "OutlinerSortFilterProxyModel.hxx" @@ -252,17 +253,7 @@ QVariant OutlinerListModel::dataForName(const QModelIndex& index, int role) cons if (s_paintingName && !m_filterString.empty()) { // highlight characters in filter - int highlightTextIndex = 0; - do - { - highlightTextIndex = label.lastIndexOf(QString(m_filterString.c_str()), highlightTextIndex - 1, Qt::CaseInsensitive); - if (highlightTextIndex >= 0) - { - const QString BACKGROUND_COLOR{ "#707070" }; - label.insert(static_cast(highlightTextIndex + m_filterString.length()), ""); - label.insert(highlightTextIndex, ""); - } - } while(highlightTextIndex > 0); + label = AzToolsFramework::RichTextHighlighter::HighlightText(label, m_filterString.c_str()); } return label; } @@ -2609,16 +2600,11 @@ void OutlinerItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optionV4.widget->style()->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter); // Now we setup a Text Document so it can draw the rich text - QTextDocument textDoc; - textDoc.setDefaultFont(optionV4.font); - textDoc.setDefaultStyleSheet("body {color: white}"); - textDoc.setHtml("" + entityNameRichText + ""); int verticalOffset = GetEntityNameVerticalOffset(entityId); painter->translate(textRect.topLeft() + QPoint(0, verticalOffset)); - textDoc.setTextWidth(textRect.width()); - textDoc.drawContents(painter, QRectF(0, 0, textRect.width(), textRect.height())); - painter->restore(); + AzToolsFramework::RichTextHighlighter::PaintHighlightedRichText(entityNameRichText, painter, optionV4, textRect); + OutlinerListModel::s_paintingName = false; } else diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index acb48c3545..8561e6dba3 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -142,9 +142,6 @@ SEditorSettings::SEditorSettings() viewports.bShowMeshStatsOnMouseOver = false; viewports.bDrawEntityLabels = false; viewports.bShowTriggerBounds = false; - viewports.bShowIcons = true; - viewports.bDistanceScaleIcons = true; - viewports.bShowSizeBasedIcons = false; viewports.nShowFrozenHelpers = true; viewports.bFillSelectedShapes = false; viewports.nTopMapTextureResolution = 512; @@ -534,8 +531,6 @@ void SEditorSettings::Save(bool isEditorClosing) SaveValue("Settings", "ShowMeshStatsOnMouseOver", viewports.bShowMeshStatsOnMouseOver); SaveValue("Settings", "DrawEntityLabels", viewports.bDrawEntityLabels); SaveValue("Settings", "ShowTriggerBounds", viewports.bShowTriggerBounds); - SaveValue("Settings", "ShowIcons", viewports.bShowIcons); - SaveValue("Settings", "ShowSizeBasedIcons", viewports.bShowSizeBasedIcons); SaveValue("Settings", "ShowFrozenHelpers", viewports.nShowFrozenHelpers); SaveValue("Settings", "FillSelectedShapes", viewports.bFillSelectedShapes); SaveValue("Settings", "MapTextureResolution", viewports.nTopMapTextureResolution); @@ -736,8 +731,6 @@ void SEditorSettings::Load() LoadValue("Settings", "ShowMeshStatsOnMouseOver", viewports.bShowMeshStatsOnMouseOver); LoadValue("Settings", "DrawEntityLabels", viewports.bDrawEntityLabels); LoadValue("Settings", "ShowTriggerBounds", viewports.bShowTriggerBounds); - LoadValue("Settings", "ShowIcons", viewports.bShowIcons); - LoadValue("Settings", "ShowSizeBasedIcons", viewports.bShowSizeBasedIcons); LoadValue("Settings", "ShowFrozenHelpers", viewports.nShowFrozenHelpers); LoadValue("Settings", "FillSelectedShapes", viewports.bFillSelectedShapes); LoadValue("Settings", "MapTextureResolution", viewports.nTopMapTextureResolution); diff --git a/Code/Editor/Settings.h b/Code/Editor/Settings.h index 9276d9b715..0ebb70501d 100644 --- a/Code/Editor/Settings.h +++ b/Code/Editor/Settings.h @@ -136,13 +136,6 @@ struct SViewportsSettings bool bDrawEntityLabels; //! Show Trigger bounds. bool bShowTriggerBounds; - //! Show Icons in viewport. - bool bShowIcons; - //! Scale icons with distance, so they aren't a fixed size no matter how far away you are - bool bDistanceScaleIcons; - - //! Show Size-based Icons in viewport. - bool bShowSizeBasedIcons; //! Show Helpers in viewport for frozen objects. int nShowFrozenHelpers; diff --git a/Code/Editor/Util/EditorUtils.cpp b/Code/Editor/Util/EditorUtils.cpp index adae34773a..47264a51ab 100644 --- a/Code/Editor/Util/EditorUtils.cpp +++ b/Code/Editor/Util/EditorUtils.cpp @@ -176,23 +176,6 @@ QString TrimTrailingZeros(QString str) return str; } -////////////////////////////////////////////////////////////////////////// -// This function is supposed to format float in user-friendly way, -// omitting the exponent notation. -// -// Why not using printf? Its formatting rules has following drawbacks: -// %g - will use exponent for small numbers; -// %.Nf - doesn't allow to control total amount of significant numbers, -// which exposes limited precision during binary-to-decimal fraction -// conversion. -////////////////////////////////////////////////////////////////////////// -void FormatFloatForUI(QString& str, int significantDigits, double value) -{ - str = TrimTrailingZeros(QString::number(value, 'f', significantDigits)); - return; -} -//////////////////////////////////////////////////////////////////////////- - ////////////////////////////////////////////////////////////////////////// QColor ColorLinearToGamma(ColorF col) { diff --git a/Code/Editor/Util/EditorUtils.h b/Code/Editor/Util/EditorUtils.h index e950d75012..5a69633d0f 100644 --- a/Code/Editor/Util/EditorUtils.h +++ b/Code/Editor/Util/EditorUtils.h @@ -212,22 +212,6 @@ namespace XmlHelpers ////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -// Drag Drop helper functions -////////////////////////////////////////////////////////////////////////// -namespace EditorDragDropHelpers -{ - inline QString GetAnimationNameClipboardFormat() - { - return QStringLiteral("application/x-animation-browser-copy"); - } - - inline QString GetFragmentClipboardFormat() - { - return QStringLiteral("application/x-preview-fragment-properties"); - } -} - ////////////////////////////////////////////////////////////////////////// /*! @@ -292,116 +276,6 @@ public: } }; - -////////////////////////////////////////////////////////////////////////// -// -// Convert String representation of color to RGB integer value. -// -////////////////////////////////////////////////////////////////////////// -inline QColor String2Color(const QString& val) -{ - unsigned int r = 0, g = 0, b = 0; - int res = 0; - res = azsscanf(val.toUtf8().data(), "R:%d,G:%d,B:%d", &r, &g, &b); - if (res != 3) - { - res = azsscanf(val.toUtf8().data(), "R:%d G:%d B:%d", &r, &g, &b); - } - if (res != 3) - { - res = azsscanf(val.toUtf8().data(), "%d,%d,%d", &r, &g, &b); - } - if (res != 3) - { - res = azsscanf(val.toUtf8().data(), "%d %d %d", &r, &g, &b); - } - if (res != 3) - { - azsscanf(val.toUtf8().data(), "%x", &r); - return r; - } - - return QColor(r, g, b); -} - -// Converts QColor to Vector. -inline Vec3 Rgb2Vec(const QColor& color) -{ - return Vec3(aznumeric_cast(color.redF()), aznumeric_cast(color.greenF()), aznumeric_cast(color.blueF())); -} - -// Converts QColor to ColorF. -inline ColorF Rgb2ColorF(const QColor& color) -{ - return ColorF(aznumeric_cast(color.redF()), aznumeric_cast(color.greenF()), aznumeric_cast(color.blueF()), 1.0f); -} - -// Converts QColor to Vector. -inline QColor Vec2Rgb(const Vec3& color) -{ - return QColor(aznumeric_cast(color.x * 255), aznumeric_cast(color.y * 255), aznumeric_cast(color.z * 255)); -} - -// Converts ColorF to QColor. -inline QColor ColorF2Rgb(const ColorF& color) -{ - return QColor(aznumeric_cast(color.r * 255), aznumeric_cast(color.g * 255), aznumeric_cast(color.b * 255)); -} - -////////////////////////////////////////////////////////////////////////// -// Tokenize string. -////////////////////////////////////////////////////////////////////////// -inline QString TokenizeString(const QString& s, LPCSTR pszTokens, int& iStart) -{ - assert(iStart >= 0); - - QByteArray str = s.toUtf8(); - - if (pszTokens == nullptr) - { - return str; - } - - auto pszPlace = str.begin() + iStart; - auto pszEnd = str.end(); - if (pszPlace < pszEnd) - { - int nIncluding = (int)strspn(pszPlace, pszTokens); - ; - - if ((pszPlace + nIncluding) < pszEnd) - { - pszPlace += nIncluding; - int nExcluding = (int)strcspn(pszPlace, pszTokens); - - int iFrom = iStart + nIncluding; - int nUntil = nExcluding; - iStart = iFrom + nUntil + 1; - - return (str.mid(iFrom, nUntil)); - } - } - - // return empty string, done tokenizing - iStart = -1; - return ""; -} - -// This template function will join strings from a vector into a single string, using a separator char -template -inline void JoinStrings(const QList& rStrings, QString& rDestStr, char aSeparator = ',') -{ - for (size_t i = 0, iCount = rStrings.size(); i < iCount; ++i) - { - rDestStr += rStrings[i]; - - if (i < iCount - 1) - { - rDestStr += aSeparator; - } - } -} - // This function will split a string containing separated strings, into a vector of strings // better version of TokenizeString inline void SplitString(const QString& rSrcStr, QStringList& rDestStrings, char aSeparator = ',') @@ -435,45 +309,6 @@ inline void SplitString(const QString& rSrcStr, QStringList& rDestStrings, char } } -// Format unsigned number to string with 1000s separator -inline QString FormatWithThousandsSeperator(const unsigned int number) -{ - QString string; - - string = QString::number(number); - - for (int p = string.length() - 3; p > 0; p -= 3) - { - string.insert(p, ','); - } - - return string; -} - - -void FormatFloatForUI(QString& str, int significantDigits, double value); - -////////////////////////////////////////////////////////////////////////// -// Simply sub string searching case insensitive. -////////////////////////////////////////////////////////////////////////// -inline const char* strstri(const char* pString, const char* pSubstring) -{ - int i, j, k; - for (i = 0; pString[i]; i++) - { - for (j = i, k = 0; tolower(pString[j]) == tolower(pSubstring[k]); j++, k++) - { - if (!pSubstring[k + 1]) - { - return (pString + i); - } - } - } - - return nullptr; -} - - inline bool CheckVirtualKey(Qt::MouseButton button) { return (qApp->property("pressedMouseButtons").toInt() & button) != 0; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index 693b2f1648..72b6e807d2 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -565,10 +565,6 @@ namespace AZ m_entityActivatedEvent.DisconnectAllHandlers(); m_entityDeactivatedEvent.DisconnectAllHandlers(); -#if !defined(_RELEASE) - m_budgetTracker.Reset(); -#endif - DestroyAllocator(); } @@ -758,6 +754,12 @@ namespace AZ static_cast(m_settingsRegistry.get())->ClearNotifiers(); static_cast(m_settingsRegistry.get())->ClearMergeEvents(); +#if !defined(_RELEASE) + // the budget tracker must be cleaned up prior to module unloading to ensure + // budgets initialized cross boundary are freed properly + m_budgetTracker.Reset(); +#endif + // Uninit and unload any dynamic modules. m_moduleManager->UnloadModules(); ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})"); diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 17f9bfea54..3baf78b63d 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -361,7 +361,7 @@ namespace AZ::Dom::Json bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy) { - const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary; + const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary; return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); } @@ -373,11 +373,7 @@ namespace AZ::Dom::Json bool RapidJsonReadHandler::Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) { AZStd::string_view key = AZStd::string_view(str, length); - if (!m_visitor->SupportsRawKeys()) - { - m_visitor->Key(AZ::Name(key)); - } - const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary; + const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary; return CheckResult(m_visitor->RawKey(key, lifetime)); } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp index 9751b9cecc..c604373296 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp @@ -21,4 +21,164 @@ namespace AZ::Dom::Utils { return backend.ReadFromBufferInPlace(string.data(), string.size(), visitor); } -} + + AZ::Outcome WriteToValue(const Backend::WriteCallback& writeCallback) + { + Value value; + AZStd::unique_ptr writer = value.GetWriteHandler(); + Visitor::Result result = writeCallback(*writer); + if (!result.IsSuccess()) + { + return AZ::Failure(result.GetError().FormatVisitorErrorMessage()); + } + return AZ::Success(AZStd::move(value)); + } + + bool DeepCompareIsEqual(const Value& lhs, const Value& rhs) + { + const Value::ValueType& lhsValue = lhs.GetInternalValue(); + const Value::ValueType& rhsValue = rhs.GetInternalValue(); + + if (lhs.IsString() && rhs.IsString()) + { + // If we both hold the same ref counted string we don't need to do a full comparison + if (AZStd::holds_alternative(lhsValue) && lhsValue == rhsValue) + { + return true; + } + return lhs.GetString() == rhs.GetString(); + } + + return AZStd::visit( + [&](auto&& ourValue) -> bool + { + using Alternative = AZStd::decay_t; + + if constexpr (AZStd::is_same_v) + { + if (!rhs.IsObject()) + { + return false; + } + auto&& theirValue = AZStd::get>(rhsValue); + if (ourValue == theirValue) + { + return true; + } + + const Object::ContainerType& ourValues = ourValue->GetValues(); + const Object::ContainerType& theirValues = theirValue->GetValues(); + + if (ourValues.size() != theirValues.size()) + { + return false; + } + + for (size_t i = 0; i < ourValues.size(); ++i) + { + const Object::EntryType& lhsChild = ourValues[i]; + const Object::EntryType& rhsChild = theirValues[i]; + if (lhsChild.first != rhsChild.first || !DeepCompareIsEqual(lhsChild.second, rhsChild.second)) + { + return false; + } + } + + return true; + } + else if constexpr (AZStd::is_same_v) + { + if (!rhs.IsArray()) + { + return false; + } + auto&& theirValue = AZStd::get>(rhsValue); + if (ourValue == theirValue) + { + return true; + } + + const Array::ContainerType& ourValues = ourValue->GetValues(); + const Array::ContainerType& theirValues = theirValue->GetValues(); + + if (ourValues.size() != theirValues.size()) + { + return false; + } + + for (size_t i = 0; i < ourValues.size(); ++i) + { + const Value& lhsChild = ourValues[i]; + const Value& rhsChild = theirValues[i]; + if (!DeepCompareIsEqual(lhsChild, rhsChild)) + { + return false; + } + } + + return true; + } + else if constexpr (AZStd::is_same_v) + { + if (!rhs.IsNode()) + { + return false; + } + auto&& theirValue = AZStd::get>(rhsValue); + if (ourValue == theirValue) + { + return true; + } + + const Node& ourNode = *ourValue; + const Node& theirNode = *theirValue; + + const Object::ContainerType& ourProperties = ourNode.GetProperties(); + const Object::ContainerType& theirProperties = theirNode.GetProperties(); + + if (ourProperties.size() != theirProperties.size()) + { + return false; + } + + for (size_t i = 0; i < ourProperties.size(); ++i) + { + const Object::EntryType& lhsChild = ourProperties[i]; + const Object::EntryType& rhsChild = theirProperties[i]; + if (lhsChild.first != rhsChild.first || !DeepCompareIsEqual(lhsChild.second, rhsChild.second)) + { + return false; + } + } + + const Array::ContainerType& ourChildren = ourNode.GetChildren(); + const Array::ContainerType& theirChildren = theirNode.GetChildren(); + + for (size_t i = 0; i < ourChildren.size(); ++i) + { + const Value& lhsChild = ourChildren[i]; + const Value& rhsChild = theirChildren[i]; + if (!DeepCompareIsEqual(lhsChild, rhsChild)) + { + return false; + } + } + + return true; + } + else + { + return lhs == rhs; + } + }, + lhsValue); + } + + Value DeepCopy(const Value& value, bool copyStrings) + { + Value copiedValue; + AZStd::unique_ptr writer = copiedValue.GetWriteHandler(); + value.Accept(*writer, copyStrings); + return copiedValue; + } +} // namespace AZ::Dom::Utils diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.h b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h index 84a6eb5687..5403b93714 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h @@ -9,9 +9,15 @@ #pragma once #include +#include namespace AZ::Dom::Utils { Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor); Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor); + + AZ::Outcome WriteToValue(const Backend::WriteCallback& writeCallback); + + bool DeepCompareIsEqual(const Value& lhs, const Value& rhs); + Value DeepCopy(const Value& value, bool copyStrings = true); } // namespace AZ::Dom::Utils diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp new file mode 100644 index 0000000000..6d944c9f45 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp @@ -0,0 +1,1207 @@ +/* + * 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 +#include +#include + +namespace AZ::Dom +{ + namespace Internal + { + template + AZStd::shared_ptr& CheckCopyOnWrite(AZStd::shared_ptr& refCountedPointer) + { + if (refCountedPointer.use_count() == 1) + { + return refCountedPointer; + } + else + { + refCountedPointer = AZStd::allocate_shared(StdValueAllocator(), *refCountedPointer); + return refCountedPointer; + } + } + + template + constexpr size_t GetTypeIndexInternal(size_t index = 0); + + template + constexpr size_t GetTypeIndexInternal(size_t index = 0) + { + if constexpr (AZStd::is_same_v) + { + return index; + } + else + { + return GetTypeIndexInternal(index + 1); + } + } + + template + struct ExtractTypeArgs + { + }; + + template class TypeToExtract, typename... Args> + struct ExtractTypeArgs> + { + template + static constexpr size_t GetTypeIndex() + { + return GetTypeIndexInternal(); + } + }; + } // namespace Internal + + // Helper function, looks up the index of a type within Value::m_value's storage + template + constexpr size_t GetTypeIndex() + { + return Internal::ExtractTypeArgs::GetTypeIndex(); + } + + const Array::ContainerType& Array::GetValues() const + { + return m_values; + } + + const Object::ContainerType& Object::GetValues() const + { + return m_values; + } + + Node::Node(AZ::Name name) + : m_name(AZStd::move(name)) + { + } + + AZ::Name Node::GetName() const + { + return m_name; + } + + void Node::SetName(AZ::Name name) + { + m_name = AZStd::move(name); + } + + Object::ContainerType& Node::GetProperties() + { + return m_properties; + } + + const Object::ContainerType& Node::GetProperties() const + { + return m_properties; + } + + Array::ContainerType& Node::GetChildren() + { + return m_children; + } + + const Array::ContainerType& Node::GetChildren() const + { + return m_children; + } + + Value::Value(SharedStringType sharedString) + : m_value(AZStd::move(sharedString)) + { + } + + Value::Value(const Value& value) + : m_value(value.m_value) + { + } + + Value::Value(Value&& value) noexcept + { + memcpy(this, &value, sizeof(Value)); + memset(&value, 0, sizeof(Value)); + } + + Value::Value(AZStd::string_view stringView, bool copy) + { + if (copy) + { + CopyFromString(stringView); + } + else + { + SetString(stringView); + } + } + + Value::Value(AZStd::any opaqueValue) + : m_value(AZStd::allocate_shared(StdValueAllocator(), AZStd::move(opaqueValue))) + { + } + + Value Value::FromOpaqueValue(const AZStd::any& value) + { + return Value(value); + } + + Value::Value(int8_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(uint8_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(int16_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(uint16_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(int32_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(uint32_t value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(int64_t value) + : m_value(value) + { + } + + Value::Value(uint64_t value) + : m_value(value) + { + } + + Value::Value(float value) + : m_value(aznumeric_cast(value)) + { + } + + Value::Value(double value) + : m_value(value) + { + } + + Value::Value(bool value) + : m_value(value) + { + } + + Value::Value(Type type) + { + switch (type) + { + case Type::Null: + // Null is the default initialized value + break; + case Type::Bool: + m_value = false; + break; + case Type::Object: + SetObject(); + break; + case Type::Array: + SetArray(); + break; + case Type::String: + SetString(""); + break; + case Type::Int64: + m_value = int64_t{}; + break; + case Type::Uint64: + m_value = uint64_t{}; + break; + case Type::Double: + m_value = double{}; + break; + case Type::Node: + SetNode(""); + break; + case Type::Opaque: + AZ_Assert(false, "AZ::Dom::Value may not be constructed with an empty opaque type"); + break; + } + } + + Value& Value::operator=(const Value& other) + { + m_value = other.m_value; + return *this; + } + + Value& Value::operator=(Value&& other) noexcept + { + SetNull(); + memcpy(this, &other, sizeof(Value)); + memset(&other, 0, sizeof(Value)); + return *this; + } + + bool Value::operator==(const Value& rhs) const + { + if (IsString() && rhs.IsString()) + { + return GetString() == rhs.GetString(); + } + else + { + return m_value == rhs.m_value; + } + } + + bool Value::operator!=(const Value& rhs) const + { + return !operator==(rhs); + } + + void Value::Swap(Value& other) noexcept + { + AZStd::aligned_storage_for_t temp; + memcpy(&temp, this, sizeof(Value)); + memcpy(this, &other, sizeof(Value)); + memcpy(&other, &temp, sizeof(Value)); + } + + Type Dom::Value::GetType() const + { + return AZStd::visit( + [](auto&& value) -> Type + { + using CurrentType = AZStd::decay_t; + if constexpr (AZStd::is_same_v) + { + return Type::Null; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Int64; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Uint64; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Double; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Bool; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::String; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Object; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Array; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Node; + } + else if constexpr (AZStd::is_same_v) + { + return Type::Opaque; + } + else + { + AZ_Assert(false, "AZ::Dom::Value::GetType: m_value has an unexpected type"); + } + }, + m_value); + } + + bool Value::IsNull() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsFalse() const + { + const bool* value = AZStd::get_if(&m_value); + return value != nullptr ? !(*value) : false; + } + + bool Value::IsTrue() const + { + const bool* value = AZStd::get_if(&m_value); + return value != nullptr ? *value : false; + } + + bool Value::IsBool() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsNode() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsObject() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsArray() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsOpaqueValue() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsNumber() const + { + return AZStd::visit( + [](auto&& value) -> bool + { + using CurrentType = AZStd::decay_t; + if constexpr (AZStd::is_same_v) + { + return true; + } + else if constexpr (AZStd::is_same_v) + { + return true; + } + else if constexpr (AZStd::is_same_v) + { + return true; + } + else + { + return false; + } + }, + m_value); + } + + bool Value::IsInt() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsUint() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsDouble() const + { + return AZStd::holds_alternative(m_value); + } + + bool Value::IsString() const + { + return AZStd::visit( + [](auto&& value) -> bool + { + using CurrentType = AZStd::decay_t; + if constexpr (AZStd::is_same_v) + { + return true; + } + else if constexpr (AZStd::is_same_v) + { + return true; + } + else if constexpr (AZStd::is_same_v) + { + return true; + } + else + { + return false; + } + }, + m_value); + } + + Value& Value::SetObject() + { + m_value = AZStd::allocate_shared(StdValueAllocator()); + return *this; + } + + const Node& Value::GetNodeInternal() const + { + AZ_Assert(GetType() == Type::Node, "AZ::Dom::Value: attempted to retrieve a node from a non-node value"); + return *AZStd::get(m_value); + } + + Node& Value::GetNodeInternal() + { + AZ_Assert(GetType() == Type::Node, "AZ::Dom::Value: attempted to retrieve a node from a non-node value"); + return *Internal::CheckCopyOnWrite(AZStd::get(m_value)); + } + + const Object::ContainerType& Value::GetObjectInternal() const + { + const Type type = GetType(); + AZ_Assert( + type == Type::Object || type == Type::Node, + "AZ::Dom::Value: attempted to retrieve an object from a value that isn't an object or a node"); + if (type == Type::Object) + { + return AZStd::get(m_value)->m_values; + } + else + { + return AZStd::get(m_value)->GetProperties(); + } + } + + Object::ContainerType& Value::GetObjectInternal() + { + const Type type = GetType(); + AZ_Assert( + type == Type::Object || type == Type::Node, + "AZ::Dom::Value: attempted to retrieve an object from a value that isn't an object or a node"); + if (type == Type::Object) + { + return Internal::CheckCopyOnWrite(AZStd::get(m_value))->m_values; + } + else + { + return Internal::CheckCopyOnWrite(AZStd::get(m_value))->GetProperties(); + } + } + + const Array::ContainerType& Value::GetArrayInternal() const + { + const Type type = GetType(); + AZ_Assert( + type == Type::Array || type == Type::Node, + "AZ::Dom::Value: attempted to retrieve an array from a value that isn't an array or a node"); + if (type == Type::Array) + { + return AZStd::get(m_value)->m_values; + } + else + { + return AZStd::get(m_value)->GetChildren(); + } + } + + Array::ContainerType& Value::GetArrayInternal() + { + const Type type = GetType(); + AZ_Assert( + type == Type::Array || type == Type::Node, + "AZ::Dom::Value: attempted to retrieve an array from a value that isn't an array or node"); + if (type == Type::Array) + { + return Internal::CheckCopyOnWrite(AZStd::get(m_value))->m_values; + } + else + { + return Internal::CheckCopyOnWrite(AZStd::get(m_value))->GetChildren(); + } + } + + size_t Value::MemberCount() const + { + return GetObjectInternal().size(); + } + + size_t Value::MemberCapacity() const + { + return GetObjectInternal().size(); + } + + bool Value::ObjectEmpty() const + { + return GetObjectInternal().empty(); + } + + Value& Value::operator[](KeyType name) + { + Object::ContainerType& object = GetObjectInternal(); + auto existingEntry = AZStd::find_if( + object.begin(), object.end(), + [&name](const Object::EntryType& entry) + { + return entry.first == name; + }); + if (existingEntry != object.end()) + { + return existingEntry->second; + } + else + { + object.emplace_back(name, Value()); + return object[object.size() - 1].second; + } + } + + const Value& Value::operator[](KeyType name) const + { + return FindMember(name)->second; + } + + Value& Value::operator[](AZStd::string_view name) + { + return operator[](AZ::Name(name)); + } + + const Value& Value::operator[](AZStd::string_view name) const + { + return operator[](AZ::Name(name)); + } + + Object::ConstIterator Value::MemberBegin() const + { + return GetObjectInternal().begin(); + } + + Object::ConstIterator Value::MemberEnd() const + { + return GetObjectInternal().end(); + } + + Object::Iterator Value::MemberBegin() + { + return GetObjectInternal().begin(); + } + + Object::Iterator Value::MemberEnd() + { + return GetObjectInternal().end(); + } + + Object::ConstIterator Value::FindMember(KeyType name) const + { + const Object::ContainerType& object = GetObjectInternal(); + return AZStd::find_if( + object.begin(), object.end(), + [&name](const Object::EntryType& entry) + { + return entry.first == name; + }); + } + + Object::ConstIterator Value::FindMember(AZStd::string_view name) const + { + return FindMember(AZ::Name(name)); + } + + Object::Iterator Value::FindMutableMember(KeyType name) + { + Object::ContainerType& object = GetObjectInternal(); + return AZStd::find_if( + object.begin(), object.end(), + [&name](const Object::EntryType& entry) + { + return entry.first == name; + }); + } + + Object::Iterator Value::FindMutableMember(AZStd::string_view name) + { + return FindMutableMember(AZ::Name(name)); + } + + Value& Value::MemberReserve(size_t newCapacity) + { + GetObjectInternal().reserve(newCapacity); + return *this; + } + + bool Value::HasMember(KeyType name) const + { + return FindMember(name) != GetObjectInternal().end(); + } + + bool Value::HasMember(AZStd::string_view name) const + { + return HasMember(AZ::Name(name)); + } + + Value& Value::AddMember(KeyType name, const Value& value) + { + Object::ContainerType& object = GetObjectInternal(); + // Reserve in ReserveIncremenet chunks instead of the default vector doubling strategy + // Profiling has found that this is an aggregate performance gain for typical workflows + object.reserve(AZ_SIZE_ALIGN_UP(object.size() + 1, Object::ReserveIncrement)); + if (auto memberIt = FindMutableMember(name); memberIt != object.end()) + { + memberIt->second = value; + } + else + { + object.emplace_back(AZStd::move(name), value); + } + return *this; + } + + Value& Value::AddMember(AZStd::string_view name, const Value& value) + { + return AddMember(AZ::Name(name), value); + } + + Value& Value::AddMember(AZ::Name name, Value&& value) + { + Object::ContainerType& object = GetObjectInternal(); + if (auto memberIt = FindMutableMember(name); memberIt != object.end()) + { + memberIt->second = value; + } + else + { + object.emplace_back(AZStd::move(name), value); + } + return *this; + } + + Value& Value::AddMember(AZStd::string_view name, Value&& value) + { + return AddMember(AZ::Name(name), value); + } + + void Value::RemoveAllMembers() + { + GetObjectInternal().clear(); + } + + void Value::RemoveMember(KeyType name) + { + Object::ContainerType& object = GetObjectInternal(); + object.erase(AZStd::remove_if( + object.begin(), object.end(), + [&name](const Object::EntryType& entry) + { + return entry.first == name; + })); + } + + void Value::RemoveMember(AZStd::string_view name) + { + RemoveMember(AZ::Name(name)); + } + + Object::Iterator Value::RemoveMember(Object::Iterator pos) + { + Object::ContainerType& object = GetObjectInternal(); + if (!object.empty()) + { + *pos = AZStd::move(object.back()); + object.pop_back(); + } + return object.end(); + } + + Object::Iterator Value::EraseMember(Object::ConstIterator pos) + { + return GetObjectInternal().erase(pos); + } + + Object::Iterator Value::EraseMember(Object::ConstIterator first, Object::ConstIterator last) + { + return GetObjectInternal().erase(first, last); + } + + Object::Iterator Value::EraseMember(KeyType name) + { + return GetObjectInternal().erase(FindMember(name)); + } + + Object::Iterator Value::EraseMember(AZStd::string_view name) + { + return EraseMember(AZ::Name(name)); + } + + Object::ContainerType& Value::GetMutableObject() + { + return GetObjectInternal(); + } + + const Object::ContainerType& Value::GetObject() const + { + return GetObjectInternal(); + } + + Value& Value::SetArray() + { + m_value = AZStd::allocate_shared(StdValueAllocator()); + return *this; + } + + size_t Value::ArraySize() const + { + return GetArrayInternal().size(); + } + + size_t Value::ArrayCapacity() const + { + return GetArrayInternal().capacity(); + } + + bool Value::IsArrayEmpty() const + { + return GetArrayInternal().empty(); + } + + void Value::ClearArray() + { + GetArrayInternal().clear(); + } + + Value& Value::operator[](size_t index) + { + return GetArrayInternal()[index]; + } + + const Value& Value::operator[](size_t index) const + { + return GetArrayInternal()[index]; + } + + Value& Value::MutableArrayAt(size_t index) + { + return operator[](index); + } + + const Value& Value::ArrayAt(size_t index) const + { + return operator[](index); + } + + Array::ConstIterator Value::ArrayBegin() const + { + return GetArrayInternal().begin(); + } + + Array::ConstIterator Value::ArrayEnd() const + { + return GetArrayInternal().end(); + } + + Array::Iterator Value::ArrayBegin() + { + return GetArrayInternal().begin(); + } + + Array::Iterator Value::ArrayEnd() + { + return GetArrayInternal().end(); + } + + Value& Value::ArrayReserve(size_t newCapacity) + { + GetArrayInternal().reserve(newCapacity); + return *this; + } + + Value& Value::ArrayPushBack(Value value) + { + Array::ContainerType& array = GetArrayInternal(); + // Reserve in ReserveIncremenet chunks instead of the default vector doubling strategy + // Profiling has found that this is an aggregate performance gain for typical workflows + array.reserve(AZ_SIZE_ALIGN_UP(array.size() + 1, Array::ReserveIncrement)); + array.push_back(AZStd::move(value)); + return *this; + } + + Value& Value::ArrayPopBack() + { + GetArrayInternal().pop_back(); + return *this; + } + + Array::Iterator Value::ArrayErase(Array::ConstIterator pos) + { + return GetArrayInternal().erase(pos); + } + + Array::Iterator Value::ArrayErase(Array::ConstIterator first, Array::ConstIterator last) + { + return GetArrayInternal().erase(first, last); + } + + Array::ContainerType& Value::GetMutableArray() + { + return GetArrayInternal(); + } + + const Array::ContainerType& Value::GetArray() const + { + return GetArrayInternal(); + } + + void Value::SetNode(AZ::Name name) + { + m_value = AZStd::allocate_shared(StdValueAllocator(), AZStd::move(name)); + } + + void Value::SetNode(AZStd::string_view name) + { + SetNode(AZ::Name(name)); + } + + AZ::Name Value::GetNodeName() const + { + return GetNodeInternal().GetName(); + } + + void Value::SetNodeName(AZ::Name name) + { + GetNodeInternal().SetName(AZStd::move(name)); + } + + void Value::SetNodeName(AZStd::string_view name) + { + SetNodeName(AZ::Name(name)); + } + + void Value::SetNodeValue(Value value) + { + AZ_Assert(GetType() == Type::Node, "AZ::Dom::Value: Attempted to set value for non-node type"); + Array::ContainerType& nodeChildren = GetArrayInternal(); + + // Set the first non-node child, if one is found + for (Value& entry : nodeChildren) + { + if (entry.GetType() != Type::Node) + { + entry = AZStd::move(value); + return; + } + } + + // Otherwise, append the value entry + nodeChildren.push_back(AZStd::move(value)); + } + + Value Value::GetNodeValue() const + { + AZ_Assert(GetType() == Type::Node, "AZ::Dom::Value: Attempted to get value for non-node type"); + const Array::ContainerType& nodeChildren = GetArrayInternal(); + + // Get the first non-node child, if one is found + for (const Value& entry : nodeChildren) + { + if (entry.GetType() != Type::Node) + { + return entry; + } + } + + return Value(); + } + + Node& Value::GetMutableNode() + { + return GetNodeInternal(); + } + + const Node& Value::GetNode() const + { + return GetNodeInternal(); + } + + int64_t Value::GetInt64() const + { + switch (m_value.index()) + { + case GetTypeIndex(): + return AZStd::get(m_value); + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + } + AZ_Assert(false, "AZ::Dom::Value: Called GetInt on a non-numeric type"); + return {}; + } + + void Value::SetInt64(int64_t value) + { + m_value = value; + } + + uint64_t Value::GetUint64() const + { + switch (m_value.index()) + { + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + case GetTypeIndex(): + return AZStd::get(m_value); + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + } + AZ_Assert(false, "AZ::Dom::Value: Called GetInt on a non-numeric type"); + return {}; + } + + void Value::SetUint64(uint64_t value) + { + m_value = value; + } + + bool Value::GetBool() const + { + if (IsBool()) + { + return AZStd::get(m_value); + } + AZ_Assert(false, "AZ::Dom::Value: Called GetBool on a non-bool type"); + return {}; + } + + void Value::SetBool(bool value) + { + m_value = value; + } + + double Value::GetDouble() const + { + switch (m_value.index()) + { + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + case GetTypeIndex(): + return aznumeric_cast(AZStd::get(m_value)); + case GetTypeIndex(): + return AZStd::get(m_value); + } + AZ_Assert(false, "AZ::Dom::Value: Called GetInt on a non-numeric type"); + return {}; + } + + void Value::SetDouble(double value) + { + m_value = value; + } + + void Value::SetString(SharedStringType sharedString) + { + m_value = sharedString; + } + + AZStd::string_view Value::GetString() const + { + switch (m_value.index()) + { + case GetTypeIndex(): + return AZStd::get(m_value); + case GetTypeIndex(): + { + auto& buffer = *AZStd::get(m_value); + return { buffer.data(), buffer.size() }; + } + case GetTypeIndex(): + { + const ShortStringType& shortString = AZStd::get(m_value); + return { shortString.data(), shortString.size() }; + } + } + AZ_Assert(false, "AZ::Dom::Value: Called GetString on a non-string type"); + return {}; + } + + size_t Value::GetStringLength() const + { + return GetString().size(); + } + + void Value::SetString(AZStd::string_view value) + { + m_value = value; + } + + void Value::CopyFromString(AZStd::string_view value) + { + if (value.size() <= ShortStringSize) + { + ShortStringType buffer; + buffer.resize_no_construct(value.size()); + memcpy(buffer.data(), value.data(), value.size()); + m_value = buffer; + } + else + { + SharedStringType sharedString = AZStd::allocate_shared(StdValueAllocator(), value.begin(), value.end()); + m_value = AZStd::move(sharedString); + } + } + + const AZStd::any& Value::GetOpaqueValue() const + { + return *AZStd::get(m_value); + } + + void Value::SetOpaqueValue(AZStd::any value) + { + m_value = AZStd::allocate_shared(StdValueAllocator(), AZStd::move(value)); + } + + void Value::SetNull() + { + m_value = AZStd::monostate(); + } + + Visitor::Result Value::Accept(Visitor& visitor, bool copyStrings) const + { + Visitor::Result result = AZ::Success(); + + AZStd::visit( + [&](auto&& arg) + { + using Alternative = AZStd::decay_t; + + if constexpr (AZStd::is_same_v) + { + result = visitor.Null(); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.Int64(arg); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.Uint64(arg); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.Double(arg); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.Bool(arg); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.String(arg, copyStrings ? Lifetime::Temporary : Lifetime::Persistent); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.RefCountedString(arg, copyStrings ? Lifetime::Temporary : Lifetime::Persistent); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.StartObject(); + if (result.IsSuccess()) + { + const Object::ContainerType& object = GetObjectInternal(); + for (const Object::EntryType& entry : object) + { + result = visitor.Key(entry.first); + if (!result.IsSuccess()) + { + return; + } + result = entry.second.Accept(visitor, copyStrings); + if (!result.IsSuccess()) + { + return; + } + } + result = visitor.EndObject(object.size()); + } + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.StartArray(); + if (result.IsSuccess()) + { + const Array::ContainerType& arrayContainer = GetArrayInternal(); + for (const Value& entry : arrayContainer) + { + result = entry.Accept(visitor, copyStrings); + if (!result.IsSuccess()) + { + return; + } + } + result = visitor.EndArray(arrayContainer.size()); + } + } + else if constexpr (AZStd::is_same_v) + { + const Node& node = *AZStd::get(m_value); + result = visitor.StartNode(node.GetName()); + if (result.IsSuccess()) + { + const Object::ContainerType& object = GetObjectInternal(); + for (const Object::EntryType& entry : object) + { + result = visitor.Key(entry.first); + if (!result.IsSuccess()) + { + return; + } + result = entry.second.Accept(visitor, copyStrings); + if (!result.IsSuccess()) + { + return; + } + } + + const Array::ContainerType& arrayContainer = GetArrayInternal(); + for (const Value& entry : arrayContainer) + { + result = entry.Accept(visitor, copyStrings); + if (!result.IsSuccess()) + { + return; + } + } + + result = visitor.EndNode(object.size(), arrayContainer.size()); + } + } + else if constexpr (AZStd::is_same_v) + { + result = visitor.OpaqueValue(*arg); + } + }, + m_value); + return result; + } + + AZStd::unique_ptr Value::GetWriteHandler() + { + return AZStd::make_unique(*this); + } + + const Value::ValueType& Value::GetInternalValue() const + { + return m_value; + } +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.h b/Code/Framework/AzCore/AzCore/DOM/DomValue.h new file mode 100644 index 0000000000..ecf8326525 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.h @@ -0,0 +1,402 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::Dom +{ + using KeyType = AZ::Name; + + //! The type of underlying value stored in a value. \see Value + enum class Type + { + Null, + Bool, + Object, + Array, + String, + Int64, + Uint64, + Double, + Node, + Opaque, + }; + + //! The allocator used by Value. + //! Value heap allocates shared_ptrs for its container storage (Array / Object / Node) alongside + class ValueAllocator final : public SimpleSchemaAllocator + { + public: + AZ_TYPE_INFO(ValueAllocator, "{5BC8B389-72C7-459E-B502-12E74D61869F}"); + + using Base = SimpleSchemaAllocator; + + ValueAllocator() + : Base("DomValueAllocator", "Allocator for AZ::Dom::Value") + { + DisableOverriding(); + } + }; + + using StdValueAllocator = AZStdAlloc; + + class Value; + + //! Internal storage for a Value array: an ordered list of Values. + class Array + { + public: + using ContainerType = AZStd::vector; + using Iterator = ContainerType::iterator; + using ConstIterator = ContainerType::const_iterator; + static constexpr const size_t ReserveIncrement = 4; + static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2"); + + const ContainerType& GetValues() const; + + private: + ContainerType m_values; + + friend class Value; + }; + + using ArrayPtr = AZStd::shared_ptr; + using ConstArrayPtr = AZStd::shared_ptr; + + //! Internal storage for a Value object: an ordered list of Name / Value pairs. + class Object + { + public: + using EntryType = AZStd::pair; + using ContainerType = AZStd::vector; + using Iterator = ContainerType::iterator; + using ConstIterator = ContainerType::const_iterator; + static constexpr const size_t ReserveIncrement = 8; + static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2"); + + const ContainerType& GetValues() const; + + private: + ContainerType m_values; + + friend class Value; + }; + + using ObjectPtr = AZStd::shared_ptr; + using ConstObjectPtr = AZStd::shared_ptr; + + //! Storage for a Value node: a named Value with both properties and children. + //! Properties are stored as an ordered list of Name / Value pairs. + //! Children are stored as an oredered list of Values. + class Node + { + public: + Node() = default; + Node(const Node&) = default; + Node(Node&&) = default; + explicit Node(AZ::Name name); + + Node& operator=(const Node&) = default; + Node& operator=(Node&&) = default; + + AZ::Name GetName() const; + void SetName(AZ::Name name); + + Object::ContainerType& GetProperties(); + const Object::ContainerType& GetProperties() const; + + Array::ContainerType& GetChildren(); + const Array::ContainerType& GetChildren() const; + + private: + AZ::Name m_name; + Object::ContainerType m_properties; + Array::ContainerType m_children; + + friend class Value; + }; + + using NodePtr = AZStd::shared_ptr; + using ConstNodePtr = AZStd::shared_ptr; + + //! Value is a typed union of Dom types that can represent the types provdied by AZ::Dom::Visitor. + //! Value can be one of the following types: + //! - Null: a type with no value, this is the default type for Value + //! - Bool: a true or false boolean value + //! - Object: a container with an ordered list of Name/Value pairs, analagous to a JSON object + //! - Array: a container with an ordered list of Values, analagous to a JSON array + //! - String: a UTF-8 string + //! - Int64: a signed, 64-bit integer + //! - Uint64: an unsigned, 64-bit integer + //! - Double: a double precision floating point value + //! - Node: a container with a Name, an ordered list of Name/Values pairs (attributes), and an ordered list of Values (children), + //! analagous to an XML node + //! - Opaque: an arbitrary value stored in an AZStd::any. This is a non-serializable representation of an entry used only for in-memory + //! options. This is intended to be used as an intermediate value over the course of DOM transformation and as a proxy to pass through + //! types of which the DOM has no knowledge to other systems. + //! \note Value is a copy-on-write data structure and may be cheaply returned by value. Heap allocated data larger than the size of the + //! value itself (objects, arrays, and nodes) are copied by new Values only when their contents change, so care should be taken in + //! performance critical code to avoid mutation operations such as operator[] to avoid copies. It is recommended that an immutable Value + //! be explicitly be stored as a `const Value` to avoid accidental detach and copy operations. + class Value final + { + public: + // Determine the short string buffer size based on the size of our largest internal type (string_view) + // minus the size of the short string size field. + static constexpr const size_t ShortStringSize = sizeof(AZStd::string_view) - 2; + using ShortStringType = AZStd::fixed_string; + using SharedStringContainer = AZStd::vector; + using SharedStringType = AZStd::shared_ptr; + using OpaqueStorageType = AZStd::shared_ptr; + + //! The internal storage type for Value. + //! These types do not correspond one-to-one with the Value's external Type as there may be multiple storage classes + //! for the same type in some instances, such as string storage. + using ValueType = AZStd::variant< + // Null + AZStd::monostate, + // Int64 + int64_t, + // Uint64 + uint64_t, + // Double + double, + // Bool + bool, + // String + AZStd::string_view, + SharedStringType, + ShortStringType, + // Object + ObjectPtr, + // Array + ArrayPtr, + // Node + NodePtr, + // Opaque + OpaqueStorageType>; + + // Constructors... + Value() = default; + Value(const Value&); + Value(Value&&) noexcept; + Value(AZStd::string_view stringView, bool copy); + explicit Value(const ValueType&); + explicit Value(ValueType&&); + explicit Value(SharedStringType sharedString); + + explicit Value(int8_t value); + explicit Value(uint8_t value); + explicit Value(int16_t value); + explicit Value(uint16_t value); + explicit Value(int32_t value); + explicit Value(uint32_t value); + explicit Value(int64_t value); + explicit Value(uint64_t value); + explicit Value(float value); + explicit Value(double value); + explicit Value(bool value); + + explicit Value(Type type); + + // Disable accidental calls to Value(bool) with pointer types + template + explicit Value(T*) = delete; + + static Value FromOpaqueValue(const AZStd::any& value); + + // Equality / comparison / swap... + Value& operator=(const Value&); + Value& operator=(Value&&) noexcept; + + //! Assignment operator to allow forwarding types constructible via Value(T) to be assigned + template + auto operator=(T&& arg) + -> AZStd::enable_if_t, Value> && AZStd::is_constructible_v, Value&> + { + return operator=(Value(AZStd::forward(arg))); + } + + bool operator==(const Value& rhs) const; + bool operator!=(const Value& rhs) const; + + void Swap(Value& other) noexcept; + + // Type info... + Type GetType() const; + bool IsNull() const; + bool IsFalse() const; + bool IsTrue() const; + bool IsBool() const; + bool IsNode() const; + bool IsObject() const; + bool IsArray() const; + bool IsOpaqueValue() const; + bool IsNumber() const; + bool IsInt() const; + bool IsUint() const; + bool IsDouble() const; + bool IsString() const; + + // Object API (also used by Node)... + Value& SetObject(); + size_t MemberCount() const; + size_t MemberCapacity() const; + bool ObjectEmpty() const; + + Value& operator[](KeyType name); + const Value& operator[](KeyType name) const; + Value& operator[](AZStd::string_view name); + const Value& operator[](AZStd::string_view name) const; + + Object::ConstIterator MemberBegin() const; + Object::ConstIterator MemberEnd() const; + Object::Iterator MemberBegin(); + Object::Iterator MemberEnd(); + + Object::Iterator FindMutableMember(KeyType name); + Object::Iterator FindMutableMember(AZStd::string_view name); + Object::ConstIterator FindMember(KeyType name) const; + Object::ConstIterator FindMember(AZStd::string_view name) const; + + Value& MemberReserve(size_t newCapacity); + bool HasMember(KeyType name) const; + bool HasMember(AZStd::string_view name) const; + + Value& AddMember(KeyType name, const Value& value); + Value& AddMember(AZStd::string_view name, const Value& value); + Value& AddMember(KeyType name, Value&& value); + Value& AddMember(AZStd::string_view name, Value&& value); + + void RemoveAllMembers(); + void RemoveMember(KeyType name); + void RemoveMember(AZStd::string_view name); + Object::Iterator RemoveMember(Object::Iterator pos); + Object::Iterator EraseMember(Object::ConstIterator pos); + Object::Iterator EraseMember(Object::ConstIterator first, Object::ConstIterator last); + Object::Iterator EraseMember(KeyType name); + Object::Iterator EraseMember(AZStd::string_view name); + + Object::ContainerType& GetMutableObject(); + const Object::ContainerType& GetObject() const; + + // Array API (also used by Node)... + Value& SetArray(); + + size_t ArraySize() const; + size_t ArrayCapacity() const; + bool IsArrayEmpty() const; + void ClearArray(); + + Value& operator[](size_t index); + const Value& operator[](size_t index) const; + + Value& MutableArrayAt(size_t index); + const Value& ArrayAt(size_t index) const; + + Array::ConstIterator ArrayBegin() const; + Array::ConstIterator ArrayEnd() const; + Array::Iterator ArrayBegin(); + Array::Iterator ArrayEnd(); + + Value& ArrayReserve(size_t newCapacity); + Value& ArrayPushBack(Value value); + Value& ArrayPopBack(); + + Array::Iterator ArrayErase(Array::ConstIterator pos); + Array::Iterator ArrayErase(Array::ConstIterator first, Array::ConstIterator last); + + Array::ContainerType& GetMutableArray(); + const Array::ContainerType& GetArray() const; + + // Node API (supports both object + array API, plus a dedicated NodeName)... + void SetNode(AZ::Name name); + void SetNode(AZStd::string_view name); + + AZ::Name GetNodeName() const; + void SetNodeName(AZ::Name name); + void SetNodeName(AZStd::string_view name); + //! Convenience method, sets the first non-node element of a Node. + void SetNodeValue(Value value); + //! Convenience method, gets the first non-node element of a Node. + Value GetNodeValue() const; + + Node& GetMutableNode(); + const Node& GetNode() const; + + // int API... + int64_t GetInt64() const; + void SetInt64(int64_t); + + // uint API... + uint64_t GetUint64() const; + void SetUint64(uint64_t); + + // bool API... + bool GetBool() const; + void SetBool(bool); + + // double API... + double GetDouble() const; + void SetDouble(double); + + // String API... + AZStd::string_view GetString() const; + size_t GetStringLength() const; + void SetString(AZStd::string_view); + void SetString(SharedStringType sharedString); + void CopyFromString(AZStd::string_view); + + // Opaque type API... + const AZStd::any& GetOpaqueValue() const; + //! This sets this Value to represent a value of an type that the DOM has + //! no formal knowledge of. Where possible, it should be preferred to + //! serialize an opaque type into a DOM value instead, as serializers + //! and other systems will have no means of dealing with fully arbitrary + //! values. + void SetOpaqueValue(AZStd::any); + + // Null API... + void SetNull(); + + // Visitor API... + Visitor::Result Accept(Visitor& visitor, bool copyStrings) const; + AZStd::unique_ptr GetWriteHandler(); + + //! Gets the internal value of this Value. Note that this value's types may not correspond one-to-one with the Type enumeration, + //! as internally the same type might have different storage mechanisms. Where possible, prefer using the typed API. + const ValueType& GetInternalValue() const; + + private: + const Node& GetNodeInternal() const; + Node& GetNodeInternal(); + const Object::ContainerType& GetObjectInternal() const; + Object::ContainerType& GetObjectInternal(); + const Array::ContainerType& GetArrayInternal() const; + Array::ContainerType& GetArrayInternal(); + + explicit Value(AZStd::any opaqueValue); + + static_assert( + sizeof(ValueType) == sizeof(ShortStringType) + sizeof(size_t), "ValueType should have no members larger than ShortStringType"); + + ValueType m_value; + }; +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp new file mode 100644 index 0000000000..433e650d04 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp @@ -0,0 +1,262 @@ +/* + * 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 + +namespace AZ::Dom +{ + ValueWriter::ValueWriter(Value& outputValue) + : m_result(outputValue) + { + } + + VisitorFlags ValueWriter::GetVisitorFlags() const + { + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes; + } + + ValueWriter::ValueInfo::ValueInfo(Value& container) + : m_container(container) + { + } + + Visitor::Result ValueWriter::Null() + { + CurrentValue().SetNull(); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Bool(bool value) + { + CurrentValue().SetBool(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Int64(AZ::s64 value) + { + CurrentValue().SetInt64(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Uint64(AZ::u64 value) + { + CurrentValue().SetUint64(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Double(double value) + { + CurrentValue().SetDouble(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::String(AZStd::string_view value, Lifetime lifetime) + { + if (lifetime == Lifetime::Persistent) + { + CurrentValue().SetString(value); + } + else + { + CurrentValue().CopyFromString(value); + } + return FinishWrite(); + } + + Visitor::Result ValueWriter::RefCountedString(AZStd::shared_ptr> value, [[maybe_unused]] Lifetime lifetime) + { + CurrentValue().SetString(AZStd::move(value)); + return FinishWrite(); + } + + Visitor::Result ValueWriter::StartObject() + { + CurrentValue().SetObject(); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + template + void MoveVectorMemory(AZStd::vector& dest, AZStd::vector& source) + { + dest.resize_no_construct(source.size()); + const size_t size = sizeof(T) * source.size(); + memcpy(dest.data(), source.data(), size); + memset(source.data(), 0, size); + source.resize(0); + } + + Visitor::Result ValueWriter::EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount) + { + const char* endMethodName; + switch (containerType) + { + case Type::Object: + endMethodName = "EndObject"; + break; + case Type::Array: + endMethodName = "EndArray"; + break; + case Type::Node: + endMethodName = "EndNode"; + break; + default: + AZ_Assert(false, "Invalid container type specified"); + return VisitorFailure(VisitorErrorCode::InternalError, "AZ::Dom::ValueWriter: EndContainer called with invalid container type"); + } + + if (m_entryStack.empty()) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format("AZ::Dom::ValueWriter: %s called without a matching call", endMethodName)); + } + + const ValueInfo& topEntry = m_entryStack.top(); + Value& container = topEntry.m_container; + ValueBuffer& buffer = GetValueBuffer(); + + if (container.GetType() != containerType) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format("AZ::Dom::ValueWriter: %s called from within a different container type", endMethodName)); + } + + if (aznumeric_cast(buffer.m_attributes.size()) != attributeCount) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format( + "AZ::Dom::ValueWriter: %s expected %llu attributes but received %zu attributes instead", endMethodName, attributeCount, + buffer.m_attributes.size())); + } + + if (aznumeric_cast(buffer.m_elements.size()) != elementCount) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format( + "AZ::Dom::ValueWriter: %s expected %llu elements but received %zu elements instead", endMethodName, elementCount, + buffer.m_elements.size())); + } + + if (buffer.m_attributes.size() > 0) + { + MoveVectorMemory(container.GetMutableObject(), buffer.m_attributes); + } + + if(buffer.m_elements.size() > 0) + { + MoveVectorMemory(container.GetMutableArray(), buffer.m_elements); + } + + m_entryStack.pop(); + return FinishWrite(); + } + + ValueWriter::ValueBuffer& ValueWriter::GetValueBuffer() + { + if (m_entryStack.size() <= m_valueBuffers.size()) + { + return m_valueBuffers[m_entryStack.size() - 1]; + } + + m_valueBuffers.resize(m_entryStack.size()); + return m_valueBuffers[m_entryStack.size() - 1]; + } + + Visitor::Result ValueWriter::EndObject(AZ::u64 attributeCount) + { + return EndContainer(Type::Object, attributeCount, 0); + } + + Visitor::Result ValueWriter::Key(AZ::Name key) + { + AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); + AZ_Assert(!m_entryStack.top().m_container.IsArray(), "Attempted to push a key to an array"); + m_entryStack.top().m_key = AZStd::move(key); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime) + { + return Key(AZ::Name(key)); + } + + Visitor::Result ValueWriter::StartArray() + { + CurrentValue().SetArray(); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::EndArray(AZ::u64 elementCount) + { + return EndContainer(Type::Array, 0, elementCount); + } + + Visitor::Result ValueWriter::StartNode(AZ::Name name) + { + CurrentValue().SetNode(name); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime) + { + return StartNode(AZ::Name(name)); + } + + Visitor::Result ValueWriter::EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) + { + return EndContainer(Type::Node, attributeCount, elementCount); + } + + Visitor::Result ValueWriter::OpaqueValue(OpaqueType& value) + { + CurrentValue().SetOpaqueValue(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::FinishWrite() + { + if (m_entryStack.empty()) + { + return VisitorSuccess(); + } + + Value value; + m_entryStack.top().m_value.Swap(value); + ValueInfo& newEntry = m_entryStack.top(); + + if (!newEntry.m_key.IsEmpty()) + { + GetValueBuffer().m_attributes.emplace_back(AZStd::move(newEntry.m_key), AZStd::move(value)); + newEntry.m_key = AZ::Name(); + } + else + { + GetValueBuffer().m_elements.emplace_back(AZStd::move(value)); + } + + return VisitorSuccess(); + } + + Value& ValueWriter::CurrentValue() + { + if (m_entryStack.empty()) + { + return m_result; + } + return m_entryStack.top().m_value; + } +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h new file mode 100644 index 0000000000..4fdea293eb --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AZ::Dom +{ + //! Visitor that writes to a Value. + //! Supports all Visitor operations. + class ValueWriter : public Visitor + { + public: + ValueWriter(Value& outputValue); + + VisitorFlags GetVisitorFlags() const override; + Result Null() override; + Result Bool(bool value) override; + Result Int64(AZ::s64 value) override; + Result Uint64(AZ::u64 value) override; + Result Double(double value) override; + + Result String(AZStd::string_view value, Lifetime lifetime) override; + Result RefCountedString(AZStd::shared_ptr> value, Lifetime lifetime) override; + Result StartObject() override; + Result EndObject(AZ::u64 attributeCount) override; + Result Key(AZ::Name key) override; + Result RawKey(AZStd::string_view key, Lifetime lifetime) override; + Result StartArray() override; + Result EndArray(AZ::u64 elementCount) override; + Result StartNode(AZ::Name name) override; + Result RawStartNode(AZStd::string_view name, Lifetime lifetime) override; + Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) override; + Result OpaqueValue(OpaqueType& value) override; + + private: + Result FinishWrite(); + Value& CurrentValue(); + Visitor::Result EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount); + + struct ValueInfo + { + ValueInfo(Value& container); + + KeyType m_key; + Value m_value; + Value& m_container; + }; + + struct ValueBuffer + { + Array::ContainerType m_elements; + Object::ContainerType m_attributes; + }; + + ValueBuffer& GetValueBuffer(); + + Value& m_result; + // Stores info about the current value being processed + AZStd::stack>> m_entryStack; + // Provides temporary storage for elements and attributes to prevent extra heap allocations + // These buffers persist to be reused even as the entry stack changes + AZStd::vector> m_valueBuffers; + }; +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp index ad314da385..0da4bcd5d3 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp @@ -105,7 +105,12 @@ namespace AZ::Dom return VisitorSuccess(); } - Visitor::Result Visitor::OpaqueValue([[maybe_unused]] const OpaqueType& value, [[maybe_unused]] Lifetime lifetime) + Visitor::Result Visitor::RefCountedString(AZStd::shared_ptr> value, Lifetime lifetime) + { + return String({ value->data(), value->size() }, lifetime); + } + + Visitor::Result Visitor::OpaqueValue([[maybe_unused]] OpaqueType& value) { if (!SupportsOpaqueValues()) { diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index bbe78131c3..f9930f93c6 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include namespace AZ::Dom @@ -167,15 +169,20 @@ namespace AZ::Dom virtual Result Uint64(AZ::u64 value); //! Operates on a double precision, 64 bit floating point value. virtual Result Double(double value); - //! Operates on a string value. As strings are a reference type. - //! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy. + //! Operates on a string value. As strings are a reference type, + //! storage semantics are provided to indicate where the value may be stored persistently or requires a copy. + //! \param lifetime Specifies the lifetime of this string - if the string has a temporary lifetime, it cannot + //! safely be stored as a reference. virtual Result String(AZStd::string_view value, Lifetime lifetime); + //! Operates on a ref-counted string value. S + //! \param lifetime Specifies the lifetime of this string. If the string has a temporary lifetime, it may not + //! be safely stored as a reference, but may still be safely stored as a ref-counted shared_ptr. + virtual Result RefCountedString(AZStd::shared_ptr> value, Lifetime lifetime); //! Operates on an opaque value. As opaque values are a reference type, storage semantics are provided to //! indicate where the value may be stored persistently or requires a copy. //! The base implementation of OpaqueValue rejects the operation, as opaque values are meant for special //! cases with specific implementations, not generic usage. - //! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy. - virtual Result OpaqueValue(const OpaqueType& value, Lifetime lifetime); + virtual Result OpaqueValue(OpaqueType& value); //! Operates on a raw value encoded as a UTF-8 string that hasn't had its type deduced. //! Visitors that support raw values (\see VisitorFlags::SupportsRawValues) may parse the raw value and //! forward it to the corresponding value call or calls of their choice. diff --git a/Code/Framework/AzCore/AzCore/Debug/Budget.h b/Code/Framework/AzCore/AzCore/Debug/Budget.h index 4646ef8b2c..c909302886 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Budget.h +++ b/Code/Framework/AzCore/AzCore/Debug/Budget.h @@ -62,12 +62,16 @@ namespace AZ::Debug // // Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself) // AZ_DECLARE_BUDGET(AzCore); -#define AZ_DEFINE_BUDGET(name) \ - ::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \ - { \ - constexpr static uint32_t crc = AZ_CRC_CE(#name); \ - static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \ - return budget; \ +#define AZ_DEFINE_BUDGET(name) \ + ::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \ + { \ + static ::AZ::Debug::Budget* budget = nullptr; \ + if (budget == nullptr) \ + { \ + constexpr static uint32_t crc = AZ_CRC_CE(#name); \ + ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(budget, #name, crc); \ + } \ + return budget; \ } #endif diff --git a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.cpp b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.cpp index 2dac9a566e..faadbfc31a 100644 --- a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.cpp @@ -13,23 +13,24 @@ #include #include #include +#include #include namespace AZ::Debug { struct BudgetTracker::BudgetTrackerImpl { - AZStd::unordered_map m_budgets; + AZStd::unordered_map m_budgets; + AZStd::unordered_set m_externalBudgetRefs; }; - Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc) + void BudgetTracker::GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc) { BudgetTracker* tracker = Interface::Get(); if (tracker) { - return &tracker->GetBudget(budgetName, crc); + tracker->GetBudget(extBudgetRef, budgetName, crc); } - return nullptr; } BudgetTracker::~BudgetTracker() @@ -54,17 +55,24 @@ namespace AZ::Debug if (m_impl) { Interface::Unregister(this); + + for (auto budgetRef : m_impl->m_externalBudgetRefs) + { + *budgetRef = nullptr; + } + delete m_impl; m_impl = nullptr; } } - Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc) + void BudgetTracker::GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc) { AZStd::scoped_lock lock{ m_mutex }; - auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first; + m_impl->m_externalBudgetRefs.insert(&extBudgetRef); - return it->second; + auto iter = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first; + extBudgetRef = &iter->second; } } // namespace AZ::Debug diff --git a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h index 34d8510349..69e8185746 100644 --- a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h +++ b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h @@ -20,7 +20,7 @@ namespace AZ::Debug { public: AZ_TYPE_INFO(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}"); - static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc); + static void GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc); ~BudgetTracker(); @@ -28,7 +28,7 @@ namespace AZ::Debug bool Init(); void Reset(); - Budget& GetBudget(const char* budgetName, uint32_t crc); + void GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc); private: struct BudgetTrackerImpl; diff --git a/Code/Framework/AzCore/AzCore/UnitTest/TestTypes.h b/Code/Framework/AzCore/AzCore/UnitTest/TestTypes.h index afa6898944..0b1d7caefe 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/TestTypes.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/TestTypes.h @@ -71,18 +71,35 @@ namespace UnitTest }; /** - * RAII wrapper of AllocatorBase. - * The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed - * on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation). - */ - class ScopedAllocatorSetupFixture - : public ::testing::Test - , AllocatorsBase + * RAII wrapper of AllocatorBase. + * The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed + * on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation). + */ + class ScopedAllocatorFixture : AllocatorsBase { public: - ScopedAllocatorSetupFixture() { SetupAllocator(); } - explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) { SetupAllocator(allocatorDesc); } - ~ScopedAllocatorSetupFixture() { TeardownAllocator(); } + ScopedAllocatorFixture() + { + SetupAllocator(); + } + explicit ScopedAllocatorFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) + { + SetupAllocator(allocatorDesc); + } + ~ScopedAllocatorFixture() override + { + TeardownAllocator(); + } + }; + + // Like ScopedAllocatorFixture, but includes the Test base class + class ScopedAllocatorSetupFixture + : public ::testing::Test + , public ScopedAllocatorFixture + { + public: + ScopedAllocatorSetupFixture() = default; + explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) : ScopedAllocatorFixture(allocatorDesc){} }; /** @@ -114,6 +131,7 @@ namespace UnitTest using AllocatorsFixture = AllocatorsTestFixture; #if defined(HAVE_BENCHMARK) + /** * Helper class to handle the boiler plate of setting up a benchmark fixture that uses the system allocators * If you wish to do additional setup and tear down be sure to call the base class SetUp first and TearDown @@ -218,7 +236,7 @@ namespace UnitTest static constexpr bool sHasPadding = size < alignment; AZStd::enable_if mPadding; }; - + template int CreationCounter::s_count = 0; template diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 0dfce11247..d25a28aa24 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -117,6 +117,10 @@ set(FILES DOM/DomBackend.h DOM/DomUtils.cpp DOM/DomUtils.h + DOM/DomValue.cpp + DOM/DomValue.h + DOM/DomValueWriter.cpp + DOM/DomValueWriter.h DOM/DomVisitor.cpp DOM/DomVisitor.h DOM/Backends/JSON/JsonBackend.h diff --git a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake index 2746489f8c..d516a56295 100644 --- a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake +++ b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake @@ -64,6 +64,8 @@ set(FILES containers/rbtree.h containers/ring_buffer.h containers/set.h + containers/span.h + containers/span.inl containers/stack.h containers/unordered_map.h containers/unordered_set.h diff --git a/Code/Framework/AzCore/AzCore/std/containers/span.h b/Code/Framework/AzCore/AzCore/std/containers/span.h new file mode 100644 index 0000000000..5bb51bf481 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/containers/span.h @@ -0,0 +1,137 @@ +/* + * 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 +#include +#include + +namespace AZStd +{ + /** + * First pass partial implementation of span copied over from array_view. It + * returns non-const iterator/pointers. first(), last(), and subspan() + * are yet to be implemented. It does not maintain storage for the data, + * but just holds pointers to mark the beginning and end of the array. + * It can be conveniently constructed from a variety of other container + * types like array, vector, and fixed_vector. + * + * Example: + * Given "void Func(AZStd::span a) {...}" you can call... + * - Func({1,2,3}); + * - AZStd::array a = {1,2,3}; + * Func(a); + * - AZStd::vector v = {1,2,3}; + * Func(v); + * - AZStd::fixed_vector fv = {1,2,3}; + * Func(fv); + * + * Since the span does not copy and store any data, it is only valid as long as the data used to create it is valid. + */ + template + class span final + { + public: + using value_type = Element; + + using pointer = value_type*; + using const_pointer = const value_type*; + + using reference = value_type&; + using const_reference = const value_type&; + + using size_type = AZStd::size_t; + using difference_type = AZStd::ptrdiff_t; + + using iterator = value_type*; + using const_iterator = const value_type*; + using reverse_iterator = AZStd::reverse_iterator; + using const_reverse_iterator = AZStd::reverse_iterator; + + constexpr span(); + + ~span() = default; + + constexpr span(pointer s, size_type length); + + constexpr span(pointer first, pointer last); + + // We explicitly delete this constructor because it's too easy to accidentally + // create a span to just the first element instead of an entire array. + constexpr span(const_pointer s) = delete; + + template + constexpr span(AZStd::array& data); + + constexpr span(AZStd::vector& data); + + template + constexpr span(AZStd::fixed_vector& data); + + template + constexpr span(const AZStd::array& data); + + constexpr span(const AZStd::vector& data); + + template + constexpr span(const AZStd::fixed_vector& data); + + constexpr span(const span&) = default; + + constexpr span(span&& other); + + constexpr span& operator=(const span& other) = default; + + constexpr span& operator=(span&& other); + + constexpr size_type size() const; + + constexpr bool empty() const; + + constexpr pointer data(); + constexpr const_pointer data() const; + + constexpr const_reference operator[](size_type index) const; + constexpr reference operator[](size_type index); + + constexpr void erase(); + + constexpr iterator begin(); + constexpr iterator end(); + constexpr const_iterator begin() const; + constexpr const_iterator end() const; + + constexpr const_iterator cbegin() const; + constexpr const_iterator cend() const; + + constexpr reverse_iterator rbegin(); + constexpr reverse_iterator rend(); + constexpr const_reverse_iterator rbegin() const; + constexpr const_reverse_iterator rend() const; + + constexpr const_reverse_iterator crbegin() const; + constexpr const_reverse_iterator crend() const; + + friend bool operator==(span lhs, span rhs) + { + return lhs.m_begin == rhs.m_begin && lhs.m_end == rhs.m_end; + } + + friend bool operator!=(span lhs, span rhs) { return !(lhs == rhs); } + friend bool operator< (span lhs, span rhs) { return lhs.m_begin < rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end < rhs.m_end; } + friend bool operator> (span lhs, span rhs) { return lhs.m_begin > rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end > rhs.m_end; } + friend bool operator<=(span lhs, span rhs) { return lhs == rhs || lhs < rhs; } + friend bool operator>=(span lhs, span rhs) { return lhs == rhs || lhs > rhs; } + + private: + pointer m_begin; + pointer m_end; + }; +} // namespace AZStd + +#include diff --git a/Code/Framework/AzCore/AzCore/std/containers/span.inl b/Code/Framework/AzCore/AzCore/std/containers/span.inl new file mode 100644 index 0000000000..01bab9a5a4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/containers/span.inl @@ -0,0 +1,150 @@ +/* + * 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 + +namespace AZStd +{ + template + inline constexpr span::span() + : m_begin(nullptr) + , m_end(nullptr) + { } + + template + inline constexpr span::span(pointer s, size_type length) + : m_begin(s) + , m_end(m_begin + length) + { + if (length == 0) erase(); + } + + template + inline constexpr span::span(pointer first, pointer last) + : m_begin(first) + , m_end(last) + { } + + template + template + inline constexpr span::span(AZStd::array& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + inline constexpr span::span(AZStd::vector& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + template + inline constexpr span::span(AZStd::fixed_vector& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + template + inline constexpr span::span(const AZStd::array& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + inline constexpr span::span(const AZStd::vector& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + template + inline constexpr span::span(const AZStd::fixed_vector& data) + : m_begin(data.data()) + , m_end(m_begin + data.size()) + { } + + template + inline constexpr span::span(span&& other) + : span(other.m_begin, other.m_end) + { +#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging + other.m_begin = nullptr; + other.m_end = nullptr; +#endif + } + + template + inline constexpr AZStd::size_t span::size() const { return m_end - m_begin; } + + template + inline constexpr bool span::empty() const { return m_end == m_begin; } + + template + inline constexpr Element* span::data() { return m_begin; } + + template + inline constexpr const Element* span::data() const { return m_begin; } + + template + inline constexpr span& span::operator=(span&& other) + { + m_begin = other.m_begin; + m_end = other.m_end; +#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging + other.m_begin = nullptr; + other.m_end = nullptr; +#endif + return *this; + } + + template + inline constexpr const Element& span::operator[](AZStd::size_t index) const + { + AZ_Assert(index < size(), "index value is out of range"); + return m_begin[index]; + } + + template + inline constexpr Element& span::operator[](AZStd::size_t index) + { + AZ_Assert(index < size(), "index value is out of range"); + return m_begin[index]; + } + + template + inline constexpr void span::erase() { m_begin = m_end = nullptr; } + + template + inline constexpr Element* span::begin() { return m_begin; } + template + inline constexpr Element* span::end() { return m_end; } + template + inline constexpr const Element* span::begin() const { return m_begin; } + template + inline constexpr const Element* span::end() const { return m_end; } + + template + inline constexpr const Element* span::cbegin() const { return m_begin; } + template + inline constexpr const Element* span::cend() const { return m_end; } + + template + inline constexpr AZStd::reverse_iterator span::rbegin() { return AZStd::reverse_iterator(m_end); } + template + inline constexpr AZStd::reverse_iterator span::rend() { return AZStd::reverse_iterator(m_begin); } + template + inline constexpr AZStd::reverse_iterator span::rbegin() const { return AZStd::reverse_iterator(m_end); } + template + inline constexpr AZStd::reverse_iterator span::rend() const { return AZStd::reverse_iterator(m_begin); } + + template + inline constexpr AZStd::reverse_iterator span::crbegin() const { return AZStd::reverse_iterator(cend()); } + template + inline constexpr AZStd::reverse_iterator span::crend() const { return AZStd::reverse_iterator(cbegin()); } +} // namespace AZStd diff --git a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl index 15d2acf7a1..a1c95b7ba2 100644 --- a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl +++ b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl @@ -1760,7 +1760,8 @@ namespace AZStd template struct hash> { - inline constexpr size_t operator()(const basic_fixed_string& value) const + using is_transparent = void; + inline constexpr size_t operator()(const basic_string_view& value) const { return hash_string(value.begin(), value.length()); } diff --git a/Code/Framework/AzCore/AzCore/std/string/string.h b/Code/Framework/AzCore/AzCore/std/string/string.h index 7dd6dd7065..56afd16226 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string.h +++ b/Code/Framework/AzCore/AzCore/std/string/string.h @@ -2071,9 +2071,8 @@ namespace AZStd template struct hash< basic_string< Element, Traits, Allocator> > { - typedef basic_string< Element, Traits, Allocator> argument_type; - typedef AZStd::size_t result_type; - inline result_type operator()(const argument_type& value) const + using is_transparent = void; + inline constexpr size_t operator()(const basic_string_view& value) const { return hash_string(value.begin(), value.length()); } diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index 838142f0df..01f4086a18 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -9,8 +9,8 @@ # TODO: would like to be able to build from this path, however, the whole setup is done at the workspace's root # we also dont want to drop cmake output files everywhere. -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) if(PAL_TRAIT_PROF_PIX_SUPPORTED) set(LY_PIX_ENABLED OFF CACHE BOOL "Enables PIX profiler integration.") @@ -110,15 +110,15 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest ) - ly_get_list_relative_pal_filename(pal_test_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(pal_tests_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME AzCore.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE AZ FILES_CMAKE Tests/azcoretests_files.cmake - ${pal_test_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_tests_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake PLATFORM_INCLUDE_FILES - ${pal_test_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake + ${pal_tests_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake INCLUDE_DIRECTORIES PRIVATE Tests diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp index 0baa4aeb53..8eda110e7b 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -8,9 +8,10 @@ #if defined(HAVE_BENCHMARK) -#include #include #include +#include +#include #include #include #include @@ -25,27 +26,31 @@ namespace Benchmark { UnitTest::AllocatorsBenchmarkFixture::SetUp(st); AZ::NameDictionary::Create(); + AZ::AllocatorInstance::Create(); } void SetUp(::benchmark::State& st) override { UnitTest::AllocatorsBenchmarkFixture::SetUp(st); AZ::NameDictionary::Create(); + AZ::AllocatorInstance::Create(); } void TearDown(::benchmark::State& st) override { + AZ::AllocatorInstance::Destroy(); AZ::NameDictionary::Destroy(); UnitTest::AllocatorsBenchmarkFixture::TearDown(st); } void TearDown(const ::benchmark::State& st) override { + AZ::AllocatorInstance::Destroy(); AZ::NameDictionary::Destroy(); UnitTest::AllocatorsBenchmarkFixture::TearDown(st); } - AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) + rapidjson::Document GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength) { rapidjson::Document document; document.SetObject(); @@ -103,11 +108,28 @@ namespace Benchmark document.SetObject(); document.AddMember("entries", createObject(), document.GetAllocator()); + return document; + } + + AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) + { + rapidjson::Document document = GenerateDomJsonBenchmarkDocument(entryCount, stringTemplateLength); + AZStd::string serializedJson; auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson); AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON"); return serializedJson; } + + template + void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state) + { + { + T instance = AZStd::move(value); + state.PauseTiming(); + } + state.ResumeTiming(); + } }; // Helper macro for registering JSON benchmarks @@ -119,7 +141,7 @@ namespace Benchmark ->Args({ 100, 500 }) \ ->Unit(benchmark::kMillisecond); - BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocumentInPlace)(benchmark::State& state) + BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace)(benchmark::State& state) { AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); @@ -136,14 +158,38 @@ namespace Benchmark return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor); }); - benchmark::DoNotOptimize(result.GetValue()); + TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state); } state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocumentInPlace) + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace) - BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocument)(benchmark::State& state) + BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace)(benchmark::State& state) + { + AZ::Dom::JsonBackend backend; + AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + state.PauseTiming(); + AZStd::string payloadCopy = serializedPayload; + state.ResumeTiming(); + + auto result = AZ::Dom::Utils::WriteToValue( + [&](AZ::Dom::Visitor& visitor) + { + return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor); + }); + + TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state); + } + + state.SetBytesProcessed(serializedPayload.size() * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjson)(benchmark::State& state) { AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); @@ -156,14 +202,34 @@ namespace Benchmark return AZ::Dom::Utils::ReadFromString(backend, serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); }); - benchmark::DoNotOptimize(result.GetValue()); + TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state); } state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocument) + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToRapidjson) - BENCHMARK_DEFINE_F(DomJsonBenchmark, JsonUtilsDeserializeToDocument)(benchmark::State& state) + BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValue)(benchmark::State& state) + { + AZ::Dom::JsonBackend backend; + AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + auto result = AZ::Dom::Utils::WriteToValue( + [&](AZ::Dom::Visitor& visitor) + { + return AZ::Dom::Utils::ReadFromString(backend, serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); + }); + + TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state); + } + + state.SetBytesProcessed(serializedPayload.size() * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, AzDomDeserializeToAzDomValue) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonDeserializeToRapidjson)(benchmark::State& state) { AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); @@ -172,12 +238,78 @@ namespace Benchmark { auto result = AZ::JsonSerializationUtils::ReadJsonString(serializedPayload); - benchmark::DoNotOptimize(result.GetValue()); + TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state); } state.SetBytesProcessed(serializedPayload.size() * state.iterations()); } - BENCHMARK_REGISTER_JSON(DomJsonBenchmark, JsonUtilsDeserializeToDocument) + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonDeserializeToRapidjson) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonMakeComplexObject)(benchmark::State& state) + { + for (auto _ : state) + { + TakeAndDiscardWithoutTimingDtor(GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)), state); + } + + state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonMakeComplexObject) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonLookupMemberByString)(benchmark::State& state) + { + rapidjson::Document document(rapidjson::kObjectType); + AZStd::vector keys; + for (int64_t i = 0; i < state.range(0); ++i) + { + AZStd::string key(AZStd::string::format("key%" PRId64, i)); + keys.push_back(key); + document.AddMember(rapidjson::Value(key.data(), static_cast(key.size()), document.GetAllocator()), rapidjson::Value(i), document.GetAllocator()); + } + + for (auto _ : state) + { + for (const AZStd::string& key : keys) + { + benchmark::DoNotOptimize(document.FindMember(key.data())); + } + } + + state.SetItemsProcessed(state.iterations() * state.range(0)); + } + BENCHMARK_REGISTER_F(DomJsonBenchmark, RapidjsonLookupMemberByString)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonDeepCopy)(benchmark::State& state) + { + rapidjson::Document original = GenerateDomJsonBenchmarkDocument(state.range(0), state.range(1)); + + for (auto _ : state) + { + rapidjson::Document copy; + copy.CopyFrom(original, copy.GetAllocator(), true); + TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state); + } + + state.SetItemsProcessed(state.iterations()); + } + + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonDeepCopy) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonCopyAndMutate)(benchmark::State& state) + { + rapidjson::Document original = GenerateDomJsonBenchmarkDocument(state.range(0), state.range(1)); + + for (auto _ : state) + { + rapidjson::Document copy; + copy.CopyFrom(original, copy.GetAllocator(), true); + copy["entries"]["Key0"].PushBack(42, copy.GetAllocator()); + TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state); + } + + state.SetItemsProcessed(state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, RapidjsonCopyAndMutate) #undef BENCHMARK_REGISTER_JSON } // namespace Benchmark diff --git a/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp new file mode 100644 index 0000000000..40b96e148b --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomValueBenchmarks.cpp @@ -0,0 +1,263 @@ +/* + * 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 +#include +#include +#include +#include + +namespace AZ::Dom::Benchmark +{ + class DomValueBenchmark : public UnitTest::AllocatorsBenchmarkFixture + { + public: + void SetUp(const ::benchmark::State& st) override + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + AZ::NameDictionary::Create(); + AZ::AllocatorInstance::Create(); + } + + void SetUp(::benchmark::State& st) override + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + AZ::NameDictionary::Create(); + AZ::AllocatorInstance::Create(); + } + + void TearDown(::benchmark::State& st) override + { + AZ::AllocatorInstance::Destroy(); + AZ::NameDictionary::Destroy(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + void TearDown(const ::benchmark::State& st) override + { + AZ::AllocatorInstance::Destroy(); + AZ::NameDictionary::Destroy(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + Value GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) + { + Value root(Type::Object); + + AZStd::string entryTemplate; + while (entryTemplate.size() < static_cast(stringTemplateLength)) + { + entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; + } + entryTemplate.resize(stringTemplateLength); + AZStd::string buffer; + + auto createString = [&](int n) -> Value + { + return Value(AZStd::string::format("#%i %s", n, entryTemplate.c_str()), true); + }; + + auto createEntry = [&](int n) -> Value + { + Value entry(Type::Object); + entry.AddMember("string", createString(n)); + entry.AddMember("int", Value(n)); + entry.AddMember("double", Value(static_cast(n) * 0.5)); + entry.AddMember("bool", Value(n % 2 == 0)); + entry.AddMember("null", Value(Type::Null)); + return entry; + }; + + auto createArray = [&]() -> Value + { + Value array(Type::Array); + for (int i = 0; i < entryCount; ++i) + { + array.ArrayPushBack(createEntry(i)); + } + return array; + }; + + auto createObject = [&]() -> Value + { + Value object; + object.SetObject(); + for (int i = 0; i < entryCount; ++i) + { + buffer = AZStd::string::format("Key%i", i); + object.AddMember(AZ::Name(buffer), createArray()); + } + return object; + }; + + root["entries"] = createObject(); + + return root; + } + + template + void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state) + { + { + T instance = AZStd::move(value); + state.PauseTiming(); + } + state.ResumeTiming(); + } + }; + + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueMakeComplexObject)(benchmark::State& state) + { + for (auto _ : state) + { + TakeAndDiscardWithoutTimingDtor(GenerateDomBenchmarkPayload(state.range(0), state.range(1)), state); + } + + state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueMakeComplexObject) + ->Args({ 10, 5 }) + ->Args({ 10, 500 }) + ->Args({ 100, 5 }) + ->Args({ 100, 500 }) + ->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueShallowCopy)(benchmark::State& state) + { + Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + Value copy = original; + benchmark::DoNotOptimize(copy); + } + + state.SetItemsProcessed(state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueShallowCopy) + ->Args({ 10, 5 }) + ->Args({ 10, 500 }) + ->Args({ 100, 5 }) + ->Args({ 100, 500 }) + ->Unit(benchmark::kNanosecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueCopyAndMutate)(benchmark::State& state) + { + Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + Value copy = original; + copy["entries"]["Key0"].ArrayPushBack(Value(42)); + TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state); + } + + state.SetItemsProcessed(state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueCopyAndMutate) + ->Args({ 10, 5 }) + ->Args({ 10, 500 }) + ->Args({ 100, 5 }) + ->Args({ 100, 500 }) + ->Unit(benchmark::kNanosecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueDeepCopy)(benchmark::State& state) + { + Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + Value copy = Utils::DeepCopy(original); + TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state); + } + + state.SetItemsProcessed(state.iterations()); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueDeepCopy) + ->Args({ 10, 5 }) + ->Args({ 10, 500 }) + ->Args({ 100, 5 }) + ->Args({ 100, 500 }) + ->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByName)(benchmark::State& state) + { + Value value(Type::Object); + AZStd::vector keys; + for (int64_t i = 0; i < state.range(0); ++i) + { + AZ::Name key(AZStd::string::format("key%" PRId64, i)); + keys.push_back(key); + value[key] = i; + } + + for (auto _ : state) + { + for (const AZ::Name& key : keys) + { + benchmark::DoNotOptimize(value[key]); + } + } + + state.SetItemsProcessed(state.iterations() * state.range(0)); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByName)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByString)(benchmark::State& state) + { + Value value(Type::Object); + AZStd::vector keys; + for (int64_t i = 0; i < state.range(0); ++i) + { + AZStd::string key(AZStd::string::format("key%" PRId64, i)); + keys.push_back(key); + value[key] = i; + } + + for (auto _ : state) + { + for (const AZStd::string& key : keys) + { + benchmark::DoNotOptimize(value[key]); + } + } + + state.SetItemsProcessed(state.iterations() * state.range(0)); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByString)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByStringComparison)(benchmark::State& state) + { + Value value(Type::Object); + AZStd::vector keys; + for (int64_t i = 0; i < state.range(0); ++i) + { + AZStd::string key(AZStd::string::format("key%" PRId64, i)); + keys.push_back(key); + value[key] = i; + } + + for (auto _ : state) + { + for (const AZStd::string& key : keys) + { + const Object::ContainerType& object = value.GetObject(); + benchmark::DoNotOptimize(AZStd::find_if( + object.cbegin(), object.cend(), + [&key](const Object::EntryType& entry) + { + return key == entry.first.GetStringView(); + })); + } + } + + state.SetItemsProcessed(state.iterations() * state.range(0)); + } + BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByStringComparison)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond); + +} // namespace AZ::Dom::Benchmark diff --git a/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp new file mode 100644 index 0000000000..10e9f29a44 --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomValueTests.cpp @@ -0,0 +1,392 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::Dom::Tests +{ + class DomValueTests : public UnitTest::AllocatorsFixture + { + public: + void SetUp() override + { + UnitTest::AllocatorsFixture::SetUp(); + NameDictionary::Create(); + AZ::AllocatorInstance::Create(); + } + + void TearDown() override + { + m_value = Value(); + + AZ::AllocatorInstance::Destroy(); + NameDictionary::Destroy(); + UnitTest::AllocatorsFixture::TearDown(); + } + + void PerformValueChecks() + { + Value shallowCopy = m_value; + EXPECT_EQ(m_value, shallowCopy); + EXPECT_TRUE(Utils::DeepCompareIsEqual(m_value, shallowCopy)); + + Value deepCopy = Utils::DeepCopy(m_value); + EXPECT_TRUE(Utils::DeepCompareIsEqual(m_value, deepCopy)); + } + + Value m_value; + }; + + TEST_F(DomValueTests, EmptyArray) + { + m_value.SetArray(); + + EXPECT_TRUE(m_value.IsArray()); + EXPECT_EQ(m_value.ArraySize(), 0); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, SimpleArray) + { + m_value.SetArray(); + + for (int i = 0; i < 5; ++i) + { + m_value.ArrayPushBack(Value(i)); + EXPECT_EQ(m_value.ArraySize(), i + 1); + EXPECT_EQ(m_value[i].GetInt64(), i); + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, NestedArrays) + { + Value x(5); + m_value.SetArray(); + for (int j = 0; j < 5; ++j) + { + Value nestedArray(Type::Array); + for (int i = 0; i < 5; ++i) + { + nestedArray.ArrayPushBack(Value(i)); + } + m_value.ArrayPushBack(AZStd::move(nestedArray)); + } + + EXPECT_EQ(m_value.ArraySize(), 5); + for (int i = 0; i < 3; ++i) + { + EXPECT_EQ(m_value[i].ArraySize(), 5); + for (int j = 0; j < 5; ++j) + { + EXPECT_EQ(m_value[i][j].GetInt64(), j); + } + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, EmptyObject) + { + m_value.SetObject(); + EXPECT_EQ(m_value.MemberCount(), 0); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, SimpleObject) + { + m_value.SetObject(); + for (int i = 0; i < 5; ++i) + { + AZStd::string key = AZStd::string::format("Key%i", i); + m_value.AddMember(key, Value(i)); + EXPECT_EQ(m_value.MemberCount(), i + 1); + EXPECT_EQ(m_value[key].GetInt64(), i); + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, NestedObjects) + { + m_value.SetObject(); + for (int j = 0; j < 3; ++j) + { + Value nestedObject(Type::Object); + for (int i = 0; i < 5; ++i) + { + nestedObject.AddMember(AZStd::string::format("Key%i", i), Value(i)); + } + m_value.AddMember(AZStd::string::format("Obj%i", j), AZStd::move(nestedObject)); + } + + EXPECT_EQ(m_value.MemberCount(), 3); + for (int j = 0; j < 3; ++j) + { + const Value& nestedObject = m_value[AZStd::string::format("Obj%i", j)]; + EXPECT_EQ(nestedObject.MemberCount(), 5); + for (int i = 0; i < 5; ++i) + { + EXPECT_EQ(nestedObject[AZStd::string::format("Key%i", i)].GetInt64(), i); + } + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, EmptyNode) + { + m_value.SetNode("Test"); + EXPECT_EQ(m_value.GetNodeName(), AZ::Name("Test")); + EXPECT_EQ(m_value.MemberCount(), 0); + EXPECT_EQ(m_value.ArraySize(), 0); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, SimpleNode) + { + m_value.SetNode("Test"); + + for (int i = 0; i < 10; ++i) + { + m_value.ArrayPushBack(Value(i)); + EXPECT_EQ(m_value.ArraySize(), i + 1); + EXPECT_EQ(m_value[i].GetInt64(), i); + + if (i < 5) + { + AZ::Name key = AZ::Name(AZStd::string::format("TwoTimes%i", i)); + m_value.AddMember(key, Value(i * 2)); + EXPECT_EQ(m_value.MemberCount(), i + 1); + EXPECT_EQ(m_value[key].GetInt64(), i * 2); + } + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, NestedNodes) + { + m_value.SetNode("TopLevel"); + + const AZ::Name childNodeName("ChildNode"); + + for (int i = 0; i < 5; ++i) + { + Value childNode(Type::Node); + childNode.SetNodeName(childNodeName); + childNode.SetNodeValue(Value(i)); + + childNode.AddMember("foo", Value(i)); + childNode.AddMember("bar", Value("test", false)); + + m_value.ArrayPushBack(childNode); + } + + EXPECT_EQ(m_value.ArraySize(), 5); + for (int i = 0; i < 5; ++i) + { + const Value& childNode = m_value[i]; + EXPECT_EQ(childNode.GetNodeName(), childNodeName); + EXPECT_EQ(childNode.GetNodeValue().GetInt64(), i); + EXPECT_EQ(childNode["foo"].GetInt64(), i); + EXPECT_EQ(childNode["bar"].GetString(), "test"); + } + + PerformValueChecks(); + } + + TEST_F(DomValueTests, Int64) + { + m_value.SetObject(); + m_value["int64_min"] = AZStd::numeric_limits::min(); + m_value["int64_max"] = AZStd::numeric_limits::max(); + + EXPECT_EQ(m_value["int64_min"].GetType(), Type::Int64); + EXPECT_EQ(m_value["int64_min"].GetInt64(), AZStd::numeric_limits::min()); + EXPECT_EQ(m_value["int64_max"].GetType(), Type::Int64); + EXPECT_EQ(m_value["int64_max"].GetInt64(), AZStd::numeric_limits::max()); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, Uint64) + { + m_value.SetObject(); + m_value["uint64_min"] = AZStd::numeric_limits::min(); + m_value["uint64_max"] = AZStd::numeric_limits::max(); + + EXPECT_EQ(m_value["uint64_min"].GetType(), Type::Uint64); + EXPECT_EQ(m_value["uint64_min"].GetInt64(), AZStd::numeric_limits::min()); + EXPECT_EQ(m_value["uint64_max"].GetType(), Type::Uint64); + EXPECT_EQ(m_value["uint64_max"].GetInt64(), AZStd::numeric_limits::max()); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, Double) + { + m_value.SetObject(); + m_value["double_min"] = AZStd::numeric_limits::min(); + m_value["double_max"] = AZStd::numeric_limits::max(); + + EXPECT_EQ(m_value["double_min"].GetType(), Type::Double); + EXPECT_EQ(m_value["double_min"].GetDouble(), AZStd::numeric_limits::min()); + EXPECT_EQ(m_value["double_max"].GetType(), Type::Double); + EXPECT_EQ(m_value["double_max"].GetDouble(), AZStd::numeric_limits::max()); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, Null) + { + m_value.SetObject(); + m_value["null_value"] = Value(Type::Null); + + EXPECT_EQ(m_value["null_value"].GetType(), Type::Null); + EXPECT_EQ(m_value["null_type"], Value()); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, Bool) + { + m_value.SetObject(); + m_value["true_value"] = true; + m_value["false_value"] = false; + + EXPECT_EQ(m_value["true_value"].GetType(), Type::Bool); + EXPECT_EQ(m_value["true_value"].GetBool(), true); + EXPECT_EQ(m_value["false_value"].GetType(), Type::Bool); + EXPECT_EQ(m_value["false_value"].GetBool(), false); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, String) + { + const char* s1 = "reference string long enough to avoid SSO"; + const char* s2 = "copy string long enough to avoid SSO"; + + m_value.SetObject(); + AZStd::string stringToReference = s1; + m_value["no_copy"] = Value(stringToReference, false); + AZStd::string stringToCopy = s2; + m_value["copy"] = Value(stringToCopy, true); + + EXPECT_EQ(m_value["no_copy"].GetType(), Type::String); + EXPECT_EQ(m_value["no_copy"].GetString(), s1); + stringToReference.at(0) = 'F'; + EXPECT_NE(m_value["no_copy"].GetString(), s1); + + EXPECT_EQ(m_value["copy"].GetType(), Type::String); + EXPECT_EQ(m_value["copy"].GetString(), s2); + stringToCopy.at(0) = 'F'; + EXPECT_EQ(m_value["copy"].GetString(), s2); + + PerformValueChecks(); + } + + TEST_F(DomValueTests, CopyOnWrite_Object) + { + Value v1(Type::Object); + v1["foo"] = 5; + + Value nestedObject(Type::Object); + v1["obj"] = nestedObject; + + Value v2 = v1; + EXPECT_EQ(&v1.GetObject(), &v2.GetObject()); + EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject()); + + v2["foo"] = 0; + + EXPECT_NE(&v1.GetObject(), &v2.GetObject()); + EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject()); + + v2["obj"]["key"] = true; + + EXPECT_NE(&v1.GetObject(), &v2.GetObject()); + EXPECT_NE(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject()); + + v2 = v1; + + EXPECT_EQ(&v1.GetObject(), &v2.GetObject()); + EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject()); + } + + TEST_F(DomValueTests, CopyOnWrite_Array) + { + Value v1(Type::Array); + v1.ArrayPushBack(Value(1)); + v1.ArrayPushBack(Value(2)); + + Value nestedArray(Type::Array); + v1.ArrayPushBack(nestedArray); + Value v2 = v1; + + EXPECT_EQ(&v1.GetArray(), &v2.GetArray()); + EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray()); + + v2[0] = 0; + + EXPECT_NE(&v1.GetArray(), &v2.GetArray()); + EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray()); + + v2[2].ArrayPushBack(Value(42)); + + EXPECT_NE(&v1.GetArray(), &v2.GetArray()); + EXPECT_NE(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray()); + + v2 = v1; + + EXPECT_EQ(&v1.GetArray(), &v2.GetArray()); + EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray()); + } + + TEST_F(DomValueTests, CopyOnWrite_Node) + { + Value v1; + v1.SetNode("TopLevel"); + + v1.ArrayPushBack(Value(1)); + v1.ArrayPushBack(Value(2)); + v1["obj"].SetNode("Nested"); + Value v2 = v1; + + EXPECT_EQ(&v1.GetNode(), &v2.GetNode()); + EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode()); + + v2[0] = 0; + + EXPECT_NE(&v1.GetNode(), &v2.GetNode()); + EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode()); + + v2["obj"].ArrayPushBack(Value(42)); + + EXPECT_NE(&v1.GetNode(), &v2.GetNode()); + EXPECT_NE(&v1["obj"].GetNode(), &v2["obj"].GetNode()); + + v2 = v1; + + EXPECT_EQ(&v1.GetNode(), &v2.GetNode()); + EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode()); + } +} // namespace AZ::Dom::Tests diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 834e3431b6..7be3afb4a9 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -217,6 +217,8 @@ set(FILES AZStd/VectorAndArray.cpp DOM/DomJsonTests.cpp DOM/DomJsonBenchmarks.cpp + DOM/DomValueTests.cpp + DOM/DomValueBenchmarks.cpp ) # Prevent the following files from being grouped in UNITY builds diff --git a/Code/Framework/AzFramework/AzFramework/Components/CameraBus.h b/Code/Framework/AzFramework/AzFramework/Components/CameraBus.h index e20578e939..964bf664a0 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/CameraBus.h +++ b/Code/Framework/AzFramework/AzFramework/Components/CameraBus.h @@ -129,6 +129,32 @@ namespace Camera GetFrustumHeight() }; } + + //! Unprojects a position in screen space pixel coordinates to world space. + //! With a depth of zero, the position returned will be on the near clip plane of the camera + //! in world space. + //! @param screenPosition The absolute screen position + //! @param depth The depth offset into the world relative to the near clip plane of the camera + //! @return the position in world space + virtual AZ::Vector3 ScreenToWorld(const AZ::Vector2& screenPosition, float depth) = 0; + + //! Unprojects a position in screen space normalized device coordinates to world space. + //! With a depth of zero, the position returned will be on the near clip plane of the camera + //! in world space. + //! @param screenNdcPosition The normalized device coordinates in the range [0,1] + //! @param depth The depth offset into the world relative to the near clip plane of the camera + //! @return the position in world space + virtual AZ::Vector3 ScreenNdcToWorld(const AZ::Vector2& screenNdcPosition, float depth) = 0; + + //! Projects a position in world space to screen space for the given camera. + //! @param worldPosition The world position + //! @return The absolute screen position + virtual AZ::Vector2 WorldToScreen(const AZ::Vector3& worldPosition) = 0; + + //! Projects a position in world space to screen space normalized device coordinates. + //! @param worldPosition The world position + //! @return The normalized device coordinates in the range [0,1] + virtual AZ::Vector2 WorldToScreenNdc(const AZ::Vector3& worldPosition) = 0; }; using CameraRequestBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 2572a07494..0d16bf3460 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -11,12 +11,15 @@ #include #include #include +#include #include namespace AzFramework { namespace Terrain { + typedef AZStd::function SurfacePointRegionFillCallback; + typedef AZStd::function SurfacePointListFillCallback; //! Shared interface for terrain system implementations class TerrainDataRequests @@ -131,6 +134,53 @@ namespace AzFramework Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; + //! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each + //! XY coordinate in the list. + virtual void ProcessHeightsFromList(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessNormalsFromList(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfaceWeightsFromList(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfacePointsFromList(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessHeightsFromListOfVector2(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessNormalsFromListOfVector2(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span& inPositions, + SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + + //! Given a region(aabb) and a step size, call the provided callback function with surface data corresponding to the + //! coordinates in the region. + virtual void ProcessHeightsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessNormalsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfaceWeightsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + virtual void ProcessSurfacePointsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const = 0; + + private: // Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of // using an "out" parameter. The "out" parameter is useful for reusing memory allocated in SurfacePoint when diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt index 9f30d23a19..bd7af2724e 100644 --- a/Code/Framework/AzFramework/CMakeLists.txt +++ b/Code/Framework/AzFramework/CMakeLists.txt @@ -8,8 +8,8 @@ include(AzFramework/feature_options.cmake) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) ly_add_target( NAME AzFramework STATIC @@ -44,7 +44,7 @@ ly_add_source_properties( if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(test_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME AzFrameworkTestShared STATIC @@ -86,11 +86,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAMESPACE AZ FILES_CMAKE Tests/frameworktests_files.cmake - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${test_pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PRIVATE Tests - ${pal_dir} + ${test_pal_dir} BUILD_DEPENDENCIES PRIVATE AZ::AzFramework @@ -104,7 +104,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAME AZ::AzFramework.Tests ) - include(${pal_dir}/platform_specific_test_targets.cmake) + include(${test_pal_dir}/platform_specific_test_targets.cmake) endif() diff --git a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h index dbce11d639..f3a6cc07b3 100644 --- a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h @@ -76,5 +76,29 @@ namespace UnitTest GetSurfacePointFromVector2, void(const AZ::Vector2&, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); MOCK_CONST_METHOD5( GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*)); + MOCK_CONST_METHOD3( + ProcessHeightsFromList, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessNormalsFromList, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessSurfaceWeightsFromList, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessSurfacePointsFromList, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessHeightsFromListOfVector2, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessNormalsFromListOfVector2, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD3( + ProcessSurfacePointsFromListOfVector2, void(const AZStd::span&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler)); + MOCK_CONST_METHOD4( + ProcessHeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); + MOCK_CONST_METHOD4( + ProcessNormalsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); + MOCK_CONST_METHOD4( + ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); + MOCK_CONST_METHOD4( + ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); }; } // namespace UnitTest diff --git a/Code/Framework/AzNetworking/CMakeLists.txt b/Code/Framework/AzNetworking/CMakeLists.txt index a0a3871201..ba2eecd023 100644 --- a/Code/Framework/AzNetworking/CMakeLists.txt +++ b/Code/Framework/AzNetworking/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) ly_add_target( NAME AzNetworking STATIC diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Slider.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Slider.cpp index 14ac2010bc..f50b9c36ec 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Slider.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Slider.cpp @@ -870,8 +870,7 @@ void SliderDouble::setCurveMidpoint(double midpoint) QString SliderDouble::hoverValueText(int sliderValue) const { - // maybe format this, max number of digits? - QString valueText = locale().toString(calculateRealSliderValue(sliderValue), 'f', m_decimals); + QString valueText = toString(calculateRealSliderValue(sliderValue), m_decimals, locale(), false, true); return QStringLiteral("%1").arg(valueText); } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.cpp index 6333d28365..9d289e5d44 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace AzQtComponents { @@ -254,11 +255,12 @@ SliderDoubleCombo::~SliderDoubleCombo() { } +bool m_fromSlider{ false }; + void SliderDoubleCombo::setValueSlider(double value) { const bool doEmit = m_value != value; m_value = value; - updateSpinBox(); updateSlider(); @@ -267,6 +269,8 @@ void SliderDoubleCombo::setValueSlider(double value) // We don't want to update the slider from setValue as this // causes rounding errors in the tooltip hint. m_fromSlider = true; + QTimer::singleShot( 10, []() { m_fromSlider = false; }); + Q_EMIT valueChanged(); } } @@ -286,10 +290,6 @@ void SliderDoubleCombo::setValue(double value) Q_EMIT valueChanged(); } } - else - { - m_fromSlider = false; - } } SliderDouble* SliderDoubleCombo::slider() const diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.h index 05d0f7b51b..be6c86b520 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SliderCombo.h @@ -237,6 +237,5 @@ namespace AzQtComponents double m_softMinimum = 0.0; double m_softMaximum = 100.0; double m_value = 0.0; - bool m_fromSlider{ false }; }; } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/CMakeLists.txt b/Code/Framework/AzQtComponents/CMakeLists.txt index a24b68bcd7..76850e196b 100644 --- a/Code/Framework/AzQtComponents/CMakeLists.txt +++ b/Code/Framework/AzQtComponents/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME AzQtComponents SHARED diff --git a/Code/Framework/AzTest/AzTest/Platform/Android/platform_android_files.cmake b/Code/Framework/AzTest/AzTest/Platform/Android/platform_android_files.cmake index e0f47c8fa6..83ae97fa20 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Android/platform_android_files.cmake +++ b/Code/Framework/AzTest/AzTest/Platform/Android/platform_android_files.cmake @@ -8,6 +8,7 @@ set(FILES ../Common/UnixLike/AzTest/ColorizedOutput_UnixLike.cpp + ../Common/UnixLike/AzTest/Utils_UnixLike.cpp ScopedAutoTempDirectory_Android.cpp Platform_Android.cpp AzTest_Traits_Platform.h diff --git a/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/AzTest/Utils_Unimplemented.cpp b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/AzTest/Utils_Unimplemented.cpp new file mode 100644 index 0000000000..0f91ea1020 --- /dev/null +++ b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/AzTest/Utils_Unimplemented.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace AZ +{ + namespace Test + { + bool SetEnv([[maybe_unused]] const char* envname, [[maybe_unused]] const char* envvalue, [[maybe_unused]] bool overwrite) + { + return false; + } + + bool UnsetEnv([[maybe_unused]] const char* envname) + { + return false; + } + } // namespace Test +} // namespace AZ diff --git a/Code/Framework/AzTest/AzTest/Platform/Common/UnixLike/AzTest/Utils_UnixLike.cpp b/Code/Framework/AzTest/AzTest/Platform/Common/UnixLike/AzTest/Utils_UnixLike.cpp new file mode 100644 index 0000000000..8efdb5d082 --- /dev/null +++ b/Code/Framework/AzTest/AzTest/Platform/Common/UnixLike/AzTest/Utils_UnixLike.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace AZ +{ + namespace Test + { + bool SetEnv(const char* envname, const char* envvalue, bool overwrite) + { + return setenv(envname, envvalue, overwrite) != -1; + } + + bool UnsetEnv(const char* envname) + { + return unsetenv(envname) != -1; + } + } +} diff --git a/Code/Framework/AzTest/AzTest/Platform/Common/WinAPI/AzTest/Utils_WinAPI.cpp b/Code/Framework/AzTest/AzTest/Platform/Common/WinAPI/AzTest/Utils_WinAPI.cpp new file mode 100644 index 0000000000..a06cbf7ffe --- /dev/null +++ b/Code/Framework/AzTest/AzTest/Platform/Common/WinAPI/AzTest/Utils_WinAPI.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace AZ +{ + namespace Test + { + bool SetEnv(const char* envname, const char* envvalue, [[maybe_unused]] bool overwrite) + { + return _putenv_s(envname, envvalue); + } + + bool UnsetEnv(const char* envname) + { + return SetEnv(envname, "", 1); + } + } +} diff --git a/Code/Framework/AzTest/AzTest/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzTest/AzTest/Platform/Linux/platform_linux_files.cmake index 68ca9332c7..9c6692b409 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzTest/AzTest/Platform/Linux/platform_linux_files.cmake @@ -9,6 +9,7 @@ set(FILES ../Common/UnixLike/AzTest/ColorizedOutput_UnixLike.cpp ../Common/UnixLike/AzTest/ScopedAutoTempDirectory_UnixLike.cpp + ../Common/UnixLike/AzTest/Utils_UnixLike.cpp Platform_Linux.cpp AzTest_Traits_Platform.h AzTest_Traits_Linux.h diff --git a/Code/Framework/AzTest/AzTest/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzTest/AzTest/Platform/Mac/platform_mac_files.cmake index 3cbe35792c..cb641e2113 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzTest/AzTest/Platform/Mac/platform_mac_files.cmake @@ -9,6 +9,7 @@ set(FILES ../Common/UnixLike/AzTest/ColorizedOutput_UnixLike.cpp ../Common/UnixLike/AzTest/ScopedAutoTempDirectory_UnixLike.cpp + ../Common/UnixLike/AzTest/Utils_UnixLike.cpp Platform_Mac.cpp AzTest_Traits_Platform.h AzTest_Traits_Mac.h diff --git a/Code/Framework/AzTest/AzTest/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzTest/AzTest/Platform/Windows/platform_windows_files.cmake index 656b28a373..4730b383a2 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzTest/AzTest/Platform/Windows/platform_windows_files.cmake @@ -8,6 +8,7 @@ set(FILES ../Common/WinAPI/AzTest/ColorizedOutput_WinAPI.cpp + ../Common/WinAPI/AzTest/Utils_WinAPI.cpp Platform_Windows.cpp ScopedAutoTempDirectory_Windows.cpp AzTest_Traits_Platform.h diff --git a/Code/Framework/AzTest/AzTest/Platform/iOS/platform_ios_files.cmake b/Code/Framework/AzTest/AzTest/Platform/iOS/platform_ios_files.cmake index 64bbc27bc1..81875f71e5 100644 --- a/Code/Framework/AzTest/AzTest/Platform/iOS/platform_ios_files.cmake +++ b/Code/Framework/AzTest/AzTest/Platform/iOS/platform_ios_files.cmake @@ -9,6 +9,7 @@ set(FILES ../Common/UnixLike/AzTest/ColorizedOutput_UnixLike.cpp ../Common/Unimplemented/AzTest/ScopedAutoTempDirectory_Unimplemented.cpp + ../Common/UnixLike/AzTest/Utils_UnixLike.cpp Platform_iOS.cpp AzTest_Traits_Platform.h AzTest_Traits_iOS.h diff --git a/Code/Framework/AzTest/AzTest/Utils.h b/Code/Framework/AzTest/AzTest/Utils.h index 2778e163b3..e3b45e97f2 100644 --- a/Code/Framework/AzTest/AzTest/Utils.h +++ b/Code/Framework/AzTest/AzTest/Utils.h @@ -55,6 +55,19 @@ namespace AZ // Returns the path to the engine's root by cdup from the current execution path until engine.txt is found AZStd::string GetEngineRootPath(); + //! Create or modify environment variable. + //! @param envname The environment variable name + //! @param envvalue The environment variable name + //! @param overwrite If name does exist in the environment, then its value is changed to value if overwrite is nonzero; + //! if overwrite is zero, then the value of name is not changed + //! @returns Return true if successful, otherwise false + bool SetEnv(const char* envname, const char* envvalue, bool overwrite); + + //! Remove environment variable. + //! @param envname The environment variable name + //! @returns Return true if successful, otherwise false + bool UnsetEnv(const char* envname); + //! Provides a scoped object that will create a temporary operating-system specific folder on creation, and delete it and //! its contents on destruction. This class is only available on host platforms (Windows, Mac, and Linux) class ScopedAutoTempDirectory diff --git a/Code/Framework/AzTest/CMakeLists.txt b/Code/Framework/AzTest/CMakeLists.txt index 95e444a1e9..2edc80f893 100644 --- a/Code/Framework/AzTest/CMakeLists.txt +++ b/Code/Framework/AzTest/CMakeLists.txt @@ -7,18 +7,18 @@ # if(NOT LY_MONOLITHIC_GAME) - ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(pal_aztest_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME AzTest STATIC NAMESPACE AZ FILES_CMAKE AzTest/aztest_files.cmake - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_aztest_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PUBLIC . - ${pal_dir} + ${pal_aztest_dir} BUILD_DEPENDENCIES PUBLIC 3rdParty::googletest::GMock @@ -26,6 +26,6 @@ if(NOT LY_MONOLITHIC_GAME) 3rdParty::GoogleBenchmark AZ::AzCore PLATFORM_INCLUDE_FILES - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake + ${pal_aztest_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake ) endif() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index c6772ea2d7..21229e5570 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -68,6 +68,11 @@ namespace AzToolsFramework } } + QSharedPointer AssetBrowserFilterModel::GetStringFilter() const + { + return m_stringFilter; + } + bool AssetBrowserFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { //get the source idx, if invalid early out diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h index 5d3ad0e1b0..cafe694ad6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h @@ -48,7 +48,7 @@ namespace AzToolsFramework // AssetBrowserComponentNotificationBus ////////////////////////////////////////////////////////////////////////// void OnAssetBrowserComponentReady() override; - + QSharedPointer GetStringFilter() const; Q_SIGNALS: void filterChanged(); ////////////////////////////////////////////////////////////////////////// @@ -70,7 +70,7 @@ namespace AzToolsFramework //Asset source name match filter FilterConstType m_filter; AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: class '...' needs to have dll-interface to be used by clients of class '...' - QWeakPointer m_stringFilter; + QSharedPointer m_stringFilter; QWeakPointer m_assetTypeFilter; QCollator m_collator; // cache the collator as its somewhat expensive to constantly create and destroy one. AZ_POP_DISABLE_WARNING diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.cpp index f0e1520aab..fd05543097 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 'QRegularExpression::d': class 'QExplicitlySharedDataPointer' needs to have dll-interface to be used by clients of class 'QRegularExpression' @@ -268,6 +269,21 @@ namespace AzToolsFramework m_rootEntry = rootEntry; } + AssetBrowserFilterModel* AssetBrowserModel::GetFilterModel() + { + return m_filterModel; + } + + const AssetBrowserFilterModel* AssetBrowserModel::GetFilterModel() const + { + return m_filterModel; + } + + void AssetBrowser::AssetBrowserModel::SetFilterModel(AssetBrowserFilterModel* filterModel) + { + m_filterModel = filterModel; + } + QModelIndex AssetBrowserModel::parent(const QModelIndex& child) const { if (!child.isValid()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.h index c46b73417c..2905844a23 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserModel.h @@ -35,6 +35,7 @@ namespace AzToolsFramework class AssetBrowserEntry; class RootAssetBrowserEntry; class AssetEntryChangeset; + class AssetBrowserFilterModel; class AssetBrowserModel : public QAbstractItemModel @@ -75,7 +76,7 @@ namespace AzToolsFramework void EndAddEntry(AssetBrowserEntry* parent) override; void BeginRemoveEntry(AssetBrowserEntry* entry) override; void EndRemoveEntry() override; - + ////////////////////////////////////////////////////////////////////////// // TickBus ////////////////////////////////////////////////////////////////////////// @@ -84,10 +85,16 @@ namespace AzToolsFramework AZStd::shared_ptr GetRootEntry() const; void SetRootEntry(AZStd::shared_ptr rootEntry); + AssetBrowserFilterModel* GetFilterModel(); + const AssetBrowserFilterModel* GetFilterModel() const; + void SetFilterModel(AssetBrowserFilterModel* filterModel); + static void SourceIndexesToAssetIds(const QModelIndexList& indexes, AZStd::vector& assetIds); static void SourceIndexesToAssetDatabaseEntries(const QModelIndexList& indexes, AZStd::vector& entries); private: + //Non owning pointer + AssetBrowserFilterModel* m_filterModel = nullptr; AZStd::shared_ptr m_rootEntry; bool m_loaded; bool m_addingEntry; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp index d617638632..4ec26d4c3d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp @@ -229,6 +229,11 @@ namespace AzToolsFramework Q_EMIT updatedSignal(); } + QString StringFilter::GetFilterString() const + { + return m_filterString; + } + QString StringFilter::GetNameInternal() const { return m_filterString; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h index 94f47e0599..1d93d4d0cf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h @@ -106,6 +106,7 @@ namespace AzToolsFramework ~StringFilter() override = default; void SetFilterString(const QString& filterString); + QString GetFilterString() const; protected: QString GetNameInternal() const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp index cfcac579ff..a913009da0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp @@ -66,6 +66,7 @@ namespace AzToolsFramework m_tableModel = qobject_cast(model); AZ_Assert(m_tableModel, "Expecting AssetBrowserTableModel"); m_sourceFilterModel = qobject_cast(m_tableModel->sourceModel()); + m_delegate->Init(); AzQtComponents::TableView::setModel(model); connect(m_tableModel, &AssetBrowserTableModel::layoutChanged, this, &AssetBrowserTableView::layoutChangedSlot); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index 8b58791e68..8e69d5f788 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -9,12 +9,16 @@ #include #include #include +#include #include #include #include #include +#include #include +#include + AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer' needs to have dll-interface to be used by clients of class 'QBrush' // 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) #include @@ -160,13 +164,20 @@ namespace AzToolsFramework LoadBranchPixMaps(); } + void SearchEntryDelegate::Init() + { + AssetBrowserModel* assetBrowserModel; + AssetBrowserComponentRequestBus::BroadcastResult(assetBrowserModel, &AssetBrowserComponentRequests::GetAssetBrowserModel); + AZ_Assert(assetBrowserModel, "Failed to get filebrowser model"); + m_assetBrowserFilerModel = assetBrowserModel->GetFilterModel(); + } + void SearchEntryDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { auto data = index.data(AssetBrowserModel::Roles::EntryRole); if (data.canConvert()) { bool isEnabled = (option.state & QStyle::State_Enabled) != 0; - bool isSelected = (option.state & QStyle::State_Selected) != 0; QStyle* style = option.widget ? option.widget->style() : QApplication::style(); @@ -265,13 +276,21 @@ namespace AzToolsFramework remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing. } + QString displayString = index.column() == aznumeric_cast(AssetBrowserEntry::Column::Name) ? qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Name))) : qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Path))); - style->drawItemText( - painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString, - isSelected ? QPalette::HighlightedText : QPalette::Text); + QStyleOptionViewItem optionV4{ option }; + initStyleOption(&optionV4, index); + optionV4.state &= ~(QStyle::State_HasFocus | QStyle::State_Selected); + + if (m_assetBrowserFilerModel && m_assetBrowserFilerModel->GetStringFilter() + && !m_assetBrowserFilerModel->GetStringFilter()->GetFilterString().isEmpty()) + { + displayString = RichTextHighlighter::HighlightText(displayString, m_assetBrowserFilerModel->GetStringFilter()->GetFilterString()); + } + RichTextHighlighter::PaintHighlightedRichText(displayString, painter, optionV4, remainingRect); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h index ac68c19248..7c7d919f2d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h @@ -70,7 +70,7 @@ namespace AzToolsFramework Q_OBJECT public: explicit SearchEntryDelegate(QWidget* parent = nullptr); - + void Init(); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: @@ -78,6 +78,7 @@ namespace AzToolsFramework void DrawBranchPixMap(EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const; private: + AssetBrowserFilterModel* m_assetBrowserFilerModel; QMap m_branchIcons; }; } // namespace AssetBrowser diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.cpp new file mode 100644 index 0000000000..8b28298c3d --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.cpp @@ -0,0 +1,55 @@ +/* + * 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 "RichTextHighlighter.h" + +namespace AzToolsFramework +{ + + QString RichTextHighlighter::HighlightText(const QString& displayString, const QString& matchingSubstring) + { + QString highlightedString = displayString; + int highlightTextIndex = 0; + do + { + highlightTextIndex = highlightedString.lastIndexOf(matchingSubstring, highlightTextIndex - 1, Qt::CaseInsensitive); + if (highlightTextIndex >= 0) + { + const QString backgroundColor{ "#707070" }; + highlightedString.insert(static_cast(highlightTextIndex + matchingSubstring.length()), ""); + highlightedString.insert(highlightTextIndex, ""); + } + } while (highlightTextIndex > 0); + + return highlightedString; + } + + void RichTextHighlighter::PaintHighlightedRichText(const QString& highlightedString,QPainter* painter, QStyleOptionViewItem option, QRect availableRect) + { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + // Now we setup a Text Document so it can draw the rich text + QTextDocument textDoc; + textDoc.setDefaultFont(option.font); + if (option.state & QStyle::State_Enabled) + { + textDoc.setDefaultStyleSheet("body {color: white}"); + } + else + { + textDoc.setDefaultStyleSheet("body {color: #7C7C7C}"); + } + textDoc.setHtml("" + highlightedString + ""); + painter->translate(availableRect.topLeft()); + textDoc.setTextWidth(availableRect.width()); + textDoc.drawContents(painter, QRectF(0, 0, availableRect.width(), availableRect.height())); + + painter->restore(); + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.h new file mode 100644 index 0000000000..b5c1859497 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/RichTextHighlighter.h @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include +#include + +AZ_PUSH_DISABLE_WARNING(4251 4800,"-Wunknown-warning-option") // 4251: class 'QScopedPointer' needs to have dll-interface to be used + // by clients of class 'QBrush' 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) +#include +AZ_POP_DISABLE_WARNING + +namespace AzToolsFramework +{ + //! @class RichTextHighlighter + //! @brief Highlights a given string given a matching substring. + class RichTextHighlighter + { + public: + AZ_CLASS_ALLOCATOR(RichTextHighlighter, AZ::SystemAllocator, 0); + RichTextHighlighter() = delete; + + static QString HighlightText(const QString& displayString, const QString& matchingSubstring); + static void PaintHighlightedRichText(const QString& highlightedString,QPainter* painter, QStyleOptionViewItem option, QRect availableRect); + + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp index 40cd52cac8..a5ca034c36 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp @@ -64,6 +64,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer)); AZ_Assert(spawnable, "Failed to create a new spawnable."); + object.GetReferencedAssets() = prefab.GetReferencedAssets(); Instance& instance = prefab.GetInstance(); // Resolve entity aliases that store PrefabDOM information to use the spawnable instead. This is done before the entities are // moved from the instance as they'd otherwise can't be found. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp index 04fdea30d2..230c2226cd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp @@ -124,12 +124,22 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils return *m_instance; } + AZStd::vector>& PrefabDocument::GetReferencedAssets() + { + return m_referencedAssets; + } + + const AZStd::vector>& PrefabDocument::GetReferencedAssets() const + { + return m_referencedAssets; + } + bool PrefabDocument::ConstructInstanceFromPrefabDom(const PrefabDom& prefab) { using namespace AzToolsFramework::Prefab; m_instance->Reset(); - if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) + if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, m_referencedAssets, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) { return true; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h index 215daf7f71..661dba5edf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h @@ -53,12 +53,16 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AzToolsFramework::Prefab::Instance& GetInstance(); const AzToolsFramework::Prefab::Instance& GetInstance() const; + AZStd::vector>& GetReferencedAssets(); + const AZStd::vector>& GetReferencedAssets() const; + private: bool ConstructInstanceFromPrefabDom(const PrefabDom& prefab); mutable PrefabDom m_dom; AZStd::unique_ptr m_instance; AZStd::string m_name; + AZStd::vector> m_referencedAssets; mutable bool m_isDirty{ false }; }; } // namespace AzToolsFramework::Prefab::PrefabConversionUtils diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index 056f16c52f..e0060e2b42 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -66,6 +66,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////////////// // EntityOutlinerListModel @@ -259,17 +260,7 @@ namespace AzToolsFramework if (s_paintingName && !m_filterString.empty()) { // highlight characters in filter - int highlightTextIndex = 0; - do - { - highlightTextIndex = label.lastIndexOf(QString(m_filterString.c_str()), highlightTextIndex - 1, Qt::CaseInsensitive); - if (highlightTextIndex >= 0) - { - const QString BACKGROUND_COLOR{ "#707070" }; - label.insert(highlightTextIndex + static_cast(m_filterString.length()), ""); - label.insert(highlightTextIndex, ""); - } - } while(highlightTextIndex > 0); + label = AzToolsFramework::RichTextHighlighter::HighlightText(label, m_filterString.c_str()); } return label; } @@ -2375,23 +2366,8 @@ namespace AzToolsFramework optionV4.text.clear(); optionV4.widget->style()->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter); - // Now we setup a Text Document so it can draw the rich text - QTextDocument textDoc; - textDoc.setDefaultFont(optionV4.font); - if (option.state & QStyle::State_Enabled) - { - textDoc.setDefaultStyleSheet("body {color: white}"); - } - else - { - textDoc.setDefaultStyleSheet("body {color: #7C7C7C}"); - } - textDoc.setHtml("" + entityNameRichText + ""); - painter->translate(textRect.topLeft()); - textDoc.setTextWidth(textRect.width()); - textDoc.drawContents(painter, QRectF(0, 0, textRect.width(), textRect.height())); + AzToolsFramework::RichTextHighlighter::PaintHighlightedRichText(entityNameRichText, painter, optionV4, textRect); - painter->restore(); EntityOutlinerListModel::s_paintingName = false; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h index bb7d03367b..ed428eeac5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace AzToolsFramework { @@ -92,25 +93,11 @@ namespace AzToolsFramework { toolTipString += "\n"; } - toolTipString += "["; - if (propertyControl->minimum() <= aznumeric_cast(QtWidgetLimits::Min())) - { - toolTipString += "-" + QObject::tr(PropertyQTConstant_InfinityString); - } - else - { - toolTipString += QString::number(propertyControl->minimum()); - } - toolTipString += ", "; - if (propertyControl->maximum() >= aznumeric_cast(QtWidgetLimits::Max())) - { - toolTipString += QObject::tr(PropertyQTConstant_InfinityString); - } - else - { - toolTipString += QString::number(propertyControl->maximum()); - } - toolTipString += "]"; + + const QString minString = QLocale().toString(propertyControl->minimum()); + const QString maxString = QLocale().toString(propertyControl->maximum()); + toolTipString += QString("[%1, %2]").arg(minString).arg(maxString); + return true; } return false; @@ -128,16 +115,11 @@ namespace AzToolsFramework { toolTipString += "\n"; } - toolTipString += "[" + QString::number(propertyControl->minimum()) + ", "; - if (propertyControl->maximum() >= aznumeric_cast(QtWidgetLimits::Max())) - { - toolTipString += QObject::tr(PropertyQTConstant_InfinityString); - } - else - { - toolTipString += QString::number(propertyControl->maximum()); - } - toolTipString += "]"; + + const QString minString = QLocale().toString(propertyControl->minimum()); + const QString maxString = QLocale().toString(propertyControl->maximum()); + toolTipString += QString("[%1, %2]").arg(minString).arg(maxString); + return true; } return false; @@ -196,7 +178,7 @@ namespace AzToolsFramework } else { - AZ_WarningOnce("AzToolsFramework", false, "Property %s: 'Min' attribute from property '%s' into widget", debugName); + AZ_WarningOnce("AzToolsFramework", false, "Failed to read 'Min' attribute from property '%s' into widget", debugName); } } else if (attrib == AZ::Edit::Attributes::Max) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 05c07afecd..0d7bf05211 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -123,6 +123,8 @@ set(FILES ContainerEntity/ContainerEntitySystemComponent.h Editor/EditorContextMenuBus.h Editor/EditorSettingsAPIBus.h + Editor/RichTextHighlighter.h + Editor/RichTextHighlighter.cpp Entity/EditorEntityStartStatus.h Entity/EditorEntityAPIBus.h Entity/EditorEntityContextComponent.cpp diff --git a/Code/Framework/AzToolsFramework/Tests/PropertyIntCtrlCommonTests.h b/Code/Framework/AzToolsFramework/Tests/PropertyIntCtrlCommonTests.h index 712eeb99b7..b73e9e0a26 100644 --- a/Code/Framework/AzToolsFramework/Tests/PropertyIntCtrlCommonTests.h +++ b/Code/Framework/AzToolsFramework/Tests/PropertyIntCtrlCommonTests.h @@ -83,18 +83,6 @@ namespace UnitTest widget->setMaximum(widget->maximum() - 1); } - static std::string GetToolTipStringAtLimits() - { - if constexpr (std::is_signed::value) - { - return "[-INF, INF]"; - } - else - { - return "[0, INF]"; - } - } - void PropertyCtrlHandlersCreated() { using ::testing::Ne; @@ -125,11 +113,13 @@ namespace UnitTest auto& widget = m_widget; auto& handler = m_handler; QString tooltip; - std::string expected; // Retrieve the tooltip string for this widget auto success = handler->ModifyTooltip(widget, tooltip); - expected = GetToolTipStringAtLimits(); + + const QString minString = QLocale().toString(widget->minimum()); + const QString maxString = QLocale().toString(widget->maximum()); + const AZStd::string expected = AZStd::string::format("[%s, %s]", minString.toStdString().c_str(), maxString.toStdString().c_str()); // Expect the operation to be successful and a valid limit tooltip string generated EXPECT_TRUE(success); @@ -142,18 +132,21 @@ namespace UnitTest auto& widget = m_widget; auto& handler = m_handler; QString tooltip; - std::stringstream expected; // That is not at the extremeties of the type range limit SetWidgetRangeToNonExtremeties(widget); // Retrieve the tooltip string for this widget auto success = handler->ModifyTooltip(widget, tooltip); - expected << "[" << widget->minimum() << ", " << widget->maximum() << "]"; + + const QString minString = QLocale().toString(widget->minimum()); + const QString maxString = QLocale().toString(widget->maximum()); + + const AZStd::string expected = AZStd::string::format("[%s, %s]", minString.toStdString().c_str(), maxString.toStdString().c_str()); // Expect the operation to be successful and a valid less than limit tooltip string generated EXPECT_TRUE(success); - EXPECT_STREQ(tooltip.toStdString().c_str(), expected.str().c_str()); + EXPECT_STREQ(tooltip.toStdString().c_str(), expected.c_str()); } void EmitWidgetValueChanged() diff --git a/Code/Framework/GridMate/CMakeLists.txt b/Code/Framework/GridMate/CMakeLists.txt index 0da878081d..07c2f8b4a8 100644 --- a/Code/Framework/GridMate/CMakeLists.txt +++ b/Code/Framework/GridMate/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) ly_add_target( NAME GridMate STATIC @@ -41,7 +41,7 @@ ly_add_source_properties( ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - ly_get_list_relative_pal_filename(pal_test_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(pal_test_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME GridMate.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE AZ diff --git a/Code/LauncherUnified/CMakeLists.txt b/Code/LauncherUnified/CMakeLists.txt index 845c2cd6c7..8097570462 100644 --- a/Code/LauncherUnified/CMakeLists.txt +++ b/Code/LauncherUnified/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/LauncherUnified_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index 550a67bc49..70bcf776af 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -201,7 +201,7 @@ function(ly_delayed_generate_static_modules_inl) foreach(game_gem_dependency ${all_game_gem_dependencies}) # Sometimes, a gem's Client variant may be an interface library - # which dependes on multiple gem targets. The interface libraries + # which depends on multiple gem targets. The interface libraries # should be skipped; the real dependencies of the interface will be processed if(TARGET ${game_gem_dependency}) get_target_property(target_type ${game_gem_dependency} TYPE) diff --git a/Code/Legacy/CryCommon/CMakeLists.txt b/Code/Legacy/CryCommon/CMakeLists.txt index 1556c6a099..629f26d217 100644 --- a/Code/Legacy/CryCommon/CMakeLists.txt +++ b/Code/Legacy/CryCommon/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME CryCommon STATIC diff --git a/Code/Legacy/CryCommon/IMovieSystem.h b/Code/Legacy/CryCommon/IMovieSystem.h index 79c000bfca..a55d764afa 100644 --- a/Code/Legacy/CryCommon/IMovieSystem.h +++ b/Code/Legacy/CryCommon/IMovieSystem.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -184,7 +183,7 @@ public: private: AnimParamType m_type; - AZStd::basic_string, AZStd::stateless_allocator> m_name; + AZStd::string m_name; }; namespace AZStd @@ -620,7 +619,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::basic_string, AZStd::stateless_allocator> name; // parameter name. + AZStd::string name; // parameter name. CAnimParamType paramType; // parameter id. AnimValueType valueType; // value type, defines type of track to use for animating this parameter. ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags. diff --git a/Code/Legacy/CrySystem/CMakeLists.txt b/Code/Legacy/CrySystem/CMakeLists.txt index ebfc866f4a..3153205b69 100644 --- a/Code/Legacy/CrySystem/CMakeLists.txt +++ b/Code/Legacy/CrySystem/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) add_subdirectory(XML) diff --git a/Code/Tools/AWSNativeSDKInit/CMakeLists.txt b/Code/Tools/AWSNativeSDKInit/CMakeLists.txt index 57ee31d30d..04f61eb924 100644 --- a/Code/Tools/AWSNativeSDKInit/CMakeLists.txt +++ b/Code/Tools/AWSNativeSDKInit/CMakeLists.txt @@ -6,14 +6,14 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/source/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME AWSNativeSDKInit STATIC NAMESPACE AZ FILES_CMAKE aws_native_sdk_init_files.cmake - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PUBLIC include diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt b/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt index bfbcc35663..f32d55844e 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt @@ -11,7 +11,7 @@ ly_get_pal_tool_dirs(pal_tool_dirs ${CMAKE_CURRENT_LIST_DIR}/AssetBuilderSDK/Pla set(pal_files "") foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AssetBuilderSDK/Platform/${enabled_platform}) + o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AssetBuilderSDK/Platform/${enabled_platform} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) list(APPEND pal_files ${pal_dir}/assetbuildersdk_${enabled_platform_lowercase}_files.cmake) endforeach() diff --git a/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake b/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake index 2c4c53642c..a7a46ad62c 100644 --- a/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake +++ b/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake @@ -48,6 +48,7 @@ set(FILES native/tests/InternalBuilders/SettingsRegistryBuilderTests.cpp native/tests/MissingDependencyScannerTests.cpp native/tests/SourceFileRelocatorTests.cpp + native/tests/PathDependencyManagerTests.cpp native/tests/AssetProcessorMessagesTests.cpp native/unittests/AssetProcessingStateDataUnitTests.cpp native/unittests/AssetProcessingStateDataUnitTests.h diff --git a/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp b/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp index cf33e559ac..5edf4e1d53 100644 --- a/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp +++ b/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp @@ -172,7 +172,7 @@ namespace AssetProcessor static const char* CREATEINDEX_BUILDERGUID_SOURCE_SOURCEDEPENDENCY_STATEMENT = "CREATE INDEX IF NOT EXISTS BuilderGuid_Source_SourceDependency ON SourceDependency (BuilderGuid, Source);"; static const char* CREATEINDEX_TYPEOFDEPENDENCY_SOURCEDEPENDENCY = "AssetProcessor::CreateIndexTypeOfDependency_SourceDependency"; - static const char* CREATEINDEX_TYPEOFDEPENDENCY_SOURCEDEPENDENCY_STATEMENT = + static const char* CREATEINDEX_TYPEOFDEPENDENCY_SOURCEDEPENDENCY_STATEMENT = "CREATE INDEX IF NOT EXISTS TypeOfDependency_SourceDependency ON SourceDependency (TypeOfDependency);"; static const char* CREATEINDEX_SCANFOLDERS_SOURCES_SCANFOLDER = "AssetProcesser::CreateIndexScanFoldersSourcesScanFolder"; @@ -611,7 +611,7 @@ namespace AssetProcessor SqlParam(":missingDependencyString"), SqlParam(":lastScanTime"), SqlParam(":scanTimeSecondsSinceEpoch")); - + static const auto s_DeleteMissingProductDependencyByProductIdQuery = MakeSqlQuery( DELETE_MISSING_PRODUCT_DEPENDENCY_BY_PRODUCTID, @@ -643,7 +643,7 @@ namespace AssetProcessor SqlParam(":analysisFingerprint")); static const char* INSERT_COLUMN_ANALYSISFINGERPRINT = "AssetProcessor::AddColumnAnalysisFingerprint"; - static const char* INSERT_COLUMN_ANALYSISFINGERPRINT_STATEMENT = + static const char* INSERT_COLUMN_ANALYSISFINGERPRINT_STATEMENT = "ALTER TABLE Sources " "ADD AnalysisFingerprint TEXT NOT NULL collate nocase default('');"; @@ -653,7 +653,7 @@ namespace AssetProcessor "ADD TypeOfDependency INTEGER NOT NULL DEFAULT 0;"; static const char* INSERT_COLUMN_FILE_MODTIME = "AssetProcessor::AddFiles_ModTime"; - static const char* INSERT_COLUMN_FILE_MODTIME_STATEMENT = + static const char* INSERT_COLUMN_FILE_MODTIME_STATEMENT = "ALTER TABLE Files " "ADD ModTime INTEGER NOT NULL DEFAULT 0;"; @@ -673,7 +673,7 @@ namespace AssetProcessor "ADD UnresolvedDependencyType INTEGER NOT NULL DEFAULT 0;"; static const char* INSERT_COLUMN_PRODUCTDEPENDENCY_PLATFORM = "AssetProcessor::AddProductDependency_Platform"; - static const char* INSERT_COLUMN_PRODUCTDEPENDENCY_PLATFORM_STATEMENT = + static const char* INSERT_COLUMN_PRODUCTDEPENDENCY_PLATFORM_STATEMENT = "ALTER TABLE ProductDependencies " "ADD Platform TEXT NOT NULL collate nocase default('');"; @@ -721,7 +721,7 @@ namespace AssetProcessor SqlParam(":isfolder"), SqlParam(":modtime"), SqlParam(":hash")); - + static const char* UPDATE_FILE = "AssetProcessor::UpdateFile"; static const char* UPDATE_FILE_STATEMENT = "UPDATE Files SET " @@ -961,7 +961,7 @@ namespace AssetProcessor AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Upgraded Asset Database to version %i (AddedTypeOfDependencyIndex)\n", foundVersion) } } - + if (foundVersion == AssetDatabase::DatabaseVersion::AddedTypeOfDependencyIndex) { if (m_databaseConnection->ExecuteOneOffStatement(INSERT_COLUMN_PRODUCTDEPENDENCY_PLATFORM)) @@ -1178,7 +1178,7 @@ namespace AssetProcessor AddStatement(m_databaseConnection, s_InsertJobQuery); AddStatement(m_databaseConnection, s_UpdateJobQuery); AddStatement(m_databaseConnection, s_DeleteJobQuery); - + // --------------------------------------------------------------------------------------------- // Builder Info Table // --------------------------------------------------------------------------------------------- @@ -1207,7 +1207,7 @@ namespace AssetProcessor m_databaseConnection->AddStatement(CREATE_SOURCE_DEPENDENCY_TABLE, CREATE_SOURCE_DEPENDENCY_TABLE_STATEMENT); m_databaseConnection->AddStatement(INSERT_COLUMN_SOURCEDEPENDENCY_TYPEOFDEPENDENCY, INSERT_COLUMN_SOURCEDEPENDENCY_TYPEOFDEPENDENCY_STATEMENT); m_databaseConnection->AddStatement(INSERT_COLUMNS_SOURCEDEPENDENCY_FROM_ASSETID, INSERT_COLUMNS_SOURCEDEPENDENCY_FROM_ASSETID_STATEMENT); - + m_createStatements.push_back(CREATE_SOURCE_DEPENDENCY_TABLE); AddStatement(m_databaseConnection, s_InsertSourceDependencyQuery); @@ -1242,7 +1242,7 @@ namespace AssetProcessor AddStatement(m_databaseConnection, s_InsertProductDependencyQuery); AddStatement(m_databaseConnection, s_UpdateProductDependencyQuery); AddStatement(m_databaseConnection, s_DeleteProductDependencyByProductIdQuery); - + // --------------------------------------------------------------------------------------------- // Missing Product Dependency table // --------------------------------------------------------------------------------------------- @@ -1253,7 +1253,7 @@ namespace AssetProcessor AddStatement(m_databaseConnection, s_InsertMissingProductDependencyQuery); AddStatement(m_databaseConnection, s_UpdateMissingProductDependencyQuery); AddStatement(m_databaseConnection, s_DeleteMissingProductDependencyByProductIdQuery); - + // --------------------------------------------------------------------------------------------- // Files table // --------------------------------------------------------------------------------------------- @@ -1344,7 +1344,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetScanFolderByScanFolderID(AZ::s64 scanfolderID, ScanFolderDatabaseEntry& entry) { bool found = false; - QueryScanFolderByScanFolderID( scanfolderID, + QueryScanFolderByScanFolderID( scanfolderID, [&](ScanFolderDatabaseEntry& scanFolderEntry) { entry = scanFolderEntry; @@ -1357,7 +1357,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetScanFolderBySourceID(AZ::s64 sourceID, ScanFolderDatabaseEntry& entry) { bool found = false; - QueryScanFolderBySourceID( sourceID, + QueryScanFolderBySourceID( sourceID, [&](ScanFolderDatabaseEntry& scanFolderEntry) { entry = scanFolderEntry; @@ -1370,7 +1370,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetScanFolderByJobID(AZ::s64 jobID, ScanFolderDatabaseEntry& entry) { bool found = false; - QueryScanFolderByJobID( jobID, + QueryScanFolderByJobID( jobID, [&](ScanFolderDatabaseEntry& scanFolderEntry) { entry = scanFolderEntry; @@ -1383,7 +1383,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetScanFolderByProductID(AZ::s64 productID, ScanFolderDatabaseEntry& entry) { bool found = false; - QueryScanFolderByProductID( productID, + QueryScanFolderByProductID( productID, [&](ScanFolderDatabaseEntry& scanFolderEntry) { entry = scanFolderEntry; @@ -2105,7 +2105,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetProductsLikeProductName(QString likeProductName, LikeType likeType, ProductDatabaseEntryContainer& container, AZ::Uuid builderGuid, QString jobKey, QString platform, JobStatus status) { bool found = false; - + if (likeProductName.isEmpty()) { return false; @@ -2198,7 +2198,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetProductByJobIDSubId(AZ::s64 jobID, AZ::u32 subID, AzToolsFramework::AssetDatabase::ProductDatabaseEntry& result) { bool found = false; - QueryProductByJobIDSubID(jobID, subID, + QueryProductByJobIDSubID(jobID, subID, [&](ProductDatabaseEntry& resultFromDB) { found = true; @@ -2312,13 +2312,19 @@ namespace AssetProcessor { return false; } - - bool succeeded = true; + + ScopedTransaction transaction(m_databaseConnection); + for (auto& entry : container) { - succeeded &= SetProduct(entry); + if(!SetProduct(entry)) + { + return false; + } } - return succeeded; + + transaction.Commit(); + return true; } //! Clear the products for a given source. This removes the entry entirely, not just sets it to empty. @@ -2407,7 +2413,7 @@ namespace AssetProcessor if(!platform.isEmpty()) { AZStd::string platformStr = platform.toUtf8().constData(); - + if (!s_DeleteProductsBySourceidPlatformQuery.BindAndStep(*m_databaseConnection, sourceID, platformStr.c_str())) { return false; @@ -2521,7 +2527,7 @@ namespace AssetProcessor { succeeded = succeeded && RemoveSourceFileDependency(entry); } - + if (succeeded) { transaction.Commit(); @@ -2577,7 +2583,7 @@ namespace AssetProcessor } bool AssetDatabaseConnection::GetDependsOnSourceBySource( - const char* source, + const char* source, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::TypeOfDependency typeOfDependency, AzToolsFramework::AssetDatabase::SourceFileDependencyEntryContainer& container) { @@ -2596,7 +2602,7 @@ namespace AssetProcessor bool AssetDatabaseConnection::GetSourceFileDependencyBySourceDependencyId(AZ::s64 sourceDependencyId, SourceFileDependencyEntry& sourceDependencyEntry) { bool found = false; - QuerySourceDependencyBySourceDependencyId(sourceDependencyId, + QuerySourceDependencyBySourceDependencyId(sourceDependencyId, [&](SourceFileDependencyEntry& entry) { found = true; @@ -2624,7 +2630,7 @@ namespace AssetProcessor return false; } - + if (creatingNew) { AZ::s64 rowID = m_databaseConnection->GetLastRowID(); @@ -2958,9 +2964,25 @@ namespace AssetProcessor for(auto& entry : container) { - if(!SetProductDependency(entry)) + if(entry.m_productDependencyID == InvalidEntryId) { - return false; + if (!s_InsertProductDependencyQuery.BindAndStep( + *m_databaseConnection, entry.m_productPK, entry.m_dependencySourceGuid, entry.m_dependencySubID, + entry.m_dependencyFlags.to_ullong(), entry.m_platform.c_str(), entry.m_unresolvedPath.c_str(), + entry.m_dependencyType, entry.m_fromAssetId)) + { + return false; + } + } + else + { + if(!s_UpdateProductDependencyQuery.BindAndStep( + *m_databaseConnection, entry.m_productPK, entry.m_dependencySourceGuid, entry.m_dependencySubID, + entry.m_dependencyFlags.to_ullong(), entry.m_platform.c_str(), entry.m_unresolvedPath.c_str(), + entry.m_productDependencyID, entry.m_dependencyType, entry.m_fromAssetId)) + { + return false; + } } } @@ -2989,7 +3011,7 @@ namespace AssetProcessor } // now insert the new ones since we know there's no collisions: - + for (auto& entry : container) { @@ -3109,7 +3131,7 @@ namespace AssetProcessor } Statement* statement = autoFinal.Get(); - + if (statement->Step() == Statement::SqlError) { AZ_Warning(LOG_NAME, false, "Failed to write the new source into the database. %s", entry.m_fileName.c_str()); @@ -3126,7 +3148,7 @@ namespace AssetProcessor return UpdateFile(entry, entryAlreadyExists); } - bool AssetDatabaseConnection::UpdateFile(FileDatabaseEntry& entry, bool& entryAlreadyExists) + bool AssetDatabaseConnection::UpdateFile(FileDatabaseEntry& entry, bool& entryAlreadyExists) { entryAlreadyExists = false; diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp index d7cdd30be8..bda5eb7842 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp @@ -480,12 +480,12 @@ namespace AssetProcessor AZ::Data::AssetId assetId(combined.m_sourceGuid, combined.m_subID); // relative file path is gotten by removing the platform and game from the product name - QString relativeProductPath = AssetUtilities::StripAssetPlatform(combined.m_productName); + AZStd::string_view relativeProductPath = AssetUtilities::StripAssetPlatformNoCopy(combined.m_productName); QString fullProductPath = m_cacheRoot.absoluteFilePath(combined.m_productName.c_str()); AZ::Data::AssetInfo info; info.m_assetType = combined.m_assetType; - info.m_relativePath = relativeProductPath.toUtf8().data(); + info.m_relativePath = relativeProductPath; info.m_assetId = assetId; info.m_sizeBytes = AZ::IO::SystemFile::Length(fullProductPath.toUtf8().constData()); diff --git a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp index dc10dc2237..6dddfd62d3 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp @@ -9,18 +9,24 @@ #include "PathDependencyManager.h" #include #include +#include #include #include #include +#include namespace AssetProcessor { void SanitizeForDatabase(AZStd::string& str) { - // Not calling normalize because wildcards should be preserved. AZStd::to_lower(str.begin(), str.end()); - AZStd::replace(str.begin(), str.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR); - AzFramework::StringFunc::Replace(str, AZ_DOUBLE_CORRECT_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR_STRING); + + // Not calling normalize because wildcards should be preserved. + if (AZ::StringFunc::Contains(str, AZ_WRONG_DATABASE_SEPARATOR, true)) + { + AZStd::replace(str.begin(), str.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR); + AzFramework::StringFunc::Replace(str, AZ_DOUBLE_CORRECT_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR_STRING); + } } PathDependencyManager::PathDependencyManager(AZStd::shared_ptr stateData, PlatformConfiguration* platformConfig) @@ -29,7 +35,97 @@ namespace AssetProcessor } - void PathDependencyManager::SaveUnresolvedDependenciesToDatabase(AssetBuilderSDK::ProductPathDependencySet& unresolvedDependencies, const AzToolsFramework::AssetDatabase::ProductDatabaseEntry& productEntry, const AZStd::string& platform) + void PathDependencyManager::QueueSourceForDependencyResolution(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry) + { + m_queuedForResolve.push_back(sourceEntry); + } + + void PathDependencyManager::ProcessQueuedDependencyResolves() + { + if (m_queuedForResolve.empty()) + { + return; + } + + auto queuedForResolve = m_queuedForResolve; + m_queuedForResolve.clear(); + + // Grab every product from the database and map to Source PK -> [products] + AZStd::unordered_map> productMap; + m_stateData->QueryCombined([&productMap](const AzToolsFramework::AssetDatabase::CombinedDatabaseEntry& entry) + { + productMap[entry.m_sourcePK].push_back(entry); + return true; + }); + + // Build up a list of all the paths we need to search for: products + 2 variations of the source path + AZStd::vector searches; + + for (const auto& entry : queuedForResolve) + { + // Search for each product + for (const auto& productEntry : productMap[entry.m_sourceID]) + { + const AZStd::string& productName = productEntry.m_productName; + + // strip path of the / + AZStd::string_view result = AssetUtilities::StripAssetPlatformNoCopy(productName); + searches.emplace_back(result, false, &entry, &productEntry); + } + + // Search for the source path + AZStd::string sourceNameWithScanFolder = + ToScanFolderPrefixedPath(aznumeric_cast(entry.m_scanFolderPK), entry.m_sourceName.c_str()); + AZStd::string sanitizedSourceName = entry.m_sourceName; + + SanitizeForDatabase(sourceNameWithScanFolder); + SanitizeForDatabase(sanitizedSourceName); + + searches.emplace_back(sourceNameWithScanFolder, true, &entry, nullptr); + searches.emplace_back(sanitizedSourceName, true, &entry, nullptr); + } + + AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer unresolvedDependencies; + m_stateData->GetUnresolvedProductDependencies(unresolvedDependencies); + + AZStd::recursive_mutex mapMutex; + // Map of Map of Product Dependency>> + AZStd::unordered_map>> sourceIdToMatchedSearchDependencies; + + // For every search path we created, we're going to see if it matches up against any of the unresolved dependencies + AZ::parallel_for_each( + searches.begin(), searches.end(), + [&sourceIdToMatchedSearchDependencies, &mapMutex, &unresolvedDependencies](const SearchEntry& search) + { + AZStd::unordered_set matches; + for (const auto& entry: unresolvedDependencies) + { + AZ::IO::PathView searchPath(search.m_path); + + if(((entry.m_dependencyType == AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry::ProductDep_SourceFile && search.m_isSourcePath) + || (entry.m_dependencyType == AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry::ProductDep_ProductFile && !search.m_isSourcePath)) + && searchPath.Match(entry.m_unresolvedPath)) + { + matches.insert(entry); + } + } + + if (!matches.empty()) + { + AZStd::scoped_lock lock(mapMutex); + auto& productDependencyDatabaseEntries = sourceIdToMatchedSearchDependencies[search.m_sourceEntry->m_sourceID][&search]; + productDependencyDatabaseEntries.insert(matches.begin(), matches.end()); + } + }); + + for (const auto& entry : queuedForResolve) + { + RetryDeferredDependencies(entry, sourceIdToMatchedSearchDependencies[entry.m_sourceID], productMap[entry.m_sourceID]); + } + } + + void PathDependencyManager::SaveUnresolvedDependenciesToDatabase(AssetBuilderSDK::ProductPathDependencySet& unresolvedDependencies, + const AzToolsFramework::AssetDatabase::ProductDatabaseEntry& productEntry, const AZStd::string& platform) { using namespace AzToolsFramework::AssetDatabase; @@ -206,9 +302,9 @@ namespace AssetProcessor } void PathDependencyManager::SaveResolvedDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry, const MapSet& exclusionMaps, const AZStd::string& sourceNameWithScanFolder, - const AZStd::vector& dependencyEntries, + const AZStd::unordered_set& dependencyEntries, AZStd::string_view matchedPath, bool isSourceDependency, const AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer& matchedProducts, - AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer& dependencyContainer) const + AZStd::vector& dependencyContainer) const { for (const auto& productDependencyDatabaseEntry : dependencyEntries) { @@ -267,8 +363,7 @@ namespace AssetProcessor } // All checks passed, this is a valid dependency we need to save to the db - dependencyContainer.push_back(); - auto& entry = dependencyContainer.back(); + AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry entry; entry.m_productDependencyID = dependencyId; entry.m_productPK = productDependencyDatabaseEntry.m_productPK; @@ -276,62 +371,30 @@ namespace AssetProcessor entry.m_dependencySubID = matchedProduct.m_subID; entry.m_platform = productDependencyDatabaseEntry.m_platform; + dependencyContainer.push_back(AZStd::move(entry)); + // If there's more than 1 product, reset the ID so further products create new db entries dependencyId = AzToolsFramework::AssetDatabase::InvalidEntryId; } } } - void PathDependencyManager::RetryDeferredDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry) + void PathDependencyManager::RetryDeferredDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry, + const AZStd::unordered_map>& matches, + const AZStd::vector& products) { MapSet exclusionMaps = PopulateExclusionMaps(); - // Gather a list of all the products this source file produced - AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer products; - if (!m_stateData->GetProductsBySourceName(sourceEntry.m_sourceName.c_str(), products)) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Source %s did not have any products. Skipping dependency processing.\n", sourceEntry.m_sourceName.c_str()); - return; - } - - AZStd::unordered_map> map; - - // Build up a list of all the paths we need to search for: products + 2 variations of the source path - AZStd::vector searchPaths; - - for (const auto& productEntry : products) - { - const AZStd::string& productName = productEntry.m_productName; - - // strip path of the / - AZStd::string strippedPath = AssetUtilities::StripAssetPlatform(productName).toUtf8().constData(); - SanitizeForDatabase(strippedPath); - - searchPaths.push_back(strippedPath); - } - AZStd::string sourceNameWithScanFolder = ToScanFolderPrefixedPath(aznumeric_cast(sourceEntry.m_scanFolderPK), sourceEntry.m_sourceName.c_str()); - AZStd::string sanitizedSourceName = sourceEntry.m_sourceName; - SanitizeForDatabase(sourceNameWithScanFolder); - SanitizeForDatabase(sanitizedSourceName); - searchPaths.push_back(sourceNameWithScanFolder); - searchPaths.push_back(sanitizedSourceName); - - m_stateData->QueryProductDependenciesUnresolvedAdvanced(searchPaths, [&map](AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry& entry, const AZStd::string& matchedPath) - { - map[matchedPath].push_back(AZStd::move(entry)); - return true; - }); - - AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; + AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyVector; // Go through all the matched dependencies - for (const auto& pair : map) + for (const auto& pair : matches) { - AZStd::string_view matchedPath = pair.first; - const bool isSourceDependency = matchedPath == sanitizedSourceName || matchedPath == sourceNameWithScanFolder; + const SearchEntry* searchEntry = pair.first; + const bool isSourceDependency = searchEntry->m_isSourcePath; AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer matchedProducts; @@ -342,34 +405,24 @@ namespace AssetProcessor } else { - for (const auto& productEntry : products) - { - const AZStd::string& productName = productEntry.m_productName; - - // strip path of the leading asset platform / - AZStd::string strippedPath = AssetUtilities::StripAssetPlatform(productName).toUtf8().constData(); - SanitizeForDatabase(strippedPath); - - if (strippedPath == matchedPath) - { - matchedProducts.push_back(productEntry); - } - } + matchedProducts.push_back(*searchEntry->m_productEntry); } // Go through each dependency we're resolving and create a db entry for each product that resolved it (wildcard/source dependencies will generally create more than 1) - SaveResolvedDependencies(sourceEntry, exclusionMaps, sourceNameWithScanFolder, pair.second, matchedPath, isSourceDependency, matchedProducts, dependencyContainer); + SaveResolvedDependencies( + sourceEntry, exclusionMaps, sourceNameWithScanFolder, pair.second, searchEntry->m_path, isSourceDependency, matchedProducts, + dependencyVector); } - // Save everything to the db - if (!m_stateData->UpdateProductDependencies(dependencyContainer)) + // Save everything to the db, this will update matched non-wildcard dependencies and add new records for wildcard matches + if (!m_stateData->UpdateProductDependencies(dependencyVector)) { AZ_Error("PathDependencyManager", false, "Failed to update product dependencies"); } else { // Send a notification for each dependency that has been resolved - NotifyResolvedDependencies(dependencyContainer); + NotifyResolvedDependencies(dependencyVector); } } @@ -460,7 +513,7 @@ namespace AssetProcessor if (isExactDependency) { // Search for products in the cache platform folder - // Example: If a path dependency is "test1.asset" in AutomatedTesting on PC, this would search + // Example: If a path dependency is "test1.asset" in AutomatedTesting on PC, this would search // "AutomatedTesting/Cache/pc/test1.asset" m_stateData->GetProductsByProductName(productNameWithPlatform, productInfoContainer); diff --git a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h index 3a207ec6a9..763ee2cd74 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h @@ -39,9 +39,27 @@ namespace AssetProcessor PathDependencyManager(AZStd::shared_ptr stateData, PlatformConfiguration* platformConfig); + void QueueSourceForDependencyResolution(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry); + + void ProcessQueuedDependencyResolves(); + + struct SearchEntry + { + SearchEntry(AZStd::string path, bool isSourcePath, const AzToolsFramework::AssetDatabase::SourceDatabaseEntry* sourceEntry, const AzToolsFramework::AssetDatabase::ProductDatabaseEntry* productEntry) + : m_path(std::move(path)), + m_isSourcePath(isSourcePath), + m_sourceEntry(sourceEntry), + m_productEntry(productEntry) {} + + AZStd::string m_path; + bool m_isSourcePath; + const AzToolsFramework::AssetDatabase::SourceDatabaseEntry* m_sourceEntry = nullptr; + const AzToolsFramework::AssetDatabase::ProductDatabaseEntry* m_productEntry = nullptr; + }; + /// This function is responsible for looking up existing, unresolved dependencies that the current asset satisfies. /// These can be dependencies on either the source asset or one of the product assets - void RetryDeferredDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry); + void RetryDeferredDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry, const AZStd::unordered_map>& matches, const AZStd::vector& products); /// This function is responsible for taking the path dependencies output by the current asset and trying to resolve them to AssetIds /// This does not look for dependencies that the current asset satisfies. @@ -66,7 +84,7 @@ namespace AssetProcessor MapSet PopulateExclusionMaps() const; void NotifyResolvedDependencies(const AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer& dependencyContainer) const; - void SaveResolvedDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry, const MapSet& exclusionMaps, const AZStd::string& sourceNameWithScanFolder, const AZStd::vector& dependencyEntries, AZStd::string_view matchedPath, bool isSourceDependency, const AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer& matchedProducts, AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer& dependencyContainer) const; + void SaveResolvedDependencies(const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry, const MapSet& exclusionMaps, const AZStd::string& sourceNameWithScanFolder, const AZStd::unordered_set& dependencyEntries, AZStd::string_view matchedPath, bool isSourceDependency, const AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer& matchedProducts, AZStd::vector& dependencyContainer) const; static DependencyProductMap& SelectMap(MapSet& mapSet, bool wildcard, AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry::DependencyType type); /// Returns false if a path contains wildcards, true otherwise @@ -93,5 +111,6 @@ namespace AssetProcessor AZStd::shared_ptr m_stateData; PlatformConfiguration* m_platformConfig{}; DependencyResolvedCallback m_dependencyResolvedCallback{}; + AZStd::vector m_queuedForResolve; }; } // namespace AssetProcessor diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 8867f2379f..beb82dfcab 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -48,7 +48,7 @@ namespace AssetProcessor // note that this is not the first time we're opening the database - the main thread also opens it before this happens, // which allows it to upgrade it and check it for errors. If we get here, it means the database is already good to go. - m_stateData->OpenDatabase(); + m_stateData->OpenDatabase(); MigrateScanFolders(); @@ -70,7 +70,7 @@ namespace AssetProcessor m_excludedFolderCache = AZStd::make_unique(m_platformConfig); PopulateJobStateCache(); - + AssetProcessor::ProcessingJobInfoBus::Handler::BusConnect(); } @@ -126,7 +126,7 @@ namespace AssetProcessor { // capture scanning stats: AssetProcessor::StatsCapture::BeginCaptureStat("AssetScanning"); - + // Ensure that the source file list is populated before a scan begins m_sourceFilesInDatabase.clear(); m_fileModTimes.clear(); @@ -155,11 +155,11 @@ namespace AssetProcessor QString scanFolderPath; QString relativeToScanFolderPath = QString::fromUtf8(entry.m_fileName.c_str()); - + for (int i = 0; i < m_platformConfig->GetScanFolderCount(); ++i) { const auto& scanFolderInfo = m_platformConfig->GetScanFolderAt(i); - + if (scanFolderInfo.ScanFolderID() == entry.m_scanFolderPK) { scanFolderPath = scanFolderInfo.ScanPath(); @@ -181,7 +181,7 @@ namespace AssetProcessor { m_isCurrentlyScanning = false; AssetProcessor::StatsCapture::EndCaptureStat("AssetScanning"); - + // we cannot invoke this immediately - the scanner might be done, but we aren't actually ready until we've processed all remaining messages: QMetaObject::invokeMethod(this, "CheckMissingFiles", Qt::QueuedConnection); } @@ -216,7 +216,7 @@ namespace AssetProcessor else { QString statKey = QString("ProcessJob,%1,%2,%3").arg(jobEntry.m_databaseSourceName).arg(jobEntry.m_jobKey).arg(jobEntry.m_platformInfo.m_identifier.c_str()); - + if (status == JobStatus::InProgress) { //update to in progress status @@ -232,7 +232,7 @@ namespace AssetProcessor // without going thru the RC. // as such, all the code in this block should be crafted to work regardless of whether its double called. AssetProcessor::StatsCapture::EndCaptureStat(statKey.toUtf8().constData()); - + m_jobRunKeyToJobInfoMap.erase(jobEntry.m_jobRunKey); Q_EMIT SourceFinished(sourceUUID, legacySourceUUID); Q_EMIT JobComplete(jobEntry, status); @@ -308,7 +308,7 @@ namespace AssetProcessor //! A network request came in, Given a Job Run Key (from the above Job Request), asking for the actual log for that job. GetAbsoluteAssetDatabaseLocationResponse AssetProcessorManager::ProcessGetAbsoluteAssetDatabaseLocationRequest(MessageData messageData) - { + { GetAbsoluteAssetDatabaseLocationResponse response; AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Broadcast(&AzToolsFramework::AssetDatabase::AssetDatabaseRequests::GetAssetDatabaseLocation, response.m_absoluteAssetDatabaseLocation); @@ -525,7 +525,7 @@ namespace AssetProcessor { foundOne = true; return true; - }, + }, AZ::Uuid::CreateNull(), nullptr, platform.toUtf8().constData(), @@ -750,7 +750,7 @@ namespace AssetProcessor } OnJobStatusChanged(jobEntry, JobStatus::Failed); - + // note that we always print out the failed job status here in both batch and GUI mode. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Failed %s, (%s)... \n", jobEntry.m_pathRelativeToWatchFolder.toUtf8().constData(), @@ -868,7 +868,7 @@ namespace AssetProcessor && AzFramework::StringFunc::Equal(job.m_platform.c_str(), itProcessedAsset->m_entry.m_platformInfo.m_identifier.c_str())) { // If we are here it implies that for the same source file we have another job that outputs the same product. - // This is usually the case when two builders process the same source file and outputs the same product file. + // This is usually the case when two builders process the same source file and outputs the same product file. remove = true; AZStd::string consoleMsg = AZStd::string::format("Failing Job (source : %s , jobkey %s) because another job (source : %s , jobkey : %s ) outputted the same product %s.\n", itProcessedAsset->m_entry.m_pathRelativeToWatchFolder.toUtf8().constData(), itProcessedAsset->m_entry.m_jobKey.toUtf8().data(), source.m_sourceName.c_str(), job.m_jobKey.c_str(), newProductName.toUtf8().constData()); @@ -1128,7 +1128,7 @@ namespace AssetProcessor QString fullProductPath = m_cacheRootDir.absoluteFilePath(productName); // Strip the from the front of a relative product path - QString relativeProductPath = AssetUtilities::StripAssetPlatform(priorProduct.m_productName); + AZStd::string_view relativeProductPath = AssetUtilities::StripAssetPlatformNoCopy(priorProduct.m_productName); AZ::Data::AssetId assetId(source.m_sourceGuid, priorProduct.m_subID); @@ -1137,7 +1137,7 @@ namespace AssetProcessor AZ::Data::AssetId legacyAssetId(priorProduct.m_legacyGuid, 0); AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), priorProduct.m_subID); - AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetRemoved, priorProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str()); + AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetRemoved, priorProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str()); message.m_assetId = assetId; if (legacyAssetId != assetId) @@ -1271,7 +1271,7 @@ namespace AssetProcessor [&](AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry& dependencyEntry) { return dependencyEntry.m_dependencySubID == pair.first.m_subID - && dependencyEntry.m_dependencySourceGuid == source.m_sourceGuid; + && dependencyEntry.m_dependencySourceGuid == source.m_sourceGuid; }); if (conflictItr != dependencySet.end()) @@ -1312,14 +1312,14 @@ namespace AssetProcessor // relative file path is gotten by removing the platform and game from the product name // Strip the from the front of a relative product path - QString relativeProductPath = AssetUtilities::StripAssetPlatform(productName.toUtf8().constData()); + AZStd::string relativeProductPath = AssetUtilities::StripAssetPlatform(productName.toUtf8().constData()).toUtf8().constData(); - AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetChanged, newProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str()); + AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetChanged, newProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str()); AZ::Data::AssetId assetId(source.m_sourceGuid, newProduct.m_subID); AZ::Data::AssetId legacyAssetId(newProduct.m_legacyGuid, 0); AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), newProduct.m_subID); - message.m_data = relativeProductPath.toUtf8().data(); + message.m_data = relativeProductPath; message.m_sizeBytes = QFileInfo(fullProductPath).size(); message.m_assetId = assetId; @@ -1350,7 +1350,7 @@ namespace AssetProcessor } Q_EMIT AssetMessage( message); - + AddKnownFoldersRecursivelyForFile(fullProductPath, m_cacheRootDir.absolutePath()); } @@ -1497,7 +1497,7 @@ namespace AssetProcessor // Record the modtime for the metadata file so we don't re-analyze this change again next time AP starts up QFileInfo metadataFileInfo(originalName); auto* scanFolder = m_platformConfig->GetScanFolderForFile(originalName); - + if (scanFolder) { QString databaseName; @@ -1534,7 +1534,7 @@ namespace AssetProcessor for (const QString& absolutePath : absoluteSourcePathList) { // we need to check if its already in the "active files" (things that we are looking over) - // or if its in the "currently being examined" list. The latter is likely to be the smaller list, + // or if its in the "currently being examined" list. The latter is likely to be the smaller list, // so we check it first. Both of those are absolute paths, so we convert to absolute path before // searching those lists: if (m_filesToExamine.find(absolutePath) != m_filesToExamine.end()) @@ -1633,9 +1633,6 @@ namespace AssetProcessor } } - // Strip the from the front of a relative product path - QString relativePath = AssetUtilities::StripAssetPlatform(relativeProductFile.toUtf8().constData()); - //set the fingerprint on the job that made this product for (auto& job : jobs) { @@ -1678,7 +1675,7 @@ namespace AssetProcessor } QString fullProductPath = m_cacheRootDir.absoluteFilePath(product.m_productName.c_str()); - QString relativeProductPath(AssetUtilities::StripAssetPlatform(product.m_productName)); + AZStd::string_view relativeProductPath = AssetUtilities::StripAssetPlatformNoCopy(product.m_productName); QFileInfo productFileInfo(fullProductPath); if (productFileInfo.exists()) { @@ -1725,7 +1722,7 @@ namespace AssetProcessor AZ::Data::AssetId legacyAssetId(product.m_legacyGuid, 0); AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), product.m_subID); - AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetRemoved, product.m_assetType, job.m_platform.c_str()); + AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetRemoved, product.m_assetType, job.m_platform.c_str()); message.m_assetId = assetId; if (legacyAssetId != assetId) @@ -1759,7 +1756,7 @@ namespace AssetProcessor // and no overrides exist for it. // we must delete its products. using namespace AzToolsFramework::AssetDatabase; - + // If we fail to delete a product, the deletion event gets requeued // To avoid retrying forever, we keep track of the time of the first deletion failure and only retry // if less than this amount of time has passed. @@ -1832,7 +1829,7 @@ namespace AssetProcessor { return; } - + // Check if this file causes any file types to be re-evaluated CheckMetaDataRealFiles(normalizedPath); @@ -2046,7 +2043,7 @@ namespace AssetProcessor AZ_TracePrintf(AssetProcessor::DebugChannel, "Non-processed file: %s\n", databaseSourceFile.toUtf8().constData()); ++m_numSourcesNotHandledByAnyBuilder; - + // Record the modtime for the file so we know we've already processed it QString absolutePath = QDir(scanFolder->ScanPath()).absoluteFilePath(normalizedPath); @@ -2114,7 +2111,7 @@ namespace AssetProcessor // Check whether another job emitted this job as a job dependency and if true, queue the dependent job source file also JobDesc jobDesc(jobDetails.m_jobEntry.m_databaseSourceName.toUtf8().data(), jobDetails.m_jobEntry.m_jobKey.toUtf8().data(), jobDetails.m_jobEntry.m_platformInfo.m_identifier); - + shouldProcessAsset = true; QFileInfo file(jobDetails.m_jobEntry.GetAbsoluteSourcePath()); QDateTime dateTime(file.lastModified()); @@ -2347,7 +2344,7 @@ namespace AssetProcessor } QString canonicalRootDir = AssetUtilities::NormalizeFilePath(m_cacheRootDir.canonicalPath()); - + FileExamineContainer swapped; m_filesToExamine.swap(swapped); // makes it okay to call CheckSource(...) @@ -2470,7 +2467,7 @@ namespace AssetProcessor AZ_TracePrintf(AssetProcessor::DebugChannel, "ProcessFilesToExamineQueue: Unable to find the relative path.\n"); continue; } - + const ScanFolderInfo* scanFolderInfo = m_platformConfig->GetScanFolderForFile(normalizedPath); relativePathToFile = databasePathToFile; @@ -2494,9 +2491,9 @@ namespace AssetProcessor QString::fromUtf8(jobInfo.m_watchFolder.c_str()), relativePathToFile, databasePathToFile, - jobInfo.m_builderGuid, - *platformFromInfo, - jobInfo.m_jobKey.c_str(), 0, GenerateNewJobRunKey(), + jobInfo.m_builderGuid, + *platformFromInfo, + jobInfo.m_jobKey.c_str(), 0, GenerateNewJobRunKey(), AZ::Uuid::CreateNull()); job.m_autoFail = true; @@ -2597,7 +2594,7 @@ namespace AssetProcessor { // on the other hand, if we found a file it means that a deleted file revealed a file that // was previously overridden by it. - // Because the deleted file may have "revealed" a file with different case, + // Because the deleted file may have "revealed" a file with different case, // we have to actually correct its case here. This is rare, so it should be reasonable // to call the expensive function to discover correct case. QString pathRelativeToScanFolder; @@ -2674,6 +2671,7 @@ namespace AssetProcessor AZ_TracePrintf(ConsoleChannel, "Builder optimization: %i / %i files required full analysis, %i sources found but not processed by anyone\n", m_numSourcesNeedingFullAnalysis, m_numTotalSourcesFound, m_numSourcesNotHandledByAnyBuilder); } + m_pathDependencyManager->ProcessQueuedDependencyResolves(); QTimer::singleShot(20, this, SLOT(RemoveEmptyFolders())); } else @@ -2739,7 +2737,7 @@ namespace AssetProcessor } // over here we also want to invalidate the metafiles on disk map if it COULD Be a metafile - // note that there is no reason to do an expensive exacting computation here, it will be + // note that there is no reason to do an expensive exacting computation here, it will be // done later and cached when m_cachedMetaFilesExistMap is set to false, we just need to // know if its POSSIBLE that its a metafile, cheaply. // if its a metafile match, then invalidate the metafile table. @@ -2752,7 +2750,7 @@ namespace AssetProcessor m_metaFilesWhichActuallyExistOnDisk.clear(); // invalidate the map, force a recompuation later. } } - + } m_AssetProcessorIsBusy = true; @@ -2927,7 +2925,7 @@ namespace AssetProcessor } AZ::u64 fileHash = AssetUtilities::GetFileHash(fileInfo.m_filePath.toUtf8().constData()); - + if(fileHash != databaseHashValue) { // File contents have changed @@ -3149,7 +3147,7 @@ namespace AssetProcessor { AddMetadataFilesForFingerprinting(kvp.first.c_str(), job.m_fingerprintFiles); } - + // Check the current builder jobs with the previous ones in the database: job.m_jobEntry.m_computedFingerprint = AssetUtilities::GenerateFingerprint(job); JobIndentifier jobIndentifier(JobDesc(job.m_jobEntry.m_databaseSourceName.toUtf8().data(), job.m_jobEntry.m_jobKey.toUtf8().data(), job.m_jobEntry.m_platformInfo.m_identifier), job.m_jobEntry.m_builderGuid); @@ -3208,7 +3206,7 @@ namespace AssetProcessor { // If the database knows about the job than it implies that AP has processed it sucessfully at least once // and therefore the dependent job should not cause the job which depends on it to be processed again. - // If however we find a dependent job which is not known to AP then we know this job needs to be processed + // If however we find a dependent job which is not known to AP then we know this job needs to be processed // after all the dependent jobs have completed at least once. AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer jobs; @@ -3238,7 +3236,7 @@ namespace AssetProcessor } else if(sourceFileDependency.m_sourceDependencyType != AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards) { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "UpdateJobDependency: Failed to find builder dependency for %s job (%s, %s, %s)\n", + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "UpdateJobDependency: Failed to find builder dependency for %s job (%s, %s, %s)\n", job.m_jobEntry.GetAbsoluteSourcePath().toUtf8().constData(), jobDependencyInternal->m_jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str(), jobDependencyInternal->m_jobDependency.m_jobKey.c_str(), @@ -3262,7 +3260,7 @@ namespace AssetProcessor ++jobDependencySlot; } - // sorting job dependencies as they can effect the fingerprint of the job + // sorting job dependencies as they can effect the fingerprint of the job AZStd::sort(job.m_jobDependencyList.begin(), job.m_jobDependencyList.end(), [](const AssetProcessor::JobDependencyInternal& lhs, const AssetProcessor::JobDependencyInternal& rhs) { @@ -3289,7 +3287,7 @@ namespace AssetProcessor for (const JobDependencyInternal& jobDependencyInternal : job.m_jobDependencyList) { // Loop over all the builderUuid and check whether the corresponding entry exists in the jobsFingerprint map. - // If an entry exists, it implies than we have already send the job over to the RCController + // If an entry exists, it implies than we have already send the job over to the RCController for (auto builderIter = jobDependencyInternal.m_builderUuidList.begin(); builderIter != jobDependencyInternal.m_builderUuidList.end(); ++builderIter) { JobIndentifier jobIdentifier(JobDesc(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath, @@ -3299,7 +3297,7 @@ namespace AssetProcessor auto jobFound = m_jobFingerprintMap.find(jobIdentifier); if (jobFound == m_jobFingerprintMap.end()) { - // Job cannot be processed, since one of its dependent job hasn't been fingerprinted + // Job cannot be processed, since one of its dependent job hasn't been fingerprinted return false; } } @@ -3317,7 +3315,7 @@ namespace AssetProcessor // and call the CreateJobs function on the builder. // it bundles the results up in a JobToProcessEntry struct, while it is doing this: JobToProcessEntry entry; - + AZ::Uuid sourceUUID = AssetUtilities::CreateSafeSourceUUIDFromName(databasePathToFile.toUtf8().constData()); // first, we put the source UUID in the map so that its present for any other queries: @@ -3375,14 +3373,14 @@ namespace AssetProcessor builderInfo.m_createJobFunction(createJobsRequest, createJobsResponse); AssetProcessor::StatsCapture::EndCaptureStat(statKey.toUtf8().constData()); } - + AssetProcessor::SetThreadLocalJobId(0); bool isBuilderMissingFingerprint = (createJobsResponse.m_result == AssetBuilderSDK::CreateJobsResultCode::Success && !createJobsResponse.m_createJobOutputs.empty() && !createJobsResponse.m_createJobOutputs[0].m_additionalFingerprintInfo.empty() && builderInfo.m_analysisFingerprint.empty()); - + if (createJobsResponse.m_result == AssetBuilderSDK::CreateJobsResultCode::Failed || isBuilderMissingFingerprint) { AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Createjobs Failed: %s.\n", normalizedPath.toUtf8().constData()); @@ -3393,7 +3391,7 @@ namespace AssetProcessor char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; AZ::IO::FileIOBase::GetInstance()->ResolvePath(fullPathToLogFile.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - + JobDetails jobdetail; jobdetail.m_jobEntry = JobEntry( scanFolder->ScanPath(), @@ -3486,9 +3484,9 @@ namespace AssetProcessor scanFolder->ScanPath(), actualRelativePath, databasePathToFile, - builderInfo.m_busId, - *infoForPlatform, - jobDescriptor.m_jobKey.c_str(), 0, GenerateNewJobRunKey(), + builderInfo.m_busId, + *infoForPlatform, + jobDescriptor.m_jobKey.c_str(), 0, GenerateNewJobRunKey(), sourceUUID); newJob.m_jobEntry.m_checkExclusiveLock = jobDescriptor.m_checkExclusiveLock; newJob.m_jobParam = AZStd::move(jobDescriptor.m_jobParameters); @@ -3506,7 +3504,7 @@ namespace AssetProcessor newJob.m_jobDependencyList.push_back(JobDependencyInternal(jobDependency)); ++numJobDependencies; } - + // note that until analysis completes, the jobId is not set and neither is the destination pat JobDesc jobDesc(newJob.m_jobEntry.m_databaseSourceName.toUtf8().data(), newJob.m_jobEntry.m_jobKey.toUtf8().data(), newJob.m_jobEntry.m_platformInfo.m_identifier); m_jobDescToBuilderUuidMap[jobDesc].insert(builderInfo.m_busId); @@ -3515,7 +3513,7 @@ namespace AssetProcessor JobIndentifier jobIdentifier(jobDesc, builderInfo.m_busId); { AZStd::lock_guard lock(AssetProcessor::ProcessingJobInfoBus::GetOrCreateContext().m_contextMutex); - m_jobFingerprintMap.erase(jobIdentifier); + m_jobFingerprintMap.erase(jobIdentifier); } entry.m_jobsToAnalyze.push_back(AZStd::move(newJob)); @@ -3578,7 +3576,7 @@ namespace AssetProcessor // instead of a UUID, a path has been provided, prepare and use that. We need to turn it into a database path QString encodedFileData = QString::fromUtf8(sourceDependency.m_sourceFileDependencyPath.c_str()); encodedFileData = AssetUtilities::NormalizeFilePath(encodedFileData); - + if (sourceDependency.m_sourceDependencyType == AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards) { int wildcardIndex = encodedFileData.indexOf("*"); @@ -3653,7 +3651,7 @@ namespace AssetProcessor } // Convert to relative paths - for (auto dependencyItr = resolvedDependencyList.begin(); dependencyItr != resolvedDependencyList.end();) + for (auto dependencyItr = resolvedDependencyList.begin(); dependencyItr != resolvedDependencyList.end();) { QString relativePath, scanFolder; if (m_platformConfig->ConvertToRelativePath(*dependencyItr, relativePath, scanFolder)) @@ -3705,7 +3703,7 @@ namespace AssetProcessor return (!resultDatabaseSourceName.isEmpty()); } - + void AssetProcessorManager::UpdateSourceFileDependenciesDatabase(JobToProcessEntry& entry) { using namespace AzToolsFramework::AssetDatabase; @@ -3738,7 +3736,7 @@ namespace AssetProcessor QString resolvedDatabaseName; if (!ResolveSourceFileDependencyPath(sourceDependency.second, resolvedDatabaseName,resolvedDependencyList)) { - // ResolveDependencyPath should only fail in a data error, otherwise it always outputs something, + // ResolveDependencyPath should only fail in a data error, otherwise it always outputs something, // even if that something starts with the placeholder. continue; } @@ -3759,7 +3757,7 @@ namespace AssetProcessor SourceFileDependencyEntry newDependencyEntry( sourceDependency.first, entry.m_sourceFileInfo.m_databasePath.toUtf8().constData(), - resolvedDatabaseName.toUtf8().constData(), + resolvedDatabaseName.toUtf8().constData(), sourceDependency.second.m_sourceDependencyType == AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards ? SourceFileDependencyEntry::DEP_SourceLikeMatch : SourceFileDependencyEntry::DEP_SourceToSource, !sourceDependency.second.m_sourceFileDependencyUUID.IsNull()); // If the UUID is null, then record that this dependency came from a (resolved) path newDependencies.push_back(AZStd::move(newDependencyEntry)); @@ -3803,7 +3801,7 @@ namespace AssetProcessor } // get all the old dependencies and remove them. This function is comprehensive on all dependencies - // for a given source file so we can just eliminate all of them from that same source file and replace + // for a given source file so we can just eliminate all of them from that same source file and replace // them with all of the new ones for the given source file: AZStd::unordered_set oldDependencies; m_stateData->QueryDependsOnSourceBySourceDependency( @@ -4018,7 +4016,7 @@ namespace AssetProcessor result.m_watchFolder = QString::fromUtf8(scanFolder.m_scanFolder.c_str()); result.m_sourceRelativeToWatchFolder = result.m_sourceDatabaseName; - { + { // this scope exists to restrict the duration of the below lock. AZStd::lock_guard lock(m_sourceUUIDToSourceInfoMapMutex); m_sourceUUIDToSourceInfoMap.insert(AZStd::make_pair(sourceUuid, result)); @@ -4045,9 +4043,9 @@ namespace AssetProcessor auto jobPair = m_jobsToProcess.insert(AZStd::move(jobDetail)); if (!jobPair.second) { - // if we are here it means that this job was already found in the jobs to process list + // if we are here it means that this job was already found in the jobs to process list // and therefore insert failed, we will try to update the iterator manually here. - // Note that if insert fails the original object is not destroyed and therefore we can use move again. + // Note that if insert fails the original object is not destroyed and therefore we can use move again. // we just replaced a job, so we have to decrement its count. UpdateAnalysisTrackerForFile(jobPair.first->m_jobEntry, AnalysisTrackerUpdateType::JobFinished); @@ -4068,7 +4066,7 @@ namespace AssetProcessor QSet absoluteSourceFilePathQueue; QString databasePath; QString scanFolder; - + auto callbackFunction = [this, &absoluteSourceFilePathQueue](SourceFileDependencyEntry& entry) { QString relativeDatabaseName = QString::fromUtf8(entry.m_source.c_str()); @@ -4111,7 +4109,7 @@ namespace AssetProcessor sourceDatabaseEntry.m_sourceName = relativeSourceFilePath.toUtf8().constData(); sourceDatabaseEntry.m_sourceGuid = AssetUtilities::CreateSafeSourceUUIDFromName(sourceDatabaseEntry.m_sourceName.c_str()); - + if (!m_stateData->SetSource(sourceDatabaseEntry)) { AZ_Error(AssetProcessor::ConsoleChannel, false, "Failed to add source to the database!!!"); @@ -4260,7 +4258,7 @@ namespace AssetProcessor { AZ_TracePrintf(DebugChannel, "Builder %s analysis fingerprint changed. Files assigned to it will be re-analyzed.\n", priorBuilderUUID.ToString().c_str()); } - + if (builderIsDirty) { m_anyBuilderChange = true; @@ -4414,7 +4412,7 @@ namespace AssetProcessor source.m_analysisFingerprint.append(builderFP.ToString()); } - m_pathDependencyManager->RetryDeferredDependencies(source); + m_pathDependencyManager->QueueSourceForDependencyResolution(source); m_stateData->SetSource(source); databaseSourceName = source.m_sourceName.c_str(); @@ -4593,7 +4591,7 @@ namespace AssetProcessor { continue; } - + QString firstMatchingFile = m_platformConfig->FindFirstMatchingFile(dep); if (firstMatchingFile.isEmpty()) { @@ -4787,7 +4785,7 @@ namespace AssetProcessor assetIter->m_entry.m_sourceFileUUID); jobdetail.m_autoFail = true; jobdetail.m_critical = true; - jobdetail.m_priority = INT_MAX; // front of the queue. + jobdetail.m_priority = INT_MAX; // front of the queue. jobdetail.m_scanFolder = m_platformConfig->GetScanFolderForFile(assetIter->m_entry.GetAbsoluteSourcePath()); // the new lines make it easier to copy and paste the file names. jobdetail.m_jobParam[AZ_CRC(AutoFailReasonKey)] = autoFailReason; @@ -4859,6 +4857,6 @@ namespace AssetProcessor return filesFound; } - + } // namespace AssetProcessor diff --git a/Code/Tools/AssetProcessor/native/tests/BaseAssetProcessorTest.h b/Code/Tools/AssetProcessor/native/tests/BaseAssetProcessorTest.h index 71d3fa0f6d..be7e78d097 100644 --- a/Code/Tools/AssetProcessor/native/tests/BaseAssetProcessorTest.h +++ b/Code/Tools/AssetProcessor/native/tests/BaseAssetProcessorTest.h @@ -40,12 +40,14 @@ protected: void SetupEnvironment() override { // Setup code + AZ::Environment::Create(nullptr); qInstallMessageHandler(UnitTestMessageHandler); } void TeardownEnvironment() override { qInstallMessageHandler(nullptr); + AZ::Environment::Destroy(); } private: diff --git a/Code/Tools/AssetProcessor/native/tests/PathDependencyManagerTests.cpp b/Code/Tools/AssetProcessor/native/tests/PathDependencyManagerTests.cpp index b20d373307..1d6e92e47e 100644 --- a/Code/Tools/AssetProcessor/native/tests/PathDependencyManagerTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/PathDependencyManagerTests.cpp @@ -12,13 +12,23 @@ #include "AzToolsFramework/API/AssetDatabaseBus.h" #include "AssetDatabase/AssetDatabase.h" #include +#include +#include +#include +#include namespace UnitTests { class MockDatabaseLocationListener : public AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Handler { public: - MOCK_METHOD1(GetAssetDatabaseLocation, bool(AZStd::string&)); + bool GetAssetDatabaseLocation(AZStd::string& location) override + { + location = m_databaseLocation; + return true; + } + + AZStd::string m_databaseLocation; }; namespace Util @@ -38,25 +48,45 @@ namespace UnitTests } } - struct PathDependencyDeletionTest - : UnitTest::ScopedAllocatorSetupFixture - , UnitTest::TraceBusRedirector + struct PathDependencyBase + : UnitTest::TraceBusRedirector { - void SetUp() override; - void TearDown() override; + void Init(); + void Destroy(); QTemporaryDir m_tempDir; AZStd::string m_databaseLocation; - ::testing::NiceMock m_databaseLocationListener; + MockDatabaseLocationListener m_databaseLocationListener; AZStd::shared_ptr m_stateData; AZStd::unique_ptr m_platformConfig; + AZStd::unique_ptr m_serializeContext; + AZ::Entity* m_jobManagerEntity{}; + AZ::ComponentDescriptor* m_descriptor{}; }; - void PathDependencyDeletionTest::SetUp() + struct PathDependencyDeletionTest + : UnitTest::ScopedAllocatorSetupFixture + , PathDependencyBase + { + void SetUp() override + { + PathDependencyBase::Init(); + } + + void TearDown() override + { + PathDependencyBase::Destroy(); + } + }; + + void PathDependencyBase::Init() { using namespace ::testing; using namespace AzToolsFramework::AssetDatabase; + ::UnitTest::TestRunner::Instance().m_suppressAsserts = false; + ::UnitTest::TestRunner::Instance().m_suppressErrors = false; + BusConnect(); QDir tempPath(m_tempDir.path()); @@ -68,21 +98,39 @@ namespace UnitTests // ":memory:" databases are one-instance-only, and even if another connection is opened to ":memory:" it would // not share with others created using ":memory:" and get a unique database instead. m_databaseLocation = tempPath.absoluteFilePath("test_database.sqlite").toUtf8().constData(); - - ON_CALL(m_databaseLocationListener, GetAssetDatabaseLocation(_)) - .WillByDefault( - DoAll( // set the 0th argument ref (string) to the database location and return true. - SetArgReferee<0>(m_databaseLocation), - Return(true))); + m_databaseLocationListener.m_databaseLocation = m_databaseLocation; m_stateData = AZStd::shared_ptr(new AssetProcessor::AssetDatabaseConnection()); m_stateData->OpenDatabase(); m_platformConfig = AZStd::make_unique(); + + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + m_serializeContext = AZStd::make_unique(); + m_descriptor = AZ::JobManagerComponent::CreateDescriptor(); + m_descriptor->Reflect(m_serializeContext.get()); + + m_jobManagerEntity = aznew AZ::Entity{}; + m_jobManagerEntity->CreateComponent(); + m_jobManagerEntity->Init(); + m_jobManagerEntity->Activate(); } - void PathDependencyDeletionTest::TearDown() + void PathDependencyBase::Destroy() { + m_stateData = nullptr; + m_platformConfig = nullptr; + + m_jobManagerEntity->Deactivate(); + delete m_jobManagerEntity; + + delete m_descriptor; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + BusDisconnect(); } @@ -91,7 +139,7 @@ namespace UnitTests using namespace AzToolsFramework::AssetDatabase; // Add a product to the db with an unmet dependency - ScanFolderDatabaseEntry scanFolder("folder", "test", "test", ""); + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); m_stateData->SetScanFolder(scanFolder); SourceDatabaseEntry source1, source2; @@ -110,7 +158,8 @@ namespace UnitTests Util::CreateSourceJobAndProduct(m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.txt", "product2.jpg"); - manager.RetryDeferredDependencies(source2); + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); } TEST_F(PathDependencyDeletionTest, ExistingSourceWithUnmetDependency_RemovedFromDB_DependentProductCreatedWithoutError) @@ -118,7 +167,7 @@ namespace UnitTests using namespace AzToolsFramework::AssetDatabase; // Add a product to the db with an unmet dependency - ScanFolderDatabaseEntry scanFolder("folder", "test", "test", ""); + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); m_stateData->SetScanFolder(scanFolder); SourceDatabaseEntry source1, source2; @@ -137,7 +186,8 @@ namespace UnitTests Util::CreateSourceJobAndProduct(m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.txt", "product2.jpg"); - manager.RetryDeferredDependencies(source2); + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); } TEST_F(PathDependencyDeletionTest, NewSourceWithUnmetDependency_RemovedFromDB_DependentSourceCreatedWithoutError) @@ -147,7 +197,7 @@ namespace UnitTests AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); // Add a product to the db with an unmet dependency - ScanFolderDatabaseEntry scanFolder("folder", "test", "test", ""); + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); m_stateData->SetScanFolder(scanFolder); SourceDatabaseEntry source1, source2; @@ -166,7 +216,8 @@ namespace UnitTests Util::CreateSourceJobAndProduct(m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.txt", "product2.jpg"); - manager.RetryDeferredDependencies(source2); + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); } TEST_F(PathDependencyDeletionTest, NewSourceWithUnmetDependency_RemovedFromDB_DependentProductCreatedWithoutError) @@ -176,7 +227,7 @@ namespace UnitTests AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); // Add a product to the db with an unmet dependency - ScanFolderDatabaseEntry scanFolder("folder", "test", "test", ""); + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); m_stateData->SetScanFolder(scanFolder); SourceDatabaseEntry source1, source2; @@ -195,7 +246,8 @@ namespace UnitTests Util::CreateSourceJobAndProduct(m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.txt", "product2.jpg"); - manager.RetryDeferredDependencies(source2); + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); } TEST_F(PathDependencyDeletionTest, NewSourceWithUnmetDependency_Wildcard_RemovedFromDB_DependentSourceCreatedWithoutError) @@ -205,7 +257,7 @@ namespace UnitTests AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); // Add a product to the db with an unmet dependency - ScanFolderDatabaseEntry scanFolder("folder", "test", "test", ""); + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); m_stateData->SetScanFolder(scanFolder); SourceDatabaseEntry source1, source2; @@ -224,6 +276,266 @@ namespace UnitTests Util::CreateSourceJobAndProduct(m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.txt", "product2.jpg"); - manager.RetryDeferredDependencies(source2); + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); } + + using PathDependencyTests = PathDependencyDeletionTest; + + TEST_F(PathDependencyTests, SourceAndProductHaveSameName_SourceFileDependency_MatchesSource) + { + using namespace AzToolsFramework::AssetDatabase; + + AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); + + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); + m_stateData->SetScanFolder(scanFolder); + + SourceDatabaseEntry source1, source2; + JobDatabaseEntry job1, job2; + ProductDatabaseEntry product1, product2, product3; + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, source1, job1, product1, "source1.txt", "product1.jpg"); + + AssetBuilderSDK::ProductPathDependencySet set; + set.insert(AssetBuilderSDK::ProductPathDependency("*.xml", AssetBuilderSDK::ProductPathDependencyType::SourceFile)); + + manager.SaveUnresolvedDependenciesToDatabase(set, product1, "pc"); + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.xml", "source2.xml"); + + // Create a 2nd product for this source + product3 = ProductDatabaseEntry{ job2.m_jobID, product2.m_subID + 1, "source2.txt", AZ::Data::AssetType::CreateRandom() }; + ASSERT_TRUE(m_stateData->SetProduct(product3)); + + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); + + ProductDependencyDatabaseEntryContainer productDependencies; + m_stateData->GetProductDependencies(productDependencies); + + EXPECT_EQ(productDependencies.size(), 3); + } + + TEST_F(PathDependencyTests, SourceAndProductHaveSameName_ProductFileDependency_MatchesProduct) + { + using namespace AzToolsFramework::AssetDatabase; + + AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); + + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); + m_stateData->SetScanFolder(scanFolder); + + SourceDatabaseEntry source1, source2; + JobDatabaseEntry job1, job2; + ProductDatabaseEntry product1, product2, product3; + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, source1, job1, product1, "source1.txt", "product1.jpg"); + + AssetBuilderSDK::ProductPathDependencySet set; + set.insert(AssetBuilderSDK::ProductPathDependency("*.xml", AssetBuilderSDK::ProductPathDependencyType::ProductFile)); + + manager.SaveUnresolvedDependenciesToDatabase(set, product1, "pc"); + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, source2, job2, product2, "source2.xml", "source2.xml"); + + // Create a 2nd product for this source + product3 = ProductDatabaseEntry{job2.m_jobID, product2.m_subID + 1, "source2.txt", AZ::Data::AssetType::CreateRandom()}; + ASSERT_TRUE(m_stateData->SetProduct(product3)); + + manager.QueueSourceForDependencyResolution(source2); + manager.ProcessQueuedDependencyResolves(); + + ProductDependencyDatabaseEntryContainer productDependencies; + m_stateData->GetProductDependencies(productDependencies); + + EXPECT_EQ(productDependencies.size(), 2); + } + + struct PathDependencyBenchmarks + : UnitTest::ScopedAllocatorFixture + , PathDependencyBase + { + static inline constexpr int NumTestDependencies = 4; // Must be a multiple of 4 + static inline constexpr int NumTestProducts = 2; // Must be a multiple of 2 + + AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer m_products; + AzToolsFramework::AssetDatabase::SourceDatabaseEntry m_source1, m_source2, m_source4; + AzToolsFramework::AssetDatabase::JobDatabaseEntry m_job1, m_job2, m_job4; + AzToolsFramework::AssetDatabase::ProductDatabaseEntry m_product1, m_product2, m_product4; + AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer m_dependencies; + + void SetupTestData() + { + using namespace AzToolsFramework::AssetDatabase; + + ScanFolderDatabaseEntry scanFolder("folder", "test", "test", 0); + ASSERT_TRUE(m_stateData->SetScanFolder(scanFolder)); + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, m_source1, m_job1, m_product1, "source1.txt", "product1.jpg"); + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, m_source4, m_job4, m_product4, "source4.txt", "product4.jpg"); + + for (int i = 0; i < NumTestDependencies / 2; ++i) + { + m_dependencies.emplace_back( + m_product1.m_productID, AZ::Uuid::CreateNull(), 0, 0, "pc", 0, + AZStd::string::format("folder/folder2/%d_*2.jpg", i).c_str()); + ++i; + m_dependencies.emplace_back( + m_product1.m_productID, AZ::Uuid::CreateNull(), 0, 0, "mac", 0, + AZStd::string::format("folder/folder2/%d_*2.jpg", i).c_str()); + } + + for (int i = 0; i < NumTestDependencies / 2; ++i) + { + m_dependencies.emplace_back( + m_product4.m_productID, AZ::Uuid::CreateNull(), 0, 0, "pc", 0, + AZStd::string::format("folder/folder2/%d_*2.jpg", i).c_str()); + ++i; + m_dependencies.emplace_back( + m_product4.m_productID, AZ::Uuid::CreateNull(), 0, 0, "mac", 0, + AZStd::string::format("folder/folder2/%d_*2.jpg", i).c_str()); + } + + ASSERT_TRUE(m_stateData->SetProductDependencies(m_dependencies)); + + Util::CreateSourceJobAndProduct( + m_stateData.get(), scanFolder.m_scanFolderID, m_source2, m_job2, m_product2, "source2.txt", "product2.jpg"); + + auto job3 = JobDatabaseEntry( + m_source2.m_sourceID, "jobkey", 1111, "mac", AZ::Uuid::CreateRandom(), AzToolsFramework::AssetSystem::JobStatus::Completed, + 4444); + ASSERT_TRUE(m_stateData->SetJob(job3)); + + for (int i = 0; i < NumTestProducts; ++i) + { + m_products.emplace_back( + m_job2.m_jobID, i, AZStd::string::format("pc/folder/folder2/%d_product2.jpg", i).c_str(), + AZ::Data::AssetType::CreateRandom()); + ++i; + m_products.emplace_back( + job3.m_jobID, i, AZStd::string::format("mac/folder/folder2/%d_product2.jpg", i).c_str(), + AZ::Data::AssetType::CreateRandom()); + } + + ASSERT_TRUE(m_stateData->SetProducts(m_products)); + } + + void DoTest() + { + AssetProcessor::PathDependencyManager manager(m_stateData, m_platformConfig.get()); + + manager.QueueSourceForDependencyResolution(m_source2); + manager.ProcessQueuedDependencyResolves(); + } + + void VerifyResult() + { + using namespace AzToolsFramework::AssetDatabase; + + ProductDependencyDatabaseEntryContainer productDependencies; + m_stateData->GetProductDependencies(productDependencies); + + for (int i = 0; i < NumTestDependencies / 2 && i < NumTestProducts; ++i) + { + const auto& product = m_products[i]; + int found = 0; + + for (const auto& unresolvedProductDependency : productDependencies) + { + if (unresolvedProductDependency.m_dependencySourceGuid == m_source2.m_sourceGuid && + unresolvedProductDependency.m_dependencySubID == product.m_subID && + unresolvedProductDependency.m_productPK == m_product1.m_productID) + { + ++found; + } + + if (unresolvedProductDependency.m_dependencySourceGuid == m_source2.m_sourceGuid && + unresolvedProductDependency.m_dependencySubID == product.m_subID && + unresolvedProductDependency.m_productPK == m_product4.m_productID) + { + ++found; + } + + if (found == 2) + break; + } + + EXPECT_TRUE(found == 2) << product.m_productName.c_str() << " was not found"; + } + + EXPECT_EQ(productDependencies.size(), NumTestDependencies * 2); + } + }; + + // For some reason, BENCHMARK_F doesn't seem to call the destructor + // So we'll wrap the class and handle the new/delete ourselves + struct PathDependencyBenchmarksWrapperClass : public ::benchmark::Fixture + { + void SetUp([[maybe_unused]] const benchmark::State& st) override + { + m_benchmarks = new PathDependencyBenchmarks(); + m_benchmarks->Init(); + m_benchmarks->SetupTestData(); + } + + void SetUp([[maybe_unused]] benchmark::State& st) override + { + m_benchmarks = new PathDependencyBenchmarks(); + m_benchmarks->Init(); + m_benchmarks->SetupTestData(); + } + + void TearDown([[maybe_unused]] benchmark::State& st) override + { + m_benchmarks->Destroy(); + delete m_benchmarks; + } + + void TearDown([[maybe_unused]] const benchmark::State& st) override + { + m_benchmarks->Destroy(); + delete m_benchmarks; + } + + PathDependencyBenchmarks* m_benchmarks = {}; + }; + + struct PathDependencyTestValidation + : PathDependencyBenchmarks, ::testing::Test + { + void SetUp() override + { + PathDependencyBase::Init(); + } + void TearDown() override + { + PathDependencyBase::Destroy(); + } + }; + + TEST_F(PathDependencyTestValidation, DeferredWildcardDependencyResolution) + { + SetupTestData(); + DoTest(); + VerifyResult(); + } + + BENCHMARK_F(PathDependencyBenchmarksWrapperClass, BM_DeferredWildcardDependencyResolution)(benchmark::State& state) + { + for (auto _ : state) + { + m_benchmarks->m_stateData->SetProductDependencies(m_benchmarks->m_dependencies); + + m_benchmarks->DoTest(); + } + } + } diff --git a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp index d7801abb3d..8d52ba23bd 100644 --- a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp @@ -793,9 +793,9 @@ namespace UnitTests TEST_F(SourceFileRelocatorTest, TestInterface) { - auto* interface = AZ::Interface::Get(); + auto* sourceFileRelocator = AZ::Interface::Get(); - ASSERT_NE(interface, nullptr); + ASSERT_NE(sourceFileRelocator, nullptr); } TEST_F(SourceFileRelocatorTest, Move_Real_Succeeds) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 58f76f8da6..0908d0fdb9 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -15,6 +15,10 @@ #include #include +#include +#include +#include +#include using namespace AssetProcessor; @@ -26,6 +30,7 @@ public: friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies); friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_DeferredResolution); + friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, SameFilenameForAllPlatforms); friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath); @@ -176,8 +181,21 @@ void AssetProcessorManagerTest::SetUp() AssetProcessorTest::SetUp(); + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + m_data = AZStd::make_unique(); + m_data->m_serializeContext = AZStd::make_unique(); + + m_data->m_descriptor = AZ::JobManagerComponent::CreateDescriptor(); + m_data->m_descriptor->Reflect(m_data->m_serializeContext.get()); + + m_data->m_jobManagerEntity = aznew AZ::Entity{}; + m_data->m_jobManagerEntity->CreateComponent(); + m_data->m_jobManagerEntity->Init(); + m_data->m_jobManagerEntity->Activate(); + m_config.reset(new AssetProcessor::PlatformConfiguration()); m_mockApplicationManager.reset(new AssetProcessor::MockApplicationManager()); @@ -256,6 +274,10 @@ void AssetProcessorManagerTest::SetUp() void AssetProcessorManagerTest::TearDown() { + m_data->m_jobManagerEntity->Deactivate(); + delete m_data->m_jobManagerEntity; + delete m_data->m_descriptor; + m_data = nullptr; QObject::disconnect(m_idleConnection); @@ -271,6 +293,9 @@ void AssetProcessorManagerTest::TearDown() m_qApp.reset(); m_scopeDir.reset(); + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + AssetProcessor::AssetProcessorTest::TearDown(); } @@ -1270,7 +1295,8 @@ TEST_F(AbsolutePathProductDependencyTest, AbsolutePathProductDependency_RetryDef AZ::Data::AssetType::CreateNull()); m_assetProcessorManager->m_stateData->SetProduct(matchingProductForDependency); - m_assetProcessorManager->m_pathDependencyManager->RetryDeferredDependencies(matchingSource); + m_assetProcessorManager->m_pathDependencyManager->QueueSourceForDependencyResolution(matchingSource); + m_assetProcessorManager->m_pathDependencyManager->ProcessQueuedDependencyResolves(); // The product dependency ID shouldn't change when it goes from unresolved to resolved. AZStd::vector resolvedProductDependencies; @@ -1405,6 +1431,7 @@ bool PathDependencyTest::ProcessAsset(TestAsset& asset, const OutputAssetSet& ou // tell the APM that the asset has been processed and allow it to bubble through its event queue: m_isIdling = false; m_assetProcessorManager->AssetProcessed(capturedDetails[jobSet].m_jobEntry, processJobResponse); + m_assetProcessorManager->CheckForIdle(); jobSet++; } @@ -2646,6 +2673,44 @@ TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDepende ASSERT_NE(SearchDependencies(dependencyContainer, asset1.m_products[0]), SearchDependencies(dependencyContainer, asset1.m_products[1])); } +TEST_F(MultiplatformPathDependencyTest, SameFilenameForAllPlatforms) +{ + TestAsset asset2("asset2"); + bool result = ProcessAsset( + asset2, { { ".output" }, { ".output" } }, { { "*1.output", AssetBuilderSDK::ProductPathDependencyType::ProductFile } }, "subfolder1/", + ".txt"); + + ASSERT_TRUE(result); + + TestAsset asset1("asset1"); + result = ProcessAsset(asset1, { { ".output" }, { ".output" } }, {}); + + ASSERT_TRUE(result); + + AssetDatabaseConnection* sharedConnection = m_assetProcessorManager->m_stateData.get(); + ASSERT_TRUE(sharedConnection); + + AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; + + sharedConnection->GetProductDependencies(dependencyContainer); + int resolvedCount = 0; + int unresolvedCount = 0; + for (const auto& dep : dependencyContainer) + { + if (dep.m_unresolvedPath.empty()) + { + resolvedCount++; + } + else + { + unresolvedCount++; + } + } + ASSERT_EQ(resolvedCount, 2); + ASSERT_EQ(unresolvedCount, 2); + VerifyDependencies(dependencyContainer, { asset1.m_products[0], asset1.m_products[1] }, { "*1.output", "*1.output" }); +} + TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath) { // One product will be pc, one will be console (order is non-deterministic) @@ -4185,7 +4250,7 @@ TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeleteFails) auto theFile = m_data->m_absolutePath[1].toUtf8(); const char* theFileString = theFile.constData(); auto [sourcePath, productPath] = *m_data->m_productPaths.find(theFileString); - + { QFile file(theFileString); file.remove(); @@ -4257,7 +4322,7 @@ TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeletesWhenReleased) EXPECT_FALSE(QFile::exists(productPath)); EXPECT_EQ(m_data->m_deletedSources.size(), 1); - + EXPECT_GT(m_deleteCounter, 1); // Make sure the AP tried more than once to delete the file m_errorAbsorber->ExpectAsserts(0); } @@ -5364,7 +5429,7 @@ AZStd::vector WildcardSourceDependencyTest::FileAddedTest(const Q void WildcardSourceDependencyTest::SetUp() { AssetProcessorManagerTest::SetUp(); - + QDir tempPath(m_tempDir.path()); // Add a non-recursive scan folder. Only files directly inside of this folder should be picked up, subfolders are ignored @@ -5454,7 +5519,7 @@ TEST_F(WildcardSourceDependencyTest, Relative_Broad) { // Expect all files except for the 2 invalid ones (e and f) AZStd::vector resolvedPaths; - + ASSERT_TRUE(Test("*.foo", resolvedPaths)); ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "b.foo", "folder/one/c.foo", "folder/one/d.foo", "1a.foo", "1b.foo")); } @@ -5585,7 +5650,7 @@ TEST_F(WildcardSourceDependencyTest, Relative_CacheFolder) { AZStd::vector resolvedPaths; QDir tempPath(m_tempDir.path()); - + ASSERT_TRUE(Test("*cache.foo", resolvedPaths)); ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); } @@ -5635,7 +5700,7 @@ TEST_F(WildcardSourceDependencyTest, FilesRemovedAfterInitialCache) ASSERT_EQ(excludedFolders.size(), 3); } - + m_fileStateCache->SignalDeleteEvent(tempPath.absoluteFilePath("subfolder2/redirected/folder/two/ignored")); const auto& excludedFolders = excludedFolderCacheInterface->GetExcludedFolders(); diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h index 7bbef41f44..c532b08016 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include "resourcecompiler/rccontroller.h" @@ -39,7 +41,7 @@ class AssetProcessorManagerTest : public AssetProcessor::AssetProcessorTest { public: - + AssetProcessorManagerTest(); virtual ~AssetProcessorManagerTest() @@ -67,16 +69,19 @@ protected: { AZStd::string m_databaseLocation; ::testing::NiceMock m_databaseLocationListener; + AZ::Entity* m_jobManagerEntity{}; + AZ::ComponentDescriptor* m_descriptor{}; + AZStd::unique_ptr m_serializeContext; }; AZStd::unique_ptr m_data; - + private: int m_argc; char** m_argv; AZStd::unique_ptr m_scopeDir; - AZStd::unique_ptr m_qApp; + AZStd::unique_ptr m_qApp; }; struct AbsolutePathProductDependencyTest diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 7543e9ec8b..c62d822171 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -51,7 +51,7 @@ namespace AssetProcessor case AZ::SettingsRegistryInterface::VisitAction::Begin: { // Only continue traversal if the path is exactly the AssetProcessorSettingsKey (which indicates the start of traversal) - // or if a "Platform *" object and it's children are being traversed + // or if a "Platform *" object and it's children are being traversed if (jsonPath == AssetProcessorSettingsKey) { return AZ::SettingsRegistryInterface::VisitResponse::Continue; @@ -631,7 +631,7 @@ namespace AssetProcessor for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms) { AZStd::string_view currentRCParams = assetRecognizer.m_defaultParams; - // The "/Amazon/AssetProcessor/Settings/RC */" entry will be queried + // The "/Amazon/AssetProcessor/Settings/RC */" entry will be queried AZ::IO::Path overrideParamsKey = AZ::IO::Path(AZ::IO::PosixPathSeparator); overrideParamsKey /= path; overrideParamsKey /= platform.m_identifier; @@ -644,7 +644,7 @@ namespace AssetProcessor } else { - // otherwise check for tags associated with the platform + // otherwise check for tags associated with the platform for (const AZStd::string& tag : platform.m_tags) { overrideParamsKey.ReplaceFilename(AZ::IO::PathView(tag)); @@ -1416,6 +1416,8 @@ namespace AssetProcessor return QString(); } + auto* fileStateInterface = AZ::Interface::Get(); + for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx) { AssetProcessor::ScanFolderInfo scanFolderInfo = m_scanFolders[pathIdx]; @@ -1430,7 +1432,7 @@ namespace AssetProcessor QDir rooted(scanFolderInfo.ScanPath()); QString absolutePath = rooted.absoluteFilePath(tempRelativeName); AssetProcessor::FileStateInfo fileStateInfo; - auto* fileStateInterface = AZ::Interface::Get(); + if (fileStateInterface) { if (fileStateInterface->GetFileInfo(absolutePath, &fileStateInfo)) @@ -1499,7 +1501,7 @@ namespace AssetProcessor QRegExp nameMatch{ posixRelativeName, Qt::CaseInsensitive, QRegExp::Wildcard }; AZStd::stack dirs; dirs.push(sourceFolderDir.absolutePath()); - + while (!dirs.empty()) { QString absolutePath = dirs.top(); @@ -1528,7 +1530,7 @@ namespace AssetProcessor continue; } } - + QString pathMatch{ sourceFolderDir.relativeFilePath(dirIterator.filePath()) }; if (nameMatch.exactMatch(pathMatch)) { diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index 6bcd0dec01..a6cbfd8077 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -131,7 +131,7 @@ namespace AssetUtilsInternal } } } while (!timer.hasExpired(waitTimeInSeconds * 1000)); //We will keep retrying until the timer has expired the inputted timeout - + // once we're done, regardless of success or failure, we 'unlock' those files for further process. // if we failed, also re-trigger them to rebuild (the bool param at the end of the ebus call) QString normalized = AssetUtilities::NormalizeFilePath(outputFile); @@ -870,23 +870,27 @@ namespace AssetUtilities return true; } - QString StripAssetPlatform(AZStd::string_view relativeProductPath) + AZStd::string_view StripAssetPlatformNoCopy(AZStd::string_view relativeProductPath) { // Skip over the assetPlatform path segment if it is matches one of the platform defaults // Otherwise return the path unchanged - AZStd::string_view strippedProductPath{ relativeProductPath }; - if (AZStd::optional pathSegment = AZ::StringFunc::TokenizeNext(strippedProductPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); - pathSegment.has_value()) + + AZStd::string_view originalPath = relativeProductPath; + AZStd::optional firstPathSegment = AZ::StringFunc::TokenizeNext(relativeProductPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); + + if (firstPathSegment && AzFramework::PlatformHelper::GetPlatformIdFromName(*firstPathSegment) != AzFramework::PlatformId::Invalid) { - AZ::IO::FixedMaxPathString assetPlatformSegmentLower{ *pathSegment }; - AZStd::to_lower(assetPlatformSegmentLower.begin(), assetPlatformSegmentLower.end()); - if (AzFramework::PlatformHelper::GetPlatformIdFromName(assetPlatformSegmentLower) != AzFramework::PlatformId::Invalid) - { - return QString::fromUtf8(strippedProductPath.data(), aznumeric_cast(strippedProductPath.size())); - } + return relativeProductPath; } - return QString::fromUtf8(relativeProductPath.data(), aznumeric_cast(relativeProductPath.size())); + return originalPath; + } + + QString StripAssetPlatform(AZStd::string_view relativeProductPath) + { + AZStd::string_view result = StripAssetPlatformNoCopy(relativeProductPath); + + return QString::fromUtf8(result.data(), aznumeric_cast(result.size())); } QString NormalizeFilePath(const QString& filePath) diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h index 46ec5d6145..18cf5422de 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h @@ -145,7 +145,7 @@ namespace AssetUtilities //! Strips the first "asset platform" from the first path segment of a relative product path //! This is meant for removing the asset platform for paths such as "pc/MyAssetFolder/MyAsset.asset" //! Therefore the result here becomes "MyAssetFolder/MyAsset" - //! + //! //! Similarly invoking this function on relative path that begins with the "server" platform //! "server/AssetFolder/Server.asset2" -> "AssetFolder/Server.asset2" //! This function does not strip an asset platform from anywhere, but the first path segment @@ -153,6 +153,10 @@ namespace AssetUtilities //! would return a copy of the relative path QString StripAssetPlatform(AZStd::string_view relativeProductPath); + //! Same as StripAssetPlatform, but does not perform any string copies + //! The return result is only valid for as long as the original input is valid + AZStd::string_view StripAssetPlatformNoCopy(AZStd::string_view relativeProductPath); + //! Converts all slashes to forward slashes, removes double slashes, //! replaces all indirections such as '.' or '..' as appropriate. //! On windows, the drive letter (if present) is converted to uppercase. diff --git a/Code/Tools/AzTestRunner/CMakeLists.txt b/Code/Tools/AzTestRunner/CMakeLists.txt index 5f3bb829a8..2bd74fa1a1 100644 --- a/Code/Tools/AzTestRunner/CMakeLists.txt +++ b/Code/Tools/AzTestRunner/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Code/Tools/CrashHandler/CMakeLists.txt b/Code/Tools/CrashHandler/CMakeLists.txt index 259a7d2891..db50741326 100644 --- a/Code/Tools/CrashHandler/CMakeLists.txt +++ b/Code/Tools/CrashHandler/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Code/Tools/LuaIDE/CMakeLists.txt b/Code/Tools/LuaIDE/CMakeLists.txt index 98c8d7f04b..58e0fe505a 100644 --- a/Code/Tools/LuaIDE/CMakeLists.txt +++ b/Code/Tools/LuaIDE/CMakeLists.txt @@ -10,6 +10,8 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) + ly_add_target( NAME LuaIDE APPLICATION NAMESPACE AZ @@ -18,7 +20,7 @@ ly_add_target( AUTORCC FILES_CMAKE lua_ide_files.cmake - Platform/${PAL_PLATFORM_NAME}/lua_ide_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_dir}/lua_ide_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PRIVATE . diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 35bdfe0031..7c436a3a70 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -1221,7 +1221,7 @@ namespace O3DE::ProjectManager auto result = ExecuteWithLockErrorHandling( [&] { - for (auto repoUri : m_manifest.attr("get_repos")()) + for (auto repoUri : m_manifest.attr("get_manifest_repos")()) { gemRepos.push_back(GetGemRepoInfo(repoUri)); } diff --git a/Code/Tools/RemoteConsole/CMakeLists.txt b/Code/Tools/RemoteConsole/CMakeLists.txt index d2685b2aea..b9a08650b6 100644 --- a/Code/Tools/RemoteConsole/CMakeLists.txt +++ b/Code/Tools/RemoteConsole/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME RemoteConsoleCore STATIC diff --git a/Code/Tools/SceneAPI/SceneData/CMakeLists.txt b/Code/Tools/SceneAPI/SceneData/CMakeLists.txt index 5507ada2b9..0d4ef4a5df 100644 --- a/Code/Tools/SceneAPI/SceneData/CMakeLists.txt +++ b/Code/Tools/SceneAPI/SceneData/CMakeLists.txt @@ -10,7 +10,7 @@ if (NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_add_target( NAME SceneData SHARED diff --git a/Code/Tools/TestImpactFramework/CMakeLists.txt b/Code/Tools/TestImpactFramework/CMakeLists.txt index 1cdf02d101..15d93b1a70 100644 --- a/Code/Tools/TestImpactFramework/CMakeLists.txt +++ b/Code/Tools/TestImpactFramework/CMakeLists.txt @@ -6,9 +6,9 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) -include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(PAL_TRAIT_TEST_IMPACT_FRAMEWORK_SUPPORTED) add_subdirectory(Runtime) diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/CMakeLists.txt b/Code/Tools/TestImpactFramework/Runtime/Code/CMakeLists.txt index 0b8432642a..f3262a26af 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/CMakeLists.txt +++ b/Code/Tools/TestImpactFramework/Runtime/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME TestImpact.Runtime.Static STATIC diff --git a/Gems/AWSClientAuth/CMakeLists.txt b/Gems/AWSClientAuth/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AWSClientAuth/CMakeLists.txt +++ b/Gems/AWSClientAuth/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AWSClientAuth/Code/CMakeLists.txt b/Gems/AWSClientAuth/Code/CMakeLists.txt index 1f0c119f5a..ac9d221f07 100644 --- a/Gems/AWSClientAuth/Code/CMakeLists.txt +++ b/Gems/AWSClientAuth/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AWSClientAuth.Static STATIC diff --git a/Gems/AWSClientAuth/gem.json b/Gems/AWSClientAuth/gem.json index 9c7188f103..d6729cee99 100644 --- a/Gems/AWSClientAuth/gem.json +++ b/Gems/AWSClientAuth/gem.json @@ -3,7 +3,8 @@ "display_name": "AWS Client Authorization", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", - "origin": "Amazon Web Services, Inc.", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "AWS Client Auth provides client authentication and AWS authorization solution.", "canonical_tags": [ @@ -15,6 +16,7 @@ "SDK" ], "icon_path": "preview.png", + "requirements": "", "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/", "dependencies": [ "AWSCore", diff --git a/Gems/AWSCore/CMakeLists.txt b/Gems/AWSCore/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AWSCore/CMakeLists.txt +++ b/Gems/AWSCore/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index 877696e26c..3911aefce6 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AWSCore.Static STATIC @@ -61,7 +61,7 @@ ly_create_alias( if (PAL_TRAIT_BUILD_HOST_TOOLS) - include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_traits_editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + include(${pal_dir}/PAL_traits_editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ly_add_target( NAME AWSCore.Editor.Static STATIC diff --git a/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h index d7b1f32461..2cacfb0d34 100644 --- a/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h +++ b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h @@ -7,4 +7,4 @@ */ #pragma once -#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0 +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 1 diff --git a/Gems/AWSCore/gem.json b/Gems/AWSCore/gem.json index 3bced07e8d..3bc8e6f77c 100644 --- a/Gems/AWSCore/gem.json +++ b/Gems/AWSCore/gem.json @@ -3,7 +3,8 @@ "display_name": "AWS Core", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", - "origin": "Amazon Web Services, Inc.", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The AWS Core Gem provides basic shared AWS functionality such as AWS SDK initialization and client configuration, and is automatically added when selecting any AWS feature Gem.", "canonical_tags": [ @@ -15,5 +16,8 @@ "SDK" ], "icon_path": "preview.png", - "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-core/" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-core/", + "dependencies": [ + ] } diff --git a/Gems/AWSGameLift/gem.json b/Gems/AWSGameLift/gem.json index 1ac65c4526..e1b80cb9fe 100644 --- a/Gems/AWSGameLift/gem.json +++ b/Gems/AWSGameLift/gem.json @@ -3,7 +3,8 @@ "display_name": "AWS GameLift", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", - "origin": "Amazon Web Services, Inc.", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The AWS GameLift Gem provides a framework to extend O3DE networking layer to work with GameLift resources via GameLift server and client SDK.", "canonical_tags": [ @@ -12,7 +13,7 @@ "user_tags": [ "AWS", "Framework", - "Network", + "Network", "SDK" ], "icon_path": "preview.png", diff --git a/Gems/AWSMetrics/gem.json b/Gems/AWSMetrics/gem.json index 054c3624c4..bd462edec3 100644 --- a/Gems/AWSMetrics/gem.json +++ b/Gems/AWSMetrics/gem.json @@ -3,7 +3,8 @@ "display_name": "AWS Metrics", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", - "origin": "Amazon Web Services, Inc.", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The AWS Metrics Gem provides a solution for AWS metrics submission and analytics.", "canonical_tags": [ @@ -15,6 +16,7 @@ "SDK" ], "icon_path": "preview.png", + "requirements": "", "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/", "dependencies": [ "AWSCore" diff --git a/Gems/Achievements/CMakeLists.txt b/Gems/Achievements/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Achievements/CMakeLists.txt +++ b/Gems/Achievements/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Achievements/Code/CMakeLists.txt b/Gems/Achievements/Code/CMakeLists.txt index 2d00ac2fb2..5ac43e9736 100644 --- a/Gems/Achievements/Code/CMakeLists.txt +++ b/Gems/Achievements/Code/CMakeLists.txt @@ -6,16 +6,16 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME Achievements.Static STATIC NAMESPACE Gem PLATFORM_INCLUDE_FILES - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake FILES_CMAKE achievements_files.cmake - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PUBLIC Include diff --git a/Gems/Achievements/gem.json b/Gems/Achievements/gem.json index 8180584500..5fc83aefe2 100644 --- a/Gems/Achievements/gem.json +++ b/Gems/Achievements/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Achievements Gem provides a target platform agnostic interface for retrieving achievement details and unlocking achievements.", "canonical_tags": [ diff --git a/Gems/AssetValidation/gem.json b/Gems/AssetValidation/gem.json index 55cdffb9f3..de1d36ffb4 100644 --- a/Gems/AssetValidation/gem.json +++ b/Gems/AssetValidation/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Asset Validation Gem provides seed-related commands to ensure assets have valid seeds for asset bundling.", "canonical_tags": [ diff --git a/Gems/Atom/Asset/CMakeLists.txt b/Gems/Atom/Asset/CMakeLists.txt deleted file mode 100644 index 3ed20148a2..0000000000 --- a/Gems/Atom/Asset/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -add_subdirectory(ImageProcessingAtom) -add_subdirectory(Shader) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/CMakeLists.txt b/Gems/Atom/Asset/ImageProcessingAtom/CMakeLists.txt index 54543a000a..92079d35be 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/CMakeLists.txt +++ b/Gems/Atom/Asset/ImageProcessingAtom/CMakeLists.txt @@ -7,4 +7,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt index 982ec43715..74876994f6 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt @@ -26,15 +26,15 @@ set(pal_tools_include_dirs) foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(pal_tools_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform}) + o3de_pal_dir(pal_tools_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) list(APPEND pal_tools_include_dirs ${pal_tools_source_dir}) list(APPEND platform_tools_files ${pal_tools_source_dir}/pal_tools_${enabled_platform_lowercase}.cmake) list(APPEND pal_tools_include_files ${pal_tools_source_dir}/pal_tools_${enabled_platform_lowercase}_files.cmake) endforeach() -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME ImageProcessingAtom.Editor.Static STATIC diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp index 29d9b21775..4772a94ffa 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp @@ -226,6 +226,14 @@ namespace ImageProcessingAtom MultiplatformTextureSettings settings; PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList(); PresetName suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath); + + // If the suggested preset doesn't exist (or was failed to be loaded), return empty texture settings + if (BuilderSettingManager::Instance()->GetPreset(suggestedPreset) == nullptr) + { + AZ_Error("Image Processing", false, "Failed to find suggested preset [%s]", suggestedPreset.GetCStr()); + return settings; + } + for (PlatformName& platform : platformsList) { TextureSettings textureSettings; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index 5e021a3fdd..55a6c1ea8f 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -241,8 +241,7 @@ namespace ImageProcessingAtom // Reload preset if it was changed ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetName); - AZStd::string_view filePath; - auto presetSettings = BuilderSettingManager::Instance()->GetPreset(presetName, /*default platform*/"", &filePath); + auto presetSettings = BuilderSettingManager::Instance()->GetPreset(presetName, /*default platform*/""); AssetBuilderSDK::SourceFileDependency sourceFileDependency; sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute; @@ -274,6 +273,32 @@ namespace ImageProcessingAtom } } + void ReloadPresetIfNeeded(PresetName presetName) + { + // Reload preset if it was changed + ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetName); + + auto presetSettings = BuilderSettingManager::Instance()->GetPreset(presetName, /*default platform*/""); + + if (presetSettings) + { + // handle special case here + // Cubemap setting may reference some other presets + if (presetSettings->m_cubemapSetting) + { + if (presetSettings->m_cubemapSetting->m_generateIBLDiffuse && !presetSettings->m_cubemapSetting->m_iblDiffusePreset.IsEmpty()) + { + ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetSettings->m_cubemapSetting->m_iblDiffusePreset); + } + + if (presetSettings->m_cubemapSetting->m_generateIBLSpecular && !presetSettings->m_cubemapSetting->m_iblSpecularPreset.IsEmpty()) + { + ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetSettings->m_cubemapSetting->m_iblSpecularPreset); + } + } + } + } + // this happens early on in the file scanning pass // this function should consistently always create the same jobs, and should do no checking whether the job is up to date or not - just be consistent. void ImageBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) @@ -336,6 +361,11 @@ namespace ImageProcessingAtom // Do conversion and get exported file's path if (needConversion) { + + // Handles preset changes + auto presetName = GetImagePreset(request.m_fullPath); + ReloadPresetIfNeeded(presetName); + AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Performing image conversion: %s\n", request.m_fullPath.c_str()); ImageConvertProcess* process = CreateImageConvertProcess(request.m_fullPath, request.m_tempDirPath, request.m_jobDescription.GetPlatformIdentifier(), response.m_outputProducts); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/gem.json b/Gems/Atom/Asset/ImageProcessingAtom/gem.json index 4fd437d298..c2af4b7e7e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/gem.json +++ b/Gems/Atom/Asset/ImageProcessingAtom/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom_RHI", diff --git a/Gems/Atom/Asset/Shader/CMakeLists.txt b/Gems/Atom/Asset/Shader/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Asset/Shader/CMakeLists.txt +++ b/Gems/Atom/Asset/Shader/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt index ed5aa45bbf..9ebd5e6d2d 100644 --- a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt @@ -10,8 +10,8 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) #for PAL_TRAIT_BUILD_ATOM_ASSET_SHADER_SUPPORTED @@ -71,7 +71,7 @@ ly_add_target( set(builder_tools_include_files) foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(builder_tools_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform}) + o3de_pal_dir(builder_tools_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) list(APPEND builder_tools_include_files ${builder_tools_source_dir}/platform_builders_${enabled_platform_lowercase}.cmake) endforeach() diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 5eaa0d9ddb..8dc67bb3d1 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -241,7 +241,7 @@ namespace AZ { // Need to get the name of the shader file from the template so that we can preprocess the shader data and setup // source file dependencies. - if (!RPI::JsonUtils::LoadObjectFromFile(variantListFullPath, shaderVariantList)) + if (!RPI::JsonUtils::LoadObjectFromFile(variantListFullPath, shaderVariantList, AZStd::numeric_limits::max())) { AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse Shader Variant List Descriptor JSON from [%s]", variantListFullPath.c_str()); return LoadResult{LoadResult::Code::Error}; @@ -635,7 +635,7 @@ namespace AZ AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), variantListFullPath, true); RPI::ShaderVariantListSourceData shaderVariantListDescriptor; - if (!RPI::JsonUtils::LoadObjectFromFile(variantListFullPath, shaderVariantListDescriptor)) + if (!RPI::JsonUtils::LoadObjectFromFile(variantListFullPath, shaderVariantListDescriptor, AZStd::numeric_limits::max())) { AZ_Assert(false, "Failed to parse Shader Variant List Descriptor JSON [%s]", variantListFullPath.c_str()); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; diff --git a/Gems/Atom/Asset/Shader/gem.json b/Gems/Atom/Asset/Shader/gem.json index 9f59c65f78..8b4ba4fb0d 100644 --- a/Gems/Atom/Asset/Shader/gem.json +++ b/Gems/Atom/Asset/Shader/gem.json @@ -4,13 +4,17 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Atom Shader Builder", "canonical_tags": [ "Gem" ], - "user_tags": [], + "user_tags": [ + "AtomShader" + ], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI", "Atom_RPI" diff --git a/Gems/Atom/Bootstrap/CMakeLists.txt b/Gems/Atom/Bootstrap/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Bootstrap/CMakeLists.txt +++ b/Gems/Atom/Bootstrap/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Bootstrap/Code/CMakeLists.txt b/Gems/Atom/Bootstrap/Code/CMakeLists.txt index fd9df96124..0ba8d17865 100644 --- a/Gems/Atom/Bootstrap/Code/CMakeLists.txt +++ b/Gems/Atom/Bootstrap/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME Atom_Bootstrap.Headers HEADERONLY diff --git a/Gems/Atom/Bootstrap/gem.json b/Gems/Atom/Bootstrap/gem.json index df615366da..543efe0f34 100644 --- a/Gems/Atom/Bootstrap/gem.json +++ b/Gems/Atom/Bootstrap/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI" ] diff --git a/Gems/Atom/CMakeLists.txt b/Gems/Atom/CMakeLists.txt index a71afa64e0..b5dd311e5a 100644 --- a/Gems/Atom/CMakeLists.txt +++ b/Gems/Atom/CMakeLists.txt @@ -6,12 +6,10 @@ # # -add_subdirectory(Asset) -add_subdirectory(Bootstrap) -add_subdirectory(Component) -add_subdirectory(Feature) -add_subdirectory(RHI) -add_subdirectory(RPI) +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Tools) add_subdirectory(Utils) diff --git a/Gems/Atom/Component/CMakeLists.txt b/Gems/Atom/Component/CMakeLists.txt deleted file mode 100644 index 8b867b8c67..0000000000 --- a/Gems/Atom/Component/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -add_subdirectory(DebugCamera) diff --git a/Gems/Atom/Component/DebugCamera/CMakeLists.txt b/Gems/Atom/Component/DebugCamera/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Component/DebugCamera/CMakeLists.txt +++ b/Gems/Atom/Component/DebugCamera/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Component/DebugCamera/Code/Include/Atom/Component/DebugCamera/CameraComponent.h b/Gems/Atom/Component/DebugCamera/Code/Include/Atom/Component/DebugCamera/CameraComponent.h index fb9c543bca..47254bcdc5 100644 --- a/Gems/Atom/Component/DebugCamera/Code/Include/Atom/Component/DebugCamera/CameraComponent.h +++ b/Gems/Atom/Component/DebugCamera/Code/Include/Atom/Component/DebugCamera/CameraComponent.h @@ -104,6 +104,10 @@ namespace AZ void SetOrthographicHalfWidth(float halfWidth) override; void MakeActiveView() override; bool IsActiveView() override; + AZ::Vector3 ScreenToWorld(const AZ::Vector2& screenPosition, float depth) override; + AZ::Vector3 ScreenNdcToWorld(const AZ::Vector2& screenPosition, float depth) override; + AZ::Vector2 WorldToScreen(const AZ::Vector3& worldPosition) override; + AZ::Vector2 WorldToScreenNdc(const AZ::Vector3& worldPosition) override; // RPI::WindowContextNotificationBus overrides... void OnViewportResized(uint32_t width, uint32_t height) override; diff --git a/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp b/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp index f3123e2b38..c4420dc417 100644 --- a/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp +++ b/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp @@ -245,7 +245,7 @@ namespace AZ AZ_Assert(false, "DebugCamera does not support orthographic projection"); } - void CameraComponent::MakeActiveView() + void CameraComponent::MakeActiveView() { // do nothing } @@ -255,6 +255,30 @@ namespace AZ return false; } + AZ::Vector3 CameraComponent::ScreenToWorld([[maybe_unused]] const AZ::Vector2& screenPosition, [[maybe_unused]] float depth) + { + // not implemented + return AZ::Vector3::CreateZero(); + } + + AZ::Vector3 CameraComponent::ScreenNdcToWorld([[maybe_unused]] const AZ::Vector2& screenPosition, [[maybe_unused]] float depth) + { + // not implemented + return AZ::Vector3::CreateZero(); + } + + AZ::Vector2 CameraComponent::WorldToScreen([[maybe_unused]] const AZ::Vector3& worldPosition) + { + // not implemented + return AZ::Vector2::CreateZero(); + } + + AZ::Vector2 CameraComponent::WorldToScreenNdc([[maybe_unused]] const AZ::Vector3& worldPosition) + { + // not implemented + return AZ::Vector2::CreateZero(); + } + void CameraComponent::OnViewportResized(uint32_t width, uint32_t height) { AZ_UNUSED(width); diff --git a/Gems/Atom/Component/DebugCamera/gem.json b/Gems/Atom/Component/DebugCamera/gem.json index 8eab74f41d..74d88a21b6 100644 --- a/Gems/Atom/Component/DebugCamera/gem.json +++ b/Gems/Atom/Component/DebugCamera/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI" ] diff --git a/Gems/Atom/Feature/CMakeLists.txt b/Gems/Atom/Feature/CMakeLists.txt deleted file mode 100644 index 32d654d5c4..0000000000 --- a/Gems/Atom/Feature/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -add_subdirectory(Common) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_DepthPass_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_DepthPass_WithPS.azsl index f2564cf10c..08642decc0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_DepthPass_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_DepthPass_WithPS.azsl @@ -28,7 +28,7 @@ struct VSInput struct VSDepthOutput { - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float2 m_uv[UvSetCount] : UV1; // only used for parallax depth calculation @@ -62,7 +62,7 @@ VSDepthOutput MainVS(VSInput IN) struct PSDepthOutput { - float m_depth : SV_Depth; + precise float m_depth : SV_Depth; }; PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index 0f9771e480..4b37f67930 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -67,7 +67,7 @@ struct VSInput struct VSOutput { // Base fields (required by the template azsli file)... - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float3 m_normal: NORMAL; float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl index 523353f8fa..00dee50c93 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl @@ -86,7 +86,7 @@ struct VSInput struct VSOutput { // Base fields (required by the template azsli file)... - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float3 m_normal: NORMAL; float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl index 39597e2bdd..7875457489 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl @@ -41,7 +41,7 @@ struct VSInput struct VSDepthOutput { - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float2 m_uv[UvSetCount] : UV1; // only used for parallax depth calculation @@ -88,7 +88,7 @@ VSDepthOutput MainVS(VSInput IN) struct PSDepthOutput { - float m_depth : SV_Depth; + precise float m_depth : SV_Depth; }; PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl index 8f58c6dd33..5b05e48d3b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl @@ -80,7 +80,7 @@ struct VSInput struct VSOutput { // Base fields (required by the template azsli file)... - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float3 m_normal: NORMAL; float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_DepthPass_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_DepthPass_WithPS.azsl index 264542cd0a..04fd104407 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_DepthPass_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_DepthPass_WithPS.azsl @@ -63,7 +63,7 @@ VSDepthOutput MainVS(VSInput IN) struct PSDepthOutput { - float m_depth : SV_Depth; + precise float m_depth : SV_Depth; }; PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) diff --git a/Gems/Atom/Feature/Common/CMakeLists.txt b/Gems/Atom/Feature/Common/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Feature/Common/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index db9ac8560f..a832c46539 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME Atom_Feature_Common.Static STATIC diff --git a/Gems/Atom/Feature/Common/gem.json b/Gems/Atom/Feature/Common/gem.json index 84ab07a9f9..f4c936dc4a 100644 --- a/Gems/Atom/Feature/Common/gem.json +++ b/Gems/Atom/Feature/Common/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom", diff --git a/Gems/Atom/RHI/CMakeLists.txt b/Gems/Atom/RHI/CMakeLists.txt index 074f6acfd7..5812828c1a 100644 --- a/Gems/Atom/RHI/CMakeLists.txt +++ b/Gems/Atom/RHI/CMakeLists.txt @@ -6,10 +6,10 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + ly_add_external_target_path(${CMAKE_CURRENT_LIST_DIR}/3rdParty) add_subdirectory(Code) -add_subdirectory(DX12) -add_subdirectory(Metal) -add_subdirectory(Vulkan) -add_subdirectory(Null) diff --git a/Gems/Atom/RHI/Code/CMakeLists.txt b/Gems/Atom/RHI/Code/CMakeLists.txt index 5238985feb..fe9db107a8 100644 --- a/Gems/Atom/RHI/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/AtomRHITests_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/PhysicalDeviceDescriptor.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/PhysicalDeviceDescriptor.h index ac79ff0521..4d78d24ca8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/PhysicalDeviceDescriptor.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/PhysicalDeviceDescriptor.h @@ -28,7 +28,8 @@ namespace AZ (AMD, 0x1002), (Qualcomm, 0x5143), (Samsung, 0x1099), - (ARM, 0x13B5) + (ARM, 0x13B5), + (Warp, 0x1414) ); void ReflectVendorIdEnums(ReflectContext* context); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h index eb2b0b5b0c..47cf7709db 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h @@ -164,23 +164,27 @@ namespace AZ //! it will defer to the platform for parallel dispatch support. void Execute(JobPolicy jobPolicy); - /// Returns the timing statistics for the previous frame. + //! Returns the timing statistics for the previous frame. const TransientAttachmentStatistics* GetTransientAttachmentStatistics() const; - /// Returns current CPU frame to frame time in milliseconds. + //! Returns current CPU frame to frame time in milliseconds. double GetCpuFrameTime() const; - /// Returns memory statistics for the previous frame. + //! Returns memory statistics for the previous frame. const MemoryStatistics* GetMemoryStatistics() const; - /// Returns the implicit root scope id. + //! Returns the implicit root scope id. ScopeId GetRootScopeId() const; + //! Returns the descriptor which has information on the properties of a TransientAttachmentPool. const TransientAttachmentPoolDescriptor* GetTransientAttachmentPoolDescriptor() const; //! Adds a RayTracingShaderTable to be built this frame void QueueRayTracingShaderTableForBuild(RayTracingShaderTable* rayTracingShaderTable); + //! Returns PhysicalDeviceDescriptor which can be used to extract vendor/driver information + const PhysicalDeviceDescriptor& GetPhysicalDeviceDescriptor(); + private: const ScopeId m_rootScopeId{"Root"}; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h index 6d416b77fc..c2a3162025 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h @@ -53,6 +53,7 @@ namespace AZ const RHI::TransientAttachmentPoolDescriptor* GetTransientAttachmentPoolDescriptor() const override; ConstPtr GetPlatformLimitsDescriptor() const override; void QueueRayTracingShaderTableForBuild(RayTracingShaderTable* rayTracingShaderTable) override; + const PhysicalDeviceDescriptor& GetPhysicalDeviceDescriptor() override; ////////////////////////////////////////////////////////////////////////// private: @@ -65,6 +66,8 @@ namespace AZ RHI::Ptr m_pipelineStateCache; RHI::FrameScheduler m_frameScheduler; RHI::FrameSchedulerCompileRequest m_compileRequest; + PhysicalDeviceDescriptor m_physicalDeviceDescriptor; + }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h index 19ba1cb762..66f6b2bcde 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h @@ -26,6 +26,7 @@ namespace AZ class PipelineState; class PipelineStateCache; class PlatformLimitsDescriptor; + class PhysicalDeviceDescriptor; class RayTracingShaderTable; struct FrameSchedulerCompileRequest; struct TransientAttachmentStatistics; @@ -65,6 +66,8 @@ namespace AZ virtual ConstPtr GetPlatformLimitsDescriptor() const = 0; virtual void QueueRayTracingShaderTableForBuild(RayTracingShaderTable* rayTracingShaderTable) = 0; + + virtual const PhysicalDeviceDescriptor& GetPhysicalDeviceDescriptor() = 0; }; //! This bus exists to give RHI samples the ability to slot in scopes manually diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index e7515bbf6e..3ec0cfeb93 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -165,6 +165,7 @@ namespace AZ RHI::Ptr device = RHI::Factory::Get().CreateDevice(); if (device->Init(*physicalDeviceFound) == RHI::ResultCode::Success) { + m_physicalDeviceDescriptor = physicalDeviceFound->GetDescriptor(); PlatformLimitsDescriptor::Create(); return device; } @@ -279,5 +280,10 @@ namespace AZ { m_frameScheduler.QueueRayTracingShaderTableForBuild(rayTracingShaderTable); } + + const PhysicalDeviceDescriptor& RHISystem::GetPhysicalDeviceDescriptor() + { + return m_physicalDeviceDescriptor; + } } //namespace RPI } //namespace AZ diff --git a/Gems/Atom/RHI/DX12/CMakeLists.txt b/Gems/Atom/RHI/DX12/CMakeLists.txt index 51912a5ff0..5812828c1a 100644 --- a/Gems/Atom/RHI/DX12/CMakeLists.txt +++ b/Gems/Atom/RHI/DX12/CMakeLists.txt @@ -6,6 +6,10 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + ly_add_external_target_path(${CMAKE_CURRENT_LIST_DIR}/3rdParty) add_subdirectory(Code) diff --git a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt index 975b838ffa..95118c60a7 100644 --- a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # PAL_TRAIT_ATOM_RHI_DX12_SUPPORTED @@ -23,7 +23,7 @@ set(pal_builder_tools_files) set(pal_builder_tools_includes) foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(pal_builder_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform}) + o3de_pal_dir(pal_builder_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) list(APPEND pal_builder_tools_includes ${pal_builder_source_dir}) list(APPEND pal_builder_tools_files ${pal_builder_source_dir}/platform_builders_${enabled_platform_lowercase}_tools_files.cmake) endforeach() diff --git a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/Device_Windows.cpp b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/Device_Windows.cpp index f6ed3be692..a2ed31ff84 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/Device_Windows.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/Device_Windows.cpp @@ -157,7 +157,10 @@ namespace AZ disabledMessages.push_back(D3D12_MESSAGE_ID_COPY_DESCRIPTORS_INVALID_RANGES); } - // [GFX TODO][ATOM-4712] - Fix PipelineLibrary Loading. These warnings were silenced for a release and need to be fixed properly. + // We disable these warnings as the our current implementation of Pipeline Library will trigger these warnings unknowingly. For example + // it will always first try to load a pso from pipelinelibrary triggering D3D12_MESSAGE_ID_LOADPIPELINE_NAMENOTFOUND (for the first time) before storing the PSO in a library. + // Similarly when we merge multiple pipeline libraries (in multiple threads) we may trigger D3D12_MESSAGE_ID_STOREPIPELINE_DUPLICATENAME as it is possible to save + // a PSO already saved in the main library. #if defined (AZ_DX12_USE_PIPELINE_LIBRARY) disabledMessages.push_back(D3D12_MESSAGE_ID_LOADPIPELINE_NAMENOTFOUND); disabledMessages.push_back(D3D12_MESSAGE_ID_STOREPIPELINE_DUPLICATENAME); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/PipelineLibrary.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/PipelineLibrary.cpp index 63625fde72..ae3053f446 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/PipelineLibrary.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/PipelineLibrary.cpp @@ -50,10 +50,9 @@ namespace AZ bool shouldCreateLibFromSerializedData = true; if (RHI::Factory::Get().IsRenderDocModuleLoaded() || - RHI::Factory::Get().IsPixModuleLoaded() || - RHI::Factory::Get().UsingWarpDevice()) + RHI::Factory::Get().IsPixModuleLoaded()) { - // CreatePipelineLibrary api does not function properly if Renderdoc, Pix or Warp is enabled + // CreatePipelineLibrary api does not function properly if Renderdoc or Pix is enabled shouldCreateLibFromSerializedData = false; } @@ -218,10 +217,9 @@ namespace AZ RHI::ResultCode PipelineLibrary::MergeIntoInternal([[maybe_unused]] AZStd::array_view pipelineLibraries) { if (RHI::Factory::Get().IsRenderDocModuleLoaded() || - RHI::Factory::Get().IsPixModuleLoaded() || - RHI::Factory::Get().UsingWarpDevice()) + RHI::Factory::Get().IsPixModuleLoaded()) { - // StorePipeline api does not function properly if RenderDoc, Pix or Warp is enabled + // StorePipeline api does not function properly if RenderDoc or Pix is enabled return RHI::ResultCode::Fail; } diff --git a/Gems/Atom/RHI/DX12/gem.json b/Gems/Atom/RHI/DX12/gem.json index 868acd43db..803ae4f4d0 100644 --- a/Gems/Atom/RHI/DX12/gem.json +++ b/Gems/Atom/RHI/DX12/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI" ] diff --git a/Gems/Atom/RHI/Metal/CMakeLists.txt b/Gems/Atom/RHI/Metal/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/RHI/Metal/CMakeLists.txt +++ b/Gems/Atom/RHI/Metal/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/RHI/Metal/Code/CMakeLists.txt b/Gems/Atom/RHI/Metal/Code/CMakeLists.txt index 11876e0a30..3df00a30e0 100644 --- a/Gems/Atom/RHI/Metal/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Metal/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL2_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Gems/Atom/RHI/Metal/gem.json b/Gems/Atom/RHI/Metal/gem.json index 6e983ba505..0257048bd3 100644 --- a/Gems/Atom/RHI/Metal/gem.json +++ b/Gems/Atom/RHI/Metal/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI" ] diff --git a/Gems/Atom/RHI/Null/CMakeLists.txt b/Gems/Atom/RHI/Null/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/RHI/Null/CMakeLists.txt +++ b/Gems/Atom/RHI/Null/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/RHI/Null/Code/CMakeLists.txt b/Gems/Atom/RHI/Null/Code/CMakeLists.txt index 71df9f696f..081edd4c44 100644 --- a/Gems/Atom/RHI/Null/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Null/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( diff --git a/Gems/Atom/RHI/Null/gem.json b/Gems/Atom/RHI/Null/gem.json index e9f22c5fcb..1ea2eb4cb0 100644 --- a/Gems/Atom/RHI/Null/gem.json +++ b/Gems/Atom/RHI/Null/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI" ] diff --git a/Gems/Atom/RHI/Vulkan/CMakeLists.txt b/Gems/Atom/RHI/Vulkan/CMakeLists.txt index 51912a5ff0..5812828c1a 100644 --- a/Gems/Atom/RHI/Vulkan/CMakeLists.txt +++ b/Gems/Atom/RHI/Vulkan/CMakeLists.txt @@ -6,6 +6,10 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + ly_add_external_target_path(${CMAKE_CURRENT_LIST_DIR}/3rdParty) add_subdirectory(Code) diff --git a/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt b/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt index fb13d1fddb..674e5aff9e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # PAL_TRAIT_ATOM_RHI_VULKAN_SUPPORTED / PAL_TRAIT_ATOM_RHI_VULKAN_TARGETS_ALREADY_DEFINED diff --git a/Gems/Atom/RHI/Vulkan/gem.json b/Gems/Atom/RHI/Vulkan/gem.json index 1dfeb9eafa..508ad85c75 100644 --- a/Gems/Atom/RHI/Vulkan/gem.json +++ b/Gems/Atom/RHI/Vulkan/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI" ] diff --git a/Gems/Atom/RHI/gem.json b/Gems/Atom/RHI/gem.json index de46c312ad..858a64fc17 100644 --- a/Gems/Atom/RHI/gem.json +++ b/Gems/Atom/RHI/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,12 @@ ], "user_tags": [], "requirements": "", + "external_subdirectories": [ + "DX12", + "Metal", + "Null", + "Vulkan" + ], "dependencies": [ "Atom_RHI_DX12", "Atom_RHI_Metal", diff --git a/Gems/Atom/RPI/CMakeLists.txt b/Gems/Atom/RPI/CMakeLists.txt index 6d148328ec..2c2cee5804 100644 --- a/Gems/Atom/RPI/CMakeLists.txt +++ b/Gems/Atom/RPI/CMakeLists.txt @@ -6,6 +6,10 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) add_subdirectory(Tools) diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index f0459a23c2..dcdad13c10 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) #for PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED and PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) @@ -176,8 +176,8 @@ endif() if(PAL_TRAIT_BUILD_HOST_TOOLS) - ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) - ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) + o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) + set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) if(NOT PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/JsonUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/JsonUtils.h index 4715acd64c..9f4cdcf31b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/JsonUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/JsonUtils.h @@ -29,7 +29,7 @@ namespace AZ //! Loads serialized object data from a json file at the specified path //! Errors will be reported using AZ trace template - bool LoadObjectFromFile(const AZStd::string& path, ObjectType& objectData); + bool LoadObjectFromFile(const AZStd::string& path, ObjectType& objectData, size_t maxFileSize = DefaultMaxFileSize); //! Saves serialized object data to a json file at the specified path //! Errors will be reported using AZ trace @@ -39,11 +39,11 @@ namespace AZ // Definitions... template - bool LoadObjectFromFile(const AZStd::string& path, ObjectType& objectData) + bool LoadObjectFromFile(const AZStd::string& path, ObjectType& objectData, size_t maxFileSize) { objectData = ObjectType(); - auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path, DefaultMaxFileSize); + auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path, maxFileSize); if (!loadOutcome.IsSuccess()) { AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str()); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h index 92b67c3a7a..be20d89d65 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h @@ -136,11 +136,6 @@ namespace AZ //! This tag corresponds to the ShaderAsset object's DrawListName. RHI::DrawListTag GetDrawListTag() const; - //! Changes the supervariant of the shader to the specified supervariantIndex. - //! [GFX TODO][ATOM-15813]: this can be removed when the shader InstanceDatabase can support multiple shader - //! instances with different supervariants. - void ChangeSupervariant(SupervariantIndex supervariantIndex); - private: explicit Shader(const SupervariantIndex& supervariantIndex) : m_supervariantIndex(supervariantIndex){}; Shader() = delete; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h index 5146ae370a..b65d9837f7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h @@ -50,6 +50,7 @@ namespace AZ RPI::ShaderVariantStableId GetStableId() const { return m_stableId; } const ShaderVariantId& GetShaderVariantId() const { return m_shaderVariantId; } + uint32_t GetSupervariantIndex() const; //! Returns the shader stage function associated with the provided stage enum value. const RHI::ShaderStageFunction* GetShaderStageFunction(RHI::ShaderStage shaderStage) const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index 6a0b10633e..e2d4bd629a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -53,7 +53,7 @@ namespace AZ { AssetBuilderSDK::AssetBuilderDesc builder; builder.m_name = PassBuilderJobKey; - builder.m_version = 14; // making .pass files emit product dependencies for the shaders they reference so they are picked up by the asset bundler + builder.m_version = 15; // Changed dependency type to OrderOnce builder.m_busId = azrtti_typeid(); builder.m_createJobFunction = AZStd::bind(&PassBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2); builder.m_processJobFunction = AZStd::bind(&PassBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2); @@ -97,27 +97,16 @@ namespace AZ // Helper function to get a file reference and create a corresponding job dependency bool AddDependency(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) { - AZStd::string_view& file = params.dependencySourceFile; - AZ::Data::AssetInfo sourceInfo; - AZStd::string watchFolder; - bool fileFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.data(), sourceInfo, watchFolder); - - if (fileFound) - { - AssetBuilderSDK::JobDependency jobDependency; - jobDependency.m_jobKey = params.jobKey; - jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; - jobDependency.m_sourceFile.m_sourceFileDependencyPath = file; - job->m_jobDependencyList.push_back(jobDependency); - AZ_TracePrintf(PassBuilderName, "Creating job dependency on file [%s] \n", file.data()); - return true; - } - else - { - AZ_Error(PassBuilderName, false, "Could not find referenced file [%s]", file.data()); - return false; - } + // We use an OrderOnce job dependency to ensure that the Asset Processor knows about the + // referenced asset, so we can make an AssetId for it later in ProcessJob. OrderOnce is + // enough because we don't need to read any data from the asset, we just needs its ID. + AssetBuilderSDK::JobDependency jobDependency; + jobDependency.m_jobKey = params.jobKey; + jobDependency.m_type = AssetBuilderSDK::JobDependencyType::OrderOnce; + jobDependency.m_sourceFile.m_sourceFileDependencyPath = params.dependencySourceFile; + job->m_jobDependencyList.push_back(jobDependency); + AZ_TracePrintf(PassBuilderName, "Creating job dependency on file [%.*s] \n", AZ_STRING_ARG(params.dependencySourceFile)); + return true; } bool SetJobKeyForExtension(const AZStd::string& filePath, FindPassReferenceAssetParams& params) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/StreamingImage.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/StreamingImage.cpp index fb03d109a2..49cd52f212 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/StreamingImage.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/StreamingImage.cpp @@ -143,11 +143,6 @@ namespace AZ RHI::ResultCode resultCode = RHI::ResultCode::Success; const ImageMipChainAsset& mipChainTailAsset = imageAsset.GetTailMipChain(); - -#ifdef AZ_RPI_STREAMING_IMAGE_DEBUG_LOG - m_image->SetName(Name(imageAsset.GetHint().c_str())); - AZ_TracePrintf("StreamingImage", "Init image [%s]\n", m_image->GetName().data()); -#endif { RHI::StreamingImageInitRequest initRequest; @@ -193,6 +188,13 @@ namespace AZ m_rhiPool = rhiPool; m_pool = pool; m_pool->AttachImage(this); + + // Set rhi image name + m_image->SetName(Name(m_imageAsset.GetHint())); + +#ifdef AZ_RPI_STREAMING_IMAGE_DEBUG_LOG + AZ_TracePrintf("StreamingImage", "Init image [%s]\n", m_image->GetName().data()); +#endif #if defined (AZ_RPI_STREAMING_IMAGE_HOT_RELOADING) BusConnect(imageAsset.GetId()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index b1ae460af6..130c0158d1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -17,6 +17,7 @@ #include +#define PSOCacheVersion 0 // Bump this if you want to reset PSO cache for everyone namespace AZ { @@ -25,21 +26,34 @@ namespace AZ Data::Instance Shader::FindOrCreate(const Data::Asset& shaderAsset, const Name& supervariantName) { auto anySupervariantName = AZStd::any(supervariantName); - Data::Instance shaderInstance = Data::InstanceDatabase::Instance().FindOrCreate( - Data::InstanceId::CreateFromAssetId(shaderAsset.GetId()), shaderAsset, &anySupervariantName); - if (shaderInstance) + // retrieve the supervariant index from the shader asset + SupervariantIndex supervariantIndex = shaderAsset->GetSupervariantIndex(supervariantName); + if (!supervariantIndex.IsValid()) { - // [GFX TODO][ATOM-15813] Change InstanceDatabase to support multiple instances with different supervariants. - // At this time we do not support multiple supervariants loaded for a shader asset simultaneously, so if this shader - // is referring to the wrong supervariant we need to change it to the correct one. - SupervariantIndex supervariantIndex = shaderAsset->GetSupervariantIndex(supervariantName); - if (supervariantIndex.IsValid() && shaderInstance->GetSupervariantIndex() != supervariantIndex) - { - shaderInstance->ChangeSupervariant(supervariantIndex); - } + AZ_Error("Shader", false, "Supervariant with name %s, was not found in shader %s", supervariantName.GetCStr(), shaderAsset->GetName().GetCStr()); + return nullptr; } + // create the InstanceId from the combined assetId and supervariantIndex + const Data::AssetId& assetId = shaderAsset.GetId(); + uint32_t shaderSupervariantIndex = supervariantIndex.GetIndex(); + + const uint32_t instanceIdDataSize = sizeof(assetId.m_guid) + sizeof(assetId.m_subId) + sizeof(shaderSupervariantIndex); + uint8_t instanceIdData[instanceIdDataSize]; + uint8_t* instanceIdDataPtr = instanceIdData; + + memcpy(instanceIdDataPtr, &assetId.m_guid, sizeof(assetId.m_guid)); + instanceIdDataPtr += sizeof(assetId.m_guid); + memcpy(instanceIdDataPtr, &assetId.m_subId, sizeof(assetId.m_subId)); + instanceIdDataPtr += sizeof(assetId.m_subId); + memcpy(instanceIdDataPtr, &shaderSupervariantIndex, sizeof(shaderSupervariantIndex)); + + Data::InstanceId instanceId = Data::InstanceId::CreateData(instanceIdData, instanceIdDataSize); + + // retrieve the shader instance from the Instance database + Data::Instance shaderInstance = Data::InstanceDatabase::Instance().FindOrCreate(instanceId, shaderAsset, &anySupervariantName); + return shaderInstance; } @@ -85,10 +99,17 @@ namespace AZ AZStd::string uuidString; assetId.m_guid.ToString(uuidString, false, false); + RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get(); + RHI::PhysicalDeviceDescriptor physicalDeviceDesc = rhiSystem->GetPhysicalDeviceDescriptor(); + char pipelineLibraryPathTemp[AZ_MAX_PATH_LEN]; azsnprintf( - pipelineLibraryPathTemp, AZ_MAX_PATH_LEN, "@user@/Atom/PipelineStateCache/%s/%s_%s_%d.bin", platformName.GetCStr(), - shaderName.GetCStr(), uuidString.data(), assetId.m_subId); + pipelineLibraryPathTemp, AZ_MAX_PATH_LEN, "@user@/Atom/PipelineStateCache_%s_%i_%i _Ver_%i/%s/%s_%s_%d.bin", + ToString(physicalDeviceDesc.m_vendorId).data(), physicalDeviceDesc.m_deviceId, physicalDeviceDesc.m_driverVersion, PSOCacheVersion, + platformName.GetCStr(), + shaderName.GetCStr(), + uuidString.data(), + assetId.m_subId); fileIOBase->ResolvePath(pipelineLibraryPathTemp, pipelineLibraryPath, pipelineLibraryPathLength); return true; @@ -240,6 +261,12 @@ namespace AZ AZ_Assert(shaderVariantAsset, "Reloaded ShaderVariantAsset is null"); const ShaderVariantStableId stableId = shaderVariantAsset->GetStableId(); + // check the supervariantIndex of the ShaderVariantAsset to make sure it matches the supervariantIndex of this shader instance + if (shaderVariantAsset->GetSupervariantIndex() != m_supervariantIndex.GetIndex()) + { + return; + } + // We make a copy of the updated variant because OnShaderVariantReinitialized must not be called inside // m_variantCacheMutex or deadlocks may occur. // Or if there is an error, we leave this object in its default state to indicate there was an error. @@ -478,14 +505,5 @@ namespace AZ return m_drawListTag; } - void Shader::ChangeSupervariant(SupervariantIndex supervariantIndex) - { - if (supervariantIndex != m_supervariantIndex) - { - m_supervariantIndex = supervariantIndex; - Init(*m_asset); - } - } - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp index ec1a65a6d5..f9f046ac8a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp @@ -65,6 +65,11 @@ namespace AZ return m_buildTimestamp; } + uint32_t ShaderVariantAsset::GetSupervariantIndex() const + { + return (m_assetId.m_subId >> SupervariantIndexBitPosition) & SupervariantIndexMaxValue; + } + const RHI::ShaderStageFunction* ShaderVariantAsset::GetShaderStageFunction(RHI::ShaderStage shaderStage) const { return m_functionsByStage[static_cast(shaderStage)].get(); diff --git a/Gems/Atom/RPI/gem.json b/Gems/Atom/RPI/gem.json index 885f150508..0acef5179b 100644 --- a/Gems/Atom/RPI/gem.json +++ b/Gems/Atom/RPI/gem.json @@ -1,16 +1,18 @@ { "gem_name": "Atom_RPI", "display_name": "Atom API", - "summary": "", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", + "summary": "", "canonical_tags": [ "Gem" ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI" ] diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl index 2dbba46d8b..05ce5f4774 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl @@ -28,7 +28,7 @@ struct VSInput struct VSOutput { - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float3 m_normal: NORMAL; float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl index 2f6f038e4b..fe9e4099d0 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl @@ -33,7 +33,7 @@ struct VSInput struct VSOutput { - float4 m_position : SV_Position; + precise linear centroid float4 m_position : SV_Position; float3 m_normal: NORMAL; float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; diff --git a/Gems/Atom/Tools/AtomToolsFramework/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index e7e8208722..0fc896e88a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AtomToolsFramework.Static STATIC diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 505ff70122..b15cf53427 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -68,6 +68,7 @@ namespace AtomToolsFramework { return false; } + const AzFramework::ViewportId newId = m_viewportContext->GetId(); SetControllerList(AZStd::make_shared()); @@ -78,14 +79,14 @@ namespace AtomToolsFramework m_viewportInteractionImpl = AZStd::make_unique(m_defaultCamera); m_viewportInteractionImpl->m_deviceScalingFactorFn = [this] { return aznumeric_cast(devicePixelRatioF()); }; m_viewportInteractionImpl->m_screenSizeFn = [this] { return AzFramework::ScreenSize(width(), height()); }; - m_viewportInteractionImpl->Connect(id); + m_viewportInteractionImpl->Connect(newId); AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(GetId()); AzFramework::InputChannelEventListener::Connect(); AZ::TickBus::Handler::BusConnect(); AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle); - m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id); + m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, newId); // Forward input events to our controller list. QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this, diff --git a/Gems/Atom/Tools/AtomToolsFramework/gem.json b/Gems/Atom/Tools/AtomToolsFramework/gem.json index de2a9e06f2..6e5a7b311a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/gem.json +++ b/Gems/Atom/Tools/AtomToolsFramework/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom_RHI", diff --git a/Gems/Atom/Tools/CMakeLists.txt b/Gems/Atom/Tools/CMakeLists.txt index 653babd0b3..82a803bdef 100644 --- a/Gems/Atom/Tools/CMakeLists.txt +++ b/Gems/Atom/Tools/CMakeLists.txt @@ -6,6 +6,4 @@ # # -add_subdirectory(AtomToolsFramework) -add_subdirectory(MaterialEditor) add_subdirectory(ShaderManagementConsole) diff --git a/Gems/Atom/Tools/MaterialEditor/CMakeLists.txt b/Gems/Atom/Tools/MaterialEditor/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Atom/Tools/MaterialEditor/CMakeLists.txt +++ b/Gems/Atom/Tools/MaterialEditor/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt index 99beb721d6..1d9295f9b3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # PAL_TRAIT_ATOM_MATERIAL_EDITOR_APPLICATION_SUPPORTED diff --git a/Gems/Atom/Tools/MaterialEditor/gem.json b/Gems/Atom/Tools/MaterialEditor/gem.json index 807e3fa65f..463553c27d 100644 --- a/Gems/Atom/Tools/MaterialEditor/gem.json +++ b/Gems/Atom/Tools/MaterialEditor/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "Editor for creating, modifying, and previewing materials", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "AtomToolsFramework", "Atom_RPI", diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt index d384378b09..3f7788418a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # PAL_TRAIT_ATOM_SHADER_MANAGEMENT_CONSOLE_APPLICATION_SUPPORTED diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 90d7ce501b..a657262f2d 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -6,8 +6,6 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) - ly_add_target( NAME Atom_Utils.Static STATIC NAMESPACE Gem @@ -52,6 +50,9 @@ endif() # Tests ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + + o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) + ly_add_target( NAME Atom_Utils.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem diff --git a/Gems/Atom/gem.json b/Gems/Atom/gem.json index 0f409ad993..ee6a617ee7 100644 --- a/Gems/Atom/gem.json +++ b/Gems/Atom/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Atom Renderer Gem provides Atom Renderer and its associated tools (such as Material Editor), utilites, libraries, and interfaces.", "canonical_tags": [ @@ -15,6 +16,17 @@ ], "requirements": "", "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/atom/atom/", + "external_subdirectories": [ + "Asset/ImageProcessingAtom", + "Asset/Shader", + "Bootstrap", + "Component/DebugCamera", + "Feature/Common", + "RHI", + "RPI", + "Tools/AtomToolsFramework", + "Tools/MaterialEditor" + ], "dependencies": [ "Atom_Feature_Common", "AtomShader", diff --git a/Gems/AtomContent/CMakeLists.txt b/Gems/AtomContent/CMakeLists.txt index ee06f07bc3..29477608b9 100644 --- a/Gems/AtomContent/CMakeLists.txt +++ b/Gems/AtomContent/CMakeLists.txt @@ -5,8 +5,6 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT # # -add_subdirectory(ReferenceMaterials) -add_subdirectory(Sponza) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_create_alias(NAME AtomContent.Builders NAMESPACE Gem TARGETS Gem::AtomContent_ReferenceMaterials.Builders Gem::AtomContent_Sponza.Builders) diff --git a/Gems/AtomContent/ReferenceMaterials/gem.json b/Gems/AtomContent/ReferenceMaterials/gem.json index b75b01e1ae..49a488b9d3 100644 --- a/Gems/AtomContent/ReferenceMaterials/gem.json +++ b/Gems/AtomContent/ReferenceMaterials/gem.json @@ -2,7 +2,9 @@ "gem_name": "ReferenceMaterials", "display_name": "PBR Reference Materials", "license": "Code, text, data files: Apache-2.0 Or MIT, assets/content/images: CC BY 4.0", - "origin": "https://github.com/aws-lumberyard-dev/o3de.git", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "Atom Asset Gem with a library of reference materials for StandardPBR (and others in the future)", "canonical_tags": [ @@ -14,6 +16,8 @@ "Materials" ], "icon_path": "preview.png", - "dependencies": [], - "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt" + "requirements": "", + "documentation_url": "", + "dependencies": [ + ] } diff --git a/Gems/AtomContent/Sponza/gem.json b/Gems/AtomContent/Sponza/gem.json index 68749cd5f4..f15d57a4d1 100644 --- a/Gems/AtomContent/Sponza/gem.json +++ b/Gems/AtomContent/Sponza/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "A standard test scene for Global Illumination (forked from crytek sponza scene)", "canonical_tags": [ @@ -13,5 +14,7 @@ "Assets" ], "requirements": "", - "dependencies": [] + "documentation_url": "", + "dependencies": [ + ] } diff --git a/Gems/AtomContent/gem.json b/Gems/AtomContent/gem.json index 400e897a3b..9be15f7da8 100644 --- a/Gems/AtomContent/gem.json +++ b/Gems/AtomContent/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The Atom Content Gem provides assets for Atom Renderer and a modified version of the Pixar Look Development Studio.", "canonical_tags": [ @@ -17,7 +18,11 @@ "requirements": "", "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/atom/atom-content/", "dependencies": [ - "ReferenceMaterials", - "Sponza" + "Sponza", + "ReferenceMaterials" + ], + "external_subdirectories": [ + "Sponza", + "ReferenceMaterials" ] } diff --git a/Gems/AtomLyIntegration/AtomBridge/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AtomLyIntegration/AtomBridge/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index 67f28767e0..fa3669d7c2 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME Atom_AtomBridge.Static STATIC diff --git a/Gems/AtomLyIntegration/AtomBridge/gem.json b/Gems/AtomLyIntegration/AtomBridge/gem.json index e8ca413023..5a8512c90d 100644 --- a/Gems/AtomLyIntegration/AtomBridge/gem.json +++ b/Gems/AtomLyIntegration/AtomBridge/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom_Bootstrap", diff --git a/Gems/AtomLyIntegration/AtomFont/CMakeLists.txt b/Gems/AtomLyIntegration/AtomFont/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AtomLyIntegration/AtomFont/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomFont/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt index 6567736f02..79d97e797d 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} diff --git a/Gems/AtomLyIntegration/AtomFont/gem.json b/Gems/AtomLyIntegration/AtomFont/gem.json index 8907ec0979..d979509059 100644 --- a/Gems/AtomLyIntegration/AtomFont/gem.json +++ b/Gems/AtomLyIntegration/AtomFont/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI", "Atom_RPI", diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json index e188ba0cb8..205120f6f0 100644 --- a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json +++ b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "", "canonical_tags": [ @@ -14,6 +15,7 @@ "Rendering" ], "requirements": "", + "documentation_url": "", "dependencies": [ "ImguiAtom", "Atom" diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json index 5a0763e0da..cff957c1f1 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI", "Atom_RPI", diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json index 639d93d301..a2bc92c76d 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RHI", "Atom_RPI" diff --git a/Gems/AtomLyIntegration/CMakeLists.txt b/Gems/AtomLyIntegration/CMakeLists.txt index 4ab976d68f..25d7356b01 100644 --- a/Gems/AtomLyIntegration/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CMakeLists.txt @@ -6,13 +6,4 @@ # # -add_subdirectory(CommonFeatures) -add_subdirectory(ImguiAtom) -add_subdirectory(AtomImGuiTools) -add_subdirectory(EMotionFXAtom) -add_subdirectory(AtomFont) -add_subdirectory(TechnicalArt) -add_subdirectory(AtomBridge) -add_subdirectory(AtomViewportDisplayInfo) -add_subdirectory(AtomViewportDisplayIcons) diff --git a/Gems/AtomLyIntegration/CommonFeatures/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index 7b685ece13..3234db2292 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME AtomLyIntegration_CommonFeatures.Public HEADERONLY diff --git a/Gems/AtomLyIntegration/CommonFeatures/gem.json b/Gems/AtomLyIntegration/CommonFeatures/gem.json index 6fa8938332..a06f607fab 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/gem.json +++ b/Gems/AtomLyIntegration/CommonFeatures/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_Feature_Common", "LmbrCentral", diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json index 3514d4c1b9..8bea93da91 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json +++ b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "EMotionFX", "Atom", diff --git a/Gems/AtomLyIntegration/ImguiAtom/gem.json b/Gems/AtomLyIntegration/ImguiAtom/gem.json index fa611d8224..4c65d80e33 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/gem.json +++ b/Gems/AtomLyIntegration/ImguiAtom/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "", "canonical_tags": [ @@ -11,6 +12,7 @@ ], "user_tags": [], "requirements": "", + "documentation_url": "", "dependencies": [ "ImGui", "Atom_Feature_Common" diff --git a/Gems/AtomLyIntegration/TechnicalArt/CMakeLists.txt b/Gems/AtomLyIntegration/TechnicalArt/CMakeLists.txt deleted file mode 100644 index 4fc1e5241d..0000000000 --- a/Gems/AtomLyIntegration/TechnicalArt/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -add_subdirectory(DccScriptingInterface) diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/CMakeLists.txt b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/CMakeLists.txt index 5780172755..f26d18b90e 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/CMakeLists.txt +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/CMakeLists.txt @@ -6,5 +6,4 @@ # # -add_subdirectory(Code) update_pip_requirements(${CMAKE_CURRENT_LIST_DIR}/requirements.txt DccScriptingInterface) diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json index 4cc6fff169..7786a8adf4 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json @@ -1,11 +1,12 @@ { "gem_name": "DccScriptingInterface", "display_name": "Atom DccScriptingInterface (DCCsi)", - "summary": "A python framework for working with various DCC tools and workflows.", "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", + "summary": "A python framework for working with various DCC tools and workflows.", "canonical_tags": [ "Gem" ], @@ -16,5 +17,6 @@ "Creation" ], "requirements": "", + "documentation_url": "", "dependencies": [] } diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json index d9e526aee0..c491126269 100644 --- a/Gems/AtomLyIntegration/gem.json +++ b/Gems/AtomLyIntegration/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Atom O3DE Integration Gem provides components, libraries, and functionality to support and integrate Atom Renderer in Open 3D Engine.", "canonical_tags": [ @@ -25,5 +26,16 @@ "CommonFeaturesAtom", "EMotionFX_Atom", "ImguiAtom" + ], + "external_subdirectories": [ + "AtomBridge", + "AtomFont", + "AtomImGuiTools", + "AtomViewportDisplayIcons", + "AtomViewportDisplayInfo", + "CommonFeatures", + "EMotionFXAtom", + "ImguiAtom", + "TechnicalArt/DccScriptingInterface" ] } diff --git a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp index fe167cae8b..472a610016 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp @@ -213,6 +213,8 @@ namespace AZ Data::Instance rasterShader, uint32_t vertexCount, uint32_t strandsCount ) { + m_initialized = false; + AZ_Assert(vertexCount <= std::numeric_limits().max(), "Hair vertex count exceeds uint32_t size."); // Create the dynamic shared buffers Srg. @@ -608,8 +610,16 @@ namespace AZ // First, Directly loading from the asset stored in the render settings. if (pRenderSettings) { - m_baseAlbedo = RPI::StreamingImage::FindOrCreate(pRenderSettings->m_baseAlbedoAsset); - m_strandAlbedo = RPI::StreamingImage::FindOrCreate(pRenderSettings->m_strandAlbedoAsset); + if (pRenderSettings->m_baseAlbedoAsset) + { + pRenderSettings->m_baseAlbedoAsset.BlockUntilLoadComplete(); + m_baseAlbedo = RPI::StreamingImage::FindOrCreate(pRenderSettings->m_baseAlbedoAsset); + } + if (pRenderSettings->m_strandAlbedoAsset) + { + pRenderSettings->m_strandAlbedoAsset.BlockUntilLoadComplete(); + m_strandAlbedo = RPI::StreamingImage::FindOrCreate(pRenderSettings->m_strandAlbedoAsset); + } } // Fallback using the texture name stored in the render settings. @@ -1142,7 +1152,7 @@ namespace AZ if (!renderMaterialSrg || !simSrg) { - AZ_Error("Hair Gem", false, "Failed to get thre hair material Srg for the raster pass."); + AZ_Error("Hair Gem", false, "Failed to get the hair material Srg for the raster pass."); return false; } // No need to compile the simSrg since it was compiled already by the Compute pass this frame diff --git a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h index 817ebd89fa..564272e6f0 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h +++ b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h @@ -110,8 +110,14 @@ namespace AZ PrepareSrgDescriptors(m_dynamicBuffersDescriptors, vertexCount, strandsCount); } - Data::Instance GetSimSrgForCompute() { return m_simSrgForCompute; } - Data::Instance GetSimSrgForRaster() { return m_simSrgForRaster; } + Data::Instance GetSimSrgForCompute() + { + return m_initialized ? m_simSrgForCompute : nullptr; + } + + Data::Instance GetSimSrgForRaster() + { + return m_initialized ? m_simSrgForRaster : nullptr; } bool IsInitialized() { return m_initialized; } diff --git a/Gems/AtomTressFX/gem.json b/Gems/AtomTressFX/gem.json index b7588ea374..1bd619a418 100644 --- a/Gems/AtomTressFX/gem.json +++ b/Gems/AtomTressFX/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "Atom TressFX Gem provides a cutting edge hair and fur simulation and rendering in Atom enhancing the AMD TressFX 4.1. The open source TressFX can be found here: https://github.com/GPUOpen-Effects/TressFX", "canonical_tags": [ @@ -15,5 +16,7 @@ "Animation" ], "requirements": "", - "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/amd/atom-tressfx/" + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/amd/atom-tressfx/", + "dependencies": [ + ] } diff --git a/Gems/AudioEngineWwise/CMakeLists.txt b/Gems/AudioEngineWwise/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AudioEngineWwise/CMakeLists.txt +++ b/Gems/AudioEngineWwise/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 33c80bc31c..02d4f1e6c8 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) #for PAL_TRAIT_AUDIO_ENGINE_WWISE Traits diff --git a/Gems/AudioEngineWwise/gem.json b/Gems/AudioEngineWwise/gem.json index 2b0af30d40..f0d8c73be2 100644 --- a/Gems/AudioEngineWwise/gem.json +++ b/Gems/AudioEngineWwise/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Wwise Audio Engine Gem provides support for Audiokinetic Wave Works Interactive Sound Engine (Wwise).", "canonical_tags": [ diff --git a/Gems/AudioSystem/CMakeLists.txt b/Gems/AudioSystem/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/AudioSystem/CMakeLists.txt +++ b/Gems/AudioSystem/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/AudioSystem/Code/CMakeLists.txt b/Gems/AudioSystem/Code/CMakeLists.txt index 17dbd91878..e5778e9152 100644 --- a/Gems/AudioSystem/Code/CMakeLists.txt +++ b/Gems/AudioSystem/Code/CMakeLists.txt @@ -10,7 +10,7 @@ set(AUDIOSYSTEM_COMPILEDEFINITIONS $,AUDIO_RELEASE,ENABLE_AUDIO_LOGGING> ) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME AudioSystem.Static STATIC @@ -65,7 +65,7 @@ ly_create_alias(NAME AudioSystem.Clients NAMESPACE Gem TARGETS Gem::AudioSystem # Tests ################################################################################ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) - ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) + set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) ly_add_target( NAME AudioSystem.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem diff --git a/Gems/AudioSystem/Code/Source/Editor/QConnectionsWidget.cpp b/Gems/AudioSystem/Code/Source/Editor/QConnectionsWidget.cpp index d827f657b8..f8414e25e4 100644 --- a/Gems/AudioSystem/Code/Source/Editor/QConnectionsWidget.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/QConnectionsWidget.cpp @@ -33,6 +33,7 @@ namespace AudioControls { setupUi(this); + m_connectionPropertiesFrame->setHidden(true); m_connectionList->viewport()->installEventFilter(this); m_connectionList->installEventFilter(this); diff --git a/Gems/AudioSystem/gem.json b/Gems/AudioSystem/gem.json index ed028068a1..be618ee44e 100644 --- a/Gems/AudioSystem/gem.json +++ b/Gems/AudioSystem/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Audio System Gem provides the Audio Translation Layer (ATL) and Audio Controls Editor, which add support for audio in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/BarrierInput/gem.json b/Gems/BarrierInput/gem.json index 72d6398550..e8dcf0d93c 100644 --- a/Gems/BarrierInput/gem.json +++ b/Gems/BarrierInput/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Barrier Input Gem allows the Open 3D Engine to function as a Barrier client so that it can receive input from a remote Barrier server.", "canonical_tags": [ @@ -16,6 +17,7 @@ ], "icon_path": "preview.png", "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI" ] diff --git a/Gems/Blast/CMakeLists.txt b/Gems/Blast/CMakeLists.txt index 7c478ef2b2..e2fe57d8cc 100644 --- a/Gems/Blast/CMakeLists.txt +++ b/Gems/Blast/CMakeLists.txt @@ -6,5 +6,9 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Blast/Code/CMakeLists.txt b/Gems/Blast/Code/CMakeLists.txt index d3555b2855..7f478054b8 100644 --- a/Gems/Blast/Code/CMakeLists.txt +++ b/Gems/Blast/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_BLAST Traits diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.h b/Gems/Blast/Code/Source/Components/BlastSystemComponent.h index 8f6c200870..a3d4b200bc 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.h +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.h @@ -100,11 +100,14 @@ namespace Blast class AZBlastAllocatorCallback : public Nv::Blast::AllocatorCallback { public: + // Blast requires 16-byte alignment + static const size_t alignment = 16; + void* allocate( size_t size, const char* typeName, [[maybe_unused]] const char* filename, [[maybe_unused]] int line) override { - return azmalloc_4(size, 0, AZ::SystemAllocator, typeName); + return azmalloc_4(size, alignment, AZ::SystemAllocator, typeName); } void deallocate(void* ptr) override diff --git a/Gems/Blast/gem.json b/Gems/Blast/gem.json index 761eb04761..dc90c587d7 100644 --- a/Gems/Blast/gem.json +++ b/Gems/Blast/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The NVIDIA Blast Gem provides tools to author fractured mesh assets in Houdini, and functionality to create realistic destruction simulations in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/Camera/Code/Source/CameraComponent.cpp b/Gems/Camera/Code/Source/CameraComponent.cpp index 960f13a082..290691bbbe 100644 --- a/Gems/Camera/Code/Source/CameraComponent.cpp +++ b/Gems/Camera/Code/Source/CameraComponent.cpp @@ -106,6 +106,10 @@ namespace Camera ->Event("SetOrthographic", &CameraRequestBus::Events::SetOrthographic) ->Event("GetOrthographicHalfWidth", &CameraRequestBus::Events::GetOrthographicHalfWidth) ->Event("SetOrthographicHalfWidth", &CameraRequestBus::Events::SetOrthographicHalfWidth) + ->Event("ScreenToWorld", &CameraRequestBus::Events::ScreenToWorld) + ->Event("ScreenNdcToWorld", &CameraRequestBus::Events::ScreenNdcToWorld) + ->Event("WorldToScreen", &CameraRequestBus::Events::WorldToScreen) + ->Event("WorldToScreenNdc", &CameraRequestBus::Events::WorldToScreenNdc) ->VirtualProperty("FieldOfView","GetFovDegrees","SetFovDegrees") ->VirtualProperty("NearClipDistance", "GetNearClipDistance", "SetNearClipDistance") ->VirtualProperty("FarClipDistance", "GetFarClipDistance", "SetFarClipDistance") diff --git a/Gems/Camera/Code/Source/CameraComponentController.cpp b/Gems/Camera/Code/Source/CameraComponentController.cpp index 5b2e26b897..dfb2810fe2 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.cpp +++ b/Gems/Camera/Code/Source/CameraComponentController.cpp @@ -10,12 +10,15 @@ #include "CameraViewRegistrationBus.h" #include +#include #include #include #include #include +#include + namespace Camera { void CameraComponentConfig::Reflect(AZ::ReflectContext* context) @@ -412,6 +415,66 @@ namespace Camera return m_isActiveView; } + namespace Util + { + AZ::Vector3 GetWorldPosition(const AZ::Vector3& origin, float depth, const AzFramework::CameraState& cameraState) + { + if (depth == 0.f) + { + return origin; + } + else + { + const AZ::Vector3 rayDirection = cameraState.m_orthographic ? cameraState.m_forward : (origin - cameraState.m_position); + return origin + (rayDirection.GetNormalized() * depth); + } + } + } + + AZ::Vector3 CameraComponentController::ScreenToWorld(const AZ::Vector2& screenPosition, float depth) + { + const AzFramework::ScreenPoint point{ static_cast(screenPosition.GetX()), static_cast(screenPosition.GetY()) }; + const AzFramework::CameraState& cameraState = GetCameraState(); + const AZ::Vector3 origin = AzFramework::ScreenToWorld(point, cameraState); + return Util::GetWorldPosition(origin, depth, cameraState); + } + + AZ::Vector3 CameraComponentController::ScreenNdcToWorld(const AZ::Vector2& screenNdcPosition, float depth) + { + const AzFramework::CameraState& cameraState = GetCameraState(); + const AZ::Vector3 origin = AzFramework::ScreenNdcToWorld(screenNdcPosition, AzFramework::InverseCameraView(cameraState), AzFramework::InverseCameraProjection(cameraState)); + return Util::GetWorldPosition(origin, depth, cameraState); + } + + AZ::Vector2 CameraComponentController::WorldToScreenNdc(const AZ::Vector3& worldPosition) + { + const AzFramework::CameraState& cameraState = GetCameraState(); + const AZ::Vector3 screenPosition = AzFramework::WorldToScreenNdc(worldPosition, AzFramework::CameraView(cameraState), AzFramework::CameraProjection(cameraState)); + return AZ::Vector3ToVector2(screenPosition); + } + + AZ::Vector2 CameraComponentController::WorldToScreen(const AZ::Vector3& worldPosition) + { + const AzFramework::ScreenPoint& point = AzFramework::WorldToScreen(worldPosition, GetCameraState()); + return AZ::Vector2(static_cast(point.m_x), static_cast(point.m_y)); + } + + AzFramework::CameraState CameraComponentController::GetCameraState() + { + auto viewportContext = GetViewportContext(); + if (!m_atomCamera || ! viewportContext) + { + return AzFramework::CameraState(); + } + + auto windowSize = viewportContext->GetViewportSize(); + auto viewportSize = AzFramework::Vector2FromScreenSize(AzFramework::ScreenSize(windowSize.m_width, windowSize.m_height)); + + AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(m_atomCamera->GetCameraTransform(), viewportSize); + AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, m_atomCamera->GetViewToClipMatrix()); + return cameraState; + } + void CameraComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) { if (m_updatingTransformFromEntity) diff --git a/Gems/Camera/Code/Source/CameraComponentController.h b/Gems/Camera/Code/Source/CameraComponentController.h index 09af7529dc..265ffaa0e9 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.h +++ b/Gems/Camera/Code/Source/CameraComponentController.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,11 @@ namespace Camera void MakeActiveView() override; bool IsActiveView() override; + AZ::Vector3 ScreenToWorld(const AZ::Vector2& screenPosition, float depth) override; + AZ::Vector3 ScreenNdcToWorld(const AZ::Vector2& screenNdcPosition, float depth) override; + AZ::Vector2 WorldToScreen(const AZ::Vector3& worldPosition) override; + AZ::Vector2 WorldToScreenNdc(const AZ::Vector3& worldPosition) override; + // AZ::TransformNotificationBus::Handler interface void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; @@ -127,6 +133,7 @@ namespace Camera void DeactivateAtomView(); void UpdateCamera(); void SetupAtomAuxGeom(AZ::RPI::ViewportContextPtr viewportContext); + AzFramework::CameraState GetCameraState(); CameraComponentConfig m_config; AZ::EntityId m_entityId; diff --git a/Gems/Camera/gem.json b/Gems/Camera/gem.json index 4cf0747c7b..c6367d4663 100644 --- a/Gems/Camera/gem.json +++ b/Gems/Camera/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Camera Gem provides a basic camera component that defines a frustum for runtime rendering.", "canonical_tags": [ diff --git a/Gems/CameraFramework/gem.json b/Gems/CameraFramework/gem.json index d24014be61..0803fd7522 100644 --- a/Gems/CameraFramework/gem.json +++ b/Gems/CameraFramework/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Camera Framework Gem provides a base for implementing more complex camera systems.", "canonical_tags": [ diff --git a/Gems/CertificateManager/gem.json b/Gems/CertificateManager/gem.json index 11ea14ea5e..c582e932be 100644 --- a/Gems/CertificateManager/gem.json +++ b/Gems/CertificateManager/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Certificate Manager Gem provides access to authentication files for secure game connections from Amazon S3, files on disk, and other 3rd party sources.", "canonical_tags": [ diff --git a/Gems/CrashReporting/CMakeLists.txt b/Gems/CrashReporting/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/CrashReporting/CMakeLists.txt +++ b/Gems/CrashReporting/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/CrashReporting/Code/CMakeLists.txt b/Gems/CrashReporting/Code/CMakeLists.txt index 8bcb143d1c..7d7b2c76da 100644 --- a/Gems/CrashReporting/Code/CMakeLists.txt +++ b/Gems/CrashReporting/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Gems/CrashReporting/gem.json b/Gems/CrashReporting/gem.json index b8c75548a4..1651bad7b8 100644 --- a/Gems/CrashReporting/gem.json +++ b/Gems/CrashReporting/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Crash Reporting Gem provides support for external crash reporting for Open 3D Engine projects.", "canonical_tags": [ diff --git a/Gems/CustomAssetExample/gem.json b/Gems/CustomAssetExample/gem.json index 89492ee6ea..ba1030b280 100644 --- a/Gems/CustomAssetExample/gem.json +++ b/Gems/CustomAssetExample/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Custom Asset Example Gem provides example code for creating a custom asset for Open 3D Engine's asset pipeline.", "canonical_tags": [ diff --git a/Gems/DebugDraw/gem.json b/Gems/DebugDraw/gem.json index 58eff5f87a..e140d642b8 100644 --- a/Gems/DebugDraw/gem.json +++ b/Gems/DebugDraw/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Debug Draw Gem provides Editor and runtime debug visualization features for Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/DevTextures/gem.json b/Gems/DevTextures/gem.json index 00cafbd6fb..f8c436887d 100644 --- a/Gems/DevTextures/gem.json +++ b/Gems/DevTextures/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The Dev Textures Gem provides a collection of general purpose texture assets useful for prototypes and preproduction.", "canonical_tags": [ diff --git a/Gems/EMotionFX/CMakeLists.txt b/Gems/EMotionFX/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/EMotionFX/CMakeLists.txt +++ b/Gems/EMotionFX/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index 67d0ba6d85..bd90e589c9 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -6,10 +6,9 @@ # # -ly_get_list_relative_pal_filename(core_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) - -ly_get_list_relative_pal_filename(editor_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Editor/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(editor_common_dir ${CMAKE_CURRENT_LIST_DIR}/Editor/Platform/Common) +o3de_pal_dir(core_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(editor_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Editor/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(editor_common_dir ${CMAKE_CURRENT_LIST_DIR}/Editor/Platform/Common) ly_add_target( NAME EMotionFXStaticLib STATIC diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp index 0ebaf8bfee..23e5d25824 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp @@ -952,7 +952,15 @@ namespace MCommon } else { - worldTM = AZ::Transform::CreateFromQuaternion(MCore::AzEulerAnglesToAzQuat(0.0f, 0.0f, MCore::Math::DegreesToRadians(180.0f))); + if (direction.GetX() > 0) + { + worldTM = AZ::Transform::CreateFromQuaternion(MCore::AzEulerAnglesToAzQuat(MCore::Math::DegreesToRadians(180.0f), 0.0f, MCore::Math::DegreesToRadians(180.0f))); + } + else + { + worldTM = AZ::Transform::CreateFromQuaternion(MCore::AzEulerAnglesToAzQuat(0.0f, 0.0f, 0.0f)); + } + } // set the cylinder to the given position diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeWidget.cpp b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeWidget.cpp index 29745beb68..538ad3ba52 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeWidget.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeWidget.cpp @@ -125,6 +125,10 @@ namespace EMotionFX Physics::RagdollNodeConfiguration* ragdollNodeConfig = GetRagdollNodeConfig(); if (ragdollNodeConfig) { + AzPhysics::JointConfiguration* jointLimitConfig = ragdollNodeConfig->m_jointConfig.get(); + jointLimitConfig->SetPropertyVisibility(AzPhysics::JointConfiguration::PropertyVisibility::ParentLocalRotation, jointLimitConfig != nullptr); + jointLimitConfig->SetPropertyVisibility(AzPhysics::JointConfiguration::PropertyVisibility::ChildLocalRotation, jointLimitConfig != nullptr); + m_addColliderButton->show(); m_addRemoveButton->setText("Remove from ragdoll"); diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 15037793f1..08607c330d 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -400,17 +400,16 @@ namespace EMotionFX behaviorContext->EBus("SystemNotificationBus") ; - // In order for a property to be displayed in ScriptCanvas. Both a setter and a getter are necessary(both must be non-null). - // This is being worked on in dragon branch, once this is complete the dummy lambda functions can be removed. + // In order for a property to be displayed in ScriptCanvas. behaviorContext->Class("MotionEvent") - ->Property("entityId", BehaviorValueGetter(&MotionEvent::m_entityId), [](MotionEvent*, const AZ::EntityId&) {}) - ->Property("parameter", BehaviorValueGetter(&MotionEvent::m_parameter), [](MotionEvent*, const char*) {}) - ->Property("eventType", BehaviorValueGetter(&MotionEvent::m_eventType), [](MotionEvent*, const AZ::u32&) {}) - ->Property("eventTypeName", BehaviorValueGetter(&MotionEvent::m_eventTypeName), [](MotionEvent*, const char*) {}) - ->Property("time", BehaviorValueGetter(&MotionEvent::m_time), [](MotionEvent*, const float&) {}) - ->Property("globalWeight", BehaviorValueGetter(&MotionEvent::m_globalWeight), [](MotionEvent*, const float&) {}) - ->Property("localWeight", BehaviorValueGetter(&MotionEvent::m_localWeight), [](MotionEvent*, const float&) {}) - ->Property("isEventStart", BehaviorValueGetter(&MotionEvent::m_isEventStart), [](MotionEvent*, const bool&) {}) + ->Property("entityId", BehaviorValueGetter(&MotionEvent::m_entityId), nullptr) + ->Property("parameter", BehaviorValueGetter(&MotionEvent::m_parameter), nullptr) + ->Property("eventType", BehaviorValueGetter(&MotionEvent::m_eventType), nullptr) + ->Property("eventTypeName", BehaviorValueGetter(&MotionEvent::m_eventTypeName), nullptr) + ->Property("time", BehaviorValueGetter(&MotionEvent::m_time), nullptr) + ->Property("globalWeight", BehaviorValueGetter(&MotionEvent::m_globalWeight), nullptr) + ->Property("localWeight", BehaviorValueGetter(&MotionEvent::m_localWeight), nullptr) + ->Property("isEventStart", BehaviorValueGetter(&MotionEvent::m_isEventStart), nullptr) ; behaviorContext->EBus("ActorNotificationBus") diff --git a/Gems/EMotionFX/gem.json b/Gems/EMotionFX/gem.json index ed80517af1..c07c8368c2 100644 --- a/Gems/EMotionFX/gem.json +++ b/Gems/EMotionFX/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The EMotion FX Animation Gem provides Open 3D Engine's animation system for rigged actors and includes Animation Editor, a tool for creating animated behaviors, simulated objects, and colliders for rigged actors.", "canonical_tags": [ diff --git a/Gems/EditorPythonBindings/gem.json b/Gems/EditorPythonBindings/gem.json index 475483f13b..a5ee9f5631 100644 --- a/Gems/EditorPythonBindings/gem.json +++ b/Gems/EditorPythonBindings/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Editor Python Bindings Gem provides Python commands for Open 3D Engine Editor functions.", "canonical_tags": [ diff --git a/Gems/ExpressionEvaluation/gem.json b/Gems/ExpressionEvaluation/gem.json index cd712f4da9..667eebbcb5 100644 --- a/Gems/ExpressionEvaluation/gem.json +++ b/Gems/ExpressionEvaluation/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Expression Evaluation Gem provides a method for parsing and executing string expressions in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/FastNoise/gem.json b/Gems/FastNoise/gem.json index d8dfb878b4..a9c0f1f42d 100644 --- a/Gems/FastNoise/gem.json +++ b/Gems/FastNoise/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The FastNoise Gradient Gem uses the third-party, open source FastNoise library to provide a variety of high-performance noise generation algorithms.", "canonical_tags": [ diff --git a/Gems/GameState/gem.json b/Gems/GameState/gem.json index fe3a338997..d3e2d76c5a 100644 --- a/Gems/GameState/gem.json +++ b/Gems/GameState/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Game State Gem provides a generic framework to determine and manage game states and game state transitions in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/GameStateSamples/CMakeLists.txt b/Gems/GameStateSamples/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/GameStateSamples/CMakeLists.txt +++ b/Gems/GameStateSamples/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index 5d1d180de0..939b2ce1bd 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(include_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(include_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME GameStateSamples.Headers HEADERONLY @@ -21,7 +21,7 @@ ly_add_target( INTERFACE Gem::GameState Gem::LocalUser - Gem::LyShine.Static + Gem::LyShine.Clients.API Gem::SaveData.Static Gem::MessagePopup.Static Legacy::CryCommon diff --git a/Gems/GameStateSamples/gem.json b/Gems/GameStateSamples/gem.json index 80018ff1a8..94556ee677 100644 --- a/Gems/GameStateSamples/gem.json +++ b/Gems/GameStateSamples/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Game State Samples Gem provides a set of sample game states (built on top of the Game State Gem), including primary user selection, main menu, level loading, level running, and level paused.", "canonical_tags": [ diff --git a/Gems/Gestures/gem.json b/Gems/Gestures/gem.json index 8efd389d53..c0609c8d54 100644 --- a/Gems/Gestures/gem.json +++ b/Gems/Gestures/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Gestures Gem provides detection for common gesture-based input actions on iOS and Android devices.", "canonical_tags": [ diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index d4cf666630..d2d8f8c696 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -19,7 +19,6 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC AZ::AzCore - AZ::AtomCore AZ::AzFramework Gem::SurfaceData Gem::ImageProcessingAtom.Headers @@ -41,7 +40,6 @@ ly_add_target( Gem::LmbrCentral PUBLIC AZ::AzCore - AZ::AtomCore Gem::GradientSignal.Static Gem::ImageProcessingAtom.Headers # Atom/ImageProcessing/PixelFormats.h is part of a header in Includes RUNTIME_DEPENDENCIES @@ -73,7 +71,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC 3rdParty::Qt::Widgets AZ::AzCore - AZ::AtomCore AZ::AzFramework AZ::AzToolsFramework AZ::AssetBuilderSDK @@ -97,8 +94,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PRIVATE Gem::GradientSignal.Editor.Static Gem::LmbrCentral.Editor - PUBLIC - AZ::AtomCore RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ConstantGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ConstantGradientComponent.h index cb27914b8a..1ed06a976a 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ConstantGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ConstantGradientComponent.h @@ -62,6 +62,7 @@ namespace GradientSignal ////////////////////////////////////////////////////////////////////////// // GradientRequestBus float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; protected: ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/DitherGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/DitherGradientComponent.h index ed12ec2ff7..add6de06cf 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/DitherGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/DitherGradientComponent.h @@ -77,6 +77,7 @@ namespace GradientSignal ////////////////////////////////////////////////////////////////////////// // GradientRequestBus float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override; ////////////////////////////////////////////////////////////////////////// @@ -102,6 +103,13 @@ namespace GradientSignal GradientSampler& GetGradientSampler() override; private: + static int ScaledPositionToPatternIndex(const AZ::Vector3& scaledPosition, int patternSize); + static float GetDitherValue4x4(const AZ::Vector3& scaledPosition); + static float GetDitherValue8x8(const AZ::Vector3& scaledPosition); + + float GetCalculatedPointsPerUnit() const; + float GetDitherValue(const AZ::Vector3& scaledPosition, float value) const; + DitherGradientConfig m_configuration; LmbrCentral::DependencyMonitor m_dependencyMonitor; }; diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ImageGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ImageGradientComponent.h index 8214436f83..79d42ec478 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ImageGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ImageGradientComponent.h @@ -69,6 +69,7 @@ namespace GradientSignal // GradientRequestBus overrides... float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; // AZ::Data::AssetBus overrides... void OnAssetReady(AZ::Data::Asset asset) override; diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/InvertGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/InvertGradientComponent.h index 79dbea975b..a370286b0b 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/InvertGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/InvertGradientComponent.h @@ -64,6 +64,7 @@ namespace GradientSignal ////////////////////////////////////////////////////////////////////////// // GradientRequestBus float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override; protected: diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/LevelsGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/LevelsGradientComponent.h index 5e70adfe32..093f84ef3a 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/LevelsGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/LevelsGradientComponent.h @@ -69,6 +69,7 @@ namespace GradientSignal ////////////////////////////////////////////////////////////////////////// // GradientRequestBus float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; bool IsEntityInHierarchy(const AZ::EntityId& entityId) const override; protected: diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/PerlinGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/PerlinGradientComponent.h index ef171f5319..19f3fe7294 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/PerlinGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/PerlinGradientComponent.h @@ -70,6 +70,7 @@ namespace GradientSignal // GradientRequestBus overrides... float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; private: PerlinGradientConfig m_configuration; diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/RandomGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/RandomGradientComponent.h index b0dbd964a0..328fed5118 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/RandomGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/RandomGradientComponent.h @@ -61,6 +61,7 @@ namespace GradientSignal // GradientRequestBus overrides... float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; private: RandomGradientConfig m_configuration; @@ -73,5 +74,7 @@ namespace GradientSignal // RandomGradientRequestBus overrides... int GetRandomSeed() const override; void SetRandomSeed(int seed) override; + + float GetRandomValue(const AZ::Vector3& position, AZStd::size_t seed) const; }; } diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ShapeAreaFalloffGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ShapeAreaFalloffGradientComponent.h index d7c2344fd2..27b2da58a3 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/ShapeAreaFalloffGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/ShapeAreaFalloffGradientComponent.h @@ -69,6 +69,7 @@ namespace GradientSignal ////////////////////////////////////////////////////////////////////////// // GradientRequestBus float GetValue(const GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; protected: ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h index 3a215c5b5d..45b5a173a3 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h @@ -10,8 +10,7 @@ #include #include #include - -#include +#include namespace GradientSignal { @@ -57,7 +56,7 @@ namespace GradientSignal * \param positions The input list of positions to query. * \param outValues The output list of values. This list is expected to be the same size as the positions list. */ - virtual void GetValues(AZStd::array_view positions, AZStd::array_view outValues) const + virtual void GetValues(AZStd::span positions, AZStd::span outValues) const { // Reference implementation of GetValues for any gradients that don't have their own optimized implementations. // This is 10%-60% faster than calling GetValue via EBus many times due to the per-call EBus overhead. @@ -72,11 +71,7 @@ namespace GradientSignal for (size_t index = 0; index < positions.size(); index++) { sampleParams.m_position = positions[index]; - - // The const_cast is necessary for now since array_view currently only supports const entries. - // If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed. - auto& outValue = const_cast(outValues[index]); - outValue = GetValue(sampleParams); + outValues[index] = GetValue(sampleParams); } } diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h b/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h index a2e1849590..c9aa7f680c 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h @@ -33,7 +33,7 @@ namespace GradientSignal static void Reflect(AZ::ReflectContext* context); inline float GetValue(const GradientSampleParams& sampleParams) const; - inline void GetValues(AZStd::array_view positions, AZStd::array_view outValues) const; + inline void GetValues(AZStd::span positions, AZStd::span outValues) const; bool IsEntityInHierarchy(const AZ::EntityId& entityId) const; @@ -147,18 +147,12 @@ namespace GradientSignal return output * m_opacity; } - inline void GradientSampler::GetValues(AZStd::array_view positions, AZStd::array_view outValues) const + inline void GradientSampler::GetValues(AZStd::span positions, AZStd::span outValues) const { - auto ClearOutputValues = [](AZStd::array_view outValues) + auto ClearOutputValues = [](AZStd::span outValues) { // If we don't have a valid gradient (or it is fully transparent), clear out all the output values. - for (size_t index = 0; index < outValues.size(); index++) - { - // The const_cast is necessary for now since array_view currently only supports const entries. - // If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed. - auto& outValue = const_cast(outValues[index]); - outValue = 0.0f; - } + memset(outValues.data(), 0, outValues.size() * sizeof(float)); }; if (m_opacity <= 0.0f || !m_gradientId.IsValid()) @@ -214,12 +208,8 @@ namespace GradientSignal } // Perform any post-fetch transformations on the gradient values (invert, levels, opacity). - for (size_t index = 0; index < outValues.size(); index++) + for (auto& outValue : outValues) { - // The const_cast is necessary for now since array_view currently only supports const entries. - // If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed. - auto& outValue = const_cast(outValues[index]); - if (m_invertInput) { outValue = 1.0f - outValue; diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Util.h b/Gems/GradientSignal/Code/Include/GradientSignal/Util.h index fa1791c053..f91c5d54f1 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Util.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Util.h @@ -7,11 +7,12 @@ */ #pragma once +#include #include #include -#include #include #include +#include #include #include @@ -53,28 +54,61 @@ namespace GradientSignal inline float GetLevels(float input, float inputMid, float inputMin, float inputMax, float outputMin, float outputMax) { - input = AZ::GetClamp(input, 0.0f, 1.0f); - inputMid = AZ::GetClamp(inputMid, 0.01f, 10.0f); // Clamp the midpoint to a non-zero value so that it's always safe to divide by it. + inputMid = AZ::GetClamp(inputMid, 0.01f, 10.0f); // Clamp the midpoint to a non-zero value so that it's always safe to divide by it. inputMin = AZ::GetClamp(inputMin, 0.0f, 1.0f); inputMax = AZ::GetClamp(inputMax, 0.0f, 1.0f); outputMin = AZ::GetClamp(outputMin, 0.0f, 1.0f); outputMax = AZ::GetClamp(outputMax, 0.0f, 1.0f); - float inputCorrected = 0.0f; if (inputMin == inputMax) { - inputCorrected = (input <= inputMin) ? 0.0f : 1.0f; - } - else - { - const float inputRemapped = AZ::GetMin(AZ::GetMax(input - inputMin, 0.0f) / (inputMax - inputMin), 1.0f); - // Note: Some paint programs map the midpoint using 1/mid where low values are dark and high values are light, - // others do the reverse and use mid directly, so low values are light and high values are dark. We've chosen to - // align with 1/mid since it appears to be the more prevalent of the two approaches. - inputCorrected = powf(inputRemapped, 1.0f / inputMid); + return (AZ::GetClamp(input, 0.0f, 1.0f) <= inputMin) ? outputMin : outputMax; } + const float inputMidReciprocal = 1.0f / inputMid; + const float inputExtentsReciprocal = 1.0f / (inputMax - inputMin); + + const float inputRemapped = + AZ::GetMin(AZ::GetMax(AZ::GetClamp(input, 0.0f, 1.0f) - inputMin, 0.0f) * inputExtentsReciprocal, 1.0f); + + // Note: Some paint programs map the midpoint using 1/mid where low values are dark and high values are light, + // others do the reverse and use mid directly, so low values are light and high values are dark. We've chosen to + // align with 1/mid since it appears to be the more prevalent of the two approaches. + const float inputCorrected = powf(inputRemapped, inputMidReciprocal); + return AZ::Lerp(outputMin, outputMax, inputCorrected); } + inline void GetLevels(AZStd::span inOutValues, float inputMid, float inputMin, float inputMax, float outputMin, float outputMax) + { + inputMid = AZ::GetClamp(inputMid, 0.01f, 10.0f); // Clamp the midpoint to a non-zero value so that it's always safe to divide by it. + inputMin = AZ::GetClamp(inputMin, 0.0f, 1.0f); + inputMax = AZ::GetClamp(inputMax, 0.0f, 1.0f); + outputMin = AZ::GetClamp(outputMin, 0.0f, 1.0f); + outputMax = AZ::GetClamp(outputMax, 0.0f, 1.0f); + + if (inputMin == inputMax) + { + for (auto& inOutValue : inOutValues) + { + inOutValue = (AZ::GetClamp(inOutValue, 0.0f, 1.0f) <= inputMin) ? outputMin : outputMax; + } + } + + const float inputMidReciprocal = 1.0f / inputMid; + const float inputExtentsReciprocal = 1.0f / (inputMax - inputMin); + + for (auto& inOutValue : inOutValues) + { + const float inputRemapped = + AZ::GetMin(AZ::GetMax(AZ::GetClamp(inOutValue, 0.0f, 1.0f) - inputMin, 0.0f) * inputExtentsReciprocal, 1.0f); + + // Note: Some paint programs map the midpoint using 1/mid where low values are dark and high values are light, + // others do the reverse and use mid directly, so low values are light and high values are dark. We've chosen to + // align with 1/mid since it appears to be the more prevalent of the two approaches. + const float inputCorrected = powf(inputRemapped, inputMidReciprocal); + + inOutValue = AZ::Lerp(outputMin, outputMax, inputCorrected); + } + } } // namespace GradientSignal diff --git a/Gems/GradientSignal/Code/Source/Components/ConstantGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/ConstantGradientComponent.cpp index 86e8a5abc6..ac81f616c6 100644 --- a/Gems/GradientSignal/Code/Source/Components/ConstantGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/ConstantGradientComponent.cpp @@ -134,6 +134,18 @@ namespace GradientSignal return m_configuration.m_value; } + void ConstantGradientComponent::GetValues( + [[maybe_unused]] AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + AZStd::fill(outValues.begin(), outValues.end(), m_configuration.m_value); + } + float ConstantGradientComponent::GetConstantValue() const { return m_configuration.m_value; diff --git a/Gems/GradientSignal/Code/Source/Components/DitherGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/DitherGradientComponent.cpp index c7845a41a6..1b320afeb9 100644 --- a/Gems/GradientSignal/Code/Source/Components/DitherGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/DitherGradientComponent.cpp @@ -174,90 +174,122 @@ namespace GradientSignal return false; } - int PositionToMatrixIndex(float position, int patternSize) + int DitherGradientComponent::ScaledPositionToPatternIndex(const AZ::Vector3& scaledPosition, int patternSize) { - int result = static_cast(std::floor(fmod(position, static_cast(patternSize)))); + // The input position is expected to be scaled up so that each integer value is a unique point in our dither pattern, and + // the fractional value is just the amount within the point. The output is the specific index into an NxN pattern to use + // for the dither comparison value. - if (result < 0) - { - result += patternSize; - } + // Get the floor before casting to int because we want fractional negative values to go "down" to the next negative value. + AZ::Vector3 flooredScaledPosition = scaledPosition.GetFloor(); - return result; + // For a pattern of 4, we want our indices to go 0, 1, 2, 3, 0, 1, 2, 3, etc. However, we want it continuous across + // negative and positive positions so we can't just use mod with abs(). Instead, we use a double-mod which gives us + // a result that's continuous across all coordinate space. + const int x = ((static_cast(flooredScaledPosition.GetX()) % patternSize) + patternSize) % patternSize; + const int y = ((static_cast(flooredScaledPosition.GetY()) % patternSize) + patternSize) % patternSize; + + return (patternSize * y + x); } - float GetDitherValue4x4(const AZ::Vector3& position) + float DitherGradientComponent::GetDitherValue4x4(const AZ::Vector3& scaledPosition) { - const int patternSize = 4; - const int patternSizeSq = patternSize * patternSize; - const int indexMatrix[patternSizeSq] = { - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5 }; + constexpr int patternSize = 4; + constexpr float indexMatrix[] = { + 0.0f / 16.0f, 8.0f / 16.0f, 2.0f / 16.0f, 10.0f / 16.0f, + 12.0f / 16.0f, 4.0f / 16.0f, 14.0f / 16.0f, 6.0f / 16.0f, + 3.0f / 16.0f, 11.0f / 16.0f, 1.0f / 16.0f, 9.0f / 16.0f, + 15.0f / 16.0f, 7.0f / 16.0f, 13.0f / 16.0f, 5.0f / 16.0f }; - const int x = PositionToMatrixIndex(position.GetX(), patternSize); - const int y = PositionToMatrixIndex(position.GetY(), patternSize); - - return indexMatrix[patternSize * y + x] / static_cast(patternSizeSq); + return indexMatrix[ScaledPositionToPatternIndex(scaledPosition, patternSize)]; } - float GetDitherValue8x8(const AZ::Vector3& position) + float DitherGradientComponent::GetDitherValue8x8(const AZ::Vector3& scaledPosition) { - const int patternSize = 8; - const int patternSizeSq = patternSize * patternSize; - const int indexMatrix[patternSizeSq] = { - 0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21 }; + constexpr int patternSize = 8; + constexpr float indexMatrix[] = { + 0.0f / 64.0f, 32.0f / 64.0f, 8.0f / 64.0f, 40.0f / 64.0f, 2.0f / 64.0f, 34.0f / 64.0f, 10.0f / 64.0f, 42.0f / 64.0f, + 48.0f / 64.0f, 16.0f / 64.0f, 56.0f / 64.0f, 24.0f / 64.0f, 50.0f / 64.0f, 18.0f / 64.0f, 58.0f / 64.0f, 26.0f / 64.0f, + 12.0f / 64.0f, 44.0f / 64.0f, 4.0f / 64.0f, 36.0f / 64.0f, 14.0f / 64.0f, 46.0f / 64.0f, 6.0f / 64.0f, 38.0f / 64.0f, + 60.0f / 64.0f, 28.0f / 64.0f, 52.0f / 64.0f, 20.0f / 64.0f, 62.0f / 64.0f, 30.0f / 64.0f, 54.0f / 64.0f, 22.0f / 64.0f, + 3.0f / 64.0f, 35.0f / 64.0f, 11.0f / 64.0f, 43.0f / 64.0f, 1.0f / 64.0f, 33.0f / 64.0f, 9.0f / 64.0f, 41.0f / 64.0f, + 51.0f / 64.0f, 19.0f / 64.0f, 59.0f / 64.0f, 27.0f / 64.0f, 49.0f / 64.0f, 17.0f / 64.0f, 57.0f / 64.0f, 25.0f / 64.0f, + 15.0f / 64.0f, 47.0f / 64.0f, 7.0f / 64.0f, 39.0f / 64.0f, 13.0f / 64.0f, 45.0f / 64.0f, 5.0f / 64.0f, 37.0f / 64.0f, + 63.0f / 64.0f, 31.0f / 64.0f, 55.0f / 64.0f, 23.0f / 64.0f, 61.0f / 64.0f, 29.0f / 64.0f, 53.0f / 64.0f, 21.0f / 64.0f + }; - const int x = PositionToMatrixIndex(position.GetX(), patternSize); - const int y = PositionToMatrixIndex(position.GetY(), patternSize); - - return indexMatrix[patternSize * y + x] / static_cast(patternSizeSq); + return indexMatrix[ScaledPositionToPatternIndex(scaledPosition, patternSize)]; } - float DitherGradientComponent::GetValue(const GradientSampleParams& sampleParams) const + float DitherGradientComponent::GetCalculatedPointsPerUnit() const { - AZ_PROFILE_FUNCTION(Entity); - - const AZ::Vector3& coordinate = sampleParams.m_position; - float pointsPerUnit = m_configuration.m_pointsPerUnit; if (m_configuration.m_useSystemPointsPerUnit) { SectorDataRequestBus::Broadcast(&SectorDataRequestBus::Events::GetPointsPerMeter, pointsPerUnit); } - pointsPerUnit = AZ::GetMax(pointsPerUnit, 0.0001f); - - auto scaledCoordinate = coordinate * pointsPerUnit; - auto x = std::floor(scaledCoordinate.GetX()) / pointsPerUnit; - auto y = std::floor(scaledCoordinate.GetY()) / pointsPerUnit; - auto z = std::floor(scaledCoordinate.GetZ()) / pointsPerUnit; - AZ::Vector3 flooredCoordinate(x, y, z); - - GradientSampleParams adjustedSampleParams = sampleParams; - adjustedSampleParams.m_position = flooredCoordinate; - float value = m_configuration.m_gradientSampler.GetValue(adjustedSampleParams); + return AZ::GetMax(pointsPerUnit, 0.0001f); + } + float DitherGradientComponent::GetDitherValue(const AZ::Vector3& scaledPosition, float value) const + { float d = 0.0f; switch (m_configuration.m_patternType) { default: case DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4: - d = GetDitherValue4x4((scaledCoordinate) + m_configuration.m_patternOffset); + d = GetDitherValue4x4(scaledPosition + m_configuration.m_patternOffset); break; case DitherGradientConfig::BayerPatternType::PATTERN_SIZE_8x8: - d = GetDitherValue8x8((scaledCoordinate) + m_configuration.m_patternOffset); + d = GetDitherValue8x8(scaledPosition + m_configuration.m_patternOffset); break; } - return value > d ? 1.0f : 0.0f; + return (value > d) ? 1.0f : 0.0f; + } + + float DitherGradientComponent::GetValue(const GradientSampleParams& sampleParams) const + { + const AZ::Vector3& coordinate = sampleParams.m_position; + + const float pointsPerUnit = GetCalculatedPointsPerUnit(); + + AZ::Vector3 scaledCoordinate = coordinate * pointsPerUnit; + AZ::Vector3 flooredCoordinate = scaledCoordinate.GetFloor() / pointsPerUnit; + + GradientSampleParams adjustedSampleParams = sampleParams; + adjustedSampleParams.m_position = flooredCoordinate; + float value = m_configuration.m_gradientSampler.GetValue(adjustedSampleParams); + + return GetDitherValue(scaledCoordinate, value); + } + + void DitherGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + const float pointsPerUnit = GetCalculatedPointsPerUnit(); + + // Create the entire set of floored coordinates to use in the gradient value lookups. + AZStd::vector flooredCoordinates(positions.size()); + for (size_t index = 0; index < positions.size(); index++) + { + AZ::Vector3 scaledCoordinate = positions[index] * pointsPerUnit; + flooredCoordinates[index] = scaledCoordinate.GetFloor() / pointsPerUnit; + } + + m_configuration.m_gradientSampler.GetValues(flooredCoordinates, outValues); + + // For each gradient value, turn it into a 0 or 1 based on the location and the dither pattern. + for (size_t index = 0; index < positions.size(); index++) + { + AZ::Vector3 scaledCoordinate = positions[index] * pointsPerUnit; + outValues[index] = GetDitherValue(scaledCoordinate, outValues[index]); + } } bool DitherGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const diff --git a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp index 269bfbc2df..d948f6269e 100644 --- a/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/ImageGradientComponent.cpp @@ -219,6 +219,35 @@ namespace GradientSignal return 0.0f; } + void ImageGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + AZ::Vector3 uvw; + bool wasPointRejected = false; + + AZStd::shared_lock imageLock(m_imageMutex); + + for (size_t index = 0; index < positions.size(); index++) + { + m_gradientTransform.TransformPositionToUVWNormalized(positions[index], uvw, wasPointRejected); + + if (!wasPointRejected) + { + outValues[index] = GetValueFromImageAsset( + m_configuration.m_imageAsset, uvw, m_configuration.m_tilingX, m_configuration.m_tilingY, 0.0f); + } + else + { + outValues[index] = 0.0f; + } + } + } + AZStd::string ImageGradientComponent::GetImageAssetPath() const { AZStd::string assetPathString; diff --git a/Gems/GradientSignal/Code/Source/Components/InvertGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/InvertGradientComponent.cpp index 678f3b363c..aef5cc7a52 100644 --- a/Gems/GradientSignal/Code/Source/Components/InvertGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/InvertGradientComponent.cpp @@ -137,6 +137,21 @@ namespace GradientSignal return output; } + void InvertGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + m_configuration.m_gradientSampler.GetValues(positions, outValues); + for (auto& outValue : outValues) + { + outValue = 1.0f - AZ::GetClamp(outValue, 0.0f, 1.0f); + } + } + bool InvertGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const { return m_configuration.m_gradientSampler.IsEntityInHierarchy(entityId); diff --git a/Gems/GradientSignal/Code/Source/Components/LevelsGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/LevelsGradientComponent.cpp index b2958c590c..25f6a34614 100644 --- a/Gems/GradientSignal/Code/Source/Components/LevelsGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/LevelsGradientComponent.cpp @@ -172,8 +172,6 @@ namespace GradientSignal float LevelsGradientComponent::GetValue(const GradientSampleParams& sampleParams) const { - AZ_PROFILE_FUNCTION(Entity); - float output = 0.0f; output = GetLevels( @@ -187,6 +185,21 @@ namespace GradientSignal return output; } + void LevelsGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + m_configuration.m_gradientSampler.GetValues(positions, outValues); + + GetLevels(outValues, + m_configuration.m_inputMid, m_configuration.m_inputMin, m_configuration.m_inputMax, + m_configuration.m_outputMin, m_configuration.m_outputMax); + } + bool LevelsGradientComponent::IsEntityInHierarchy(const AZ::EntityId& entityId) const { return m_configuration.m_gradientSampler.IsEntityInHierarchy(entityId); diff --git a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp index 3096afa3dc..e3dfaf2161 100644 --- a/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/PerlinGradientComponent.cpp @@ -203,6 +203,36 @@ namespace GradientSignal return 0.0f; } + void PerlinGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + AZ::Vector3 uvw; + bool wasPointRejected = false; + + AZStd::shared_lock lock(m_transformMutex); + + for (size_t index = 0; index < positions.size(); index++) + { + m_gradientTransform.TransformPositionToUVW(positions[index], uvw, wasPointRejected); + + if (!wasPointRejected) + { + outValues[index] = m_perlinImprovedNoise->GenerateOctaveNoise( + uvw.GetX(), uvw.GetY(), uvw.GetZ(), m_configuration.m_octave, m_configuration.m_amplitude, + m_configuration.m_frequency); + } + else + { + outValues[index] = 0.0f; + } + } + } + int PerlinGradientComponent::GetRandomSeed() const { return m_configuration.m_randomSeed; diff --git a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp index 1b6753560c..0f4ece38a1 100644 --- a/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/RandomGradientComponent.cpp @@ -145,6 +145,22 @@ namespace GradientSignal m_gradientTransform = newTransform; } + float RandomGradientComponent::GetRandomValue(const AZ::Vector3& position, AZStd::size_t seed) const + { + // generating stable pseudo-random noise from a position based hash + float x = position.GetX(); + float y = position.GetY(); + AZStd::size_t result = 0; + + AZStd::hash_combine(result, x * seed + y); + AZStd::hash_combine(result, y * seed + x); + AZStd::hash_combine(result, x * y * seed); + + // always returns [0.0,1.0] + return static_cast(result % std::numeric_limits::max()) / static_cast(std::numeric_limits::max()); + } + + float RandomGradientComponent::GetValue(const GradientSampleParams& sampleParams) const { @@ -158,23 +174,46 @@ namespace GradientSignal if (!wasPointRejected) { - //generating stable pseudo-random noise from a position based hash - float x = uvw.GetX(); - float y = uvw.GetY(); - AZStd::size_t result = 0; - const AZStd::size_t seed = m_configuration.m_randomSeed + AZStd::size_t(2); // Add 2 to avoid seeds 0 and 1, which can create strange patterns with this particular algorithm + const AZStd::size_t seed = m_configuration.m_randomSeed + + AZStd::size_t(2); // Add 2 to avoid seeds 0 and 1, which can create strange patterns with this particular algorithm - AZStd::hash_combine(result, x * seed + y); - AZStd::hash_combine(result, y * seed + x); - AZStd::hash_combine(result, x * y * seed); - - //always returns [0.0,1.0] - return static_cast(result % std::numeric_limits::max()) / static_cast(std::numeric_limits::max()); + return GetRandomValue(uvw, seed); } return 0.0f; } + void RandomGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) + { + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } + + AZ::Vector3 uvw; + bool wasPointRejected = false; + const AZStd::size_t seed = m_configuration.m_randomSeed + + AZStd::size_t(2); // Add 2 to avoid seeds 0 and 1, which can create strange patterns with this particular algorithm + + AZStd::shared_lock lock(m_transformMutex); + + for (size_t index = 0; index < positions.size(); index++) + { + m_gradientTransform.TransformPositionToUVW(positions[index], uvw, wasPointRejected); + + if (!wasPointRejected) + { + outValues[index] = GetRandomValue(uvw, seed); + } + else + { + outValues[index] = 0.0f; + } + } + } + + int RandomGradientComponent::GetRandomSeed() const { return m_configuration.m_randomSeed; diff --git a/Gems/GradientSignal/Code/Source/Components/ShapeAreaFalloffGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/ShapeAreaFalloffGradientComponent.cpp index 9e1a250900..77b7f1a428 100644 --- a/Gems/GradientSignal/Code/Source/Components/ShapeAreaFalloffGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/ShapeAreaFalloffGradientComponent.cpp @@ -157,21 +157,55 @@ namespace GradientSignal float ShapeAreaFalloffGradientComponent::GetValue(const GradientSampleParams& sampleParams) const { - AZ_PROFILE_FUNCTION(Entity); - float distance = 0.0f; LmbrCentral::ShapeComponentRequestsBus::EventResult(distance, m_configuration.m_shapeEntityId, &LmbrCentral::ShapeComponentRequestsBus::Events::DistanceFromPoint, sampleParams.m_position); - // In the special case of 0 falloff, make sure that all points inside the shape (0 distance) return - // 1.0, and all points outside the shape return 0. - if (m_configuration.m_falloffWidth == 0.0f) + // Since this is outer falloff, distance should give us values from 1.0 at the minimum distance to 0.0 at the maximum distance. + // The statement is written specifically to handle the 0 falloff case as well. For 0 falloff, all points inside the shape + // (0 distance) return 1.0, and all points outside the shape return 0. This works because division by 0 gives infinity, which gets + // clamped by the GetMax() to 0. However, if distance == 0, it would give us NaN, so we have the separate conditional check to + // handle that case and clamp to 1.0. + return (distance <= 0.0f) ? 1.0f : AZ::GetMax(1.0f - (distance / m_configuration.m_falloffWidth), 0.0f); + } + + void ShapeAreaFalloffGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) { - return (distance > 0.0f) ? 0.0f : 1.0f; + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; } - // Since this is outer falloff, distance should give us values from 1.0 at the minimum distance - // to 0.0 at the maximum distance. - return GetRatio(m_configuration.m_falloffWidth, 0.0f, distance); + bool shapeConnected = false; + const float falloffWidth = m_configuration.m_falloffWidth; + + LmbrCentral::ShapeComponentRequestsBus::Event( + m_configuration.m_shapeEntityId, + [falloffWidth, positions, &outValues, &shapeConnected](LmbrCentral::ShapeComponentRequestsBus::Events* shapeRequests) + { + shapeConnected = true; + + for (size_t index = 0; index < positions.size(); index++) + { + float distance = shapeRequests->DistanceFromPoint(positions[index]); + + // Since this is outer falloff, distance should give us values from 1.0 at the minimum distance to 0.0 at the maximum + // distance. The statement is written specifically to handle the 0 falloff case as well. For 0 falloff, all points + // inside the shape (0 distance) return 1.0, and all points outside the shape return 0. This works because division by 0 + // gives infinity, which gets clamped by the GetMax() to 0. However, if distance == 0, it would give us NaN, so we have + // the separate conditional check to handle that case and clamp to 1.0. + outValues[index] = (distance <= 0.0f) ? 1.0f : AZ::GetMax(1.0f - (distance / falloffWidth), 0.0f); + } + }); + + // If there's no shape, there's no falloff. + if (!shapeConnected) + { + for (auto& outValue : outValues) + { + outValue = 1.0f; + } + } } AZ::EntityId ShapeAreaFalloffGradientComponent::GetShapeEntityId() const diff --git a/Gems/GradientSignal/Code/Tests/EditorGradientSignalPreviewTests.cpp b/Gems/GradientSignal/Code/Tests/EditorGradientSignalPreviewTests.cpp index e8bd9f2dff..83892f1c69 100644 --- a/Gems/GradientSignal/Code/Tests/EditorGradientSignalPreviewTests.cpp +++ b/Gems/GradientSignal/Code/Tests/EditorGradientSignalPreviewTests.cpp @@ -29,21 +29,34 @@ namespace UnitTest { GradientSignalTest::SetUp(); - // Set up job manager with two threads so that we can run and test the preview job logic. - AZ::JobManagerDesc desc; - AZ::JobManagerThreadDesc threadDesc; - desc.m_workerThreads.push_back(threadDesc); - desc.m_workerThreads.push_back(threadDesc); - m_jobManager = aznew AZ::JobManager(desc); - m_jobContext = aznew AZ::JobContext(*m_jobManager); - AZ::JobContext::SetGlobalContext(m_jobContext); + auto globalContext = AZ::JobContext::GetGlobalContext(); + if (globalContext) + { + AZ_Assert( + globalContext->GetJobManager().GetNumWorkerThreads() >= 2, + "Job Manager previously started by test environment with too few threads for this test."); + } + else + { + // Set up job manager with two threads so that we can run and test the preview job logic. + AZ::JobManagerDesc desc; + AZ::JobManagerThreadDesc threadDesc; + desc.m_workerThreads.push_back(threadDesc); + desc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(desc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + } } void TearDown() override { - AZ::JobContext::SetGlobalContext(nullptr); - delete m_jobContext; - delete m_jobManager; + if (m_jobContext) + { + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + } GradientSignalTest::TearDown(); } @@ -180,4 +193,5 @@ namespace UnitTest } } -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +// This uses a custom test hook so that we can load LmbrCentral and use Shape components in our unit tests. +AZ_UNIT_TEST_HOOK(new UnitTest::GradientSignalTestEnvironment); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp index 5504fa5b45..6c4ebcc4c0 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp @@ -56,9 +56,9 @@ namespace UnitTest params.m_position = positions[positionIndex]; float value = gradientSampler.GetValue(params); - // We use ASSERT_EQ instead of EXPECT_EQ because if one value doesn't match, they probably all won't, so there's no reason - // to keep running and printing failures for every value. - ASSERT_EQ(value, results[positionIndex]); + // We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no + // reason to keep running and printing failures for every value. + ASSERT_NEAR(value, results[positionIndex], 0.000001f); } } }; diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp index 5cd3c7edf6..8ec190000d 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp @@ -14,10 +14,13 @@ #include #include #include +#include #include #include +#include + namespace UnitTest { struct GradientSignalImageTestsFixture @@ -89,23 +92,21 @@ namespace UnitTest test.m_imageSize, test.m_imageSize, static_cast(test.m_pixel.GetX()), static_cast(test.m_pixel.GetY())); config.m_tilingX = test.m_tiling; config.m_tilingY = test.m_tiling; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); // Create the Gradient Transform Component. GradientSignal::GradientTransformConfig gradientTransformConfig; gradientTransformConfig.m_wrappingType = test.m_wrappingType; - CreateComponent(entity.get(), gradientTransformConfig); + entity->CreateComponent(gradientTransformConfig); - // Create a mock Shape component that describes the bounds that we're using to map our ImageGradient into world space. - CreateComponent(entity.get()); - MockShapeComponentHandler mockShapeHandler(entity->GetId()); - mockShapeHandler.m_GetLocalBounds = AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds); + LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(shapeHalfBounds * 2.0f)); + auto boxComponent = entity->CreateComponent(LmbrCentral::AxisAlignedBoxShapeComponentTypeId); + boxComponent->SetConfiguration(boxConfig); - // Create a mock Transform component that locates our ImageGradient in the center of our desired mock Shape. - MockTransformHandler mockTransformHandler; - mockTransformHandler.m_GetLocalTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)); - mockTransformHandler.m_GetWorldTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)); - mockTransformHandler.BusConnect(entity->GetId()); + // Create a transform that locates our gradient in the center of our desired mock Shape. + auto transform = entity->CreateComponent(); + transform->SetLocalTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); + transform->SetWorldTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); // All components are created, so activate the entity ActivateEntity(entity.get()); @@ -365,7 +366,7 @@ namespace UnitTest mockShapeTransformHandler.BusConnect(mockShape->GetId()); // Create the mock shape that maps our 3x3 image to a 3x3 sample space in the world. - CreateComponent(mockShape.get()); + mockShape->CreateComponent(); MockShapeComponentHandler mockShapeComponentHandler(mockShape->GetId()); // Create a 2x2 box shape (shapes are inclusive, so that's 3x3 sampling space), so that each pixel in the image directly maps to 1 meter in the box. mockShapeComponentHandler.m_GetEncompassingAabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(0.0f), AZ::Vector3(2.0f)); @@ -379,7 +380,7 @@ namespace UnitTest // Create an ImageGradient with a 3x3 asset with the center pixel set. GradientSignal::ImageGradientConfig gradientConfig; gradientConfig.m_imageAsset = ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(3, 3, 1, 1); - CreateComponent(entity.get(), gradientConfig); + entity->CreateComponent(gradientConfig); // Create the test GradientTransform GradientSignal::GradientTransformConfig config; @@ -400,7 +401,7 @@ namespace UnitTest config.m_overrideRotate = false; config.m_overrideScale = false; config.m_is3d = false; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); // Set up the transform on the gradient entity. MockTransformHandler mockTransformHandler; @@ -409,7 +410,7 @@ namespace UnitTest mockTransformHandler.BusConnect(entity->GetId()); // Put a default shape on our gradient entity. This is only used for previews, so it doesn't matter what it gets set to. - CreateComponent(entity.get()); + entity->CreateComponent(); MockShapeComponentHandler mockShapeHandler(entity->GetId()); ActivateEntity(entity.get()); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp index cc91c58fce..72bdfa202e 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp @@ -55,7 +55,7 @@ namespace UnitTest config.m_layers.push_back(layer); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -88,7 +88,7 @@ namespace UnitTest config.m_smoothStep.m_falloffStrength = falloffStrength; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -391,7 +391,7 @@ namespace UnitTest GradientSignal::ReferenceGradientConfig referenceGradientConfig1; referenceGradientConfig1.m_gradientSampler.m_ownerEntityId = referenceGradientEntity1->GetId(); referenceGradientConfig1.m_gradientSampler.m_gradientId = constantGradientEntity->GetId(); - CreateComponent(referenceGradientEntity1.get(), referenceGradientConfig1); + referenceGradientEntity1->CreateComponent(referenceGradientConfig1); ActivateEntity(referenceGradientEntity1.get()); EXPECT_TRUE(referenceGradientConfig1.m_gradientSampler.ValidateGradientEntityId()); @@ -400,7 +400,7 @@ namespace UnitTest GradientSignal::ReferenceGradientConfig referenceGradientConfig2; referenceGradientConfig2.m_gradientSampler.m_ownerEntityId = referenceGradientEntity2->GetId(); referenceGradientConfig2.m_gradientSampler.m_gradientId = referenceGradientEntity1->GetId(); - CreateComponent(referenceGradientEntity2.get(), referenceGradientConfig2); + referenceGradientEntity2->CreateComponent(referenceGradientConfig2); ActivateEntity(referenceGradientEntity2.get()); EXPECT_TRUE(referenceGradientConfig2.m_gradientSampler.ValidateGradientEntityId()); @@ -409,7 +409,7 @@ namespace UnitTest GradientSignal::ReferenceGradientConfig referenceGradientConfig3; referenceGradientConfig3.m_gradientSampler.m_ownerEntityId = referenceGradientEntity3->GetId(); referenceGradientConfig3.m_gradientSampler.m_gradientId = referenceGradientEntity3->GetId(); - CreateComponent(referenceGradientEntity3.get(), referenceGradientConfig3); + referenceGradientEntity3->CreateComponent(referenceGradientConfig3); ActivateEntity(referenceGradientEntity3.get()); EXPECT_FALSE(referenceGradientConfig3.m_gradientSampler.ValidateGradientEntityId()); EXPECT_EQ(referenceGradientConfig3.m_gradientSampler.m_gradientId, AZ::EntityId()); @@ -422,19 +422,19 @@ namespace UnitTest GradientSignal::ReferenceGradientConfig referenceGradientConfig4; referenceGradientConfig4.m_gradientSampler.m_ownerEntityId = referenceGradientEntity4->GetId(); referenceGradientConfig4.m_gradientSampler.m_gradientId = referenceGradientEntity5->GetId(); - CreateComponent(referenceGradientEntity4.get(), referenceGradientConfig4); + referenceGradientEntity4->CreateComponent(referenceGradientConfig4); ActivateEntity(referenceGradientEntity4.get()); GradientSignal::ReferenceGradientConfig referenceGradientConfig5; referenceGradientConfig5.m_gradientSampler.m_ownerEntityId = referenceGradientEntity5->GetId(); referenceGradientConfig5.m_gradientSampler.m_gradientId = referenceGradientEntity6->GetId(); - CreateComponent(referenceGradientEntity5.get(), referenceGradientConfig5); + referenceGradientEntity5->CreateComponent(referenceGradientConfig5); ActivateEntity(referenceGradientEntity5.get()); GradientSignal::ReferenceGradientConfig referenceGradientConfig6; referenceGradientConfig6.m_gradientSampler.m_ownerEntityId = referenceGradientEntity6->GetId(); referenceGradientConfig6.m_gradientSampler.m_gradientId = referenceGradientEntity4->GetId(); - CreateComponent(referenceGradientEntity6.get(), referenceGradientConfig6); + referenceGradientEntity6->CreateComponent(referenceGradientConfig6); ActivateEntity(referenceGradientEntity6.get()); EXPECT_FALSE(referenceGradientConfig6.m_gradientSampler.ValidateGradientEntityId()); @@ -456,7 +456,7 @@ namespace UnitTest // Create an AABB from -1 to 1, so points at coorindates 0 and 1 fall on it, but any points at coordinate 2 won't. auto entityShape = CreateEntity(); - CreateComponent(entityShape.get()); + entityShape->CreateComponent(); MockShapeComponentHandler mockShapeComponentHandler(entityShape->GetId()); mockShapeComponentHandler.m_GetEncompassingAabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-1.0f), AZ::Vector3(1.0f)); @@ -466,7 +466,7 @@ namespace UnitTest config.m_falloffType = GradientSignal::FalloffType::Outer; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -481,7 +481,7 @@ namespace UnitTest // Create our test shape from -1 to 0, so we have a corner directly on (0, 0). auto entityShape = CreateEntity(); - CreateComponent(entityShape.get()); + entityShape->CreateComponent(); MockShapeComponentHandler mockShapeComponentHandler(entityShape->GetId()); mockShapeComponentHandler.m_GetEncompassingAabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-1.0f), AZ::Vector3(0.0f)); @@ -512,7 +512,7 @@ namespace UnitTest } auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -533,7 +533,7 @@ namespace UnitTest // We're pinning a shape, so the bounding box of (0, 0, 0) - (10, 10, 10) will be the one that applies. auto entityShape = CreateEntity(); - CreateComponent(entityShape.get()); + entityShape->CreateComponent(); MockShapeComponentHandler mockShapeComponentHandler(entityShape->GetId()); mockShapeComponentHandler.m_GetEncompassingAabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3::CreateZero(), AZ::Vector3(10.0f)); @@ -551,7 +551,7 @@ namespace UnitTest config.m_altitudeMax = 24.0f; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -584,7 +584,7 @@ namespace UnitTest config.m_altitudeMax = 10.0f; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -612,7 +612,7 @@ namespace UnitTest config.m_altitudeMax = 15.0f; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -649,7 +649,7 @@ namespace UnitTest config.m_altitudeMax = 15.0f; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -684,7 +684,7 @@ namespace UnitTest config.m_surfaceTagList.push_back(AZ_CRC("test_mask", 0x7a16e9ff)); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -711,7 +711,7 @@ namespace UnitTest config.m_surfaceTagList.push_back(AZ_CRC("test_mask", 0x7a16e9ff)); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp index ec770f038d..830c578b9b 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include #include @@ -31,7 +33,7 @@ namespace UnitTest config.m_value = expectedOutput; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); GradientSignal::GradientSampler gradientSampler; @@ -75,12 +77,136 @@ namespace UnitTest config.m_gradientSampler.m_gradientId = entityMock->GetId(); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); } + TEST_F(GradientSignalServicesTestsFixture, DitherGradientComponent_4x4At50Pct_CrossingZero) + { + // With a 4x4 gradient filled with 8/16 (0.5), verify that the resulting dithered output + // is an expected checkerboard pattern with 8 of 16 pixels filled. The pattern offset is + // shifted -2 in the X direction so that the lookups go from [-2, 2) to verify that the + // pattern remains consistent across negative and positive coordinates. + + constexpr int dataSize = 4; + + AZStd::vector inputData(dataSize * dataSize, 8.0f / 16.0f); + AZStd::vector expectedOutput = { + 1.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 1.0f, + }; + + auto entityMock = CreateEntity(); + const AZ::EntityId id = entityMock->GetId(); + UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); + + GradientSignal::DitherGradientConfig config; + config.m_useSystemPointsPerUnit = false; + config.m_pointsPerUnit = 1.0f; + config.m_patternOffset = AZ::Vector3(-2.0f, 0.0f, 0.0f); + config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4; + config.m_gradientSampler.m_gradientId = entityMock->GetId(); + + auto entity = CreateEntity(); + entity->CreateComponent(config); + ActivateEntity(entity.get()); + + TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); + } + + TEST_F(GradientSignalServicesTestsFixture, DitherGradientComponent_4x4At50Pct_MorePointsPerUnit) + { + // With a 4x4 gradient filled with 8/16 (0.5), and 1/2 point per unit, if we query a 4x4 region, + // we should get a checkerboard in 2x2 blocks of the same value because it takes 2 units before the value changes. + + constexpr int dataSize = 4; + + AZStd::vector inputData(dataSize * dataSize, 8.0f / 16.0f); + AZStd::vector expectedOutput = { + 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + }; + + auto entityMock = CreateEntity(); + const AZ::EntityId id = entityMock->GetId(); + UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); + + GradientSignal::DitherGradientConfig config; + config.m_useSystemPointsPerUnit = false; + config.m_pointsPerUnit = 0.5f; + config.m_patternOffset = AZ::Vector3::CreateZero(); + config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4; + config.m_gradientSampler.m_gradientId = entityMock->GetId(); + + auto entity = CreateEntity(); + entity->CreateComponent(config); + ActivateEntity(entity.get()); + + TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); + } + + TEST_F(GradientSignalServicesTestsFixture, DitherGradientComponent_4x4At50Pct_MorePointsAndCrossingZero) + { + // With a 4x4 gradient filled with 8/16 (0.5), and 2 points per unit, verify that querying + // from -1 to 1 produces a constant checkerboard pattern of results as it crosses the 0 boundary. + // Our expected results are a consistent checkerboard pattern, but with 2x2 blocks of the same value because we're + // querying at 2x the point density (i.e. querying 4 points per unit) to ensure that fractional position lookups work too. + + float expectedValues[] = { + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + }; + + // Create a 50% constant gradient. + GradientSignal::ConstantGradientConfig constantConfig; + constantConfig.m_value = 8.0f / 16.0f; + auto constantGradientEntity = CreateEntity(); + constantGradientEntity->CreateComponent(constantConfig); + ActivateEntity(constantGradientEntity.get()); + + GradientSignal::DitherGradientConfig config; + config.m_useSystemPointsPerUnit = false; + config.m_pointsPerUnit = 2.0f; + config.m_patternOffset = AZ::Vector3::CreateZero(); + config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4; + config.m_gradientSampler.m_gradientId = constantGradientEntity->GetId(); + + auto entity = CreateEntity(); + entity->CreateComponent(config); + ActivateEntity(entity.get()); + + // Run through [-1, 1) at 1/4 intervals and make sure we get our expected checkerboard. This is testing both that + // we have a consistent pattern across the 0 boundary and that fractional position lookups work correctly + GradientSignal::GradientSampler gradientSampler; + gradientSampler.m_gradientId = entity->GetId(); + int expectedValueIndex = 0; + for (float y = -1.0f; y < 1.0f; y += 0.25f) + { + for (float x = -1.0f; x < 1.0f; x += 0.25f) + { + GradientSignal::GradientSampleParams params; + params.m_position = AZ::Vector3(x, y, 0.0f); + + float actualValue = gradientSampler.GetValue(params); + float expectedValue = expectedValues[expectedValueIndex++]; + + EXPECT_NEAR(actualValue, expectedValue, 0.01f); + } + } + } + TEST_F(GradientSignalServicesTestsFixture, DitherGradientComponent_4x4At31Pct) { // With a 4x4 gradient filled with 5/16 (0.3125), verify that the resulting dithered output @@ -109,7 +235,7 @@ namespace UnitTest config.m_gradientSampler.m_gradientId = entityMock->GetId(); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -147,7 +273,7 @@ namespace UnitTest config.m_gradientSampler.m_gradientId = entityMock->GetId(); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -185,7 +311,7 @@ namespace UnitTest config.m_gradientSampler.m_gradientId = entityMock->GetId(); auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp index 702965c0de..a716fc79b8 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp @@ -44,11 +44,9 @@ namespace UnitTest // This lets our component register with surfaceData successfully. MockSurfaceDataSystem mockSurfaceDataSystem; - // Create a mock shape entity in case we want to use it. + // Create a mock shape entity in case our gradient test uses shape constraints. // The mock shape is a cube that goes from -0.5 to 0.5 in space. - auto mockShapeEntity = CreateEntity(); - CreateComponent(mockShapeEntity.get()); - MockShapeComponentHandler mockShapeHandler(mockShapeEntity->GetId()); + auto mockShapeEntity = CreateTestEntity(0.5f); ActivateEntity(mockShapeEntity.get()); // For ease of testing, use a constant gradient as our input gradient. @@ -76,8 +74,8 @@ namespace UnitTest // Create the test entity with the GradientSurfaceData component and the required gradient dependency auto entity = CreateEntity(); - CreateComponent(entity.get(), constantGradientConfig); - CreateComponent(entity.get(), config); + entity->CreateComponent(constantGradientConfig); + entity->CreateComponent(config); ActivateEntity(entity.get()); // Get our registered modifier handle (and verify that it's valid) diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTest.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalTest.cpp index adc35e6738..13e535e072 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTest.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTest.cpp @@ -27,14 +27,12 @@ namespace UnitTest void TestLevelsGradientComponent(int dataSize, const AZStd::vector& inputData, const AZStd::vector& expectedOutput, float inputMin, float inputMid, float inputMax, float outputMin, float outputMax) { - auto entityMock = CreateEntity(); + auto entityMock = CreateTestEntity(1.0f); const AZ::EntityId id = entityMock->GetId(); UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entityMock.get(), gradientTransformConfig); - CreateComponent(entityMock.get()); - MockShapeComponentHandler mockShapeHandler(entityMock->GetId()); + entityMock->CreateComponent(gradientTransformConfig); ActivateEntity(entityMock.get()); @@ -47,7 +45,7 @@ namespace UnitTest config.m_outputMax = outputMax; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -56,14 +54,12 @@ namespace UnitTest void TestPosterizeGradientComponent(int dataSize, const AZStd::vector& inputData, const AZStd::vector& expectedOutput, GradientSignal::PosterizeGradientConfig::ModeType posterizeMode, int bands) { - auto entityMock = CreateEntity(); + auto entityMock = CreateTestEntity(0.5f); const AZ::EntityId id = entityMock->GetId(); UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entityMock.get(), gradientTransformConfig); - CreateComponent(entityMock.get()); - MockShapeComponentHandler mockShapeHandler(entityMock->GetId()); + entityMock->CreateComponent(gradientTransformConfig); ActivateEntity(entityMock.get()); @@ -73,7 +69,7 @@ namespace UnitTest config.m_bands = bands; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -82,14 +78,12 @@ namespace UnitTest void TestSmoothStepGradientComponent(int dataSize, const AZStd::vector& inputData, const AZStd::vector& expectedOutput, float midpoint, float range, float softness) { - auto entityMock = CreateEntity(); + auto entityMock = CreateTestEntity(0.5f); const AZ::EntityId id = entityMock->GetId(); UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entityMock.get(), gradientTransformConfig); - CreateComponent(entityMock.get()); - MockShapeComponentHandler mockShapeHandler(entityMock->GetId()); + entityMock->CreateComponent(gradientTransformConfig); ActivateEntity(entityMock.get()); @@ -100,7 +94,7 @@ namespace UnitTest config.m_smoothStep.m_falloffStrength = softness; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -108,14 +102,12 @@ namespace UnitTest void TestThresholdGradientComponent(int dataSize, const AZStd::vector& inputData, const AZStd::vector& expectedOutput, float threshold) { - auto entityMock = CreateEntity(); + auto entityMock = CreateTestEntity(0.5f); const AZ::EntityId id = entityMock->GetId(); UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entityMock.get(), gradientTransformConfig); - CreateComponent(entityMock.get()); - MockShapeComponentHandler mockShapeHandler(entityMock->GetId()); + entityMock->CreateComponent(gradientTransformConfig); ActivateEntity(entityMock.get()); @@ -124,7 +116,7 @@ namespace UnitTest config.m_threshold = threshold; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); @@ -167,11 +159,11 @@ namespace UnitTest AZStd::vector expectedOutput = { AZ_TRAIT_UNIT_TEST_PERLINE_GRADIANT_GOLDEN_VALUES_7878 }; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entity.get(), gradientTransformConfig); - CreateComponent(entity.get()); + entity->CreateComponent(gradientTransformConfig); + entity->CreateComponent(); MockShapeComponentHandler mockShapeHandler(entity->GetId()); ActivateEntity(entity.get()); @@ -197,11 +189,11 @@ namespace UnitTest config.m_randomSeed = 5656; auto entity = CreateEntity(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); GradientSignal::GradientTransformConfig gradientTransformConfig; - CreateComponent(entity.get(), gradientTransformConfig); - CreateComponent(entity.get()); + entity->CreateComponent(gradientTransformConfig); + entity->CreateComponent(); MockShapeComponentHandler mockShapeHandler(entity->GetId()); ActivateEntity(entity.get()); @@ -546,4 +538,5 @@ namespace UnitTest } } -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +// This uses custom test / benchmark hooks so that we can load LmbrCentral and use Shape components in our unit tests and benchmarks. +AZ_UNIT_TEST_HOOK(new UnitTest::GradientSignalTestEnvironment, UnitTest::GradientSignalBenchmarkEnvironment); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp index 154e9032b2..d81370f6a8 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp @@ -10,7 +10,9 @@ #include #include +#include #include +#include // Base gradient components #include @@ -36,65 +38,48 @@ namespace UnitTest { + void GradientSignalTestEnvironment::AddGemsAndComponents() + { + AddDynamicModulePaths({ "LmbrCentral" }); + + AddComponentDescriptors({ + AzFramework::TransformComponent::CreateDescriptor(), + + GradientSignal::ConstantGradientComponent::CreateDescriptor(), + GradientSignal::DitherGradientComponent::CreateDescriptor(), + GradientSignal::GradientSurfaceDataComponent::CreateDescriptor(), + GradientSignal::GradientTransformComponent::CreateDescriptor(), + GradientSignal::ImageGradientComponent::CreateDescriptor(), + GradientSignal::InvertGradientComponent::CreateDescriptor(), + GradientSignal::LevelsGradientComponent::CreateDescriptor(), + GradientSignal::MixedGradientComponent::CreateDescriptor(), + GradientSignal::PerlinGradientComponent::CreateDescriptor(), + GradientSignal::PosterizeGradientComponent::CreateDescriptor(), + GradientSignal::RandomGradientComponent::CreateDescriptor(), + GradientSignal::ReferenceGradientComponent::CreateDescriptor(), + GradientSignal::ShapeAreaFalloffGradientComponent::CreateDescriptor(), + GradientSignal::SmoothStepGradientComponent::CreateDescriptor(), + GradientSignal::SurfaceAltitudeGradientComponent::CreateDescriptor(), + GradientSignal::SurfaceMaskGradientComponent::CreateDescriptor(), + GradientSignal::SurfaceSlopeGradientComponent::CreateDescriptor(), + GradientSignal::ThresholdGradientComponent::CreateDescriptor(), + + MockShapeComponent::CreateDescriptor(), + }); + } + void GradientSignalBaseFixture::SetupCoreSystems() { - m_app = AZStd::make_unique(); - ASSERT_TRUE(m_app != nullptr); - - AZ::ComponentApplication::Descriptor componentAppDesc; - - m_systemEntity = m_app->Create(componentAppDesc); - ASSERT_TRUE(m_systemEntity != nullptr); - m_app->AddEntity(m_systemEntity); - - AZ::AllocatorInstance::Create(); - AZ::Data::AssetManager::Descriptor desc; - AZ::Data::AssetManager::Create(desc); - m_mockHandler = new ImageAssetMockAssetHandler(); + m_mockHandler = new UnitTest::ImageAssetMockAssetHandler(); AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid()); - - m_mockShapeHandlers = new AZStd::vector>>(); } void GradientSignalBaseFixture::TearDownCoreSystems() { - // Clear any mock shape handlers that we've created for our test entities. - delete m_mockShapeHandlers; - AZ::Data::AssetManager::Instance().UnregisterHandler(m_mockHandler); delete m_mockHandler; // delete after removing from the asset manager AzFramework::LegacyAssetEventBus::ClearQueuedEvents(); - AZ::Data::AssetManager::Destroy(); - AZ::AllocatorInstance::Destroy(); - - m_app->Destroy(); - m_app.reset(); - m_systemEntity = nullptr; - } - - AZStd::unique_ptr> GradientSignalBaseFixture::CreateMockShape( - const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId) - { - AZStd::unique_ptr> mockShape = - AZStd::make_unique>(shapeEntityId); - - ON_CALL(*mockShape, GetEncompassingAabb).WillByDefault(testing::Return(spawnerBox)); - ON_CALL(*mockShape, GetTransformAndLocalBounds) - .WillByDefault( - [spawnerBox](AZ::Transform& transform, AZ::Aabb& bounds) - { - transform = AZ::Transform::CreateTranslation(spawnerBox.GetCenter()); - bounds = spawnerBox.GetTranslated(-spawnerBox.GetCenter()); - }); - ON_CALL(*mockShape, IsPointInside) - .WillByDefault( - [spawnerBox](const AZ::Vector3& point) -> bool - { - return spawnerBox.Contains(point); - }); - - return mockShape; } AZStd::unique_ptr GradientSignalBaseFixture::CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox) @@ -130,16 +115,12 @@ namespace UnitTest // Create the base entity AZStd::unique_ptr testEntity = CreateEntity(); - // Create a mock Shape component that describes the bounds that we're using to map our gradient into world space. - CreateComponent(testEntity.get()); - - // Create and keep a reference to a mock shape handler that will respond to shape requests for the mock shape. - auto mockShapeHandler = - CreateMockShape(AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds), testEntity->GetId()); - m_mockShapeHandlers->push_back(AZStd::move(mockShapeHandler)); + LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(shapeHalfBounds * 2.0f)); + auto boxComponent = testEntity->CreateComponent(LmbrCentral::AxisAlignedBoxShapeComponentTypeId); + boxComponent->SetConfiguration(boxConfig); // Create a transform that locates our gradient in the center of our desired mock Shape. - auto transform = CreateComponent(testEntity.get()); + auto transform = testEntity->CreateComponent(); transform->SetLocalTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); transform->SetWorldTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); @@ -152,7 +133,7 @@ namespace UnitTest auto entity = CreateTestEntity(shapeHalfBounds); GradientSignal::ConstantGradientConfig config; config.m_value = 0.75f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -168,12 +149,12 @@ namespace UnitTest config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed); config.m_tilingX = 1.0f; config.m_tilingY = 1.0f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); // Create a Gradient Transform Component with arbitrary parameters. GradientSignal::GradientTransformConfig gradientTransformConfig; gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity.get(), gradientTransformConfig); + entity->CreateComponent(gradientTransformConfig); ActivateEntity(entity.get()); return entity; @@ -188,12 +169,12 @@ namespace UnitTest config.m_frequency = 1.1f; config.m_octave = 4; config.m_randomSeed = 12345; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); // Create a Gradient Transform Component with arbitrary parameters. GradientSignal::GradientTransformConfig gradientTransformConfig; gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity.get(), gradientTransformConfig); + entity->CreateComponent(gradientTransformConfig); ActivateEntity(entity.get()); return entity; @@ -205,12 +186,12 @@ namespace UnitTest auto entity = CreateTestEntity(shapeHalfBounds); GradientSignal::RandomGradientConfig config; config.m_randomSeed = 12345; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); // Create a Gradient Transform Component with arbitrary parameters. GradientSignal::GradientTransformConfig gradientTransformConfig; gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity.get(), gradientTransformConfig); + entity->CreateComponent(gradientTransformConfig); ActivateEntity(entity.get()); return entity; @@ -224,7 +205,7 @@ namespace UnitTest config.m_shapeEntityId = entity->GetId(); config.m_falloffWidth = 16.0f; config.m_falloffType = GradientSignal::FalloffType::InnerOuter; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -238,10 +219,11 @@ namespace UnitTest GradientSignal::DitherGradientConfig config; config.m_gradientSampler.m_gradientId = inputGradientId; config.m_useSystemPointsPerUnit = false; - config.m_pointsPerUnit = 1.0f; + // Use a number other than 1.0f for pointsPerUnit to ensure the dither math is getting exercised properly. + config.m_pointsPerUnit = 0.25f; config.m_patternOffset = AZ::Vector3::CreateZero(); config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -254,7 +236,7 @@ namespace UnitTest auto entity = CreateTestEntity(shapeHalfBounds); GradientSignal::InvertGradientConfig config; config.m_gradientSampler.m_gradientId = inputGradientId; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -272,7 +254,7 @@ namespace UnitTest config.m_inputMax = 0.9f; config.m_outputMin = 0.0f; config.m_outputMax = 1.0f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -298,7 +280,7 @@ namespace UnitTest layer.m_gradientSampler.m_opacity = 0.75f; config.m_layers.push_back(layer); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -313,7 +295,7 @@ namespace UnitTest config.m_gradientSampler.m_gradientId = inputGradientId; config.m_mode = GradientSignal::PosterizeGradientConfig::ModeType::Ps; config.m_bands = 5; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -327,7 +309,7 @@ namespace UnitTest GradientSignal::ReferenceGradientConfig config; config.m_gradientSampler.m_gradientId = inputGradientId; config.m_gradientSampler.m_ownerEntityId = entity->GetId(); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -343,7 +325,7 @@ namespace UnitTest config.m_smoothStep.m_falloffMidpoint = 0.75f; config.m_smoothStep.m_falloffRange = 0.125f; config.m_smoothStep.m_falloffStrength = 0.25f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -357,7 +339,7 @@ namespace UnitTest GradientSignal::ThresholdGradientConfig config; config.m_gradientSampler.m_gradientId = inputGradientId; config.m_threshold = 0.75f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -370,7 +352,7 @@ namespace UnitTest GradientSignal::SurfaceAltitudeGradientConfig config; config.m_altitudeMin = -5.0f; config.m_altitudeMax = 15.0f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -382,7 +364,7 @@ namespace UnitTest auto entity = CreateTestEntity(shapeHalfBounds); GradientSignal::SurfaceMaskGradientConfig config; config.m_surfaceTagList.push_back(AZ_CRC_CE("test_mask")); - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; @@ -399,7 +381,7 @@ namespace UnitTest config.m_smoothStep.m_falloffMidpoint = 0.75f; config.m_smoothStep.m_falloffRange = 0.125f; config.m_smoothStep.m_falloffStrength = 0.25f; - CreateComponent(entity.get(), config); + entity->CreateComponent(config); ActivateEntity(entity.get()); return entity; diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h index 478f1c1d92..5fda88ea27 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h @@ -9,9 +9,39 @@ #include #include +#include namespace UnitTest { + // The GradientSignal unit tests need to use the GemTestEnvironment to load the LmbrCentral Gem so that Shape components can be used + // in the unit tests and benchmarks. + class GradientSignalTestEnvironment + : public AZ::Test::GemTestEnvironment + { + public: + void AddGemsAndComponents() override; + }; + +#ifdef HAVE_BENCHMARK + //! The Benchmark environment is used for one time setup and tear down of shared resources + class GradientSignalBenchmarkEnvironment + : public AZ::Test::BenchmarkEnvironmentBase + , public GradientSignalTestEnvironment + + { + protected: + void SetUpBenchmark() override + { + SetupEnvironment(); + } + + void TearDownBenchmark() override + { + TeardownEnvironment(); + } + }; +#endif + // Base test fixture used for GradientSignal unit tests and benchmark tests class GradientSignalBaseFixture { @@ -30,24 +60,6 @@ namespace UnitTest entity->Activate(); } - template - Component* CreateComponent(AZ::Entity* entity, const Configuration& config) - { - m_app->RegisterComponentDescriptor(Component::CreateDescriptor()); - return entity->CreateComponent(config); - } - - template - Component* CreateComponent(AZ::Entity* entity) - { - m_app->RegisterComponentDescriptor(Component::CreateDescriptor()); - return entity->CreateComponent(); - } - - // Create a mock shape that will respond to the shape bus with proper responses for the given input box. - AZStd::unique_ptr> CreateMockShape( - const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId); - // Create a mock SurfaceDataSystem that will respond to requests for surface points with mock responses for points inside // the given input box. AZStd::unique_ptr CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox); @@ -77,27 +89,22 @@ namespace UnitTest AZStd::unique_ptr BuildTestSurfaceMaskGradient(float shapeHalfBounds); AZStd::unique_ptr BuildTestSurfaceSlopeGradient(float shapeHalfBounds); - AZStd::unique_ptr m_app; - AZ::Entity* m_systemEntity = nullptr; - ImageAssetMockAssetHandler* m_mockHandler = nullptr; - AZStd::vector>>* m_mockShapeHandlers = nullptr; + UnitTest::ImageAssetMockAssetHandler* m_mockHandler = nullptr; }; struct GradientSignalTest : public GradientSignalBaseFixture - , public UnitTest::AllocatorsTestFixture + , public ::testing::Test { protected: void SetUp() override { - UnitTest::AllocatorsTestFixture::SetUp(); SetupCoreSystems(); } void TearDown() override { TearDownCoreSystems(); - UnitTest::AllocatorsTestFixture::TearDown(); } void TestFixedDataSampler(const AZStd::vector& expectedOutput, int size, AZ::EntityId gradientEntityId); @@ -106,41 +113,36 @@ namespace UnitTest #ifdef HAVE_BENCHMARK class GradientSignalBenchmarkFixture : public GradientSignalBaseFixture - , public UnitTest::AllocatorsBenchmarkFixture - , public UnitTest::TraceBusRedirector + , public ::benchmark::Fixture { public: - void internalSetUp(const benchmark::State& state) + void internalSetUp() { - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - UnitTest::AllocatorsBenchmarkFixture::SetUp(state); SetupCoreSystems(); } - void internalTearDown(const benchmark::State& state) + void internalTearDown() { TearDownCoreSystems(); - UnitTest::AllocatorsBenchmarkFixture::TearDown(state); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); } protected: - void SetUp(const benchmark::State& state) override + void SetUp([[maybe_unused]] const benchmark::State& state) override { - internalSetUp(state); + internalSetUp(); } - void SetUp(benchmark::State& state) override + void SetUp([[maybe_unused]] benchmark::State& state) override { - internalSetUp(state); + internalSetUp(); } - void TearDown(const benchmark::State& state) override + void TearDown([[maybe_unused]] const benchmark::State& state) override { - internalTearDown(state); + internalTearDown(); } - void TearDown(benchmark::State& state) override + void TearDown([[maybe_unused]] benchmark::State& state) override { - internalTearDown(state); + internalTearDown(); } }; #endif diff --git a/Gems/GradientSignal/Code/Tests/ImageAssetTests.cpp b/Gems/GradientSignal/Code/Tests/ImageAssetTests.cpp index 0111f10c3a..7b1c260d45 100644 --- a/Gems/GradientSignal/Code/Tests/ImageAssetTests.cpp +++ b/Gems/GradientSignal/Code/Tests/ImageAssetTests.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -64,26 +65,8 @@ namespace } } - class ImageAssetTest - : public ::testing::Test + class ImageAssetTest : public ::testing::Test { - protected: - AZ::ComponentApplication m_app; - AZ::Entity* m_systemEntity = nullptr; - - void SetUp() override - { - AZ::ComponentApplication::Descriptor appDesc; - appDesc.m_memoryBlocksByteSize = 128 * 1024 * 1024; - m_systemEntity = m_app.Create(appDesc); - m_app.AddEntity(m_systemEntity); - } - - void TearDown() override - { - m_app.Destroy(); - m_systemEntity = nullptr; - } }; #if AZ_TRAIT_DISABLE_FAILED_GRADIENT_SIGNAL_TESTS diff --git a/Gems/GradientSignal/gem.json b/Gems/GradientSignal/gem.json index aac4c652c5..f0136ef104 100644 --- a/Gems/GradientSignal/gem.json +++ b/Gems/GradientSignal/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Gradient Signal Gem provides a number of components for generating, modifying, and mixing gradient signals.", "canonical_tags": [ diff --git a/Gems/GraphCanvas/Code/Include/GraphCanvas/Components/Connections/ConnectionFilters/DataConnectionFilters.h b/Gems/GraphCanvas/Code/Include/GraphCanvas/Components/Connections/ConnectionFilters/DataConnectionFilters.h index c7721e284d..452b6e744a 100644 --- a/Gems/GraphCanvas/Code/Include/GraphCanvas/Components/Connections/ConnectionFilters/DataConnectionFilters.h +++ b/Gems/GraphCanvas/Code/Include/GraphCanvas/Components/Connections/ConnectionFilters/DataConnectionFilters.h @@ -97,7 +97,7 @@ namespace GraphCanvas // Only want to try to convert to references when we have no connections if (!hasConnections) { - DataSlotRequestBus::EventResult(acceptConnection, sourceEndpoint.GetSlotId(), &DataSlotRequests::CanConvertToReference); + DataSlotRequestBus::EventResult(acceptConnection, sourceEndpoint.GetSlotId(), &DataSlotRequests::CanConvertToReference, false); } } else if (targetType == DataSlotType::Value) @@ -115,7 +115,7 @@ namespace GraphCanvas // Only want to try to convert to references when we have no connections if (!hasConnections) { - DataSlotRequestBus::EventResult(acceptConnection, targetEndpoint.GetSlotId(), &DataSlotRequests::CanConvertToReference); + DataSlotRequestBus::EventResult(acceptConnection, targetEndpoint.GetSlotId(), &DataSlotRequests::CanConvertToReference, false); } } else if (sourceType == DataSlotType::Value) diff --git a/Gems/GraphCanvas/Code/Source/Components/Connections/DataConnections/DataConnectionComponent.cpp b/Gems/GraphCanvas/Code/Source/Components/Connections/DataConnections/DataConnectionComponent.cpp index f4ec0bfa1d..46e6f25978 100644 --- a/Gems/GraphCanvas/Code/Source/Components/Connections/DataConnections/DataConnectionComponent.cpp +++ b/Gems/GraphCanvas/Code/Source/Components/Connections/DataConnections/DataConnectionComponent.cpp @@ -92,7 +92,7 @@ namespace GraphCanvas } else if (sourceSlotType == DataSlotType::Reference) { - DataSlotRequestBus::EventResult(converted, GetTargetSlotId(), &DataSlotRequests::ConvertToReference); + DataSlotRequestBus::EventResult(converted, GetTargetSlotId(), &DataSlotRequests::ConvertToReference, false); } } else if (m_dragContext == DragContext::MoveSource) @@ -103,7 +103,7 @@ namespace GraphCanvas } else if (targetSlotType == DataSlotType::Reference) { - DataSlotRequestBus::EventResult(converted, GetSourceSlotId(), &DataSlotRequests::ConvertToReference); + DataSlotRequestBus::EventResult(converted, GetSourceSlotId(), &DataSlotRequests::ConvertToReference, false); } } else if (m_dragContext == DragContext::TryConnection) diff --git a/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.cpp b/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.cpp index db62b29de5..c053c37fbc 100644 --- a/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.cpp +++ b/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.cpp @@ -294,9 +294,9 @@ namespace GraphCanvas } } - bool DataSlotComponent::ConvertToReference() + bool DataSlotComponent::ConvertToReference(bool isNewSlot) { - if (CanConvertToReference()) + if (CanConvertToReference(isNewSlot)) { AZ::EntityId nodeId = GetNode(); GraphId graphId; @@ -307,7 +307,7 @@ namespace GraphCanvas ScopedGraphUndoBlocker undoBlocker(graphId); bool convertedToReference = false; - GraphModelRequestBus::EventResult(convertedToReference, graphId, &GraphModelRequests::ConvertSlotToReference, Endpoint(nodeId, GetEntityId())); + GraphModelRequestBus::EventResult(convertedToReference, graphId, &GraphModelRequests::ConvertSlotToReference, Endpoint(nodeId, GetEntityId()), isNewSlot); if (convertedToReference) { @@ -326,7 +326,7 @@ namespace GraphCanvas return m_dataSlotType == DataSlotType::Reference; } - bool DataSlotComponent::CanConvertToReference() const + bool DataSlotComponent::CanConvertToReference([[maybe_unused]] bool isNewSlot) const { bool canToggleReference = false; @@ -336,7 +336,7 @@ namespace GraphCanvas GraphId graphId; SceneMemberRequestBus::EventResult(graphId, nodeId, &SceneMemberRequests::GetScene); - GraphModelRequestBus::EventResult(canToggleReference, graphId, &GraphModelRequests::CanConvertSlotToReference, Endpoint(nodeId, GetEntityId())); + GraphModelRequestBus::EventResult(canToggleReference, graphId, &GraphModelRequests::CanConvertSlotToReference, Endpoint(nodeId, GetEntityId()), isNewSlot); } return canToggleReference; diff --git a/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.h b/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.h index fb76c2c80e..5bd35d9f34 100644 --- a/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.h +++ b/Gems/GraphCanvas/Code/Source/Components/Slots/Data/DataSlotComponent.h @@ -47,8 +47,8 @@ namespace GraphCanvas //// // DataSlotRequestBus - bool ConvertToReference() override; - bool CanConvertToReference() const override; + bool ConvertToReference(bool isNewSlot = false) override; + bool CanConvertToReference(bool isNewSlot = false) const override; bool ConvertToValue() override; bool CanConvertToValue() const override; diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Components/Slots/Data/DataSlotBus.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Components/Slots/Data/DataSlotBus.h index 3d007dda91..fbdae8a971 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Components/Slots/Data/DataSlotBus.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Components/Slots/Data/DataSlotBus.h @@ -70,8 +70,8 @@ namespace GraphCanvas static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = AZ::EntityId; - virtual bool ConvertToReference() = 0; - virtual bool CanConvertToReference() const = 0; + virtual bool ConvertToReference(bool isNewSlot = false) = 0; + virtual bool CanConvertToReference(bool isNewSlot = false) const = 0; virtual bool ConvertToValue() = 0; virtual bool CanConvertToValue() const = 0; diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Editor/GraphModelBus.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Editor/GraphModelBus.h index 769cdb2a10..23aa612dd5 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Editor/GraphModelBus.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Editor/GraphModelBus.h @@ -125,12 +125,12 @@ namespace GraphCanvas return false; } - virtual bool ConvertSlotToReference([[maybe_unused]] const Endpoint& endpoint) + virtual bool ConvertSlotToReference([[maybe_unused]] const Endpoint& endpoint, [[maybe_unused]] bool isNewSlot) { return false; } - virtual bool CanConvertSlotToReference([[maybe_unused]] const Endpoint& endpoint) + virtual bool CanConvertSlotToReference([[maybe_unused]] const Endpoint& endpoint, [[maybe_unused]] bool isNewSlot) { return false; } @@ -145,12 +145,13 @@ namespace GraphCanvas return false; } - virtual bool CanPromoteToVariable([[maybe_unused]] const Endpoint& endpoint) const + virtual bool CanPromoteToVariable([[maybe_unused]] const Endpoint& endpoint, [[maybe_unused]] bool isNewSlot = false) const { return false; } - virtual bool PromoteToVariableAction([[maybe_unused]] const Endpoint& endpoint) + virtual bool PromoteToVariableAction([[maybe_unused]] const Endpoint& endpoint + , [[maybe_unused]] bool isNewSlot) { return false; } diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/SelectorImplementations.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/SelectorImplementations.h index 1c65bf1915..eac9abdec8 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/SelectorImplementations.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/SelectorImplementations.h @@ -79,7 +79,7 @@ namespace GraphCanvas private: AZStd::string m_value; - AZStd::hash::result_type m_hash; + size_t m_hash; friend class BasicSelectorEventHandler; }; diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SlotMenuActions/SlotContextMenuActions.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SlotMenuActions/SlotContextMenuActions.cpp index a255c97120..38e97f90cc 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SlotMenuActions/SlotContextMenuActions.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SlotMenuActions/SlotContextMenuActions.cpp @@ -258,7 +258,7 @@ namespace GraphCanvas if (DataSlotUtils::IsValueDataSlotType(dataSlotType)) { setText("Convert to Reference"); - DataSlotRequestBus::EventResult(canToggleState, targetId, &DataSlotRequests::CanConvertToReference); + DataSlotRequestBus::EventResult(canToggleState, targetId, &DataSlotRequests::CanConvertToReference, false); } else { @@ -291,7 +291,7 @@ namespace GraphCanvas if (DataSlotUtils::IsValueDataSlotType(dataSlotType)) { - DataSlotRequestBus::EventResult(toggledState, targetId, &DataSlotRequests::ConvertToReference); + DataSlotRequestBus::EventResult(toggledState, targetId, &DataSlotRequests::ConvertToReference, false); } else { @@ -345,14 +345,14 @@ namespace GraphCanvas if (DataSlotUtils::IsValueDataSlotType(dataSlotType)) { - DataSlotRequestBus::EventResult(enableAction, targetId, &DataSlotRequests::CanConvertToReference); + DataSlotRequestBus::EventResult(enableAction, targetId, &DataSlotRequests::CanConvertToReference, false); if (enableAction) { Endpoint endpoint; SlotRequestBus::EventResult(endpoint, targetId, &SlotRequests::GetEndpoint); - GraphModelRequestBus::EventResult(enableAction, graphId, &GraphModelRequests::CanPromoteToVariable, endpoint); + GraphModelRequestBus::EventResult(enableAction, graphId, &GraphModelRequests::CanPromoteToVariable, endpoint, false); } } } @@ -371,7 +371,7 @@ namespace GraphCanvas SlotRequestBus::EventResult(endpoint, targetId, &SlotRequests::GetEndpoint); bool promotedElement = false; - GraphModelRequestBus::EventResult(promotedElement, graphId, &GraphModelRequests::PromoteToVariableAction, endpoint); + GraphModelRequestBus::EventResult(promotedElement, graphId, &GraphModelRequests::PromoteToVariableAction, endpoint, false); if (promotedElement) { diff --git a/Gems/GraphCanvas/gem.json b/Gems/GraphCanvas/gem.json index 4762cfef35..c2038f4645 100644 --- a/Gems/GraphCanvas/gem.json +++ b/Gems/GraphCanvas/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Graph Canvas Gem provides a C++ framework for creating custom graphical node based editors for Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/GraphModel/Code/Tests/MockGraphCanvas.cpp b/Gems/GraphModel/Code/Tests/MockGraphCanvas.cpp index 91a25d6a30..5face707c3 100644 --- a/Gems/GraphModel/Code/Tests/MockGraphCanvas.cpp +++ b/Gems/GraphModel/Code/Tests/MockGraphCanvas.cpp @@ -94,12 +94,12 @@ namespace MockGraphCanvasServices GraphCanvas::DataSlotRequestBus::Handler::BusDisconnect(); } - bool MockDataSlotComponent::ConvertToReference() + bool MockDataSlotComponent::ConvertToReference([[maybe_unused]] bool isNewSlot) { return false; } - bool MockDataSlotComponent::CanConvertToReference() const + bool MockDataSlotComponent::CanConvertToReference([[maybe_unused]] bool isNewSlot) const { return false; } diff --git a/Gems/GraphModel/Code/Tests/MockGraphCanvas.h b/Gems/GraphModel/Code/Tests/MockGraphCanvas.h index c7865e769e..00bd80aa02 100644 --- a/Gems/GraphModel/Code/Tests/MockGraphCanvas.h +++ b/Gems/GraphModel/Code/Tests/MockGraphCanvas.h @@ -72,8 +72,8 @@ namespace MockGraphCanvasServices void Deactivate() override; // GraphCanvas::DataSlotRequestBus overrides ... - bool ConvertToReference() override; - bool CanConvertToReference() const override; + bool ConvertToReference(bool isNewSlot = false) override; + bool CanConvertToReference(bool isNewSlot = false) const override; bool ConvertToValue() override; bool CanConvertToValue() const override; bool IsUserSlot() const override; diff --git a/Gems/GraphModel/gem.json b/Gems/GraphModel/gem.json index ad6b592430..ece520278b 100644 --- a/Gems/GraphModel/gem.json +++ b/Gems/GraphModel/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Graph Model Gem provides a generic node graph data model framework for Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/HttpRequestor/CMakeLists.txt b/Gems/HttpRequestor/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/HttpRequestor/CMakeLists.txt +++ b/Gems/HttpRequestor/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/HttpRequestor/Code/CMakeLists.txt b/Gems/HttpRequestor/Code/CMakeLists.txt index 831eb52231..56d3527e24 100644 --- a/Gems/HttpRequestor/Code/CMakeLists.txt +++ b/Gems/HttpRequestor/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(source_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(source_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME HttpRequestor.Static STATIC @@ -71,5 +71,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::HttpRequestor.Tests + TEST_SUITE sandbox ) endif() diff --git a/Gems/HttpRequestor/gem.json b/Gems/HttpRequestor/gem.json index 582bfa0071..a8e111ac63 100644 --- a/Gems/HttpRequestor/gem.json +++ b/Gems/HttpRequestor/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The HTTP Requestor Gem provides functionality to make asynchronous HTTP/HTTPS requests and return data through a user-provided call back function.", "canonical_tags": [ diff --git a/Gems/ImGui/CMakeLists.txt b/Gems/ImGui/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/ImGui/CMakeLists.txt +++ b/Gems/ImGui/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index e345e3d546..c293065636 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -8,7 +8,7 @@ set(config_base_defines $,IMGUI_DISABLED,IMGUI_ENABLED>) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) # This library is the 3rdParty imgui that is in the Gem's External ly_add_target( diff --git a/Gems/ImGui/gem.json b/Gems/ImGui/gem.json index dfc12f64b4..0ed889f693 100644 --- a/Gems/ImGui/gem.json +++ b/Gems/ImGui/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Immediate Mode GUI Gem provides the 3rdParty library IMGUI which can be used to create run time immediate mode overlays for debugging and profiling information in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/InAppPurchases/CMakeLists.txt b/Gems/InAppPurchases/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/InAppPurchases/CMakeLists.txt +++ b/Gems/InAppPurchases/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/InAppPurchases/Code/CMakeLists.txt b/Gems/InAppPurchases/Code/CMakeLists.txt index 99fc937919..e7b34296d1 100644 --- a/Gems/InAppPurchases/Code/CMakeLists.txt +++ b/Gems/InAppPurchases/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME InAppPurchases.Static STATIC diff --git a/Gems/InAppPurchases/gem.json b/Gems/InAppPurchases/gem.json index 21febbfeca..0b3d2e65e4 100644 --- a/Gems/InAppPurchases/gem.json +++ b/Gems/InAppPurchases/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The In-App Purchases Gem provides functionality for in app purchases for iOS and Android.", "canonical_tags": [ diff --git a/Gems/LandscapeCanvas/gem.json b/Gems/LandscapeCanvas/gem.json index 8653da40e1..f1e326efce 100644 --- a/Gems/LandscapeCanvas/gem.json +++ b/Gems/LandscapeCanvas/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Landscape Canvas Gem provides the Landscape Canvas editor, a node-based graph tool for authoring workflows to populate landscape with dynamic vegetation.", "canonical_tags": [ diff --git a/Gems/LmbrCentral/CMakeLists.txt b/Gems/LmbrCentral/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/LmbrCentral/CMakeLists.txt +++ b/Gems/LmbrCentral/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/LmbrCentral/Code/CMakeLists.txt b/Gems/LmbrCentral/Code/CMakeLists.txt index 4401d3b752..a4c94a7b40 100644 --- a/Gems/LmbrCentral/Code/CMakeLists.txt +++ b/Gems/LmbrCentral/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) ly_add_target( NAME LmbrCentral.Static STATIC diff --git a/Gems/LmbrCentral/gem.json b/Gems/LmbrCentral/gem.json index a0a6ea813f..4eea28d26e 100644 --- a/Gems/LmbrCentral/gem.json +++ b/Gems/LmbrCentral/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The O3DE Core (LmbrCentral) Gem provides required code and assets for running Open 3D Engine Editor.", "canonical_tags": [ diff --git a/Gems/LocalUser/CMakeLists.txt b/Gems/LocalUser/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/LocalUser/CMakeLists.txt +++ b/Gems/LocalUser/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/LocalUser/Code/CMakeLists.txt b/Gems/LocalUser/Code/CMakeLists.txt index 055cfe6c7c..ce937e9dc5 100644 --- a/Gems/LocalUser/Code/CMakeLists.txt +++ b/Gems/LocalUser/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME LocalUser.Static STATIC diff --git a/Gems/LocalUser/gem.json b/Gems/LocalUser/gem.json index 5199b4f777..04f2145956 100644 --- a/Gems/LocalUser/gem.json +++ b/Gems/LocalUser/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Local User Gem provides functionality for mapping local user ids to local player slots and managing local user profiles.", "canonical_tags": [ diff --git a/Gems/LyShine/CMakeLists.txt b/Gems/LyShine/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/LyShine/CMakeLists.txt +++ b/Gems/LyShine/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 4f2c4e90a7..76d7742ddf 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME LyShine.Static STATIC @@ -58,10 +58,13 @@ ly_add_target( # by default, load the above "Gem::LyShine" module in Client and Server applications: ly_create_alias(NAME LyShine.Clients NAMESPACE Gem TARGETS Gem::LyShine) ly_create_alias(NAME LyShine.Servers NAMESPACE Gem TARGETS Gem::LyShine) +# create an alias for other gems to depend on an LyShine public API (may be converted to a target in the future): +ly_create_alias(NAME LyShine.Clients.API NAMESPACE Gem TARGETS Gem::LyShine.Clients) +ly_create_alias(NAME LyShine.Servers.API NAMESPACE Gem TARGETS Gem::LyShine.Servers) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME LyShine.Editor.Static STATIC + NAME LyShine.Tools.Static STATIC NAMESPACE Gem AUTOMOC AUTOUIC @@ -73,7 +76,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) . Source Editor - PUBLIC Include BUILD_DEPENDENCIES PRIVATE @@ -100,7 +102,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME LyShine.Editor GEM_MODULE + NAME LyShine.Tools GEM_MODULE NAMESPACE Gem FILES_CMAKE lyshine_common_module_files.cmake @@ -112,18 +114,18 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) . Source Editor - PUBLIC Include BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon AZ::AzToolsFramework - Gem::LyShine.Editor.Static + Gem::LyShine.Tools.Static Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor + Gem::UiBasics.Tools ) # by naming this target LyShine.Builders it ensures that it is loaded @@ -179,10 +181,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::LyShine.Builders.Static Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor + RUNTIME_DEPENDENCIES + Gem::UiBasics.Builders ) - - # by default, load the above "Gem::LyShine.Editor" module in dev tools: - ly_create_alias(NAME LyShine.Tools NAMESPACE Gem TARGETS Gem::LyShine.Editor) endif() ################################################################################ @@ -241,7 +242,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon AZ::AssetBuilderSDK - Gem::LyShine.Editor.Static + Gem::LyShine.Tools.Static Gem::LyShine.Builders.Static Gem::LmbrCentral.Editor Gem::TextureAtlas diff --git a/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp b/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp index 41f7300002..85270df355 100644 --- a/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp +++ b/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp @@ -92,23 +92,6 @@ QString TrimTrailingZeros(QString str) return str; } -////////////////////////////////////////////////////////////////////////// -// This function is supposed to format float in user-friendly way, -// omitting the exponent notation. -// -// Why not using printf? Its formatting rules has following drawbacks: -// %g - will use exponent for small numbers; -// %.Nf - doesn't allow to control total amount of significant numbers, -// which exposes limited precision during binary-to-decimal fraction -// conversion. -////////////////////////////////////////////////////////////////////////// -void FormatFloatForUI(QString& str, int significantDigits, double value) -{ - str = TrimTrailingZeros(QString::number(value, 'f', significantDigits)); - return; -} -//////////////////////////////////////////////////////////////////////////- - ////////////////////////////////////////////////////////////////////////// QColor ColorLinearToGamma(ColorF col) { diff --git a/Gems/LyShine/Code/Editor/GuideHelpers.cpp b/Gems/LyShine/Code/Editor/GuideHelpers.cpp index eb5966568e..b6d7acc57a 100644 --- a/Gems/LyShine/Code/Editor/GuideHelpers.cpp +++ b/Gems/LyShine/Code/Editor/GuideHelpers.cpp @@ -173,7 +173,7 @@ namespace GuideHelpers // the line is drawn as the inverse of the background color AZ::Color guideColor(1.0f, 1.0f, 1.0f, 1.0f); - CDraw2d::RenderState renderState; + IDraw2d::RenderState renderState; renderState.m_blendState.m_blendSource = AZ::RHI::BlendFactor::ColorDestInverse; renderState.m_blendState.m_blendDest = AZ::RHI::BlendFactor::Zero; diff --git a/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp b/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp index 668c4e8024..b1961de0a1 100644 --- a/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp +++ b/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp @@ -50,7 +50,7 @@ void ViewportCanvasBackground::Draw(Draw2dHelper& draw2d, const AZ::Vector2& can // now draw the same as Stretched but with UV's adjusted const AZ::Vector2 uvs[4] = { AZ::Vector2(0, 0), AZ::Vector2(uvScale.GetX(), 0), AZ::Vector2(uvScale.GetX(), uvScale.GetY()), AZ::Vector2(0, uvScale.GetY()) }; AZ::Color colorWhite(1.0f, 1.0f, 1.0f, 1.0f); - CDraw2d::VertexPosColUV verts[4]; + IDraw2d::VertexPosColUV verts[4]; for (int i = 0; i < 4; ++i) { verts[i].position = positions[i]; diff --git a/Gems/LyShine/Code/Editor/ViewportDragInteraction.h b/Gems/LyShine/Code/Editor/ViewportDragInteraction.h index 3b26b66308..6b48fc0133 100644 --- a/Gems/LyShine/Code/Editor/ViewportDragInteraction.h +++ b/Gems/LyShine/Code/Editor/ViewportDragInteraction.h @@ -8,7 +8,7 @@ #pragma once #include -#include +#include //! Abstract base class for drag interactions in the UI Editor viewport window. class ViewportDragInteraction diff --git a/Gems/LyShine/Code/Editor/ViewportHelpers.h b/Gems/LyShine/Code/Editor/ViewportHelpers.h index 8068f4af65..f2722fb6b8 100644 --- a/Gems/LyShine/Code/Editor/ViewportHelpers.h +++ b/Gems/LyShine/Code/Editor/ViewportHelpers.h @@ -7,7 +7,7 @@ */ #pragma once -#include +#include namespace ViewportHelpers { diff --git a/Gems/LyShine/Code/Editor/ViewportIcon.cpp b/Gems/LyShine/Code/Editor/ViewportIcon.cpp index 3f0fdfaba0..33f2f40ffe 100644 --- a/Gems/LyShine/Code/Editor/ViewportIcon.cpp +++ b/Gems/LyShine/Code/Editor/ViewportIcon.cpp @@ -6,7 +6,7 @@ * */ #include "EditorCommon.h" -#include +#include #include #include @@ -15,7 +15,7 @@ float ViewportIcon::m_dpiScaleFactor = 1.0f; ViewportIcon::ViewportIcon(const char* textureFilename) { - m_image = CDraw2d::LoadTexture(textureFilename); + m_image = Draw2dHelper::LoadTexture(textureFilename); } ViewportIcon::~ViewportIcon() @@ -48,7 +48,7 @@ void ViewportIcon::DrawImageAligned(Draw2dHelper& draw2d, AZ::Vector2& pivot, fl opacity); } -void ViewportIcon::DrawImageTiled(Draw2dHelper& draw2d, CDraw2d::VertexPosColUV* verts) +void ViewportIcon::DrawImageTiled(Draw2dHelper& draw2d, IDraw2d::VertexPosColUV* verts) { // Use default blending and rounding modes IDraw2d::Rounding rounding = IDraw2d::Rounding::Nearest; @@ -63,7 +63,7 @@ void ViewportIcon::DrawAxisAlignedBoundingBox(Draw2dHelper& draw2d, AZ::Vector2 float endTexCoordU = fabsf((bound1.GetX() - bound0.GetX()) * pixelLengthForDottedLineTexture); float endTexCoordV = fabsf((bound1.GetY() - bound0.GetY()) * pixelLengthForDottedLineTexture); - CDraw2d::VertexPosColUV verts[2]; + IDraw2d::VertexPosColUV verts[2]; { verts[0].color = dottedColor; verts[1].color = dottedColor; @@ -158,7 +158,7 @@ void ViewportIcon::Draw(Draw2dHelper& draw2d, AZ::Vector2 anchorPos, const AZ::M AZ::Matrix4x4 moveFromPivotSpaceMat = AZ::Matrix4x4::CreateTranslation(pivot3); AZ::Matrix4x4 newTransform = transform * moveFromPivotSpaceMat * rotMat * moveToPivotSpaceMat; - CDraw2d::VertexPosColUV verts[4]; + IDraw2d::VertexPosColUV verts[4]; // points are a clockwise quad static const AZ::Vector2 uvs[4] = { AZ::Vector2(0.0f, 0.0f), AZ::Vector2(1.0f, 0.0f), AZ::Vector2(1.0f, 1.0f), AZ::Vector2(0.0f, 1.0f) @@ -251,7 +251,7 @@ void ViewportIcon::DrawDistanceLine(Draw2dHelper& draw2d, AZ::Vector2 start, AZ: const float pixelLengthForDottedLineTexture = 8.0f; float endTexCoordU = length / pixelLengthForDottedLineTexture; - CDraw2d::VertexPosColUV verts[2]; + IDraw2d::VertexPosColUV verts[2]; verts[0].position = start; verts[0].color = dottedColor; diff --git a/Gems/LyShine/Code/Editor/ViewportIcon.h b/Gems/LyShine/Code/Editor/ViewportIcon.h index f815b244e9..fadd829bcf 100644 --- a/Gems/LyShine/Code/Editor/ViewportIcon.h +++ b/Gems/LyShine/Code/Editor/ViewportIcon.h @@ -20,7 +20,7 @@ public: void DrawImageAligned(Draw2dHelper& draw2d, AZ::Vector2& pivot, float opacity); - void DrawImageTiled(Draw2dHelper& draw2d, CDraw2d::VertexPosColUV* verts); + void DrawImageTiled(Draw2dHelper& draw2d, IDraw2d::VertexPosColUV* verts); void Draw(Draw2dHelper& draw2d, AZ::Vector2 anchorPos, const AZ::Matrix4x4& transform, float iconRot = 0.0f, AZ::Color color = AZ::Color(1.0f, 1.0f, 1.0f, 1.0f)) const; diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index 993f57aeeb..b481e9cbf1 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "LyShine.h" #include "UiRenderer.h" @@ -27,6 +26,7 @@ #include "RulerWidget.h" #include "CanvasHelpers.h" #include "AssetDropHelpers.h" +#include "Draw2d.h" #include "QtHelpers.h" #include diff --git a/Gems/LyShine/Code/Include/LyShine/IDraw2d.h b/Gems/LyShine/Code/Include/LyShine/IDraw2d.h index 620b8c23c9..77dc5ac601 100644 --- a/Gems/LyShine/Code/Include/LyShine/IDraw2d.h +++ b/Gems/LyShine/Code/Include/LyShine/IDraw2d.h @@ -482,6 +482,50 @@ public: // static member functions return nullptr; } + //! Helper to load a texture + static AZ::Data::Instance LoadTexture(const AZStd::string& pathName) + { + if (gEnv && gEnv->pLyShine) // [LYSHINE_ATOM_TODO][GHI #3569] Remove LyShine global interface pointer from legacy global environment + { + return gEnv->pLyShine->LoadTexture(pathName); + } + + return nullptr; + } + + //! Given a position and size and an alignment return the top left corner of the aligned quad + static AZ::Vector2 Align(AZ::Vector2 position, AZ::Vector2 size, IDraw2d::HAlign horizontalAlignment, IDraw2d::VAlign verticalAlignment) + { + AZ::Vector2 result = AZ::Vector2::CreateZero(); + switch (horizontalAlignment) + { + case IDraw2d::HAlign::Left: + result.SetX(position.GetX()); + break; + case IDraw2d::HAlign::Center: + result.SetX(position.GetX() - size.GetX() * 0.5f); + break; + case IDraw2d::HAlign::Right: + result.SetX(position.GetX() - size.GetX()); + break; + } + + switch (verticalAlignment) + { + case IDraw2d::VAlign::Top: + result.SetY(position.GetY()); + break; + case IDraw2d::VAlign::Center: + result.SetY(position.GetY() - size.GetY() * 0.5f); + break; + case IDraw2d::VAlign::Bottom: + result.SetY(position.GetY() - size.GetY()); + break; + } + + return result; + } + //! Round the X and Y coordinates of a point using the given rounding policy template static T RoundXY(T value, IDraw2d::Rounding roundingType) diff --git a/Gems/LyShine/Code/Include/LyShine/ILyShine.h b/Gems/LyShine/Code/Include/LyShine/ILyShine.h index 7832497d8c..71ca6ec074 100644 --- a/Gems/LyShine/Code/Include/LyShine/ILyShine.h +++ b/Gems/LyShine/Code/Include/LyShine/ILyShine.h @@ -9,12 +9,18 @@ #include #include +#include class IDraw2d; class ISprite; struct IUiAnimationSystem; class UiEntityContext; +namespace AZ::RPI +{ + class Image; +} + // The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the LYSHINE_EXPORTS // symbol defined in the StdAfx.h. this symbol should not be defined on any project @@ -82,6 +88,9 @@ public: //! Check if a sprite's texture asset exists. The .sprite sidecar file is optional and is not checked virtual bool DoesSpriteTextureAssetExist(const AZStd::string& pathname) = 0; + //! Load an image asset by texture pathname + virtual AZ::Data::Instance LoadTexture(const AZStd::string& pathName) = 0; + //! Perform post-initialization (script system will be available) virtual void PostInit() = 0; diff --git a/Gems/LyShine/Code/Source/Animation/AnimNode.h b/Gems/LyShine/Code/Source/Animation/AnimNode.h index 4d139e99ca..0076276204 100644 --- a/Gems/LyShine/Code/Source/Animation/AnimNode.h +++ b/Gems/LyShine/Code/Source/Animation/AnimNode.h @@ -13,7 +13,6 @@ #include #include "UiAnimationSystem.h" -#include /*! @@ -40,7 +39,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::basic_string, AZStd::stateless_allocator> name; // parameter name. + AZStd::string name; // parameter name. CUiAnimParamType paramType; // parameter id. EUiAnimValue valueType; // value type, defines type of track to use for animating this parameter. ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags. diff --git a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp index c8818836d6..06e7110fe2 100644 --- a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp +++ b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp @@ -14,77 +14,59 @@ #include "UiAnimSerialize.h" #include -#include #include #include -#include #include #include #include ////////////////////////////////////////////////////////////////////////// -namespace -{ - using UiAnimParamSystemString = AZStd::basic_string, AZStd::stateless_allocator>; - template > - using UiAnimSystemOrderedMap = AZStd::map; - template , typename EqualKey = AZStd::equal_to> - using UiAnimSystemUnorderedMap = AZStd::unordered_map; -} // Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(!g_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \ - g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \ - g_animNodeStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name; +#define REGISTER_NODE_TYPE(name) assert(!m_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \ + m_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \ + m_animNodeStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name; -#define REGISTER_PARAM_TYPE(name) assert(!g_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \ - g_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \ - g_animParamStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name; +#define REGISTER_PARAM_TYPE(name) assert(!m_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \ + m_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \ + m_animParamStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name; -namespace + +// If you get an assert in this function, it means two node types have the same enum value. +void UiAnimationSystem::RegisterNodeTypes() { - UiAnimSystemUnorderedMap g_animNodeEnumToStringMap; - UiAnimSystemOrderedMap> g_animNodeStringToEnumMap; + REGISTER_NODE_TYPE(Entity) + REGISTER_NODE_TYPE(Director) + REGISTER_NODE_TYPE(Camera) + REGISTER_NODE_TYPE(CVar) + REGISTER_NODE_TYPE(ScriptVar) + REGISTER_NODE_TYPE(Material) + REGISTER_NODE_TYPE(Event) + REGISTER_NODE_TYPE(Group) + REGISTER_NODE_TYPE(Layer) + REGISTER_NODE_TYPE(Comment) + REGISTER_NODE_TYPE(RadialBlur) + REGISTER_NODE_TYPE(ColorCorrection) + REGISTER_NODE_TYPE(DepthOfField) + REGISTER_NODE_TYPE(ScreenFader) + REGISTER_NODE_TYPE(Light) + REGISTER_NODE_TYPE(HDRSetup) + REGISTER_NODE_TYPE(ShadowSetup) + REGISTER_NODE_TYPE(Alembic) + REGISTER_NODE_TYPE(GeomCache) + REGISTER_NODE_TYPE(Environment) + REGISTER_NODE_TYPE(ScreenDropsSetup) + REGISTER_NODE_TYPE(AzEntity) +} - UiAnimSystemUnorderedMap g_animParamEnumToStringMap; - UiAnimSystemOrderedMap> g_animParamStringToEnumMap; - - // If you get an assert in this function, it means two node types have the same enum value. - void RegisterNodeTypes() - { - REGISTER_NODE_TYPE(Entity) - REGISTER_NODE_TYPE(Director) - REGISTER_NODE_TYPE(Camera) - REGISTER_NODE_TYPE(CVar) - REGISTER_NODE_TYPE(ScriptVar) - REGISTER_NODE_TYPE(Material) - REGISTER_NODE_TYPE(Event) - REGISTER_NODE_TYPE(Group) - REGISTER_NODE_TYPE(Layer) - REGISTER_NODE_TYPE(Comment) - REGISTER_NODE_TYPE(RadialBlur) - REGISTER_NODE_TYPE(ColorCorrection) - REGISTER_NODE_TYPE(DepthOfField) - REGISTER_NODE_TYPE(ScreenFader) - REGISTER_NODE_TYPE(Light) - REGISTER_NODE_TYPE(HDRSetup) - REGISTER_NODE_TYPE(ShadowSetup) - REGISTER_NODE_TYPE(Alembic) - REGISTER_NODE_TYPE(GeomCache) - REGISTER_NODE_TYPE(Environment) - REGISTER_NODE_TYPE(ScreenDropsSetup) - REGISTER_NODE_TYPE(AzEntity) - } - - // If you get an assert in this function, it means two param types have the same enum value. - void RegisterParamTypes() - { - REGISTER_PARAM_TYPE(Event) - REGISTER_PARAM_TYPE(Float) - REGISTER_PARAM_TYPE(TrackEvent) - REGISTER_PARAM_TYPE(AzComponentField) - } +// If you get an assert in this function, it means two param types have the same enum value. +void UiAnimationSystem::RegisterParamTypes() +{ + REGISTER_PARAM_TYPE(Event) + REGISTER_PARAM_TYPE(Float) + REGISTER_PARAM_TYPE(TrackEvent) + REGISTER_PARAM_TYPE(AzComponentField) } ////////////////////////////////////////////////////////////////////////// @@ -98,6 +80,10 @@ UiAnimationSystem::UiAnimationSystem() m_lastUpdateTime = AZ::Time::ZeroTimeUs; m_nextSequenceId = 1; + + DoNodeStaticInitialisation(); + RegisterNodeTypes(); + RegisterParamTypes(); } ////////////////////////////////////////////////////////////////////////// @@ -1173,16 +1159,16 @@ void UiAnimationSystem::SerializeNodeType(EUiAnimNodeType& animNodeType, XmlNode XmlString nodeTypeString; if (xmlNode->getAttr(kType, nodeTypeString)) { - assert(g_animNodeStringToEnumMap.find(nodeTypeString.c_str()) != g_animNodeStringToEnumMap.end()); - animNodeType = stl::find_in_map(g_animNodeStringToEnumMap, nodeTypeString.c_str(), eUiAnimNodeType_Invalid); + assert(m_animNodeStringToEnumMap.contains(nodeTypeString.c_str())); + animNodeType = stl::find_in_map(m_animNodeStringToEnumMap, nodeTypeString.c_str(), eUiAnimNodeType_Invalid); } } } else { const char* pTypeString = "Invalid"; - assert(g_animNodeEnumToStringMap.find(animNodeType) != g_animNodeEnumToStringMap.end()); - pTypeString = g_animNodeEnumToStringMap[animNodeType].c_str(); + assert(m_animNodeEnumToStringMap.find(animNodeType) != m_animNodeEnumToStringMap.end()); + pTypeString = m_animNodeEnumToStringMap[animNodeType].c_str(); xmlNode->setAttr(kType, pTypeString); } } @@ -1242,8 +1228,8 @@ void UiAnimationSystem::SerializeParamType(CUiAnimParamType& animParamType, XmlN } else { - assert(g_animParamStringToEnumMap.find(paramTypeString.c_str()) != g_animParamStringToEnumMap.end()); - animParamType.m_type = stl::find_in_map(g_animParamStringToEnumMap, paramTypeString.c_str(), eUiAnimParamType_Invalid); + assert(m_animParamStringToEnumMap.contains(paramTypeString.c_str())); + animParamType.m_type = stl::find_in_map(m_animParamStringToEnumMap, paramTypeString.c_str(), eUiAnimParamType_Invalid); } } } @@ -1265,8 +1251,8 @@ void UiAnimationSystem::SerializeParamType(CUiAnimParamType& animParamType, XmlN } else { - assert(g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end()); - pTypeString = g_animParamEnumToStringMap[animParamType.m_type].c_str(); + assert(m_animParamEnumToStringMap.find(animParamType.m_type) != m_animParamEnumToStringMap.end()); + pTypeString = m_animParamEnumToStringMap[animParamType.m_type].c_str(); } xmlNode->setAttr(kParamType, pTypeString); @@ -1332,9 +1318,9 @@ const char* UiAnimationSystem::GetParamTypeName(const CUiAnimParamType& animPara } else { - if (g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end()) + if (m_animParamEnumToStringMap.find(animParamType.m_type) != m_animParamEnumToStringMap.end()) { - return g_animParamEnumToStringMap[animParamType.m_type].c_str(); + return m_animParamEnumToStringMap[animParamType.m_type].c_str(); } } @@ -1346,15 +1332,6 @@ void UiAnimationSystem::OnCameraCut() { } -////////////////////////////////////////////////////////////////////////// -void UiAnimationSystem::StaticInitialize() -{ - DoNodeStaticInitialisation(); - - RegisterNodeTypes(); - RegisterParamTypes(); -} - ////////////////////////////////////////////////////////////////////////// void UiAnimationSystem::Reflect(AZ::SerializeContext* serializeContext) { @@ -1380,13 +1357,13 @@ void UiAnimationSystem::Reflect(AZ::SerializeContext* serializeContext) ////////////////////////////////////////////////////////////////////////// EUiAnimNodeType UiAnimationSystem::GetNodeTypeFromString(const char* pString) const { - return stl::find_in_map(g_animNodeStringToEnumMap, pString, eUiAnimNodeType_Invalid); + return stl::find_in_map(m_animNodeStringToEnumMap, pString, eUiAnimNodeType_Invalid); } ////////////////////////////////////////////////////////////////////////// CUiAnimParamType UiAnimationSystem::GetParamTypeFromString(const char* pString) const { - const EUiAnimParamType paramType = stl::find_in_map(g_animParamStringToEnumMap, pString, eUiAnimParamType_Invalid); + const EUiAnimParamType paramType = stl::find_in_map(m_animParamStringToEnumMap, pString, eUiAnimParamType_Invalid); if (paramType != eUiAnimParamType_Invalid) { diff --git a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.h b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.h index cd51cd51d0..6c710205fa 100644 --- a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.h +++ b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.h @@ -14,6 +14,8 @@ #include #include +#include + struct PlayingUIAnimSequence { //! Sequence playing @@ -134,12 +136,10 @@ public: void SerializeParamType(CUiAnimParamType& animParamType, XmlNodeRef& xmlNode, bool bLoading, const uint version) override; void SerializeParamData(UiAnimParamData& animParamData, XmlNodeRef& xmlNode, bool bLoading) override; - static const char* GetParamTypeName(const CUiAnimParamType& animParamType); + const char* GetParamTypeName(const CUiAnimParamType& animParamType); void OnCameraCut(); - static void StaticInitialize(); - static void Reflect(AZ::SerializeContext* serializeContext); void NotifyTrackEventListeners(const char* eventName, const char* valueName, IUiAnimSequence* pSequence) override; @@ -187,5 +187,21 @@ private: // A sequence which turned on the early animation update last time uint32 m_nextSequenceId; + + using UiAnimParamSystemString = AZStd::string; + template > + using UiAnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to<>> + using UiAnimSystemUnorderedMap = AZStd::unordered_map; + + UiAnimSystemUnorderedMap m_animNodeEnumToStringMap; + UiAnimSystemOrderedMap m_animNodeStringToEnumMap; + + UiAnimSystemUnorderedMap m_animParamEnumToStringMap; + UiAnimSystemOrderedMap m_animParamStringToEnumMap; + + void RegisterNodeTypes(); + void RegisterParamTypes(); + void ShowPlayedSequencesDebug(); }; diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index 2838ed4877..ff8c7f1c6d 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -6,7 +6,7 @@ * */ -#include +#include "Draw2d.h" #include #include "LyShinePassDataBus.h" @@ -215,7 +215,7 @@ void CDraw2d::DrawImageAligned(AZ::Data::Instance image, AZ::Vec HAlign horizontalAlignment, VAlign verticalAlignment, float opacity, float rotation, const AZ::Vector2* minMaxTexCoords, ImageOptions* imageOptions) { - AZ::Vector2 alignedPosition = Align(position, size, horizontalAlignment, verticalAlignment); + AZ::Vector2 alignedPosition = Draw2dHelper::Align(position, size, horizontalAlignment, verticalAlignment); DrawImage(image, alignedPosition, size, opacity, rotation, &position, minMaxTexCoords, imageOptions); } @@ -524,40 +524,6 @@ void CDraw2d::SetSortKey(int64_t key) // PUBLIC STATIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -AZ::Vector2 CDraw2d::Align(AZ::Vector2 position, AZ::Vector2 size, - HAlign horizontalAlignment, VAlign verticalAlignment) -{ - AZ::Vector2 result = AZ::Vector2::CreateZero(); - switch (horizontalAlignment) - { - case HAlign::Left: - result.SetX(position.GetX()); - break; - case HAlign::Center: - result.SetX(position.GetX() - size.GetX() * 0.5f); - break; - case HAlign::Right: - result.SetX(position.GetX() - size.GetX()); - break; - } - - switch (verticalAlignment) - { - case VAlign::Top: - result.SetY(position.GetY()); - break; - case VAlign::Center: - result.SetY(position.GetY() - size.GetY() * 0.5f); - break; - case VAlign::Bottom: - result.SetY(position.GetY() - size.GetY()); - break; - } - - return result; -} - //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::Data::Instance CDraw2d::LoadTexture(const AZStd::string& pathName) { diff --git a/Gems/LyShine/Code/Include/LyShine/Draw2d.h b/Gems/LyShine/Code/Source/Draw2d.h similarity index 98% rename from Gems/LyShine/Code/Include/LyShine/Draw2d.h rename to Gems/LyShine/Code/Source/Draw2d.h index d138f41b03..6d400c6b55 100644 --- a/Gems/LyShine/Code/Include/LyShine/Draw2d.h +++ b/Gems/LyShine/Code/Source/Draw2d.h @@ -180,9 +180,6 @@ private: public: // static member functions - //! Given a position and size and an alignment return the top left corner of the aligned quad - static AZ::Vector2 Align(AZ::Vector2 position, AZ::Vector2 size, HAlign horizontalAlignment, VAlign verticalAlignment); - //! Helper to load a texture static AZ::Data::Instance LoadTexture(const AZStd::string& pathName); diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index 683d72f4ab..b362ed2106 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -43,11 +43,11 @@ #include "Sprite.h" #include "UiSerialize.h" #include "UiRenderer.h" +#include "Draw2d.h" #include #include #include -#include #if defined(LYSHINE_INTERNAL_UNIT_TEST) #include "TextMarkup.h" @@ -156,8 +156,6 @@ CLyShine::CLyShine([[maybe_unused]] ISystem* system) UiElementComponent::Initialize(); UiCanvasComponent::Initialize(); - UiAnimationSystem::StaticInitialize(); - AzFramework::InputChannelEventListener::Connect(); AzFramework::InputTextEventListener::Connect(); UiCursorBus::Handler::BusConnect(); @@ -355,6 +353,12 @@ bool CLyShine::DoesSpriteTextureAssetExist(const AZStd::string& pathname) return CSprite::DoesSpriteTextureAssetExist(pathname); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +AZ::Data::Instance CLyShine::LoadTexture(const AZStd::string& pathname) +{ + return CDraw2d::LoadTexture(pathname); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::PostInit() { @@ -691,7 +695,7 @@ void CLyShine::RenderUiCursor() AZ::RHI::Size cursorSize = m_uiCursorTexture->GetDescriptor().m_size; const AZ::Vector2 dimensions(aznumeric_cast(cursorSize.m_width), aznumeric_cast(cursorSize.m_height)); - CDraw2d::ImageOptions imageOptions; + IDraw2d::ImageOptions imageOptions; imageOptions.m_clamp = true; const float opacity = 1.0f; const float rotation = 0.0f; diff --git a/Gems/LyShine/Code/Source/LyShine.h b/Gems/LyShine/Code/Source/LyShine.h index 82f902a9f8..eab52258c1 100644 --- a/Gems/LyShine/Code/Source/LyShine.h +++ b/Gems/LyShine/Code/Source/LyShine.h @@ -72,6 +72,7 @@ public: ISprite* LoadSprite(const AZStd::string& pathname) override; ISprite* CreateSprite(const AZStd::string& renderTargetName) override; bool DoesSpriteTextureAssetExist(const AZStd::string& pathname) override; + AZ::Data::Instance LoadTexture(const AZStd::string& pathname) override; void PostInit() override; diff --git a/Gems/LyShine/Code/Source/LyShineDebug.cpp b/Gems/LyShine/Code/Source/LyShineDebug.cpp index bb57e70857..7e99652f45 100644 --- a/Gems/LyShine/Code/Source/LyShineDebug.cpp +++ b/Gems/LyShine/Code/Source/LyShineDebug.cpp @@ -7,7 +7,7 @@ */ #include "LyShineDebug.h" #include "IConsole.h" -#include +#include #include @@ -377,7 +377,7 @@ static void DebugDrawColoredBox(AZ::Vector2 pos, AZ::Vector2 size, AZ::Color col { IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); imageOptions.color = color.GetAsVector3(); auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White); draw2d->DrawImageAligned(whiteTexture, pos, size, horizontalAlignment, verticalAlignment, @@ -392,7 +392,7 @@ static void DebugDrawStringWithSizeBox(AZStd::string_view font, unsigned int eff { IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d(); - CDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); + IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); if (!font.empty()) { textOptions.fontName = font; @@ -618,7 +618,7 @@ static AZ::Vector2 DebugDrawFontColorTestBox(AZ::Vector2 pos, const char* string float pointSize = 32.0f; const float spacing = 6.0f; - CDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); + IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); textOptions.effectIndex = 1; // no drop shadow baked in textOptions.color = color; @@ -742,7 +742,7 @@ static void DebugDraw2dImageColor() AZ::Data::Instance texture = GetMonoAlphaTestTexture(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); draw2d->DrawText( "Testing image colors, image is black and white, top row is opacity=1, bottom row is opacity = 0.5", @@ -780,7 +780,7 @@ static void DebugDraw2dImageBlendMode() AZ::Data::Instance texture = GetColorAlphaTestTexture(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); draw2d->DrawText("Testing blend modes, src blend changes across x-axis, dst blend changes across y axis", AZ::Vector2(20, 20), 16); @@ -801,7 +801,7 @@ static void DebugDraw2dImageBlendMode() AZ::Vector2 pos(xStart + xSpacing * srcIndex, yStart + ySpacing * dstIndex); // first draw a background with varying color and alpha - CDraw2d::VertexPosColUV verts[4] = + IDraw2d::VertexPosColUV verts[4] = { { // top left AZ::Vector2(pos.GetX(), pos.GetY()), @@ -828,7 +828,7 @@ static void DebugDraw2dImageBlendMode() // Draw the image with this color - CDraw2d::RenderState renderState; + IDraw2d::RenderState renderState; renderState.m_blendState.m_blendSource = g_srcBlendModes[srcIndex]; renderState.m_blendState.m_blendDest = g_dstBlendModes[dstIndex]; draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, 0, &imageOptions); @@ -845,7 +845,7 @@ static void DebugDraw2dImageUVs() AZ::Data::Instance texture = GetColorTestTexture(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); draw2d->DrawText( "Testing DrawImage with minMaxTexCoords. Full image, top left quadrant, middle section, full flipped", @@ -894,7 +894,7 @@ static void DebugDraw2dImagePixelRounding() AZ::Data::Instance texture = GetColorTestTexture(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); draw2d->DrawText("Testing DrawImage pixel rounding options", AZ::Vector2(20, 20), 16); @@ -933,7 +933,7 @@ static void DebugDraw2dLineBasic() { IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d(); - CDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); + IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions(); draw2d->DrawText("Testing DrawLine", AZ::Vector2(20, 20), 16); diff --git a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp index 0a21f92119..ea6e3681a3 100644 --- a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.cpp b/Gems/LyShine/Code/Source/UiCanvasManager.cpp index 70646246f0..fc373f17f6 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasManager.cpp @@ -6,7 +6,7 @@ * */ #include "UiCanvasManager.h" -#include +#include #include "UiCanvasFileObject.h" #include "UiCanvasComponent.h" @@ -1020,7 +1020,7 @@ void UiCanvasManager::DebugDisplayCanvasData(int setting) const // local function to write a line of text (with a background rect) and increment Y offset AZStd::function WriteLine = [&](const char* buffer, const AZ::Vector3& color) { - CDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); + IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); textOptions.color = color; AZ::Vector2 textSize = draw2d->GetTextSize(buffer, fontSize, &textOptions); AZ::Vector2 rectTopLeft = AZ::Vector2(xOffset - 2, yOffset); @@ -1174,7 +1174,7 @@ void UiCanvasManager::DebugDisplayDrawCallData() const // local function to write a line of text (with a background rect) and increment Y offset AZStd::function WriteLine = [&](const char* buffer, const AZ::Vector3& color) { - CDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); + IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); textOptions.color = color; AZ::Vector2 textSize = draw2d->GetTextSize(buffer, fontSize, &textOptions); AZ::Vector2 rectTopLeft = AZ::Vector2(xOffset - 2, yOffset); diff --git a/Gems/LyShine/Code/Source/UiFaderComponent.cpp b/Gems/LyShine/Code/Source/UiFaderComponent.cpp index e1f5153e99..e84e5162b5 100644 --- a/Gems/LyShine/Code/Source/UiFaderComponent.cpp +++ b/Gems/LyShine/Code/Source/UiFaderComponent.cpp @@ -7,7 +7,7 @@ */ #include "UiFaderComponent.h" #include "RenderGraph.h" -#include +#include #include #include diff --git a/Gems/LyShine/Code/Source/UiImageComponent.cpp b/Gems/LyShine/Code/Source/UiImageComponent.cpp index baf210a629..a8b4210d6b 100644 --- a/Gems/LyShine/Code/Source/UiImageComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageComponent.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp index 4e7d22d96a..3559dc6306 100644 --- a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp @@ -9,7 +9,7 @@ #include "Sprite.h" #include "RenderGraph.h" -#include +#include #include #include #include diff --git a/Gems/LyShine/Code/Source/UiMaskComponent.cpp b/Gems/LyShine/Code/Source/UiMaskComponent.cpp index 09975d1351..67ba8ee0fb 100644 --- a/Gems/LyShine/Code/Source/UiMaskComponent.cpp +++ b/Gems/LyShine/Code/Source/UiMaskComponent.cpp @@ -6,7 +6,7 @@ * */ #include "UiMaskComponent.h" -#include +#include #include #include diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 3b835dec92..a9c56ece90 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include //////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC MEMBER FUNCTIONS @@ -449,7 +449,7 @@ void UiRenderer::DebugDisplayTextureData(int recordingOption) // local function to write a line of text (with a background rect) and increment Y offset AZStd::function WriteLine = [&](const char* buffer, const AZ::Vector3& color) { - CDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); + IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions(); textOptions.color = color; AZ::Vector2 textSize = draw2d->GetTextSize(buffer, fontSize, &textOptions); AZ::Vector2 rectTopLeft = AZ::Vector2(xOffset - 2, yOffset); diff --git a/Gems/LyShine/Code/Source/UiTextComponent.cpp b/Gems/LyShine/Code/Source/UiTextComponent.cpp index 01cfd49e99..aa0235470a 100644 --- a/Gems/LyShine/Code/Source/UiTextComponent.cpp +++ b/Gems/LyShine/Code/Source/UiTextComponent.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include @@ -1105,7 +1105,7 @@ UiTextComponent::InlineImage::InlineImage(const AZStd::string& texturePathname, else { // Load the texture - m_texture = CDraw2d::LoadTexture(m_filepath); + m_texture = Draw2dHelper::LoadTexture(m_filepath); if (m_texture) { AZ::RHI::Size size = m_texture->GetDescriptor().m_size; @@ -1157,7 +1157,7 @@ bool UiTextComponent::InlineImage::OnAtlasUnloaded(const TextureAtlasNamespace:: else { // Load the texture - m_texture = CDraw2d::LoadTexture(m_filepath); + m_texture = Draw2dHelper::LoadTexture(m_filepath); } return true; } @@ -2675,7 +2675,7 @@ void UiTextComponent::GetClickableTextRects(UiClickableTextInterface::ClickableT } else { - alignedPosition = CDraw2d::Align(pos, drawBatchLine.lineSize, m_textHAlignment, IDraw2d::VAlign::Top); // y is already aligned + alignedPosition = Draw2dHelper::Align(pos, drawBatchLine.lineSize, m_textHAlignment, IDraw2d::VAlign::Top); // y is already aligned } alignedPosition.SetY(alignedPosition.GetY() + newlinePosYIncrement); @@ -4043,7 +4043,7 @@ void UiTextComponent::RenderDrawBatchLines( } else { - alignedPosition = CDraw2d::Align(pos, drawBatchLine.lineSize, m_textHAlignment, IDraw2d::VAlign::Top); // y is already aligned + alignedPosition = Draw2dHelper::Align(pos, drawBatchLine.lineSize, m_textHAlignment, IDraw2d::VAlign::Top); // y is already aligned } alignedPosition.SetY(alignedPosition.GetY() + newlinePosYIncrement); diff --git a/Gems/LyShine/Code/lyshine_static_files.cmake b/Gems/LyShine/Code/lyshine_static_files.cmake index 1adbe1b796..925658e756 100644 --- a/Gems/LyShine/Code/lyshine_static_files.cmake +++ b/Gems/LyShine/Code/lyshine_static_files.cmake @@ -7,8 +7,6 @@ # set(FILES - Source/Draw2d.cpp - Include/LyShine/Draw2d.h Include/LyShine/IDraw2d.h Include/LyShine/IRenderGraph.h Include/LyShine/ISprite.h @@ -88,6 +86,8 @@ set(FILES Include/LyShine/Bus/World/UiCanvasOnMeshBus.h Include/LyShine/Bus/World/UiCanvasRefBus.h Include/LyShine/Bus/Tools/UiSystemToolsBus.h + Source/Draw2d.cpp + Source/Draw2d.h Source/LyShine.cpp Source/LyShine.h Source/LyShinePassDataBus.h diff --git a/Gems/LyShine/gem.json b/Gems/LyShine/gem.json index f3c3fc2c67..7ebb733b0f 100644 --- a/Gems/LyShine/gem.json +++ b/Gems/LyShine/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The LyShine Gem provides the runtime UI system and creation tools for Open 3D Engine projects.", "canonical_tags": [ @@ -24,6 +25,7 @@ "Atom_Bootstrap", "AtomFont", "TextureAtlas", - "AtomToolsFramework" + "AtomToolsFramework", + "UiBasics" ] } diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 6e8f53d5cd..40032d6342 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -21,7 +21,7 @@ ly_add_target( Gem::LmbrCentral PUBLIC Legacy::CryCommon - Gem::LyShine.Static + Gem::LyShine.Clients.API ) ly_add_target( @@ -42,7 +42,7 @@ ly_add_target( # if enabled, LyShineExamples is used by all kinds of applications, however, the dependency to LmbrCentral is different # per application type -ly_create_alias(NAME LyShineExamples.Builders NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral.Editor) +ly_create_alias(NAME LyShineExamples.Builders NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::UiBasics.Builders Gem::LmbrCentral.Editor) ly_create_alias(NAME LyShineExamples.Tools NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral.Editor) ly_create_alias(NAME LyShineExamples.Clients NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral) ly_create_alias(NAME LyShineExamples.Servers NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral) diff --git a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp index 542e18b98c..e8b0e4370a 100644 --- a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp +++ b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/Gems/LyShineExamples/gem.json b/Gems/LyShineExamples/gem.json index 74d2b6fe51..c91e9b819e 100644 --- a/Gems/LyShineExamples/gem.json +++ b/Gems/LyShineExamples/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The LyShine Examples Gem provides example code and assets for LyShine, the runtime UI system and editor for Open 3D Engine projects.", "canonical_tags": [ diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp index b535033351..7e32301b71 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp @@ -8,7 +8,6 @@ #include -#include #include "AnimPostFXNode.h" #include "AnimSplineTrack.h" #include "CompoundSplineTrack.h" @@ -39,7 +38,7 @@ public: virtual void GetDefault(bool& val) const = 0; virtual void GetDefault(Vec4& val) const = 0; - AZStd::basic_string, AZStd::stateless_allocator> m_name; + AZStd::string m_name; protected: virtual ~CControlParamBase(){} diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp index dc0782f982..51be8a4c24 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -28,7 +27,6 @@ #include "LayerNode.h" #include "ShadowsSetupNode.h" -#include #include #include @@ -74,136 +72,117 @@ static SMovieSequenceAutoComplete s_movieSequenceAutoComplete; #endif ////////////////////////////////////////////////////////////////////////// -namespace -{ - using AnimParamSystemString = AZStd::basic_string, AZStd::stateless_allocator>; +// Serialization for anim nodes & param types +#define REGISTER_NODE_TYPE(name) assert(!m_animNodeEnumToStringMap.contains(AnimNodeType::name)); \ + m_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \ + m_animNodeStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimNodeType::name; - template > - using AnimSystemOrderedMap = AZStd::map; - template , typename EqualKey = AZStd::equal_to> - using AnimSystemUnorderedMap = AZStd::unordered_map; +#define REGISTER_PARAM_TYPE(name) assert(!m_animParamEnumToStringMap.contains(AnimParamType::name)); \ + m_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \ + m_animParamStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimParamType::name; + +// If you get an assert in this function, it means two node types have the same enum value. +void CMovieSystem::RegisterNodeTypes() +{ + REGISTER_NODE_TYPE(Entity) + REGISTER_NODE_TYPE(Director) + REGISTER_NODE_TYPE(Camera) + REGISTER_NODE_TYPE(CVar) + REGISTER_NODE_TYPE(ScriptVar) + REGISTER_NODE_TYPE(Material) + REGISTER_NODE_TYPE(Event) + REGISTER_NODE_TYPE(Group) + REGISTER_NODE_TYPE(Layer) + REGISTER_NODE_TYPE(Comment) + REGISTER_NODE_TYPE(RadialBlur) + REGISTER_NODE_TYPE(ColorCorrection) + REGISTER_NODE_TYPE(DepthOfField) + REGISTER_NODE_TYPE(ScreenFader) + REGISTER_NODE_TYPE(Light) + REGISTER_NODE_TYPE(ShadowSetup) + REGISTER_NODE_TYPE(Alembic) + REGISTER_NODE_TYPE(GeomCache) + REGISTER_NODE_TYPE(Environment) + REGISTER_NODE_TYPE(AzEntity) + REGISTER_NODE_TYPE(Component) } -// Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(!g_animNodeEnumToStringMap.contains(AnimNodeType::name)); \ - g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \ - g_animNodeStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimNodeType::name; - -#define REGISTER_PARAM_TYPE(name) assert(!g_animParamEnumToStringMap.contains(AnimParamType::name)); \ - g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \ - g_animParamStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimParamType::name; - -namespace +// If you get an assert in this function, it means two param types have the same enum value. +void CMovieSystem::RegisterParamTypes() { - AnimSystemUnorderedMap g_animNodeEnumToStringMap; - AnimSystemOrderedMap> g_animNodeStringToEnumMap; - - AnimSystemUnorderedMap g_animParamEnumToStringMap; - AnimSystemOrderedMap> g_animParamStringToEnumMap; - - // If you get an assert in this function, it means two node types have the same enum value. - void RegisterNodeTypes() - { - REGISTER_NODE_TYPE(Entity) - REGISTER_NODE_TYPE(Director) - REGISTER_NODE_TYPE(Camera) - REGISTER_NODE_TYPE(CVar) - REGISTER_NODE_TYPE(ScriptVar) - REGISTER_NODE_TYPE(Material) - REGISTER_NODE_TYPE(Event) - REGISTER_NODE_TYPE(Group) - REGISTER_NODE_TYPE(Layer) - REGISTER_NODE_TYPE(Comment) - REGISTER_NODE_TYPE(RadialBlur) - REGISTER_NODE_TYPE(ColorCorrection) - REGISTER_NODE_TYPE(DepthOfField) - REGISTER_NODE_TYPE(ScreenFader) - REGISTER_NODE_TYPE(Light) - REGISTER_NODE_TYPE(ShadowSetup) - REGISTER_NODE_TYPE(Alembic) - REGISTER_NODE_TYPE(GeomCache) - REGISTER_NODE_TYPE(Environment) - REGISTER_NODE_TYPE(AzEntity) - REGISTER_NODE_TYPE(Component) - } - - // If you get an assert in this function, it means two param types have the same enum value. - void RegisterParamTypes() - { - REGISTER_PARAM_TYPE(FOV) - REGISTER_PARAM_TYPE(Position) - REGISTER_PARAM_TYPE(Rotation) - REGISTER_PARAM_TYPE(Scale) - REGISTER_PARAM_TYPE(Event) - REGISTER_PARAM_TYPE(Visibility) - REGISTER_PARAM_TYPE(Camera) - REGISTER_PARAM_TYPE(Animation) - REGISTER_PARAM_TYPE(Sound) - REGISTER_PARAM_TYPE(Sequence) - REGISTER_PARAM_TYPE(Console) - REGISTER_PARAM_TYPE(Music) ///@deprecated in 1.11, left in for legacy serialization - REGISTER_PARAM_TYPE(Float) - REGISTER_PARAM_TYPE(LookAt) - REGISTER_PARAM_TYPE(TrackEvent) - REGISTER_PARAM_TYPE(ShakeAmplitudeA) - REGISTER_PARAM_TYPE(ShakeAmplitudeB) - REGISTER_PARAM_TYPE(ShakeFrequencyA) - REGISTER_PARAM_TYPE(ShakeFrequencyB) - REGISTER_PARAM_TYPE(ShakeMultiplier) - REGISTER_PARAM_TYPE(ShakeNoise) - REGISTER_PARAM_TYPE(ShakeWorking) - REGISTER_PARAM_TYPE(ShakeAmpAMult) - REGISTER_PARAM_TYPE(ShakeAmpBMult) - REGISTER_PARAM_TYPE(ShakeFreqAMult) - REGISTER_PARAM_TYPE(ShakeFreqBMult) - REGISTER_PARAM_TYPE(DepthOfField) - REGISTER_PARAM_TYPE(FocusDistance) - REGISTER_PARAM_TYPE(FocusRange) - REGISTER_PARAM_TYPE(BlurAmount) - REGISTER_PARAM_TYPE(Capture) - REGISTER_PARAM_TYPE(TransformNoise) - REGISTER_PARAM_TYPE(TimeWarp) - REGISTER_PARAM_TYPE(FixedTimeStep) - REGISTER_PARAM_TYPE(NearZ) - REGISTER_PARAM_TYPE(Goto) - REGISTER_PARAM_TYPE(PositionX) - REGISTER_PARAM_TYPE(PositionY) - REGISTER_PARAM_TYPE(PositionZ) - REGISTER_PARAM_TYPE(RotationX) - REGISTER_PARAM_TYPE(RotationY) - REGISTER_PARAM_TYPE(RotationZ) - REGISTER_PARAM_TYPE(ScaleX) - REGISTER_PARAM_TYPE(ScaleY) - REGISTER_PARAM_TYPE(ScaleZ) - REGISTER_PARAM_TYPE(ColorR) - REGISTER_PARAM_TYPE(ColorG) - REGISTER_PARAM_TYPE(ColorB) - REGISTER_PARAM_TYPE(CommentText) - REGISTER_PARAM_TYPE(ScreenFader) - REGISTER_PARAM_TYPE(LightDiffuse) - REGISTER_PARAM_TYPE(LightRadius) - REGISTER_PARAM_TYPE(LightDiffuseMult) - REGISTER_PARAM_TYPE(LightHDRDynamic) - REGISTER_PARAM_TYPE(LightSpecularMult) - REGISTER_PARAM_TYPE(LightSpecPercentage) - REGISTER_PARAM_TYPE(MaterialDiffuse) - REGISTER_PARAM_TYPE(MaterialSpecular) - REGISTER_PARAM_TYPE(MaterialEmissive) - REGISTER_PARAM_TYPE(MaterialEmissiveIntensity) - REGISTER_PARAM_TYPE(MaterialOpacity) - REGISTER_PARAM_TYPE(MaterialSmoothness) - REGISTER_PARAM_TYPE(TimeRanges) - REGISTER_PARAM_TYPE(Physics) - REGISTER_PARAM_TYPE(GSMCache) - REGISTER_PARAM_TYPE(ShutterSpeed) - REGISTER_PARAM_TYPE(Physicalize) - REGISTER_PARAM_TYPE(PhysicsDriven) - REGISTER_PARAM_TYPE(SunLongitude) - REGISTER_PARAM_TYPE(SunLatitude) - REGISTER_PARAM_TYPE(MoonLongitude) - REGISTER_PARAM_TYPE(MoonLatitude) - REGISTER_PARAM_TYPE(ProceduralEyes) - } + REGISTER_PARAM_TYPE(FOV) + REGISTER_PARAM_TYPE(Position) + REGISTER_PARAM_TYPE(Rotation) + REGISTER_PARAM_TYPE(Scale) + REGISTER_PARAM_TYPE(Event) + REGISTER_PARAM_TYPE(Visibility) + REGISTER_PARAM_TYPE(Camera) + REGISTER_PARAM_TYPE(Animation) + REGISTER_PARAM_TYPE(Sound) + REGISTER_PARAM_TYPE(Sequence) + REGISTER_PARAM_TYPE(Console) + REGISTER_PARAM_TYPE(Music) ///@deprecated in 1.11, left in for legacy serialization + REGISTER_PARAM_TYPE(Float) + REGISTER_PARAM_TYPE(LookAt) + REGISTER_PARAM_TYPE(TrackEvent) + REGISTER_PARAM_TYPE(ShakeAmplitudeA) + REGISTER_PARAM_TYPE(ShakeAmplitudeB) + REGISTER_PARAM_TYPE(ShakeFrequencyA) + REGISTER_PARAM_TYPE(ShakeFrequencyB) + REGISTER_PARAM_TYPE(ShakeMultiplier) + REGISTER_PARAM_TYPE(ShakeNoise) + REGISTER_PARAM_TYPE(ShakeWorking) + REGISTER_PARAM_TYPE(ShakeAmpAMult) + REGISTER_PARAM_TYPE(ShakeAmpBMult) + REGISTER_PARAM_TYPE(ShakeFreqAMult) + REGISTER_PARAM_TYPE(ShakeFreqBMult) + REGISTER_PARAM_TYPE(DepthOfField) + REGISTER_PARAM_TYPE(FocusDistance) + REGISTER_PARAM_TYPE(FocusRange) + REGISTER_PARAM_TYPE(BlurAmount) + REGISTER_PARAM_TYPE(Capture) + REGISTER_PARAM_TYPE(TransformNoise) + REGISTER_PARAM_TYPE(TimeWarp) + REGISTER_PARAM_TYPE(FixedTimeStep) + REGISTER_PARAM_TYPE(NearZ) + REGISTER_PARAM_TYPE(Goto) + REGISTER_PARAM_TYPE(PositionX) + REGISTER_PARAM_TYPE(PositionY) + REGISTER_PARAM_TYPE(PositionZ) + REGISTER_PARAM_TYPE(RotationX) + REGISTER_PARAM_TYPE(RotationY) + REGISTER_PARAM_TYPE(RotationZ) + REGISTER_PARAM_TYPE(ScaleX) + REGISTER_PARAM_TYPE(ScaleY) + REGISTER_PARAM_TYPE(ScaleZ) + REGISTER_PARAM_TYPE(ColorR) + REGISTER_PARAM_TYPE(ColorG) + REGISTER_PARAM_TYPE(ColorB) + REGISTER_PARAM_TYPE(CommentText) + REGISTER_PARAM_TYPE(ScreenFader) + REGISTER_PARAM_TYPE(LightDiffuse) + REGISTER_PARAM_TYPE(LightRadius) + REGISTER_PARAM_TYPE(LightDiffuseMult) + REGISTER_PARAM_TYPE(LightHDRDynamic) + REGISTER_PARAM_TYPE(LightSpecularMult) + REGISTER_PARAM_TYPE(LightSpecPercentage) + REGISTER_PARAM_TYPE(MaterialDiffuse) + REGISTER_PARAM_TYPE(MaterialSpecular) + REGISTER_PARAM_TYPE(MaterialEmissive) + REGISTER_PARAM_TYPE(MaterialEmissiveIntensity) + REGISTER_PARAM_TYPE(MaterialOpacity) + REGISTER_PARAM_TYPE(MaterialSmoothness) + REGISTER_PARAM_TYPE(TimeRanges) + REGISTER_PARAM_TYPE(Physics) + REGISTER_PARAM_TYPE(GSMCache) + REGISTER_PARAM_TYPE(ShutterSpeed) + REGISTER_PARAM_TYPE(Physicalize) + REGISTER_PARAM_TYPE(PhysicsDriven) + REGISTER_PARAM_TYPE(SunLongitude) + REGISTER_PARAM_TYPE(SunLatitude) + REGISTER_PARAM_TYPE(MoonLongitude) + REGISTER_PARAM_TYPE(MoonLatitude) + REGISTER_PARAM_TYPE(ProceduralEyes) } namespace Internal @@ -1666,16 +1645,16 @@ void CMovieSystem::SerializeNodeType(AnimNodeType& animNodeType, XmlNodeRef& xml XmlString nodeTypeString; if (xmlNode->getAttr(kType, nodeTypeString)) { - assert(g_animNodeStringToEnumMap.find(nodeTypeString.c_str()) != g_animNodeStringToEnumMap.end()); - animNodeType = stl::find_in_map(g_animNodeStringToEnumMap, nodeTypeString.c_str(), AnimNodeType::Invalid); + assert(m_animNodeStringToEnumMap.find(nodeTypeString.c_str()) != m_animNodeStringToEnumMap.end()); + animNodeType = stl::find_in_map(m_animNodeStringToEnumMap, nodeTypeString.c_str(), AnimNodeType::Invalid); } } } else { const char* pTypeString = "Invalid"; - assert(g_animNodeEnumToStringMap.find(animNodeType) != g_animNodeEnumToStringMap.end()); - pTypeString = g_animNodeEnumToStringMap[animNodeType].c_str(); + assert(m_animNodeEnumToStringMap.find(animNodeType) != m_animNodeEnumToStringMap.end()); + pTypeString = m_animNodeEnumToStringMap[animNodeType].c_str(); xmlNode->setAttr(kType, pTypeString); } } @@ -1744,8 +1723,8 @@ void CMovieSystem::LoadParamTypeFromXml(CAnimParamType& animParamType, const Xml animParamType.m_name = virtualPropertyValue; } - assert(g_animParamStringToEnumMap.find(paramTypeString.c_str()) != g_animParamStringToEnumMap.end()); - animParamType.m_type = stl::find_in_map(g_animParamStringToEnumMap, paramTypeString.c_str(), AnimParamType::Invalid); + assert(m_animParamStringToEnumMap.find(paramTypeString.c_str()) != m_animParamStringToEnumMap.end()); + animParamType.m_type = stl::find_in_map(m_animParamStringToEnumMap, paramTypeString.c_str(), AnimParamType::Invalid); } } } @@ -1775,8 +1754,8 @@ void CMovieSystem::SaveParamTypeToXml(const CAnimParamType& animParamType, XmlNo xmlNode->setAttr(CAnimParamTypeXmlNames::kVirtualPropertyName, animParamType.m_name.c_str()); } - assert(g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end()); - pTypeString = g_animParamEnumToStringMap[animParamType.m_type].c_str(); + assert(m_animParamEnumToStringMap.find(animParamType.m_type) != m_animParamEnumToStringMap.end()); + pTypeString = m_animParamEnumToStringMap[animParamType.m_type].c_str(); } xmlNode->setAttr(kParamType, pTypeString); @@ -1809,9 +1788,9 @@ const char* CMovieSystem::GetParamTypeName(const CAnimParamType& animParamType) } else { - if (g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end()) + if (m_animParamEnumToStringMap.contains(animParamType.m_type)) { - return g_animParamEnumToStringMap[animParamType.m_type].c_str(); + return m_animParamEnumToStringMap[animParamType.m_type].c_str(); } } @@ -1973,13 +1952,13 @@ void CLightAnimWrapper::RemoveCachedLightAnim(const char* name) ////////////////////////////////////////////////////////////////////////// AnimNodeType CMovieSystem::GetNodeTypeFromString(const char* pString) const { - return stl::find_in_map(g_animNodeStringToEnumMap, pString, AnimNodeType::Invalid); + return stl::find_in_map(m_animNodeStringToEnumMap, pString, AnimNodeType::Invalid); } ////////////////////////////////////////////////////////////////////////// CAnimParamType CMovieSystem::GetParamTypeFromString(const char* pString) const { - const AnimParamType paramType = stl::find_in_map(g_animParamStringToEnumMap, pString, AnimParamType::Invalid); + const AnimParamType paramType = stl::find_in_map(m_animParamStringToEnumMap, pString, AnimParamType::Invalid); if (paramType != AnimParamType::Invalid) { diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.h b/Gems/Maestro/Code/Source/Cinematics/Movie.h index ab2c2e649b..4af2b55ced 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.h +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.h @@ -18,6 +18,7 @@ #include #include +#include #include "IMovieSystem.h" #include "IShader.h" @@ -192,7 +193,7 @@ public: void SaveParamTypeToXml(const CAnimParamType& animParamType, XmlNodeRef& xmlNode) override; void SerializeParamType(CAnimParamType& animParamType, XmlNodeRef& xmlNode, bool bLoading, const uint version) override; - static const char* GetParamTypeName(const CAnimParamType& animParamType); + const char* GetParamTypeName(const CAnimParamType& animParamType); void OnCameraCut(); @@ -290,6 +291,23 @@ private: void ShowPlayedSequencesDebug(); + + using AnimParamSystemString = AZStd::string; + + template > + using AnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to<>> + using AnimSystemUnorderedMap = AZStd::unordered_map; + + AnimSystemUnorderedMap m_animNodeEnumToStringMap; + AnimSystemOrderedMap m_animNodeStringToEnumMap; + + AnimSystemUnorderedMap m_animParamEnumToStringMap; + AnimSystemOrderedMap m_animParamStringToEnumMap; + + void RegisterNodeTypes(); + void RegisterParamTypes(); + public: static float m_mov_cameraPrecacheTime; #if !defined(_RELEASE) diff --git a/Gems/Maestro/gem.json b/Gems/Maestro/gem.json index d8f884e271..95aa43c179 100644 --- a/Gems/Maestro/gem.json +++ b/Gems/Maestro/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Maestro Cinematics Gem provides Track View, Open 3D Engine's animated sequence and cinematics editor.", "canonical_tags": [ diff --git a/Gems/MessagePopup/Code/CMakeLists.txt b/Gems/MessagePopup/Code/CMakeLists.txt index 51ec1a3bd1..2ed9c71632 100644 --- a/Gems/MessagePopup/Code/CMakeLists.txt +++ b/Gems/MessagePopup/Code/CMakeLists.txt @@ -19,7 +19,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LyShine + Gem::LyShine.Clients.API ) ly_add_target( @@ -39,4 +39,4 @@ ly_add_target( # MessagePopup is used only in client applications ly_create_alias(NAME MessagePopup.Clients NAMESPACE Gem TARGETS Gem::MessagePopup) - +ly_create_alias(NAME MessagePopup.Builders NAMESPACE Gem TARGETS Gem::UiBasics.Builders) diff --git a/Gems/MessagePopup/gem.json b/Gems/MessagePopup/gem.json index fb44dd93a5..5e1b4843b0 100644 --- a/Gems/MessagePopup/gem.json +++ b/Gems/MessagePopup/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Message Popup Gem provides an example implementation of popup messages using LyShine in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/Metastream/CMakeLists.txt b/Gems/Metastream/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Metastream/CMakeLists.txt +++ b/Gems/Metastream/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Metastream/Code/CMakeLists.txt b/Gems/Metastream/Code/CMakeLists.txt index a032fc34ff..f1652058ac 100644 --- a/Gems/Metastream/Code/CMakeLists.txt +++ b/Gems/Metastream/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME Metastream.Static STATIC diff --git a/Gems/Metastream/gem.json b/Gems/Metastream/gem.json index 309f16b221..9a37a0a8ee 100644 --- a/Gems/Metastream/gem.json +++ b/Gems/Metastream/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Metastream Gem provides functionality for an HTTP server that allows broadcasters to customize game streams with overlays of statistics and event data from a game session.", "canonical_tags": [ diff --git a/Gems/Microphone/CMakeLists.txt b/Gems/Microphone/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Microphone/CMakeLists.txt +++ b/Gems/Microphone/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Microphone/Code/CMakeLists.txt b/Gems/Microphone/Code/CMakeLists.txt index 5b40521f6a..873d05e98d 100644 --- a/Gems/Microphone/Code/CMakeLists.txt +++ b/Gems/Microphone/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME Microphone.Static STATIC diff --git a/Gems/Microphone/gem.json b/Gems/Microphone/gem.json index 6e57bec854..6a5b415a22 100644 --- a/Gems/Microphone/gem.json +++ b/Gems/Microphone/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Microphone Gem provides support for audio input through microphones.", "canonical_tags": [ diff --git a/Gems/Multiplayer/CMakeLists.txt b/Gems/Multiplayer/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Multiplayer/CMakeLists.txt +++ b/Gems/Multiplayer/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index afe40408ab..66085476e5 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -6,6 +6,8 @@ # # +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) + ly_add_target( NAME Multiplayer.Static STATIC NAMESPACE Gem diff --git a/Gems/Multiplayer/gem.json b/Gems/Multiplayer/gem.json index f895c78c5d..2b412084af 100644 --- a/Gems/Multiplayer/gem.json +++ b/Gems/Multiplayer/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Multiplayer Gem provides a public API for multiplayer functionality such as connecting and hosting.", "canonical_tags": [ @@ -16,6 +17,7 @@ ], "icon_path": "preview.png", "requirements": "", + "documentation_url": "", "dependencies": [ "CertificateManager", "Atom_Feature_Common", diff --git a/Gems/MultiplayerCompression/gem.json b/Gems/MultiplayerCompression/gem.json index 98156cc404..a9cf3fa460 100644 --- a/Gems/MultiplayerCompression/gem.json +++ b/Gems/MultiplayerCompression/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Multiplayer Compression Gem provides an open source Compressor for use with AzNetworking's transport layer.", "canonical_tags": [ diff --git a/Gems/NvCloth/CMakeLists.txt b/Gems/NvCloth/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/NvCloth/CMakeLists.txt +++ b/Gems/NvCloth/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/NvCloth/Code/CMakeLists.txt b/Gems/NvCloth/Code/CMakeLists.txt index 5b5bba9d8b..76f5bcfeb8 100644 --- a/Gems/NvCloth/Code/CMakeLists.txt +++ b/Gems/NvCloth/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) #for PAL_TRAIT_NVCLOTH Traits diff --git a/Gems/NvCloth/gem.json b/Gems/NvCloth/gem.json index 86a70b9373..9494d65e82 100644 --- a/Gems/NvCloth/gem.json +++ b/Gems/NvCloth/gem.json @@ -2,8 +2,9 @@ "gem_name": "NvCloth", "display_name": "NVIDIA Cloth (NvCloth)", "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The NVIDIA Cloth Gem provides functionality to create fast, realistic cloth simulation with the NVIDIA Cloth library.", "canonical_tags": [ diff --git a/Gems/PhysX/CMakeLists.txt b/Gems/PhysX/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/PhysX/CMakeLists.txt +++ b/Gems/PhysX/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index f045d6b00d..1cad877542 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory(NumericalMethods) -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_PHYSX_SUPPORTED set(LY_PHYSX_ENABLE_RUNNING_BENCHMARKS OFF CACHE BOOL "Adds a target to allow running of the physx benchmarks.") diff --git a/Gems/PhysXDebug/CMakeLists.txt b/Gems/PhysXDebug/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/PhysXDebug/CMakeLists.txt +++ b/Gems/PhysXDebug/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/PhysXDebug/Code/CMakeLists.txt b/Gems/PhysXDebug/Code/CMakeLists.txt index 3ddec9d105..0886f2bf34 100644 --- a/Gems/PhysXDebug/Code/CMakeLists.txt +++ b/Gems/PhysXDebug/Code/CMakeLists.txt @@ -6,7 +6,11 @@ # # -ly_get_list_relative_pal_filename(physx_pal_source_dir ${LY_ROOT_FOLDER}/Gems/PhysX/Code/Source/Platform/${PAL_PLATFORM_NAME}) +# This gem relies on the PhysX gem +o3de_find_gem("PhysX" physx_gem_path) +set(physx_gem_json ${physx_gem_path}/gem.json) +o3de_restricted_path(${physx_gem_json} physx_gem_restricted_path physx_gem_parent_relative_path) +o3de_pal_dir(physx_pal_source_dir ${physx_gem_path}/Code/Source/Platform/${PAL_PLATFORM_NAME} ${physx_gem_restricted_path} ${physx_gem_path} ${physx_gem_parent_relative_path}) include(${physx_pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_PHYSX_SUPPORTED diff --git a/Gems/PhysXDebug/gem.json b/Gems/PhysXDebug/gem.json index 2d9f4dc24d..1087eefad4 100644 --- a/Gems/PhysXDebug/gem.json +++ b/Gems/PhysXDebug/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The PhysX Debug Gem provides debugging functionality and visualizations for NVIDIA PhysX in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/Prefab/PrefabBuilder/gem.json b/Gems/Prefab/PrefabBuilder/gem.json index 2233a7235e..1c0dcd9a72 100644 --- a/Gems/Prefab/PrefabBuilder/gem.json +++ b/Gems/Prefab/PrefabBuilder/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Prefab Builder Gem provides an Asset Processor module for prefabs, which are complex assets built by combining smaller entities.", "canonical_tags": [ diff --git a/Gems/Presence/CMakeLists.txt b/Gems/Presence/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Presence/CMakeLists.txt +++ b/Gems/Presence/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Presence/Code/CMakeLists.txt b/Gems/Presence/Code/CMakeLists.txt index c1c807d432..cc84771201 100644 --- a/Gems/Presence/Code/CMakeLists.txt +++ b/Gems/Presence/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME Presence.Headers HEADERONLY diff --git a/Gems/Presence/gem.json b/Gems/Presence/gem.json index 624af2e62d..48d9dd5ef0 100644 --- a/Gems/Presence/gem.json +++ b/Gems/Presence/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Presence Gem provides a target platform agnostic interface for Presence services.", "canonical_tags": [ diff --git a/Gems/PrimitiveAssets/gem.json b/Gems/PrimitiveAssets/gem.json index 0e4c4689dc..7669477220 100644 --- a/Gems/PrimitiveAssets/gem.json +++ b/Gems/PrimitiveAssets/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The Primitive Assets Gem provides primitive shape mesh assets with physics enabled.", "canonical_tags": [ diff --git a/Gems/Profiler/gem.json b/Gems/Profiler/gem.json index b160bc4b3c..40478deae1 100644 --- a/Gems/Profiler/gem.json +++ b/Gems/Profiler/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "A collection of utilities for capturing performance data", "canonical_tags": [ diff --git a/Gems/PythonAssetBuilder/gem.json b/Gems/PythonAssetBuilder/gem.json index 8046104f03..54fbb949f9 100644 --- a/Gems/PythonAssetBuilder/gem.json +++ b/Gems/PythonAssetBuilder/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Python Asset Builder Gem provides functionality to implement custom asset builders in Python for Asset Processor.", "canonical_tags": [ diff --git a/Gems/QtForPython/Code/CMakeLists.txt b/Gems/QtForPython/Code/CMakeLists.txt index da763978a6..d63c71492d 100644 --- a/Gems/QtForPython/Code/CMakeLists.txt +++ b/Gems/QtForPython/Code/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) include(${CMAKE_CURRENT_SOURCE_DIR}/Source/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Gems/QtForPython/gem.json b/Gems/QtForPython/gem.json index 17d3a26f21..63805a5bc7 100644 --- a/Gems/QtForPython/gem.json +++ b/Gems/QtForPython/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Qt for Python Gem provides the PySide2 Python libraries to manage Qt widgets.", "canonical_tags": [ diff --git a/Gems/SaveData/CMakeLists.txt b/Gems/SaveData/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/SaveData/CMakeLists.txt +++ b/Gems/SaveData/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/SaveData/Code/CMakeLists.txt b/Gems/SaveData/Code/CMakeLists.txt index 38d145f8e5..5d4eb361cc 100644 --- a/Gems/SaveData/Code/CMakeLists.txt +++ b/Gems/SaveData/Code/CMakeLists.txt @@ -6,7 +6,7 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) ly_add_target( NAME SaveData.Static STATIC diff --git a/Gems/SaveData/gem.json b/Gems/SaveData/gem.json index 1ee5a54cec..3a686242d7 100644 --- a/Gems/SaveData/gem.json +++ b/Gems/SaveData/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Save Data Gem provides a platform independent API to save and load persistent user data in Open 3D Engine projects.", "canonical_tags": [ diff --git a/Gems/SceneLoggingExample/gem.json b/Gems/SceneLoggingExample/gem.json index ad950f3992..dc6b5179b6 100644 --- a/Gems/SceneLoggingExample/gem.json +++ b/Gems/SceneLoggingExample/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The Scene Logging Example Gem demonstrates the basics of extending the Open 3D Engine Scene API by adding additional logging to the pipeline.", "canonical_tags": [ diff --git a/Gems/SceneProcessing/gem.json b/Gems/SceneProcessing/gem.json index 576460d0a9..3689c2500a 100644 --- a/Gems/SceneProcessing/gem.json +++ b/Gems/SceneProcessing/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Scene Processing Gem provides Scene Settings, a tool you can use to specify the default settings for processing asset files for actors, meshes, motions, and PhysX.", "canonical_tags": [ diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/CameraRequestBus.names b/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/CameraRequestBus.names index 6c0112bfc2..ad2127c2a1 100644 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/CameraRequestBus.names +++ b/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/CameraRequestBus.names @@ -31,6 +31,66 @@ } ] }, + { + "base": "WorldToScreen", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke World To Screen" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after World To Screen is invoked" + }, + "details": { + "name": "World To Screen" + }, + "params": [ + { + "typeid": "{8379EB7D-01FA-4538-B64B-A6543B4BE73D}", + "details": { + "name": "World Position" + } + } + ], + "results": [ + { + "typeid": "{3D80F623-C85C-4741-90D0-E4E66164E6BF}", + "details": { + "name": "Screen Position" + } + } + ] + }, + { + "base": "WorldToScreenNdc", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke World To Screen Ndc" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after World To Screen Ndc is invoked" + }, + "details": { + "name": "World To Screen NDC" + }, + "params": [ + { + "typeid": "{8379EB7D-01FA-4538-B64B-A6543B4BE73D}", + "details": { + "name": "World Position" + } + } + ], + "results": [ + { + "typeid": "{3D80F623-C85C-4741-90D0-E4E66164E6BF}", + "details": { + "name": "Screen NDC Position" + } + } + ] + }, { "base": "GetFov", "entry": { @@ -53,6 +113,78 @@ } ] }, + { + "base": "ScreenToWorld", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke Screen To World" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after Screen To World is invoked" + }, + "details": { + "name": "Screen To World" + }, + "params": [ + { + "typeid": "{3D80F623-C85C-4741-90D0-E4E66164E6BF}", + "details": { + "name": "Screen Position" + } + }, + { + "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", + "details": { + "name": "Depth" + } + } + ], + "results": [ + { + "typeid": "{8379EB7D-01FA-4538-B64B-A6543B4BE73D}", + "details": { + "name": "World Position" + } + } + ] + }, + { + "base": "ScreenNdcToWorld", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke Screen Ndc To World" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after Screen Ndc To World is invoked" + }, + "details": { + "name": "Screen NDC To World" + }, + "params": [ + { + "typeid": "{3D80F623-C85C-4741-90D0-E4E66164E6BF}", + "details": { + "name": "Screen NDC Position" + } + }, + { + "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", + "details": { + "name": "Depth" + } + } + ], + "results": [ + { + "typeid": "{8379EB7D-01FA-4538-B64B-A6543B4BE73D}", + "details": { + "name": "World Position" + } + } + ] + }, { "base": "SetFovRadians", "entry": { @@ -356,4 +488,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/UiFlipbookAnimationBus.names b/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/UiFlipbookAnimationBus.names index c0f62a816b..e869048b0c 100644 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/UiFlipbookAnimationBus.names +++ b/Gems/ScriptCanvas/Assets/TranslationAssets/EBus/Senders/UiFlipbookAnimationBus.names @@ -21,7 +21,8 @@ }, "details": { "name": "Get Loop Type", - "tooltip": "Gets the type of looping behavior for the animation" + "tooltip": "Gets the type of looping behavior for the animation", + "subtitle": "UI Flipbook" }, "results": [ { @@ -44,7 +45,8 @@ }, "details": { "name": "Get Reverse Delay", - "tooltip": "Gets the delay (in seconds) before playing the reverse loop sequence (PingPong loop types only)" + "tooltip": "Gets the delay (in seconds) before playing the reverse loop sequence (PingPong loop types only)", + "subtitle": "UI Flipbook" }, "results": [ { @@ -67,7 +69,8 @@ }, "details": { "name": "Set Is Auto Play Enabled", - "tooltip": "Sets whether the animation will begin playing as soon as the element is activated" + "tooltip": "Sets whether the animation will begin playing as soon as the element is activated", + "subtitle": "UI Flipbook" }, "params": [ { @@ -91,7 +94,8 @@ }, "details": { "name": "Set Current Frame", - "tooltip": "Sets the frame to immediately display for the animation" + "tooltip": "Sets the frame to immediately display for the animation", + "subtitle": "UI Flipbook" }, "params": [ { @@ -115,7 +119,8 @@ }, "details": { "name": "Get Loop Start Frame", - "tooltip": "Gets the first frame that is displayed within an animation loop. Applicable only when the \"Loop Type\" is set to anything other than \"None\"" + "tooltip": "Gets the first frame that is displayed within an animation loop. Applicable only when the \"Loop Type\" is set to anything other than \"None\"", + "subtitle": "UI Flipbook" }, "results": [ { @@ -138,7 +143,8 @@ }, "details": { "name": "Set Loop Type", - "tooltip": "Sets the type of looping behavior for this animation" + "tooltip": "Sets the type of looping behavior for this animation", + "subtitle": "UI Flipbook" }, "params": [ { @@ -162,7 +168,8 @@ }, "details": { "name": "Get Start Delay", - "tooltip": "Gets the delay (in seconds) before playing the flipbook (applied only once during playback)" + "tooltip": "Gets the delay (in seconds) before playing the flipbook (applied only once during playback)", + "subtitle": "UI Flipbook" }, "results": [ { @@ -185,7 +192,8 @@ }, "details": { "name": "Set Start Delay", - "tooltip": "Sets the delay (in seconds) before playing the flipbook (applied only once during playback)" + "tooltip": "Sets the delay (in seconds) before playing the flipbook (applied only once during playback)", + "subtitle": "UI Flipbook" }, "params": [ { @@ -209,7 +217,8 @@ }, "details": { "name": "Get Current Frame", - "tooltip": "Gets the frame of the animation currently displayed" + "tooltip": "Gets the frame of the animation currently displayed", + "subtitle": "UI Flipbook" }, "results": [ { @@ -232,7 +241,8 @@ }, "details": { "name": "Get Framerate", - "tooltip": "Gets the speed used to determine when to transition to the next frame. Framerate is defined relative to unit of time, specified by FramerateUnits" + "tooltip": "Gets the speed used to determine when to transition to the next frame. Framerate is defined relative to unit of time, specified by FramerateUnits", + "subtitle": "UI Flipbook" }, "results": [ { @@ -255,7 +265,8 @@ }, "details": { "name": "Set Loop Delay", - "tooltip": "Sets the delay (in seconds) before playing the loop sequence" + "tooltip": "Sets the delay (in seconds) before playing the loop sequence", + "subtitle": "UI Flipbook" }, "params": [ { @@ -279,7 +290,8 @@ }, "details": { "name": "Get Start Frame", - "tooltip": "Gets the first frame to display when starting the animation" + "tooltip": "Gets the first frame to display when starting the animation", + "subtitle": "UI Flipbook" }, "results": [ { @@ -302,7 +314,8 @@ }, "details": { "name": "Set Framerate Unit", - "tooltip": "Sets the framerate unit (0 = Frames per second, 1 = Seconds per frame)" + "tooltip": "Sets the framerate unit (0 = Frames per second, 1 = Seconds per frame)", + "subtitle": "UI Flipbook" }, "params": [ { @@ -326,7 +339,8 @@ }, "details": { "name": "Is Playing", - "tooltip": "Returns whether the animation is currently playing" + "tooltip": "Returns whether the animation is currently playing", + "subtitle": "UI Flipbook" }, "results": [ { @@ -349,7 +363,8 @@ }, "details": { "name": "Set End Frame", - "tooltip": "Sets the last frame to display for the animation" + "tooltip": "Sets the last frame to display for the animation", + "subtitle": "UI Flipbook" }, "params": [ { @@ -373,7 +388,8 @@ }, "details": { "name": "Set Loop Start Frame", - "tooltip": "Sets the first frame that is displayed within an animation loop. Applicable only when the \"Loop Type\" is set to anything other than \"None\"" + "tooltip": "Sets the first frame that is displayed within an animation loop. Applicable only when the \"Loop Type\" is set to anything other than \"None\"", + "subtitle": "UI Flipbook" }, "params": [ { @@ -397,7 +413,8 @@ }, "details": { "name": "Set Reverse Delay", - "tooltip": "Sets the delay (in seconds) before playing the reverse loop sequence (PingPong loop types only)" + "tooltip": "Sets the delay (in seconds) before playing the reverse loop sequence (PingPong loop types only)", + "subtitle": "UI Flipbook" }, "params": [ { @@ -421,7 +438,8 @@ }, "details": { "name": "Stop", - "tooltip": "Ends the animation" + "tooltip": "Ends the animation", + "subtitle": "UI Flipbook" } }, { @@ -436,7 +454,8 @@ }, "details": { "name": "Set Framerate", - "tooltip": "Sets the speed used to determine when to transition to the next frame. Framerate is defined relative to unit of time, specified by FramerateUnits" + "tooltip": "Sets the speed used to determine when to transition to the next frame. Framerate is defined relative to unit of time, specified by FramerateUnits", + "subtitle": "UI Flipbook" }, "params": [ { @@ -460,7 +479,8 @@ }, "details": { "name": "Is Auto Play Enabled", - "tooltip": "Returns whether the animation will begin playing as soon as the element is activated" + "tooltip": "Returns whether the animation will begin playing as soon as the element is activated", + "subtitle": "UI Flipbook" }, "results": [ { @@ -483,7 +503,8 @@ }, "details": { "name": "Start", - "tooltip": "Begins playing the flipbook animation" + "tooltip": "Begins playing the flipbook animation", + "subtitle": "UI Flipbook" } }, { @@ -498,7 +519,8 @@ }, "details": { "name": "Set Start Frame", - "tooltip": "Sets the first frame to display when starting the animation" + "tooltip": "Sets the first frame to display when starting the animation", + "subtitle": "UI Flipbook" }, "params": [ { @@ -522,7 +544,8 @@ }, "details": { "name": "Get End Frame", - "tooltip": "Gets the last frame to display for the animation" + "tooltip": "Gets the last frame to display for the animation", + "subtitle": "UI Flipbook" }, "results": [ { @@ -545,7 +568,8 @@ }, "details": { "name": "Get Framerate Unit", - "tooltip": "Gets the framerate unit (0 = Frames per second, 1 = Seconds per frame)" + "tooltip": "Gets the framerate unit (0 = Frames per second, 1 = Seconds per frame)", + "subtitle": "UI Flipbook" }, "results": [ { @@ -568,7 +592,8 @@ }, "details": { "name": "Get Loop Delay", - "tooltip": "Gets the delay (in seconds) before playing the loop sequence" + "tooltip": "Gets the delay (in seconds) before playing the loop sequence", + "subtitle": "UI Flipbook" }, "results": [ { diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/PhysXWorld_RayCastFromScreenWithGroup.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/PhysXWorld_RayCastFromScreenWithGroup.names new file mode 100644 index 0000000000..447866ae44 --- /dev/null +++ b/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/PhysXWorld_RayCastFromScreenWithGroup.names @@ -0,0 +1,88 @@ +{ + "entries": [ + { + "base": "{B164D87F-6620-5A1D-A2BC-CC09BA18C9B1}", + "context": "ScriptCanvas::Node", + "variant": "", + "details": { + "name": "Ray Cast From Screen With Group", + "category": "PhysX/World", + "tooltip": "Returns the first entity hit by a ray cast from the provided absolute 2D screen position." + }, + "slots": [ + { + "base": "Input_In_0", + "details": { + "name": "In" + } + }, + { + "base": "Output_Out_0", + "details": { + "name": "Out" + } + }, + { + "base": "DataInput_Screen Position_0", + "details": { + "name": "Screen Position" + } + }, + { + "base": "DataInput_Distance_1", + "details": { + "name": "Distance" + } + }, + { + "base": "DataInput_Collision group_2", + "details": { + "name": "Collision group" + } + }, + { + "base": "DataInput_Ignore_3", + "details": { + "name": "Ignore" + } + }, + { + "base": "DataOutput_Object hit_0", + "details": { + "name": "Object hit" + } + }, + { + "base": "DataOutput_Position_1", + "details": { + "name": "Position" + } + }, + { + "base": "DataOutput_Normal_2", + "details": { + "name": "Normal" + } + }, + { + "base": "DataOutput_Distance_3", + "details": { + "name": "Distance" + } + }, + { + "base": "DataOutput_EntityId_4", + "details": { + "name": "EntityId" + } + }, + { + "base": "DataOutput_Surface_5", + "details": { + "name": "Surface" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index d713bc09a6..510962cf4b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -667,13 +667,12 @@ namespace ScriptCanvasEditor } // Now that the slot has a valid type/name, we can actually promote it to a variable - if (PromoteToVariableAction(endpoint) /*&& slot->IsVariableReference()*/) + if (PromoteToVariableAction(endpoint, true)) { ScriptCanvas::GraphVariable* variable = slot->GetVariable(); if (variable) { - // functions 2.0 set variable scope to function if (variable->GetScope() != ScriptCanvas::VariableFlags::Scope::Function) { variable->SetScope(ScriptCanvas::VariableFlags::Scope::Function); @@ -1141,7 +1140,7 @@ namespace ScriptCanvasEditor { if (slot->IsVariableReference()) { - return true; + return !slot->IsUserAdded(); } else { @@ -1253,7 +1252,7 @@ namespace ScriptCanvasEditor return nullptr; } - if (slot->IsVariableReference()) + if (slot->IsVariableReference() && !slot->IsUserAdded()) { ScriptCanvasVariableReferenceDataInterface* dataInterface = aznew ScriptCanvasVariableReferenceDataInterface(&m_variableDataModel, GetScriptCanvasId(), scriptCanvasNodeId, scriptCanvasSlotId); GraphCanvas::NodePropertyDisplay* dataDisplay = nullptr; @@ -2081,20 +2080,20 @@ namespace ScriptCanvasEditor return false; } - bool Graph::ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) + bool Graph::ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot) { ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint); ScriptCanvas::Node* canvasNode = FindNode(scEndpoint.GetNodeId()); if (canvasNode) { - return canvasNode->ConvertSlotToReference(scEndpoint.GetSlotId()); + return canvasNode->ConvertSlotToReference(scEndpoint.GetSlotId(), isNewSlot); } return false; } - bool Graph::CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) + bool Graph::CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot) { ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint); ScriptCanvas::Node* canvasNode = FindNode(scEndpoint.GetNodeId()); @@ -2104,7 +2103,7 @@ namespace ScriptCanvasEditor ScriptCanvas::Slot* slot = canvasNode->GetSlot(scEndpoint.GetSlotId()); if (slot) { - return slot->CanConvertToReference(); + return slot->CanConvertToReference(isNewSlot); } } @@ -2170,7 +2169,7 @@ namespace ScriptCanvasEditor return handledEvent; } - bool Graph::CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint) const + bool Graph::CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint, [[maybe_unused]] bool isNewSlot) const { ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(endpoint); auto activeSlot = FindSlot(scriptCanvasEndpoint); @@ -2189,7 +2188,7 @@ namespace ScriptCanvasEditor return false; } - bool Graph::PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint) + bool Graph::PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint, bool isNewSlot) { ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(endpoint); @@ -2282,12 +2281,11 @@ namespace ScriptCanvasEditor AZ::Outcome addOutcome; - // #functions2 slot<->variable re-use the activeDatum, send the pointer (actually, all of the source slot information, and make a special conversion) ScriptCanvas::GraphVariableManagerRequestBus::EventResult(addOutcome, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::AddVariable, variableName, variableDatum, true); if (addOutcome.IsSuccess()) { - GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference); + GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, isNewSlot); activeSlot->SetVariableReference(addOutcome.GetValue()); @@ -2319,7 +2317,7 @@ namespace ScriptCanvasEditor { if (!targetSlot->IsVariableReference()) { - GraphCanvas::DataSlotRequestBus::Event(referenceTarget.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference); + GraphCanvas::DataSlotRequestBus::Event(referenceTarget.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, false); } if (targetSlot->IsVariableReference()) @@ -2884,7 +2882,7 @@ namespace ScriptCanvasEditor for (auto graphCanvasEndpoint : referencableEndpoints) { - GraphCanvas::DataSlotRequestBus::Event(graphCanvasEndpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference); + GraphCanvas::DataSlotRequestBus::Event(graphCanvasEndpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, false); ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(graphCanvasEndpoint); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 9157aaeac9..ba7ff6abaf 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -175,12 +175,12 @@ namespace ScriptCanvasEditor void RemoveSlot(const GraphCanvas::Endpoint& endpoint) override; bool IsSlotRemovable(const GraphCanvas::Endpoint& endpoint) const override; - bool ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) override; - bool CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) override; + bool ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override; + bool CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override; GraphCanvas::CanHandleMimeEventOutcome CanHandleReferenceMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override; bool HandleReferenceMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override; - bool CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint) const override; - bool PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint) override; + bool CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) const override; + bool PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override; bool SynchronizeReferences(const GraphCanvas::Endpoint& sourceEndpoint, const GraphCanvas::Endpoint& targetEndpoint) override; bool ConvertSlotToValue(const GraphCanvas::Endpoint& endpoint) override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 1176df61dc..b5b4fc7787 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -3873,7 +3873,13 @@ namespace ScriptCanvasEditor contextMenu.AddMenuAction(aznew ConvertReferenceToVariableNodeAction(&contextMenu)); contextMenu.AddMenuAction(aznew ExposeSlotMenuAction(&contextMenu)); contextMenu.AddMenuAction(aznew CreateAzEventHandlerSlotMenuAction(&contextMenu)); - contextMenu.AddMenuAction(aznew SetDataSlotTypeMenuAction(&contextMenu)); + + auto setSlotTypeAction = aznew SetDataSlotTypeMenuAction(&contextMenu); + // Changing slot type is disabled temporarily because now that that user data slots are correctly coordinated with their reference + // variables, their type cannot be changed. The next change will allow all variables to change their type post creation, and then + // that will allow this action to be enabled. + setSlotTypeAction->setEnabled(false); + contextMenu.AddMenuAction(setSlotTypeAction); return HandleContextMenu(contextMenu, slotId, screenPoint, scenePoint); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp index 6402a24b3a..662cec7195 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp @@ -516,7 +516,7 @@ namespace ScriptCanvasEditor GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId2, &GraphCanvas::SlotRequests::GetEndpoint); bool promotedElement = false; - GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint); + GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint, false); if (promotedElement) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp index 0b94fb370a..a18caf4b87 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp @@ -100,12 +100,18 @@ namespace ScriptCanvas { RuntimeAsset* runtimeAsset = asset.GetAs(); AZ_Assert(runtimeAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!"); + if (runtimeAsset && m_serializeContext) { stream->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); - bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeAsset->m_runtimeData, m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB)); + const bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeAsset->m_runtimeData + , m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB)); + AZ_Error("ScriptCanvas", loadSuccess, "ScriptCanvas failed to load runtime asset: %s - %s" + , asset.GetHint().c_str(), asset.GetId().ToString().c_str()); + return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error; } + return AZ::Data::AssetHandler::LoadResult::Error; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp index c4143e7295..6cf9da1510 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp @@ -2577,11 +2577,11 @@ namespace ScriptCanvas } } - bool Node::ConvertSlotToReference(const SlotId& slotId) + bool Node::ConvertSlotToReference(const SlotId& slotId, bool isNewSlot) { Slot* slot = GetSlot(slotId); - if (slot && slot->ConvertToReference()) + if (slot && slot->ConvertToReference(isNewSlot)) { InitializeVariableReference((*slot), {}); return true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h index 97916c8af6..f8b4ca7264 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h @@ -498,7 +498,7 @@ namespace ScriptCanvas void SanityCheckDynamicDisplay(); void SanityCheckDynamicDisplay(ExploredDynamicGroupCache& exploredGroupCache); - bool ConvertSlotToReference(const SlotId& slotId); + bool ConvertSlotToReference(const SlotId& slotId, bool isNewSlot = false); bool ConvertSlotToValue(const SlotId& slotId); NamedEndpoint CreateNamedEndpoint(SlotId slotId) const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp index 44d2367156..4bdd0daae6 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp @@ -460,14 +460,14 @@ namespace ScriptCanvas && GetDataType() != Data::Type::BehaviorContextObject(GraphScopedVariableId::TYPEINFO_Uuid()); } - bool Slot::CanConvertToReference() const - { - return !m_isUserAdded && CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this)); + bool Slot::CanConvertToReference(bool isNewSlot) const + { + return (!m_isUserAdded || isNewSlot) && CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this)); } - bool Slot::ConvertToReference() + bool Slot::ConvertToReference(bool isNewSlot) { - if (CanConvertToReference()) + if (CanConvertToReference(isNewSlot)) { m_isVariableReference = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h index b182af7c67..5649c3e34c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h @@ -147,8 +147,8 @@ namespace ScriptCanvas bool CanConvertToValue() const; bool ConvertToValue(); - bool CanConvertToReference() const; - bool ConvertToReference(); + bool CanConvertToReference(bool isNewSlot = false) const; + bool ConvertToReference(bool isNewSlot = false); void SetVariableReference(const VariableId& variableId); const VariableId& GetVariableReference() const; GraphVariable* GetVariable() const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 829a1098dc..345dc1ebda 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -240,7 +240,6 @@ namespace ScriptCanvas // #functions2 slot<->variable consider getting all variables from the UX variable manager, or from the ACM and looking them up in the variable manager for ordering m_sourceVariableByDatum.insert(AZStd::make_pair(datum, &variablePair.second)); } - } for (auto& sourceVariable : sortedVariables) @@ -1714,6 +1713,7 @@ namespace ScriptCanvas auto iter = m_inputVariableByNodelingInSlot.find(input); if (iter != m_inputVariableByNodelingInSlot.end()) { + // #sc_user_slot_variable_ux don't add variable name if not necessary VariablePtr variable = iter->second; const Slot* slot = iter->first; variable->m_name = call->ModScope()->AddVariableName(slot->GetName()); @@ -4644,35 +4644,59 @@ namespace ScriptCanvas void AbstractCodeModel::ParseNodelingVariables(const Node& node, NodelingType nodelingType) { - // #functions2 slot<->variable adjust once datums are more coordinated - auto createVariablesSlots = [&](AZStd::unordered_map& variablesBySlots, const AZStd::vector& slots, bool slotHasDatum) + // This function accounts for all the ways users have been able to introduce input/output data in their SC function definitions. + // They have been able to create slots, variables, or both. This function reads the datums to create the correct ACM + // variable per required SC user variable. It uses slots as the key, and checks datums in the SC variable list for possible + // matches. + auto createVariablesSlots = [&](AZStd::unordered_map& variablesBySlots, const AZStd::vector& slots, bool errorOnMissingDatum) { for (const auto& slot : slots) { auto variable = AZStd::make_shared(); + auto variableDatum = slot->FindDatum(); + bool initializeDatum = true; - if (slotHasDatum) + if (variableDatum) { - auto variableDatum = slot->FindDatum(); - if (!variableDatum) - { - AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str()))); - return; - } + initializeDatum = false; + } + else if (errorOnMissingDatum) + { + AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str()))); + return; + } - // #functions2 slot<->variable consider getting all variables from the UX variable manager, or from the ACM and looking them up in the variable manager for ordering -// auto iter = m_sourceVariableByDatum.find(variableDatum); -// if (iter == m_sourceVariableByDatum.end()) -// { -// AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str()))); -// return; -// } -// variable->m_sourceVariableId = iter->second->GetVariableId(); + // find the other variable + auto iter = m_sourceVariableByDatum.find(variableDatum); + if (iter != m_sourceVariableByDatum.end()) + { + initializeDatum = false; + } + else if (!variableDatum && errorOnMissingDatum) + { + AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str()))); + return; + } + + VariablePtr premadeVariable = iter != m_sourceVariableByDatum.end() + ? AZStd::const_pointer_cast(FindVariable(iter->second->GetVariableId())) + : VariablePtr(); + + if (premadeVariable) + { + initializeDatum = false; + variable = premadeVariable; + } + + variable->m_sourceSlotId = slot->GetId(); + + if (!premadeVariable && variableDatum) + { variable->m_datum = *variableDatum; } - else + + if (initializeDatum) { - // make a new datum and a source slot id and all that variable->m_datum.SetType(slot->GetDataType()); } @@ -4680,7 +4704,11 @@ namespace ScriptCanvas variable->m_sourceSlotId = slot->GetId(); variable->m_isFromFunctionDefinitionSlot = true; variablesBySlots.insert({ slot, variable }); - m_variables.push_back(variable); + + if (!premadeVariable) + { + m_variables.push_back(variable); + } } }; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariableManagerComponent.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariableManagerComponent.cpp index 58e8be0c37..0bd1b2c5a4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariableManagerComponent.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariableManagerComponent.cpp @@ -220,7 +220,6 @@ namespace ScriptCanvas return AZ::Success(newId); } - // #functions2 slot<->variable add this to the graph, using the old datum AZ::Outcome GraphVariableManagerComponent::AddVariable(AZStd::string_view name, const Datum& value, bool functionScope) { if (FindVariable(name)) diff --git a/Gems/ScriptCanvas/gem.json b/Gems/ScriptCanvas/gem.json index fc8a504917..ace6bca50c 100644 --- a/Gems/ScriptCanvas/gem.json +++ b/Gems/ScriptCanvas/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Script Canvas Gem provides Open 3D Engine's visual scripting environment, Script Canvas.", "canonical_tags": [ diff --git a/Gems/ScriptCanvasDeveloper/Code/Editor/Source/AutomationActions/DynamicSlotFullCreation.cpp b/Gems/ScriptCanvasDeveloper/Code/Editor/Source/AutomationActions/DynamicSlotFullCreation.cpp index 090622646a..c71219cc8c 100644 --- a/Gems/ScriptCanvasDeveloper/Code/Editor/Source/AutomationActions/DynamicSlotFullCreation.cpp +++ b/Gems/ScriptCanvasDeveloper/Code/Editor/Source/AutomationActions/DynamicSlotFullCreation.cpp @@ -295,11 +295,11 @@ namespace ScriptCanvasDeveloperEditor GraphCanvas::Endpoint endpoint = ConvertToGraphCanvasEndpoint(slot->GetEndpoint()); bool canConvertToReference = false; - GraphCanvas::DataSlotRequestBus::EventResult(canConvertToReference, endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::CanConvertToReference); + GraphCanvas::DataSlotRequestBus::EventResult(canConvertToReference, endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::CanConvertToReference, false); if (canConvertToReference) { - GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference); + GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, false); } } diff --git a/Gems/ScriptCanvasDeveloper/gem.json b/Gems/ScriptCanvasDeveloper/gem.json index fe1fdea0fc..c7e23dab9a 100644 --- a/Gems/ScriptCanvasDeveloper/gem.json +++ b/Gems/ScriptCanvasDeveloper/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Script Canvas Developer Gem provides a suite of utility features for the development and debugging of Script Canvas systems.", "canonical_tags": [ diff --git a/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h b/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h index 96a15a9d29..1b03bd1851 100644 --- a/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h +++ b/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -120,6 +121,43 @@ namespace ScriptCanvasPhysics "EntityId", "Surface"); + AZ_INLINE Result RayCastFromScreenWithGroup( + const AZ::Vector2& screenPosition, + float distance, + const AZStd::string& collisionGroup, + AZ::EntityId ignore) + { + AZ::EntityId camera; + Camera::CameraSystemRequestBus::BroadcastResult(camera, &Camera::CameraSystemRequestBus::Events::GetActiveCamera); + if (camera.IsValid()) + { + AZ::Vector3 origin = AZ::Vector3::CreateZero(); + Camera::CameraRequestBus::EventResult(origin, camera, &Camera::CameraRequestBus::Events::ScreenToWorld, screenPosition, 0.f); + AZ::Vector3 offset = AZ::Vector3::CreateZero(); + Camera::CameraRequestBus::EventResult(offset, camera, &Camera::CameraRequestBus::Events::ScreenToWorld, screenPosition, 1.f); + const AZ::Vector3 direction = (offset - origin).GetNormalized(); + return RayCastWorldSpaceWithGroup(origin, direction, distance, collisionGroup, ignore); + } + + // fallback in the rare case there is no active camera + return AZStd::make_tuple(false, AZ::Vector3::CreateZero(), AZ::Vector3::CreateZero(), 0.0f, AZ::EntityId(), AZ::Crc32()); + } + + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(RayCastFromScreenWithGroup, + k_categoryName, + "{8F98A766-A93F-4DA7-B281-482C3DB20649}", + "Returns the first entity hit by a ray cast from the provided absolute 2D screen position.", + "Screen Position", + "Distance", + "Collision group", + "Ignore", + "Object hit", + "Position", + "Normal", + "Distance", + "EntityId", + "Surface"); + AZ_INLINE Result RayCastLocalSpaceWithGroup(const AZ::EntityId& fromEntityId, const AZ::Vector3& direction, float distance, @@ -389,6 +427,7 @@ namespace ScriptCanvasPhysics & inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } -void TerrainSystem::ProcessHeightsFromRegion(const AZ::Aabb& inRegion, const AZ::Vector2 stepSize, Sampler sampleFilter, SurfacePointRegionFillCallback perPositionCallback, TerrainDataReadyCallback onComplete) + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position = position; + surfacePoint.m_position.SetZ(GetHeight(position, sampleFilter, &terrainExists)); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessNormalsFromList( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position = position; + surfacePoint.m_normal = GetNormal(position, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessSurfaceWeightsFromList( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position = position; + GetSurfaceWeights(position, surfacePoint.m_surfaceTags, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessSurfacePointsFromList( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position = position; + GetSurfacePoint(position, surfacePoint, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessHeightsFromListOfVector2( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position.Set(position.GetX(), position.GetY(), 0.0f); + surfacePoint.m_position.SetZ(GetHeightFromVector2(position, sampleFilter, &terrainExists)); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessNormalsFromListOfVector2( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position.Set(position.GetX(), position.GetY(), 0.0f); + surfacePoint.m_normal = GetNormalFromVector2(position, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position.Set(position.GetX(), position.GetY(), 0.0f); + GetSurfaceWeightsFromVector2(position, surfacePoint.m_surfaceTags, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessSurfacePointsFromListOfVector2( + const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + if (!perPositionCallback) + { + return; + } + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (const auto& position : inPositions) + { + bool terrainExists = false; + surfacePoint.m_position.Set(position.GetX(), position.GetY(), 0.0f); + GetSurfacePointFromVector2(position, surfacePoint, sampleFilter, &terrainExists); + perPositionCallback(surfacePoint, terrainExists); + } +} + +void TerrainSystem::ProcessHeightsFromRegion( + const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter) const { // Don't bother processing if we don't have a callback if (!perPositionCallback) @@ -540,30 +702,29 @@ void TerrainSystem::ProcessHeightsFromRegion(const AZ::Aabb& inRegion, const AZ: return; } - uint32_t numSamplesX = static_cast((inRegion.GetMax().GetX() - inRegion.GetMin().GetX()) / stepSize.GetX()); - uint32_t numSamplesY = static_cast((inRegion.GetMax().GetY() - inRegion.GetMin().GetY()) / stepSize.GetY()); - - for (uint32_t y = 0; y < numSamplesY; y++) + const size_t numSamplesX = aznumeric_cast(ceil(inRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(inRegion.GetExtents().GetY() / stepSize.GetY())); + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (size_t y = 0; y < numSamplesY; y++) { - for (uint32_t x = 0; x < numSamplesX; x++) + float fy = aznumeric_cast(inRegion.GetMin().GetY() + (y * stepSize.GetY())); + for (size_t x = 0; x < numSamplesX; x++) { - float fx = (float)(inRegion.GetMin().GetX() + (x * stepSize.GetX())); - float fy = (float)(inRegion.GetMin().GetY() + (y * stepSize.GetY())); - - SurfaceData::SurfacePoint surfacePoint; - GetHeight(AZ::Vector3(fx, fy, 0.0f), sampleFilter, surfacePoint.m_position); - perPositionCallback(surfacePoint, x, y); + bool terrainExists = false; + float fx = aznumeric_cast(inRegion.GetMin().GetX() + (x * stepSize.GetX())); + surfacePoint.m_position.Set(fx, fy, 0.0f); + surfacePoint.m_position.SetZ(GetHeight(surfacePoint.m_position, sampleFilter, &terrainExists)); + perPositionCallback(x, y, surfacePoint, terrainExists); } } - - if (onComplete) - { - onComplete(); - } } - -void TerrainSystem::ProcessSurfacePointsFromRegion(const AZ::Aabb& inRegion, const AZ::Vector2 stepSize, Sampler sampleFilter, SurfacePointRegionFillCallback perPositionCallback, TerrainDataReadyCallback onComplete) +void TerrainSystem::ProcessNormalsFromRegion( + const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter) const { // Don't bother processing if we don't have a callback if (!perPositionCallback) @@ -571,28 +732,83 @@ void TerrainSystem::ProcessSurfacePointsFromRegion(const AZ::Aabb& inRegion, con return; } - uint32_t numSamplesX = static_cast((inRegion.GetMax().GetX() - inRegion.GetMin().GetX()) / stepSize.GetX()); - uint32_t numSamplesY = static_cast((inRegion.GetMax().GetY() - inRegion.GetMin().GetY()) / stepSize.GetY()); + const size_t numSamplesX = aznumeric_cast(ceil(inRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(inRegion.GetExtents().GetY() / stepSize.GetY())); - for (uint32_t y = 0; y < numSamplesY; y++) + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (size_t y = 0; y < numSamplesY; y++) { - for (uint32_t x = 0; x < numSamplesX; x++) + float fy = aznumeric_cast(inRegion.GetMin().GetY() + (y * stepSize.GetY())); + for (size_t x = 0; x < numSamplesX; x++) { - float fx = (float)(inRegion.GetMin().GetX() + (x * stepSize.GetX())); - float fy = (float)(inRegion.GetMin().GetY() + (y * stepSize.GetY())); - - SurfaceData::SurfacePoint surfacePoint; - GetSurfacePoint(AZ::Vector3(fx, fy, inRegion.GetMin().GetZ()), sampleFilter, surfacePoint); - perPositionCallback(surfacePoint, x, y); + bool terrainExists = false; + float fx = aznumeric_cast(inRegion.GetMin().GetX() + (x * stepSize.GetX())); + surfacePoint.m_position.Set(fx, fy, 0.0f); + surfacePoint.m_normal = GetNormal(surfacePoint.m_position, sampleFilter, &terrainExists); + perPositionCallback(x, y, surfacePoint, terrainExists); } } +} - if (onComplete) +void TerrainSystem::ProcessSurfaceWeightsFromRegion( + const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + // Don't bother processing if we don't have a callback + if (!perPositionCallback) { - onComplete(); + return; + } + + const size_t numSamplesX = aznumeric_cast(ceil(inRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(inRegion.GetExtents().GetY() / stepSize.GetY())); + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (size_t y = 0; y < numSamplesY; y++) + { + float fy = aznumeric_cast(inRegion.GetMin().GetY() + (y * stepSize.GetY())); + for (size_t x = 0; x < numSamplesX; x++) + { + bool terrainExists = false; + float fx = aznumeric_cast(inRegion.GetMin().GetX() + (x * stepSize.GetX())); + surfacePoint.m_position.Set(fx, fy, 0.0f); + GetSurfaceWeights(surfacePoint.m_position, surfacePoint.m_surfaceTags, sampleFilter, &terrainExists); + perPositionCallback(x, y, surfacePoint, terrainExists); + } + } +} + +void TerrainSystem::ProcessSurfacePointsFromRegion( + const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter) const +{ + // Don't bother processing if we don't have a callback + if (!perPositionCallback) + { + return; + } + + const size_t numSamplesX = aznumeric_cast(ceil(inRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(inRegion.GetExtents().GetY() / stepSize.GetY())); + + AzFramework::SurfaceData::SurfacePoint surfacePoint; + for (size_t y = 0; y < numSamplesY; y++) + { + float fy = aznumeric_cast(inRegion.GetMin().GetY() + (y * stepSize.GetY())); + for (size_t x = 0; x < numSamplesX; x++) + { + bool terrainExists = false; + float fx = aznumeric_cast(inRegion.GetMin().GetX() + (x * stepSize.GetX())); + surfacePoint.m_position.Set(fx, fy, 0.0f); + GetSurfacePoint(surfacePoint.m_position, surfacePoint, sampleFilter, &terrainExists); + perPositionCallback(x, y, surfacePoint, terrainExists); + } } } -*/ void TerrainSystem::RegisterArea(AZ::EntityId areaId) { diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index d7267476ed..7c6e0cd91e 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -135,6 +136,52 @@ namespace Terrain Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; + //! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each + //! XY coordinate in the list. + virtual void ProcessHeightsFromList(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessNormalsFromList(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfaceWeightsFromList(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfacePointsFromList(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessHeightsFromListOfVector2(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessNormalsFromListOfVector2(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span& inPositions, + AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + + //! Given a region(aabb) and a step size, call the provided callback function with surface data corresponding to the + //! coordinates in the region. + virtual void ProcessHeightsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessNormalsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfaceWeightsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + virtual void ProcessSurfacePointsFromRegion(const AZ::Aabb& inRegion, + const AZ::Vector2& stepSize, + AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, + Sampler sampleFilter = Sampler::DEFAULT) const override; + private: void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) const; diff --git a/Gems/Terrain/Code/Tests/TerrainSystemBenchmarks.cpp b/Gems/Terrain/Code/Tests/TerrainSystemBenchmarks.cpp index 3d0cb5222e..85dd5dc0c4 100644 --- a/Gems/Terrain/Code/Tests/TerrainSystemBenchmarks.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSystemBenchmarks.cpp @@ -281,6 +281,22 @@ namespace UnitTest surfaceGradientShapeRequests.clear(); } + void GenerateInputPositionsList(const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, AZStd::vector& positions) + { + const size_t numSamplesX = aznumeric_cast(ceil(worldBounds.GetExtents().GetX() / queryResolution.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(worldBounds.GetExtents().GetY() / queryResolution.GetY())); + + for (size_t y = 0; y < numSamplesY; y++) + { + float fy = aznumeric_cast(worldBounds.GetMin().GetY() + (y * queryResolution.GetY())); + for (size_t x = 0; x < numSamplesX; x++) + { + float fx = aznumeric_cast(worldBounds.GetMin().GetX() + (x * queryResolution.GetX())); + positions.emplace_back(fx, fy, 0.0f); + } + } + } + protected: AZStd::unique_ptr m_app; }; @@ -322,6 +338,72 @@ namespace UnitTest ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegion)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + []([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_position.GetZ()); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessHeightsFromRegion, worldBounds, queryResolution, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegion) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsList)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + [this]([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + AZStd::vector inPositions; + GenerateInputPositionsList(queryResolution, worldBounds, inPositions); + + auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_position.GetZ()); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessHeightsFromList, inPositions, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsList) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 4096, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetNormal)(benchmark::State& state) { // Run the benchmark @@ -353,6 +435,66 @@ namespace UnitTest ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegion)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + []([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_normal); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessNormalsFromRegion, worldBounds, queryResolution, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegion) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsList)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + [this]([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + AZStd::vector inPositions; + GenerateInputPositionsList(queryResolution, worldBounds, inPositions); + + auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_normal); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessNormalsFromList, inPositions, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsList) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetSurfaceWeights)(benchmark::State& state) { // Run the benchmark @@ -385,6 +527,66 @@ namespace UnitTest ->Args({ 2048, 4, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegion)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + []([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_surfaceTags); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessSurfaceWeightsFromRegion, worldBounds, queryResolution, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegion) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 1024, 2, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 2, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 1024, 4, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 4, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsList)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + [this]([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + AZStd::vector inPositions; + GenerateInputPositionsList(queryResolution, worldBounds, inPositions); + + auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint.m_surfaceTags); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessSurfaceWeightsFromList, inPositions, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsList) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 1024, 2, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 2, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 1024, 4, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 4, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetSurfacePoints)(benchmark::State& state) { // Run the benchmark @@ -416,6 +618,66 @@ namespace UnitTest ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) ->Unit(::benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegion)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + []([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessSurfacePointsFromRegion, worldBounds, queryResolution, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegion) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsList)(benchmark::State& state) + { + // Run the benchmark + RunTerrainApiBenchmark( + state, + [this]([[maybe_unused]] const AZ::Vector2& queryResolution, const AZ::Aabb& worldBounds, + AzFramework::Terrain::TerrainDataRequests::Sampler sampler) + { + AZStd::vector inPositions; + GenerateInputPositionsList(queryResolution, worldBounds, inPositions); + + auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + benchmark::DoNotOptimize(surfacePoint); + }; + + AzFramework::Terrain::TerrainDataRequestBus::Broadcast( + &AzFramework::Terrain::TerrainDataRequests::ProcessSurfacePointsFromList, inPositions, perPositionCallback, sampler); + } + ); + } + + BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsList) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) }) + ->Args({ 1024, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Args({ 2048, 1, static_cast(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) }) + ->Unit(::benchmark::kMillisecond); #endif } diff --git a/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp b/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp index e5434c0a1d..a5798a3dad 100644 --- a/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSystemTest.cpp @@ -41,6 +41,28 @@ namespace UnitTest float m_expectedHeight = 0.0f; }; + struct NormalTestPoint + { + AZ::Vector2 m_testLocation = AZ::Vector2::CreateZero(); + AZ::Vector3 m_expectedNormal = AZ::Vector3::CreateZero(); + }; + + struct HeightTestRegionPoints + { + size_t m_xIndex; + size_t m_yIndex; + float m_expectedHeight; + AZ::Vector2 m_testLocation = AZ::Vector2::CreateZero(); + }; + + struct NormalTestRegionPoints + { + size_t m_xIndex; + size_t m_yIndex; + AZ::Vector3 m_expectedNormal = AZ::Vector3::CreateZero(); + AZ::Vector2 m_testLocation = AZ::Vector2::CreateZero(); + }; + AZ::ComponentApplication m_app; AZStd::unique_ptr> m_boxShapeRequests; @@ -572,4 +594,312 @@ namespace UnitTest EXPECT_EQ(tagWeight.m_surfaceType, tagWeight1.m_surfaceType); EXPECT_NEAR(tagWeight.m_weight, tagWeight1.m_weight, 0.01f); } + + TEST_F(TerrainSystemTest, TerrainProcessHeightsFromListWithBilinearSamplers) + { + // This repeats the same test as TerrainHeightQueriesWithBilinearSamplersUseQueryGridToInterpolate + // The difference is that it tests the ProcessHeightsFromList variation. + + const AZ::Aabb spawnerBox = AZ::Aabb::CreateFromMinMaxValues(-10.0f, -10.0f, -5.0f, 10.0f, 10.0f, 15.0f); + const float amplitudeMeters = 10.0f; + const float frequencyMeters = 1.0f; + auto entity = CreateAndActivateMockTerrainLayerSpawner( + spawnerBox, + [amplitudeMeters, frequencyMeters](AZ::Vector3& position, bool& terrainExists) + { + // Our generated height will be X + Y. + float expectedHeight = position.GetX() + position.GetY(); + + // If either X or Y aren't evenly divisible by the query frequency, add a scaled value to our generated height. + // This will show up as an unexpected height "spike" if it gets used in any bilinear filter queries. + float unexpectedVariance = + amplitudeMeters * (fmodf(position.GetX(), frequencyMeters) + fmodf(position.GetY(), frequencyMeters)); + position.SetZ(expectedHeight + unexpectedVariance); + terrainExists = true; + }); + + // Create and activate the terrain system with our testing defaults for world bounds, and a query resolution at 1 meter intervals. + const AZ::Vector2 queryResolution(frequencyMeters); + auto terrainSystem = CreateAndActivateTerrainSystem(queryResolution); + + // Test some points and verify that the results are the expected bilinear filtered result, + // whether they're in positive or negative space. + // (Z contains the the expected result for convenience). + const HeightTestPoint testPoints[] = { + + // Queries directly on grid points. These should return values of X + Y. + { AZ::Vector2(0.0f, 0.0f), 0.0f }, // Should return a height of 0 + 0 + { AZ::Vector2(1.0f, 0.0f), 1.0f }, // Should return a height of 1 + 0 + { AZ::Vector2(0.0f, 1.0f), 1.0f }, // Should return a height of 0 + 1 + { AZ::Vector2(1.0f, 1.0f), 2.0f }, // Should return a height of 1 + 1 + { AZ::Vector2(3.0f, 5.0f), 8.0f }, // Should return a height of 3 + 5 + + { AZ::Vector2(-1.0f, 0.0f), -1.0f }, // Should return a height of -1 + 0 + { AZ::Vector2(0.0f, -1.0f), -1.0f }, // Should return a height of 0 + -1 + { AZ::Vector2(-1.0f, -1.0f), -2.0f }, // Should return a height of -1 + -1 + { AZ::Vector2(-3.0f, -5.0f), -8.0f }, // Should return a height of -3 + -5 + + // Queries that are on a grid edge (one axis on the grid, the other somewhere in-between). + // These should just be a linear interpolation of the points, so it should still be X + Y. + + { AZ::Vector2(0.25f, 0.0f), 0.25f }, // Should return a height of -0.25 + 0 + { AZ::Vector2(3.75f, 0.0f), 3.75f }, // Should return a height of -3.75 + 0 + { AZ::Vector2(0.0f, 0.25f), 0.25f }, // Should return a height of 0 + -0.25 + { AZ::Vector2(0.0f, 3.75f), 3.75f }, // Should return a height of 0 + -3.75 + + { AZ::Vector2(2.0f, 3.75f), 5.75f }, // Should return a height of -2 + -3.75 + { AZ::Vector2(2.25f, 4.0f), 6.25f }, // Should return a height of -2.25 + -4 + + { AZ::Vector2(-0.25f, 0.0f), -0.25f }, // Should return a height of -0.25 + 0 + { AZ::Vector2(-3.75f, 0.0f), -3.75f }, // Should return a height of -3.75 + 0 + { AZ::Vector2(0.0f, -0.25f), -0.25f }, // Should return a height of 0 + -0.25 + { AZ::Vector2(0.0f, -3.75f), -3.75f }, // Should return a height of 0 + -3.75 + + { AZ::Vector2(-2.0f, -3.75f), -5.75f }, // Should return a height of -2 + -3.75 + { AZ::Vector2(-2.25f, -4.0f), -6.25f }, // Should return a height of -2.25 + -4 + + // Queries inside a grid square (both axes are in-between grid points) + // This is a full bilinear interpolation, but because we're using X + Y for our heights, the interpolated values + // should *still* be X + Y assuming the points were sampled correctly from the grid points. + + { AZ::Vector2(3.25f, 5.25f), 8.5f }, // Should return a height of 3.25 + 5.25 + { AZ::Vector2(7.71f, 9.74f), 17.45f }, // Should return a height of 7.71 + 9.74 + + { AZ::Vector2(-3.25f, -5.25f), -8.5f }, // Should return a height of -3.25 + -5.25 + { AZ::Vector2(-7.71f, -9.74f), -17.45f }, // Should return a height of -7.71 + -9.74 + }; + + auto perPositionCallback = [&testPoints](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists){ + bool found = false; + for (auto& testPoint : testPoints) + { + if (testPoint.m_testLocation.GetX() == surfacePoint.m_position.GetX() && testPoint.m_testLocation.GetY() == surfacePoint.m_position.GetY()) + { + constexpr float epsilon = 0.0001f; + EXPECT_NEAR(surfacePoint.m_position.GetZ(), testPoint.m_expectedHeight, epsilon); + found = true; + break; + } + } + EXPECT_EQ(found, true); + }; + + AZStd::vector inPositions; + for (auto& testPoint : testPoints) + { + AZ::Vector3 position(testPoint.m_testLocation.GetX(), testPoint.m_testLocation.GetY(), 0.0f); + inPositions.push_back(position); + } + + terrainSystem->ProcessHeightsFromList(inPositions, perPositionCallback, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR); + } + + TEST_F(TerrainSystemTest, TerrainProcessNormalsFromListWithBilinearSamplers) + { + // Similar to TerrainProcessHeightsFromListWithBilinearSamplers but for normals + + const AZ::Aabb spawnerBox = AZ::Aabb::CreateFromMinMaxValues(-10.0f, -10.0f, -5.0f, 10.0f, 10.0f, 15.0f); + const float amplitudeMeters = 10.0f; + const float frequencyMeters = 1.0f; + auto entity = CreateAndActivateMockTerrainLayerSpawner( + spawnerBox, + [amplitudeMeters, frequencyMeters](AZ::Vector3& position, bool& terrainExists) + { + // Our generated height will be X + Y. + float expectedHeight = position.GetX() + position.GetY(); + + // If either X or Y aren't evenly divisible by the query frequency, add a scaled value to our generated height. + // This will show up as an unexpected height "spike" if it gets used in any bilinear filter queries. + float unexpectedVariance = + amplitudeMeters * (fmodf(position.GetX(), frequencyMeters) + fmodf(position.GetY(), frequencyMeters)); + position.SetZ(expectedHeight + unexpectedVariance); + terrainExists = true; + }); + + // Create and activate the terrain system with our testing defaults for world bounds, and a query resolution at 1 meter intervals. + const AZ::Vector2 queryResolution(frequencyMeters); + auto terrainSystem = CreateAndActivateTerrainSystem(queryResolution); + + const NormalTestPoint testPoints[] = { + + { AZ::Vector2(0.0f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(1.0f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, 1.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(1.0f, 1.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(3.0f, 5.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(-1.0f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, -1.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(-1.0f, -1.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(-3.0f, -5.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(0.25f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(3.75f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, 0.25f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, 3.75f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(2.0f, 3.75f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(2.25f, 4.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(-0.25f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(-3.75f, 0.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, -0.25f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(0.0f, -3.75f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(-2.0f, -3.75f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(-2.25f, -4.0f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + + { AZ::Vector2(3.25f, 5.25f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(7.71f, 9.74f), AZ::Vector3(-0.0292f, 0.9991f, 0.0292f) }, + + { AZ::Vector2(-3.25f, -5.25f), AZ::Vector3(-0.5773f, -0.5773f, 0.5773f) }, + { AZ::Vector2(-7.71f, -9.74f), AZ::Vector3(-0.0366f, -0.9986f, 0.0366f) }, + }; + + auto perPositionCallback = [&testPoints](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists){ + bool found = false; + for (auto& testPoint : testPoints) + { + if (testPoint.m_testLocation.GetX() == surfacePoint.m_position.GetX() && testPoint.m_testLocation.GetY() == surfacePoint.m_position.GetY()) + { + constexpr float epsilon = 0.0001f; + EXPECT_NEAR(surfacePoint.m_normal.GetX(), testPoint.m_expectedNormal.GetX(), epsilon); + EXPECT_NEAR(surfacePoint.m_normal.GetY(), testPoint.m_expectedNormal.GetY(), epsilon); + EXPECT_NEAR(surfacePoint.m_normal.GetZ(), testPoint.m_expectedNormal.GetZ(), epsilon); + found = true; + break; + } + } + EXPECT_EQ(found, true); + }; + + AZStd::vector inPositions; + for (auto& testPoint : testPoints) + { + AZ::Vector3 position(testPoint.m_testLocation.GetX(), testPoint.m_testLocation.GetY(), 0.0f); + inPositions.push_back(position); + } + + terrainSystem->ProcessNormalsFromList(inPositions, perPositionCallback, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR); + } + + TEST_F(TerrainSystemTest, TerrainProcessHeightsFromRegionWithBilinearSamplers) + { + // This repeats the same test as TerrainHeightQueriesWithBilinearSamplersUseQueryGridToInterpolate + // The difference is that it tests the ProcessHeightsFromList variation. + + const AZ::Aabb spawnerBox = AZ::Aabb::CreateFromMinMaxValues(-10.0f, -10.0f, -5.0f, 10.0f, 10.0f, 15.0f); + const float amplitudeMeters = 10.0f; + const float frequencyMeters = 1.0f; + auto entity = CreateAndActivateMockTerrainLayerSpawner( + spawnerBox, + [amplitudeMeters, frequencyMeters](AZ::Vector3& position, bool& terrainExists) + { + // Our generated height will be X + Y. + float expectedHeight = position.GetX() + position.GetY(); + + // If either X or Y aren't evenly divisible by the query frequency, add a scaled value to our generated height. + // This will show up as an unexpected height "spike" if it gets used in any bilinear filter queries. + float unexpectedVariance = + amplitudeMeters * (fmodf(position.GetX(), frequencyMeters) + fmodf(position.GetY(), frequencyMeters)); + position.SetZ(expectedHeight + unexpectedVariance); + terrainExists = true; + }); + + // Create and activate the terrain system with our testing defaults for world bounds, and a query resolution at 1 meter intervals. + const AZ::Vector2 queryResolution(frequencyMeters); + auto terrainSystem = CreateAndActivateTerrainSystem(queryResolution); + + const AZ::Aabb testRegionBox = AZ::Aabb::CreateFromMinMaxValues(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f); + const AZ::Vector2 stepSize(1.0f); + + const HeightTestRegionPoints testPoints[] = { + { 0, 0, -2.0f, AZ::Vector2(-1.0f, -1.0f) }, + { 1, 0, -1.0f, AZ::Vector2(0.0f, -1.0f) }, + { 0, 1, -1.0f, AZ::Vector2(-1.0f, 0.0f) }, + { 1, 1, 0.0f, AZ::Vector2(0.0f, 0.0f) }, + }; + + auto perPositionCallback = [&testPoints](size_t xIndex, size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + bool found = false; + for (auto& testPoint : testPoints) + { + if (testPoint.m_xIndex == xIndex && testPoint.m_yIndex == yIndex + && testPoint.m_testLocation.GetX() == surfacePoint.m_position.GetX() + && testPoint.m_testLocation.GetY() == surfacePoint.m_position.GetY()) + { + constexpr float epsilon = 0.0001f; + EXPECT_NEAR(surfacePoint.m_position.GetZ(), testPoint.m_expectedHeight, epsilon); + found = true; + break; + } + } + EXPECT_EQ(found, true); + }; + + terrainSystem->ProcessHeightsFromRegion(testRegionBox, stepSize, perPositionCallback, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR); + } + + TEST_F(TerrainSystemTest, TerrainProcessNormalsFromRegionWithBilinearSamplers) + { + // This repeats the same test as TerrainHeightQueriesWithBilinearSamplersUseQueryGridToInterpolate + // The difference is that it tests the ProcessHeightsFromList variation. + + const AZ::Aabb spawnerBox = AZ::Aabb::CreateFromMinMaxValues(-10.0f, -10.0f, -5.0f, 10.0f, 10.0f, 15.0f); + const float amplitudeMeters = 10.0f; + const float frequencyMeters = 1.0f; + auto entity = CreateAndActivateMockTerrainLayerSpawner( + spawnerBox, + [amplitudeMeters, frequencyMeters](AZ::Vector3& position, bool& terrainExists) + { + // Our generated height will be X + Y. + float expectedHeight = position.GetX() + position.GetY(); + + // If either X or Y aren't evenly divisible by the query frequency, add a scaled value to our generated height. + // This will show up as an unexpected height "spike" if it gets used in any bilinear filter queries. + float unexpectedVariance = + amplitudeMeters * (fmodf(position.GetX(), frequencyMeters) + fmodf(position.GetY(), frequencyMeters)); + position.SetZ(expectedHeight + unexpectedVariance); + terrainExists = true; + }); + + // Create and activate the terrain system with our testing defaults for world bounds, and a query resolution at 1 meter intervals. + const AZ::Vector2 queryResolution(frequencyMeters); + auto terrainSystem = CreateAndActivateTerrainSystem(queryResolution); + + const AZ::Aabb testRegionBox = AZ::Aabb::CreateFromMinMaxValues(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f); + const AZ::Vector2 stepSize(1.0f); + + const NormalTestRegionPoints testPoints[] = { + { 0, 0, AZ::Vector3(-0.5773f, -0.5773f, 0.5773f), AZ::Vector2(-1.0f, -1.0f) }, + { 1, 0, AZ::Vector3(-0.5773f, -0.5773f, 0.5773f), AZ::Vector2(0.0f, -1.0f) }, + { 0, 1, AZ::Vector3(-0.5773f, -0.5773f, 0.5773f), AZ::Vector2(-1.0f, 0.0f) }, + { 1, 1, AZ::Vector3(-0.5773f, -0.5773f, 0.5773f), AZ::Vector2(0.0f, 0.0f) }, + }; + + auto perPositionCallback = [&testPoints](size_t xIndex, size_t yIndex, + const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists) + { + bool found = false; + for (auto& testPoint : testPoints) + { + if (testPoint.m_xIndex == xIndex && testPoint.m_yIndex == yIndex + && testPoint.m_testLocation.GetX() == surfacePoint.m_position.GetX() + && testPoint.m_testLocation.GetY() == surfacePoint.m_position.GetY()) + { + constexpr float epsilon = 0.0001f; + EXPECT_NEAR(surfacePoint.m_normal.GetX(), testPoint.m_expectedNormal.GetX(), epsilon); + EXPECT_NEAR(surfacePoint.m_normal.GetY(), testPoint.m_expectedNormal.GetY(), epsilon); + EXPECT_NEAR(surfacePoint.m_normal.GetZ(), testPoint.m_expectedNormal.GetZ(), epsilon); + found = true; + break; + } + } + EXPECT_EQ(found, true); + }; + + terrainSystem->ProcessNormalsFromRegion(testRegionBox, stepSize, perPositionCallback, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR); + } } // namespace UnitTest diff --git a/Gems/Terrain/gem.json b/Gems/Terrain/gem.json index 0ca470c4d3..f038eb4d90 100644 --- a/Gems/Terrain/gem.json +++ b/Gems/Terrain/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "summary": "The Terrain Gem is an experimental terrain system. The terrain system maps height, color, and surface data to regions of the world, provides gradient-based and shape-based authoring tools and workflows, includes specialized rendering for efficient display, and integrates with physics for physical simulation.", "canonical_tags": [ "Gem" diff --git a/Gems/TestAssetBuilder/gem.json b/Gems/TestAssetBuilder/gem.json index 68ed706499..96c3bb4ffb 100644 --- a/Gems/TestAssetBuilder/gem.json +++ b/Gems/TestAssetBuilder/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Test Asset Builder Gem is used to feature test Asset Processor.", "canonical_tags": [ diff --git a/Gems/TextureAtlas/Code/Source/TextureAtlasImpl.h b/Gems/TextureAtlas/Code/Source/TextureAtlasImpl.h index ce2f4826da..bb0ed650e5 100644 --- a/Gems/TextureAtlas/Code/Source/TextureAtlasImpl.h +++ b/Gems/TextureAtlas/Code/Source/TextureAtlasImpl.h @@ -33,7 +33,7 @@ namespace TextureAtlasNamespace struct hash_case_insensitive : public AZStd::hash { AZ_TYPE_INFO(hash_case_insensitive, "{FE0F4349-D80D-4286-8874-733966A32B29}"); - inline result_type operator()(const AZStd::string& value) const + inline size_t operator()(const AZStd::string& value) const { AZStd::string lowerStr = value; AZStd::to_lower(lowerStr.begin(), lowerStr.end()); diff --git a/Gems/TextureAtlas/gem.json b/Gems/TextureAtlas/gem.json index 142f0fb082..970982fb48 100644 --- a/Gems/TextureAtlas/gem.json +++ b/Gems/TextureAtlas/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Texture Atlas Gem provides the formatting for texture atlases from 2D textures for LyShine.", "canonical_tags": [ diff --git a/Gems/TickBusOrderViewer/gem.json b/Gems/TickBusOrderViewer/gem.json index a6a6fd23ac..78b4d96c5c 100644 --- a/Gems/TickBusOrderViewer/gem.json +++ b/Gems/TickBusOrderViewer/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The Tick Bus Order Viewer Gem provides a console variable that displays the order of runtime tick events.", "canonical_tags": [ diff --git a/Gems/Twitch/CMakeLists.txt b/Gems/Twitch/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/Twitch/CMakeLists.txt +++ b/Gems/Twitch/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/Twitch/Code/CMakeLists.txt b/Gems/Twitch/Code/CMakeLists.txt index 80c74e5bd4..75b18627cf 100644 --- a/Gems/Twitch/Code/CMakeLists.txt +++ b/Gems/Twitch/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) ly_add_target( NAME Twitch.Static STATIC diff --git a/Gems/Twitch/gem.json b/Gems/Twitch/gem.json index 42ec1b971e..70386e057f 100644 --- a/Gems/Twitch/gem.json +++ b/Gems/Twitch/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Twitch Gem provides access to the Twitch API v5 SDK including social functions, channels, and other APIs.", "canonical_tags": [ @@ -12,7 +13,8 @@ "user_tags": [ "Network", "SDK", - "Multiplayer" + "Multiplayer", + "Twitch" ], "icon_path": "preview.png", "requirements": "", diff --git a/Gems/UiBasics/CMakeLists.txt b/Gems/UiBasics/CMakeLists.txt index 8d71bd08c7..9c3cf01d26 100644 --- a/Gems/UiBasics/CMakeLists.txt +++ b/Gems/UiBasics/CMakeLists.txt @@ -9,4 +9,5 @@ # This will export its "SourcePaths" to the generated "cmake_dependencies..assetbuilder.setreg" if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_create_alias(NAME UiBasics.Builders NAMESPACE Gem) + ly_create_alias(NAME UiBasics.Tools NAMESPACE Gem) endif() diff --git a/Gems/UiBasics/gem.json b/Gems/UiBasics/gem.json index bb2416c235..4734aef779 100644 --- a/Gems/UiBasics/gem.json +++ b/Gems/UiBasics/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Asset", "summary": "The UI Basics Gem provides a collection of basic UI prefabs such as image, text, and button, that can be used with LyShine, the Open 3D Engine runtime User Interface system and editor.", "canonical_tags": [ diff --git a/Gems/Vegetation/gem.json b/Gems/Vegetation/gem.json index 75416933f0..8dfd3b3a59 100644 --- a/Gems/Vegetation/gem.json +++ b/Gems/Vegetation/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Vegetation Gem provides tools to place natural-looking vegetation in Open 3D Engine.", "canonical_tags": [ diff --git a/Gems/VideoPlaybackFramework/gem.json b/Gems/VideoPlaybackFramework/gem.json index 381738ab4b..9115148c50 100644 --- a/Gems/VideoPlaybackFramework/gem.json +++ b/Gems/VideoPlaybackFramework/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Video Playback Framework Gem provides the interface to play back video.", "canonical_tags": [ diff --git a/Gems/VirtualGamepad/Code/CMakeLists.txt b/Gems/VirtualGamepad/Code/CMakeLists.txt index d32834633f..6700004a30 100644 --- a/Gems/VirtualGamepad/Code/CMakeLists.txt +++ b/Gems/VirtualGamepad/Code/CMakeLists.txt @@ -21,7 +21,7 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon - Gem::LyShine + Gem::LyShine.Clients.API ) ly_add_target( @@ -42,4 +42,4 @@ ly_add_target( # the virtual gamepad is needed everywhere except servers: ly_create_alias(NAME VirtualGamepad.Clients NAMESPACE Gem TARGETS Gem::VirtualGamepad) ly_create_alias(NAME VirtualGamepad.Tools NAMESPACE Gem TARGETS Gem::VirtualGamepad) -ly_create_alias(NAME VirtualGamepad.Builders NAMESPACE Gem TARGETS Gem::VirtualGamepad) +ly_create_alias(NAME VirtualGamepad.Builders NAMESPACE Gem TARGETS Gem::VirtualGamepad Gem::UiBasics.Builders) diff --git a/Gems/VirtualGamepad/gem.json b/Gems/VirtualGamepad/gem.json index 637776ac85..a2a669bb11 100644 --- a/Gems/VirtualGamepad/gem.json +++ b/Gems/VirtualGamepad/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "The Virtual Gamepad Gem provides controls that emulate a gamepad on touch screen devices.", "canonical_tags": [ diff --git a/Gems/WhiteBox/CMakeLists.txt b/Gems/WhiteBox/CMakeLists.txt index 2bb380fae3..50f9e78c74 100644 --- a/Gems/WhiteBox/CMakeLists.txt +++ b/Gems/WhiteBox/CMakeLists.txt @@ -6,4 +6,8 @@ # # +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + add_subdirectory(Code) diff --git a/Gems/WhiteBox/Code/CMakeLists.txt b/Gems/WhiteBox/Code/CMakeLists.txt index bfc4eb724a..91536503ac 100644 --- a/Gems/WhiteBox/Code/CMakeLists.txt +++ b/Gems/WhiteBox/Code/CMakeLists.txt @@ -6,8 +6,8 @@ # # -ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) +o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/Gems/WhiteBox/gem.json b/Gems/WhiteBox/gem.json index 2d173e9a6b..18a3022b74 100644 --- a/Gems/WhiteBox/gem.json +++ b/Gems/WhiteBox/gem.json @@ -4,6 +4,7 @@ "license": "Apache-2.0 Or MIT", "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Tool", "summary": "The White Box Gem provides White Box rapid design components for Open 3D Engine.", "canonical_tags": [ diff --git a/Templates/AssetGem/Template/gem.json b/Templates/AssetGem/Template/gem.json index 2a02362256..b04ecf9dd8 100644 --- a/Templates/AssetGem/Template/gem.json +++ b/Templates/AssetGem/Template/gem.json @@ -1,18 +1,21 @@ { "gem_name": "${Name}", "display_name": "${Name}", - "license": "What license ${Name} uses goes here: i.e. Apache-2.0 Or MIT", - "license_url": "", - "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", "type": "Asset", - "summary": "A short description of ${Name}.", + "summary": "A short description of ${Name} goes here.", "canonical_tags": [ "Gem" ], "user_tags": [ - "Assets", "${Name}" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "Notice of any requirements ${Name} has goes here. i.e. This requires X other gem", + "documentation_url": "Link to any documentation of ${Name} goes here: i.e. https://o3de.org/docs/user-guide/gems/reference/design/white-box/", + "dependencies": [ + ] } diff --git a/Templates/AssetGem/template.json b/Templates/AssetGem/template.json index e858dc526d..2f390f2077 100644 --- a/Templates/AssetGem/template.json +++ b/Templates/AssetGem/template.json @@ -1,10 +1,17 @@ { "template_name": "AssetGem", - "origin": "The primary repo for AssetGem goes here: i.e. http://www.mydomain.com", - "license": "What license AssetGem uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "AssetGem", - "summary": "A short description of AssetGem template.", - "canonical_tags": [], + "template_restricted_platform_relative_path": "Templates/AssetGem", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "display_name": "Asset Gem Template", + "summary": "Use this gem template to create the minimal gem needed for adding asset(s).", + "canonical_tags": [ + "Template", + "Gem", + "Asset" + ], "user_tags": [ "AssetGem" ], @@ -12,27 +19,20 @@ "copyFiles": [ { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" } ] } diff --git a/Templates/CppToolGem/Template/gem.json b/Templates/CppToolGem/Template/gem.json index 079b7152ff..05be122226 100644 --- a/Templates/CppToolGem/Template/gem.json +++ b/Templates/CppToolGem/Template/gem.json @@ -1,11 +1,12 @@ { "gem_name": "${Name}", "display_name": "${Name}", - "license": "What license ${Name} uses goes here: i.e. Apache-2.0 Or MIT", - "license_url": "", - "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", "type": "Code", - "summary": "A short description of ${Name}.", + "summary": "A short description of ${Name} goes here.", "canonical_tags": [ "Gem" ], @@ -13,6 +14,8 @@ "${Name}" ], "icon_path": "preview.png", - "requirements": "", - "restricted_name": "gems" + "requirements": "Notice of any requirements ${Name} has goes here. i.e. This requires X other gem", + "documentation_url": "Link to any documentation of ${Name} goes here: i.e. https://o3de.org/docs/user-guide/gems/reference/design/white-box/", + "dependencies": [ + ] } diff --git a/Templates/CppToolGem/template.json b/Templates/CppToolGem/template.json index b516dbaec3..16874326ef 100644 --- a/Templates/CppToolGem/template.json +++ b/Templates/CppToolGem/template.json @@ -1,10 +1,16 @@ { "template_name": "CppToolGem", - "origin": "The primary repo for CppToolGem goes here: i.e. http://www.mydomain.com", - "license": "What license CppToolGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "template_restricted_platform_relative_path": "Templates/CppToolGem", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "display_name": "CppToolGem", "summary": "A gem template for a custom tool in C++ that gets registered with the Editor.", - "canonical_tags": [], + "canonical_tags": [ + "Template", + "Gem" + ], "user_tags": [ "CppToolGem" ], @@ -12,371 +18,255 @@ "copyFiles": [ { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Code/${NameLower}_editor_files.cmake", - "origin": "Code/${NameLower}_editor_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_shared_files.cmake", - "origin": "Code/${NameLower}_editor_shared_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_tests_files.cmake", - "origin": "Code/${NameLower}_editor_tests_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_files.cmake", - "origin": "Code/${NameLower}_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_shared_files.cmake", - "origin": "Code/${NameLower}_shared_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_tests_files.cmake", - "origin": "Code/${NameLower}_tests_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/CMakeLists.txt", - "origin": "Code/CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/${NameLower}_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_android_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/PAL_android.cmake", - "origin": "Code/Platform/Android/PAL_android.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/PAL_linux.cmake", - "origin": "Code/Platform/Linux/PAL_linux.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/PAL_mac.cmake", - "origin": "Code/Platform/Mac/PAL_mac.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/PAL_windows.cmake", - "origin": "Code/Platform/Windows/PAL_windows.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/PAL_ios.cmake", - "origin": "Code/Platform/iOS/PAL_ios.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}.qrc", - "origin": "Code/Source/${Name}.qrc", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorModule.cpp", - "origin": "Code/Source/${Name}EditorModule.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.cpp", - "origin": "Code/Source/${Name}EditorSystemComponent.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.h", - "origin": "Code/Source/${Name}EditorSystemComponent.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}Module.cpp", - "origin": "Code/Source/${Name}Module.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}ModuleInterface.h", - "origin": "Code/Source/${Name}ModuleInterface.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}SystemComponent.cpp", - "origin": "Code/Source/${Name}SystemComponent.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}SystemComponent.h", - "origin": "Code/Source/${Name}SystemComponent.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}Widget.cpp", - "origin": "Code/Source/${Name}Widget.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}Widget.h", - "origin": "Code/Source/${Name}Widget.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/toolbar_icon.svg", - "origin": "Code/Source/toolbar_icon.svg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Code/Tests/${Name}EditorTest.cpp", - "origin": "Code/Tests/${Name}EditorTest.cpp", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Code/Tests/${Name}Test.cpp", - "origin": "Code/Tests/${Name}Test.cpp", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Android/android_gem.cmake", - "origin": "Platform/Android/android_gem.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Android/android_gem.json", - "origin": "Platform/Android/android_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Linux/linux_gem.cmake", - "origin": "Platform/Linux/linux_gem.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Linux/linux_gem.json", - "origin": "Platform/Linux/linux_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_gem.cmake", - "origin": "Platform/Mac/mac_gem.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_gem.json", - "origin": "Platform/Mac/mac_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_gem.cmake", - "origin": "Platform/Windows/windows_gem.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_gem.json", - "origin": "Platform/Windows/windows_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_gem.cmake", - "origin": "Platform/iOS/ios_gem.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_gem.json", - "origin": "Platform/iOS/ios_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" }, { - "dir": "Code", - "origin": "Code" + "dir": "Code" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "Code/Include" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "Code/Include/${Name}" }, { - "dir": "Code/Platform", - "origin": "Code/Platform" + "dir": "Code/Platform" }, { - "dir": "Code/Platform/Android", - "origin": "Code/Platform/Android" + "dir": "Code/Platform/Android" }, { - "dir": "Code/Platform/Linux", - "origin": "Code/Platform/Linux" + "dir": "Code/Platform/Linux" }, { - "dir": "Code/Platform/Mac", - "origin": "Code/Platform/Mac" + "dir": "Code/Platform/Mac" }, { - "dir": "Code/Platform/Windows", - "origin": "Code/Platform/Windows" + "dir": "Code/Platform/Windows" }, { - "dir": "Code/Platform/iOS", - "origin": "Code/Platform/iOS" + "dir": "Code/Platform/iOS" }, { - "dir": "Code/Source", - "origin": "Code/Source" + "dir": "Code/Source" }, { - "dir": "Code/Tests", - "origin": "Code/Tests" + "dir": "Code/Tests" }, { - "dir": "Platform", - "origin": "Platform" + "dir": "Platform" }, { - "dir": "Platform/Android", - "origin": "Platform/Android" + "dir": "Platform/Android" }, { - "dir": "Platform/Linux", - "origin": "Platform/Linux" + "dir": "Platform/Linux" }, { - "dir": "Platform/Mac", - "origin": "Platform/Mac" + "dir": "Platform/Mac" }, { - "dir": "Platform/Windows", - "origin": "Platform/Windows" + "dir": "Platform/Windows" }, { - "dir": "Platform/iOS", - "origin": "Platform/iOS" + "dir": "Platform/iOS" } ] } diff --git a/Templates/DefaultGem/Template/CMakeLists.txt b/Templates/DefaultGem/Template/CMakeLists.txt index b19ea2edce..f4c55dd1a5 100644 --- a/Templates/DefaultGem/Template/CMakeLists.txt +++ b/Templates/DefaultGem/Template/CMakeLists.txt @@ -6,12 +6,11 @@ # # {END_LICENSE} -set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) -set(o3de_gem_json ${o3de_gem_path}/gem.json) -o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") -o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${o3de_gem_restricted_path}" ${o3de_gem_path} ${o3de_gem_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # project cmake for this platform. diff --git a/Templates/DefaultGem/Template/Code/CMakeLists.txt b/Templates/DefaultGem/Template/Code/CMakeLists.txt index f462e7f2d4..c5ff305b2a 100644 --- a/Templates/DefaultGem/Template/Code/CMakeLists.txt +++ b/Templates/DefaultGem/Template/Code/CMakeLists.txt @@ -8,11 +8,11 @@ # Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR} # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} -# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# Note: o3de_pal_dir will take care of the details for us, as this may be a restricted platform # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or # //Gems/${Name}/Code -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this gem diff --git a/Templates/DefaultGem/Template/gem.json b/Templates/DefaultGem/Template/gem.json index d4ff637bee..05be122226 100644 --- a/Templates/DefaultGem/Template/gem.json +++ b/Templates/DefaultGem/Template/gem.json @@ -1,11 +1,12 @@ { "gem_name": "${Name}", "display_name": "${Name}", - "license": "What license ${Name} uses goes here: i.e. Apache-2.0 Or MIT", - "license_url": "", - "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", "type": "Code", - "summary": "A short description of ${Name}.", + "summary": "A short description of ${Name} goes here.", "canonical_tags": [ "Gem" ], @@ -13,5 +14,8 @@ "${Name}" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "Notice of any requirements ${Name} has goes here. i.e. This requires X other gem", + "documentation_url": "Link to any documentation of ${Name} goes here: i.e. https://o3de.org/docs/user-guide/gems/reference/design/white-box/", + "dependencies": [ + ] } diff --git a/Templates/DefaultGem/template.json b/Templates/DefaultGem/template.json index e24632d6a0..e5dc570cbe 100644 --- a/Templates/DefaultGem/template.json +++ b/Templates/DefaultGem/template.json @@ -1,12 +1,16 @@ { "template_name": "DefaultGem", + "template_restricted_platform_relative_path": "Templates/DefaultGem", "restricted_name": "o3de", - "restricted_platform_relative_path": "Templates", - "origin": "The primary repo for DefaultGem goes here: i.e. http://www.mydomain.com", - "license": "What license DefaultGem uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "DefaultGem", - "summary": "A short description of DefaultGem.", - "canonical_tags": [], + "restricted_platform_relative_path": "Templates/DefaultGem", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "display_name": "Default Gem Template", + "summary": "This is the gem template that will be used if no gem template is specified during gem creation.", + "canonical_tags": [ + "Template", + "Gem" + ], "user_tags": [ "DefaultGem" ], @@ -14,347 +18,239 @@ "copyFiles": [ { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_files.cmake", - "origin": "Code/${NameLower}_editor_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_shared_files.cmake", - "origin": "Code/${NameLower}_editor_shared_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_tests_files.cmake", - "origin": "Code/${NameLower}_editor_tests_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_files.cmake", - "origin": "Code/${NameLower}_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_shared_files.cmake", - "origin": "Code/${NameLower}_shared_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_tests_files.cmake", - "origin": "Code/${NameLower}_tests_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/CMakeLists.txt", - "origin": "Code/CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/${NameLower}_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_android_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Android/PAL_android.cmake", - "origin": "Code/Platform/Android/PAL_android.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/PAL_linux.cmake", - "origin": "Code/Platform/Linux/PAL_linux.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/PAL_mac.cmake", - "origin": "Code/Platform/Mac/PAL_mac.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/PAL_windows.cmake", - "origin": "Code/Platform/Windows/PAL_windows.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/iOS/PAL_ios.cmake", - "origin": "Code/Platform/iOS/PAL_ios.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorModule.cpp", - "origin": "Code/Source/${Name}EditorModule.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.cpp", - "origin": "Code/Source/${Name}EditorSystemComponent.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.h", - "origin": "Code/Source/${Name}EditorSystemComponent.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}Module.cpp", - "origin": "Code/Source/${Name}Module.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}ModuleInterface.h", - "origin": "Code/Source/${Name}ModuleInterface.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}SystemComponent.cpp", - "origin": "Code/Source/${Name}SystemComponent.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}SystemComponent.h", - "origin": "Code/Source/${Name}SystemComponent.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Tests/${Name}EditorTest.cpp", - "origin": "Code/Tests/${Name}EditorTest.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Tests/${Name}Test.cpp", - "origin": "Code/Tests/${Name}Test.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Android/android_gem.cmake", - "origin": "Platform/Android/android_gem.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Android/android_gem.json", - "origin": "Platform/Android/android_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Linux/linux_gem.cmake", - "origin": "Platform/Linux/linux_gem.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Linux/linux_gem.json", - "origin": "Platform/Linux/linux_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_gem.cmake", - "origin": "Platform/Mac/mac_gem.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Mac/mac_gem.json", - "origin": "Platform/Mac/mac_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_gem.cmake", - "origin": "Platform/Windows/windows_gem.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Windows/windows_gem.json", - "origin": "Platform/Windows/windows_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_gem.cmake", - "origin": "Platform/iOS/ios_gem.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/iOS/ios_gem.json", - "origin": "Platform/iOS/ios_gem.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" }, { - "dir": "Code", - "origin": "Code" + "dir": "Code" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "Code/Include" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "Code/Include/${Name}" }, { - "dir": "Code/Platform", - "origin": "Code/Platform" + "dir": "Code/Platform" }, { - "dir": "Code/Platform/Android", - "origin": "Code/Platform/Android" + "dir": "Code/Platform/Android" }, { - "dir": "Code/Platform/Linux", - "origin": "Code/Platform/Linux" + "dir": "Code/Platform/Linux" }, { - "dir": "Code/Platform/Mac", - "origin": "Code/Platform/Mac" + "dir": "Code/Platform/Mac" }, { - "dir": "Code/Platform/Windows", - "origin": "Code/Platform/Windows" + "dir": "Code/Platform/Windows" }, { - "dir": "Code/Platform/iOS", - "origin": "Code/Platform/iOS" + "dir": "Code/Platform/iOS" }, { - "dir": "Code/Source", - "origin": "Code/Source" + "dir": "Code/Source" }, { - "dir": "Code/Tests", - "origin": "Code/Tests" + "dir": "Code/Tests" }, { - "dir": "Platform", - "origin": "Platform" + "dir": "Platform" }, { - "dir": "Platform/Android", - "origin": "Platform/Android" + "dir": "Platform/Android" }, { - "dir": "Platform/Linux", - "origin": "Platform/Linux" + "dir": "Platform/Linux" }, { - "dir": "Platform/Mac", - "origin": "Platform/Mac" + "dir": "Platform/Mac" }, { - "dir": "Platform/Windows", - "origin": "Platform/Windows" + "dir": "Platform/Windows" }, { - "dir": "Platform/iOS", - "origin": "Platform/iOS" + "dir": "Platform/iOS" } ] } diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index ae4bb662a3..420a92948d 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -29,5 +29,4 @@ else() set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) - add_subdirectory(Code) endif() diff --git a/Templates/DefaultProject/Template/Code/${NameLower}_files.cmake b/Templates/DefaultProject/Template/Gem/${NameLower}_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/${NameLower}_files.cmake rename to Templates/DefaultProject/Template/Gem/${NameLower}_files.cmake diff --git a/Templates/DefaultProject/Template/Code/${NameLower}_shared_files.cmake b/Templates/DefaultProject/Template/Gem/${NameLower}_shared_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/${NameLower}_shared_files.cmake rename to Templates/DefaultProject/Template/Gem/${NameLower}_shared_files.cmake diff --git a/Templates/MinimalProject/Template/Code/CMakeLists.txt b/Templates/DefaultProject/Template/Gem/CMakeLists.txt similarity index 87% rename from Templates/MinimalProject/Template/Code/CMakeLists.txt rename to Templates/DefaultProject/Template/Gem/CMakeLists.txt index 5e646c0704..fc3eab6535 100644 --- a/Templates/MinimalProject/Template/Code/CMakeLists.txt +++ b/Templates/DefaultProject/Template/Gem/CMakeLists.txt @@ -6,13 +6,17 @@ # # {END_LICENSE} +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + # Currently we are in the ${Name}/Code folder: ${CMAKE_CURRENT_LIST_DIR} # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} -# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# Note: o3de_pal_dir will take care of the details for us, as this may be a restricted platform # in which case it will see if that platform is present here or in the restricted folder. -# i.e. It could here : ${Name}/Code/Platform/ or +# i.e. It could here : ${Name}/Code/Platform/ or # //${Name}/Code -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this project @@ -71,7 +75,6 @@ ly_create_alias(NAME ${Name}.Servers NAMESPACE Gem TARGETS Gem::${Name}) # Enable the specified list of gems from GEM_FILE or GEMS list for this specific project: ly_enable_gems(PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake) - if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) # this property causes it to actually make a ServerLauncher. # if you don't want a Server application, you can remove this and the diff --git a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultProject/Template/Gem/Include/${Name}/${Name}Bus.h similarity index 99% rename from Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h rename to Templates/DefaultProject/Template/Gem/Include/${Name}/${Name}Bus.h index d09bb2b009..d72b5785c3 100644 --- a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultProject/Template/Gem/Include/${Name}/${Name}Bus.h @@ -22,7 +22,7 @@ namespace ${SanitizedCppName} virtual ~${SanitizedCppName}Requests() = default; // Put your public methods here }; - + class ${SanitizedCppName}BusTraits : public AZ::EBusTraits { diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Android/${NameLower}_android_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Android/${NameLower}_android_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Android/${NameLower}_shared_android_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Android/${NameLower}_shared_android_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/PAL_android.cmake b/Templates/DefaultProject/Template/Gem/Platform/Android/PAL_android.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Android/PAL_android.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Android/PAL_android.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Linux/${NameLower}_linux_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Linux/${NameLower}_linux_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/DefaultProject/Template/Gem/Platform/Linux/PAL_linux.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Linux/PAL_linux.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Linux/PAL_linux.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Mac/${NameLower}_mac_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Mac/${NameLower}_mac_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/DefaultProject/Template/Gem/Platform/Mac/PAL_mac.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Mac/PAL_mac.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Mac/PAL_mac.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/Windows/${NameLower}_windows_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Windows/${NameLower}_windows_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/DefaultProject/Template/Gem/Platform/Windows/PAL_windows.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/Windows/PAL_windows.cmake rename to Templates/DefaultProject/Template/Gem/Platform/Windows/PAL_windows.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/iOS/${NameLower}_ios_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/iOS/${NameLower}_ios_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake b/Templates/DefaultProject/Template/Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake rename to Templates/DefaultProject/Template/Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/PAL_ios.cmake b/Templates/DefaultProject/Template/Gem/Platform/iOS/PAL_ios.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/Platform/iOS/PAL_ios.cmake rename to Templates/DefaultProject/Template/Gem/Platform/iOS/PAL_ios.cmake diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp b/Templates/DefaultProject/Template/Gem/Source/${Name}Module.cpp similarity index 100% rename from Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp rename to Templates/DefaultProject/Template/Gem/Source/${Name}Module.cpp diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultProject/Template/Gem/Source/${Name}SystemComponent.cpp similarity index 99% rename from Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp rename to Templates/DefaultProject/Template/Gem/Source/${Name}SystemComponent.cpp index cfb6ae3c42..487391c716 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultProject/Template/Gem/Source/${Name}SystemComponent.cpp @@ -52,7 +52,7 @@ namespace ${SanitizedCppName} void ${SanitizedCppName}SystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) { } - + ${SanitizedCppName}SystemComponent::${SanitizedCppName}SystemComponent() { if (${SanitizedCppName}Interface::Get() == nullptr) diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h b/Templates/DefaultProject/Template/Gem/Source/${Name}SystemComponent.h similarity index 100% rename from Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h rename to Templates/DefaultProject/Template/Gem/Source/${Name}SystemComponent.h diff --git a/Templates/DefaultProject/Template/Code/enabled_gems.cmake b/Templates/DefaultProject/Template/Gem/enabled_gems.cmake similarity index 100% rename from Templates/DefaultProject/Template/Code/enabled_gems.cmake rename to Templates/DefaultProject/Template/Gem/enabled_gems.cmake diff --git a/Templates/DefaultProject/Template/Gem/gem.json b/Templates/DefaultProject/Template/Gem/gem.json new file mode 100644 index 0000000000..b60f512006 --- /dev/null +++ b/Templates/DefaultProject/Template/Gem/gem.json @@ -0,0 +1,21 @@ +{ + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "", + "dependencies": [ + ] +} diff --git a/Templates/DefaultProject/Template/project.json b/Templates/DefaultProject/Template/project.json index f8d4643ce9..6d1875fcaa 100644 --- a/Templates/DefaultProject/Template/project.json +++ b/Templates/DefaultProject/Template/project.json @@ -2,7 +2,7 @@ "project_name": "${Name}", "project_id": "${ProjectId}", "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", - "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT etc.", "display_name": "${Name}", "summary": "A short description of ${Name}.", "canonical_tags": [ @@ -13,5 +13,8 @@ ], "icon_path": "preview.png", "engine": "o3de", - "external_subdirectories": [] + "external_subdirectories": [ + "Gem" + ], + "restricted": "${Name}" } diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index fcffafcb34..203e1ec4ef 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -1,12 +1,18 @@ { "template_name": "DefaultProject", + "template_restricted_platform_relative_path": "Templates/DefaultProject", "restricted_name": "o3de", - "restricted_platform_relative_path": "Templates", - "origin": "The primary repo for DefaultProject goes here: i.e. http://www.mydomain.com", - "license": "What license DefaultProject uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "Standard", - "summary": "This template has everything you need to build a full online 3D game or application.", - "canonical_tags": [], + "restricted_platform_relative_path": "Templates/DefaultProject", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "display_name": "Default Project Template", + "summary": "This is the project template that will be used if no project template is specified during project creation.", + "canonical_tags": [ + "Template", + "Project" + ], "user_tags": [ "DefaultProject" ], @@ -14,657 +20,459 @@ "copyFiles": [ { "file": ".gitignore", - "origin": ".gitignore", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/${NameLower}_files.cmake", - "origin": "Code/${NameLower}_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/${NameLower}_shared_files.cmake", - "origin": "Code/${NameLower}_shared_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/CMakeLists.txt", - "origin": "Code/CMakeLists.txt", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/${NameLower}_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_android_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/PAL_android.cmake", - "origin": "Code/Platform/Android/PAL_android.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/PAL_linux.cmake", - "origin": "Code/Platform/Linux/PAL_linux.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/PAL_mac.cmake", - "origin": "Code/Platform/Mac/PAL_mac.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/PAL_windows.cmake", - "origin": "Code/Platform/Windows/PAL_windows.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/PAL_ios.cmake", - "origin": "Code/Platform/iOS/PAL_ios.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}Module.cpp", - "origin": "Code/Source/${Name}Module.cpp", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}SystemComponent.cpp", - "origin": "Code/Source/${Name}SystemComponent.cpp", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}SystemComponent.h", - "origin": "Code/Source/${Name}SystemComponent.h", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/enabled_gems.cmake", - "origin": "Code/enabled_gems.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/gem.json", - "origin": "Code/gem.json", - "isTemplated": true, - "isOptional": true - }, - { - "file": "Config/shader_global_build_options.json", - "origin": "Config/shader_global_build_options.json", - "isTemplated": false, - "isOptional": false - }, - { - "file": "Config/default_aws_resource_mappings.json", - "origin": "Config/default_aws_resource_mappings.json", - "isTemplated": false, - "isOptional": false + "isTemplated": true }, { "file": "cmake/EngineFinder.cmake", - "origin": "cmake/EngineFinder.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": true }, { "file": "cmake/CompilerSettings.cmake", - "origin": "cmake/CompilerSettings.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "cmake/Platform/Linux/CompilerSettings_linux.cmake", - "origin": "cmake/Platform/Linux/CompilerSettings_linux.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false + }, + { + "file": "Config/default_aws_resource_mappings.json", + "isTemplated": false + }, + { + "file": "Config/shader_global_build_options.json", + "isTemplated": false + }, + { + "file": "Gem/${NameLower}_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/${NameLower}_shared_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/CMakeLists.txt", + "isTemplated": true + }, + { + "file": "Gem/Include/${Name}/${Name}Bus.h", + "isTemplated": true + }, + { + "file": "Gem/Platform/Android/${NameLower}_android_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Android/${NameLower}_shared_android_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Android/PAL_android.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Linux/${NameLower}_linux_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Linux/PAL_linux.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Mac/${NameLower}_mac_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Mac/PAL_mac.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Windows/${NameLower}_windows_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/Windows/PAL_windows.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/iOS/${NameLower}_ios_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake", + "isTemplated": false + }, + { + "file": "Gem/Platform/iOS/PAL_ios.cmake", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}Module.cpp", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}SystemComponent.cpp", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}SystemComponent.h", + "isTemplated": true + }, + { + "file": "Gem/enabled_gems.cmake", + "isTemplated": true + }, + { + "file": "Gem/gem.json", + "isTemplated": true }, { "file": "Platform/Android/android_project.cmake", - "origin": "Platform/Android/android_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Android/android_project.json", - "origin": "Platform/Android/android_project.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Linux/linux_project.cmake", - "origin": "Platform/Linux/linux_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Linux/linux_project.json", - "origin": "Platform/Linux/linux_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_project.cmake", - "origin": "Platform/Mac/mac_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_project.json", - "origin": "Platform/Mac/mac_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_project.cmake", - "origin": "Platform/Windows/windows_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_project.json", - "origin": "Platform/Windows/windows_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_project.cmake", - "origin": "Platform/iOS/ios_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_project.json", - "origin": "Platform/iOS/ios_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Registry/assets_scan_folders.setreg", - "origin": "Registry/assets_scan_folders.setreg", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Registry/awscoreconfiguration.setreg", - "origin": "Registry/awscoreconfiguration.setreg", - "isTemplated": false, - "isOptional": false - }, - { - "file": "Resources/LegacyLogoLauncher.bmp", - "origin": "Resources/LegacyLogoLauncher.bmp", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/GameSDK.ico", - "origin": "Resources/GameSDK.ico", - "isTemplated": false, - "isOptional": false + "isTemplated": false + }, + { + "file": "Resources/LegacyLogoLauncher.bmp", + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/Contents.json", - "origin": "Resources/Platform/Mac/Images.xcassets/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "isTemplated": false, - "isOptional": false - }, - { - "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false + }, + { + "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128_2x.png", + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16_2x.png", - "isTemplated": false, - "isOptional": false - }, - { - "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false + }, + { + "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256_2x.png", + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Info.plist", - "origin": "Resources/Platform/Mac/Info.plist", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Resources/Platform/iOS/Images.xcassets/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon152x152.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon152x152.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon76x76.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon76x76.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadProAppIcon167x167.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadProAppIcon167x167.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon29x29.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon29x29.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon58x58.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon58x58.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon40x40.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon40x40.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon80x80.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon80x80.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon120x120.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon120x120.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon180x180.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon180x180.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon58x58.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon58x58.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon87x87.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon87x87.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon120x120.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon120x120.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon80x80.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon80x80.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Info.plist", - "origin": "Resources/Platform/iOS/Info.plist", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "ShaderLib/README.md", - "origin": "ShaderLib/README.md", - "isTemplated": false, - "isOptional": true + "isTemplated": false }, { "file": "ShaderLib/scenesrg.srgi", - "origin": "ShaderLib/scenesrg.srgi", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "ShaderLib/viewsrg.srgi", - "origin": "ShaderLib/viewsrg.srgi", - "isTemplated": true, - "isOptional": false + "isTemplated": false }, { "file": "autoexec.cfg", - "origin": "autoexec.cfg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "game.cfg", - "origin": "game.cfg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "project.json", - "origin": "project.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" }, { - "dir": "Code", - "origin": "Code" + "dir": "cmake" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "cmake/Platform" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "cmake/Platform/Linux" }, { - "dir": "Code/Platform", - "origin": "Code/Platform" + "dir": "Config" }, { - "dir": "Code/Platform/Android", - "origin": "Code/Platform/Android" + "dir": "Gem" }, { - "dir": "Code/Platform/Linux", - "origin": "Code/Platform/Linux" + "dir": "Gem/Include" }, { - "dir": "Code/Platform/Mac", - "origin": "Code/Platform/Mac" + "dir": "Gem/Include/${Name}" }, { - "dir": "Code/Platform/Windows", - "origin": "Code/Platform/Windows" + "dir": "Gem/Platform" }, { - "dir": "Code/Platform/iOS", - "origin": "Code/Platform/iOS" + "dir": "Gem/Platform/Android" }, { - "dir": "Code/Source", - "origin": "Code/Source" + "dir": "Gem/Platform/Linux" }, { - "dir": "Config", - "origin": "Config" + "dir": "Gem/Platform/Mac" }, { - "dir": "Platform", - "origin": "Platform" + "dir": "Gem/Platform/Windows" }, { - "dir": "Platform/Android", - "origin": "Platform/Android" + "dir": "Gem/Platform/iOS" }, { - "dir": "Platform/Linux", - "origin": "Platform/Linux" + "dir": "Gem/Source" }, { - "dir": "Platform/Mac", - "origin": "Platform/Mac" + "dir": "Platform" }, { - "dir": "Platform/Windows", - "origin": "Platform/Windows" + "dir": "Platform/Android" }, { - "dir": "Platform/iOS", - "origin": "Platform/iOS" + "dir": "Platform/Linux" }, { - "dir": "Registry", - "origin": "Registry" + "dir": "Platform/Mac" }, { - "dir": "Resources", - "origin": "Resources" + "dir": "Platform/Windows" }, { - "dir": "Resources/Platform", - "origin": "Resources/Platform" + "dir": "Platform/iOS" }, { - "dir": "Resources/Platform/Mac", - "origin": "Resources/Platform/Mac" + "dir": "Registry" }, { - "dir": "Resources/Platform/Mac/Images.xcassets", - "origin": "Resources/Platform/Mac/Images.xcassets" + "dir": "Resources" }, { - "dir": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset" + "dir": "Resources/Platform" }, { - "dir": "Resources/Platform/iOS", - "origin": "Resources/Platform/iOS" + "dir": "Resources/Platform/Mac" }, { - "dir": "Resources/Platform/iOS/Images.xcassets", - "origin": "Resources/Platform/iOS/Images.xcassets" + "dir": "Resources/Platform/Mac/Images.xcassets" }, { - "dir": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage" + "dir": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset" }, { - "dir": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset" + "dir": "Resources/Platform/iOS" }, { - "dir": "ShaderLib", - "origin": "ShaderLib" + "dir": "Resources/Platform/iOS/Images.xcassets" }, { - "dir": "Shaders", - "origin": "Shaders" + "dir": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage" }, { - "dir": "Shaders/ShaderResourceGroups", - "origin": "Shaders/ShaderResourceGroups" + "dir": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset" + }, + { + "dir": "ShaderLib" + }, + { + "dir": "Shaders" + }, + { + "dir": "Shaders/ShaderResourceGroups" } ] } diff --git a/Templates/GemRepo/Template/gem.json b/Templates/GemRepo/Template/gem.json index 292681b2b5..7ba555a127 100644 --- a/Templates/GemRepo/Template/gem.json +++ b/Templates/GemRepo/Template/gem.json @@ -1,19 +1,23 @@ { - "gem_name": "${Name}Gem", - "display_name": "${Name}Gem", - "license": "What license ${Name}Gem uses goes here: i.e. Apache-2.0 Or MIT", - "license_url": "", - "origin": "The primary repo for ${Name}Gem goes here: i.e. http://www.mydomain.com", - "summary": "A short description of ${Name}Gem which is zipped up in an archive named gem.zip in the root of the Gem Repo. Though not required, it is recommended that the sha256 of the gem.zip file should be placed in the sha256 field of this gem.json so the download can be verified.", + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of ${Name} which is zipped up in an archive named gem.zip in the root of the Gem Repo. Though not required, it is recommended that the sha256 of the gem.zip file be placed in the sha256 field of this gem.json so the download can be verified.", "origin_uri": "${RepoURI}/gem.zip", "sha256": "", - "type": "Code", "canonical_tags": [ "Gem" ], "user_tags": [ - "${Name}Gem" + "${Name}" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "", + "dependencies": [ + ] } diff --git a/Templates/GemRepo/template.json b/Templates/GemRepo/template.json index 88123a9dae..ca042329be 100644 --- a/Templates/GemRepo/template.json +++ b/Templates/GemRepo/template.json @@ -1,10 +1,14 @@ { "template_name": "GemRepo", - "origin": "The primary repo for GemRepo goes here: i.e. http://www.mydomain.com", - "license": "What license GemRepo uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "display_name": "GemRepo", "summary": "A Gem Repository that contains a single Gem.", - "canonical_tags": [], + "canonical_tags": [ + "Gem", + "Repo" + ], "user_tags": [ "GemRepo" ], @@ -12,15 +16,11 @@ "copyFiles": [ { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "repo.json", - "origin": "repo.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true } ], "createDirectories": [] diff --git a/Templates/MinimalProject/Template/CMakeLists.txt b/Templates/MinimalProject/Template/CMakeLists.txt index ae4bb662a3..420a92948d 100644 --- a/Templates/MinimalProject/Template/CMakeLists.txt +++ b/Templates/MinimalProject/Template/CMakeLists.txt @@ -29,5 +29,4 @@ else() set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) - add_subdirectory(Code) endif() diff --git a/Templates/MinimalProject/Template/Code/${NameLower}_files.cmake b/Templates/MinimalProject/Template/Gem/${NameLower}_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/${NameLower}_files.cmake rename to Templates/MinimalProject/Template/Gem/${NameLower}_files.cmake diff --git a/Templates/MinimalProject/Template/Code/${NameLower}_shared_files.cmake b/Templates/MinimalProject/Template/Gem/${NameLower}_shared_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/${NameLower}_shared_files.cmake rename to Templates/MinimalProject/Template/Gem/${NameLower}_shared_files.cmake diff --git a/Templates/DefaultProject/Template/Code/CMakeLists.txt b/Templates/MinimalProject/Template/Gem/CMakeLists.txt similarity index 87% rename from Templates/DefaultProject/Template/Code/CMakeLists.txt rename to Templates/MinimalProject/Template/Gem/CMakeLists.txt index 7bbb9a0852..6b1dcf9172 100644 --- a/Templates/DefaultProject/Template/Code/CMakeLists.txt +++ b/Templates/MinimalProject/Template/Gem/CMakeLists.txt @@ -6,13 +6,17 @@ # # {END_LICENSE} +set(gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(gem_json ${gem_path}/gem.json) +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + # Currently we are in the ${Name}/Code folder: ${CMAKE_CURRENT_LIST_DIR} # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} -# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# Note: o3de_pal_dir will take care of the details for us, as this may be a restricted platform # in which case it will see if that platform is present here or in the restricted folder. -# i.e. It could here : ${Name}/Code/Platform/ or +# i.e. It could here : ${Name}/Code/Platform/ or # //${Name}/Code -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this project @@ -71,6 +75,7 @@ ly_create_alias(NAME ${Name}.Servers NAMESPACE Gem TARGETS Gem::${Name}) # Enable the specified list of gems from GEM_FILE or GEMS list for this specific project: ly_enable_gems(PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake) + if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) # this property causes it to actually make a ServerLauncher. # if you don't want a Server application, you can remove this and the diff --git a/Templates/MinimalProject/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/MinimalProject/Template/Gem/Include/${Name}/${Name}Bus.h similarity index 100% rename from Templates/MinimalProject/Template/Code/Include/${Name}/${Name}Bus.h rename to Templates/MinimalProject/Template/Gem/Include/${Name}/${Name}Bus.h diff --git a/Templates/MinimalProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Android/${NameLower}_android_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Android/${NameLower}_android_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Android/${NameLower}_shared_android_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Android/${NameLower}_shared_android_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Android/PAL_android.cmake b/Templates/MinimalProject/Template/Gem/Platform/Android/PAL_android.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Android/PAL_android.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Android/PAL_android.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Linux/${NameLower}_linux_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Linux/${NameLower}_linux_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/MinimalProject/Template/Gem/Platform/Linux/PAL_linux.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Linux/PAL_linux.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Linux/PAL_linux.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Mac/${NameLower}_mac_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Mac/${NameLower}_mac_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/MinimalProject/Template/Gem/Platform/Mac/PAL_mac.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Mac/PAL_mac.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Mac/PAL_mac.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/Windows/${NameLower}_windows_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Windows/${NameLower}_windows_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/MinimalProject/Template/Gem/Platform/Windows/PAL_windows.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/Windows/PAL_windows.cmake rename to Templates/MinimalProject/Template/Gem/Platform/Windows/PAL_windows.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/iOS/${NameLower}_ios_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/iOS/${NameLower}_ios_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake b/Templates/MinimalProject/Template/Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake rename to Templates/MinimalProject/Template/Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake diff --git a/Templates/MinimalProject/Template/Code/Platform/iOS/PAL_ios.cmake b/Templates/MinimalProject/Template/Gem/Platform/iOS/PAL_ios.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/Platform/iOS/PAL_ios.cmake rename to Templates/MinimalProject/Template/Gem/Platform/iOS/PAL_ios.cmake diff --git a/Templates/MinimalProject/Template/Code/Source/${Name}Module.cpp b/Templates/MinimalProject/Template/Gem/Source/${Name}Module.cpp similarity index 100% rename from Templates/MinimalProject/Template/Code/Source/${Name}Module.cpp rename to Templates/MinimalProject/Template/Gem/Source/${Name}Module.cpp diff --git a/Templates/MinimalProject/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/MinimalProject/Template/Gem/Source/${Name}SystemComponent.cpp similarity index 100% rename from Templates/MinimalProject/Template/Code/Source/${Name}SystemComponent.cpp rename to Templates/MinimalProject/Template/Gem/Source/${Name}SystemComponent.cpp diff --git a/Templates/MinimalProject/Template/Code/Source/${Name}SystemComponent.h b/Templates/MinimalProject/Template/Gem/Source/${Name}SystemComponent.h similarity index 100% rename from Templates/MinimalProject/Template/Code/Source/${Name}SystemComponent.h rename to Templates/MinimalProject/Template/Gem/Source/${Name}SystemComponent.h diff --git a/Templates/MinimalProject/Template/Code/enabled_gems.cmake b/Templates/MinimalProject/Template/Gem/enabled_gems.cmake similarity index 100% rename from Templates/MinimalProject/Template/Code/enabled_gems.cmake rename to Templates/MinimalProject/Template/Gem/enabled_gems.cmake diff --git a/Templates/MinimalProject/Template/Gem/gem.json b/Templates/MinimalProject/Template/Gem/gem.json new file mode 100644 index 0000000000..b60f512006 --- /dev/null +++ b/Templates/MinimalProject/Template/Gem/gem.json @@ -0,0 +1,21 @@ +{ + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. Apache-2.0 or MIT", + "license_url": "Link to the license web site goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "", + "dependencies": [ + ] +} diff --git a/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake b/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake index 60bda1d45b..4efaecd60f 100644 --- a/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake +++ b/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake @@ -1,10 +1,10 @@ -# +# {BEGIN_LICENSE} # 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 # -# +# {END_LICENSE} # File to tweak compiler settings before compiler detection happens (before project() is called) # We dont have PAL enabled at this point, so we can only use pure-CMake variables diff --git a/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake b/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake index 9bb629c53b..386117873f 100644 --- a/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake +++ b/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake @@ -1,10 +1,10 @@ -# +# {BEGIN_LICENSE} # 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 # -# +# {END_LICENSE} if(NOT CMAKE_C_COMPILER AND NOT CMAKE_CXX_COMPILER AND NOT "$ENV{CC}" AND NOT "$ENV{CXX}") set(path_search diff --git a/Templates/MinimalProject/Template/project.json b/Templates/MinimalProject/Template/project.json index f8d4643ce9..a303186a64 100644 --- a/Templates/MinimalProject/Template/project.json +++ b/Templates/MinimalProject/Template/project.json @@ -2,7 +2,7 @@ "project_name": "${Name}", "project_id": "${ProjectId}", "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", - "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/Apache-2.0 Or https://opensource.org/licenses/MIT etc.", "display_name": "${Name}", "summary": "A short description of ${Name}.", "canonical_tags": [ @@ -13,5 +13,7 @@ ], "icon_path": "preview.png", "engine": "o3de", - "external_subdirectories": [] + "external_subdirectories": [ + "Gem" + ] } diff --git a/Templates/MinimalProject/template.json b/Templates/MinimalProject/template.json index 7d6a4f9b94..4cc3031ff5 100644 --- a/Templates/MinimalProject/template.json +++ b/Templates/MinimalProject/template.json @@ -1,10 +1,18 @@ { "template_name": "MinimalProject", - "origin": "The primary repo for MinimalProject goes here: i.e. http://www.mydomain.com", - "license": "What license MinimalProject uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "Minimal", - "summary": "This will be a good starting point for developers who are looking for building the game with the bare minimum of gems in O3DE, and adding more when needed. ", - "canonical_tags": [], + "template_restricted_platform_relative_path": "Templates/MinimalProject", + "restricted_name": "o3de", + "restricted_platform_relative_path": "Templates/MinimalProject", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "display_name": "Minimal Project Template", + "summary": "Use this project template to create project that is the absolute minimum needed to get started in O3DE.", + "canonical_tags": [ + "Template", + "Project" + ], "user_tags": [ "MinimalProject" ], @@ -12,645 +20,454 @@ "copyFiles": [ { "file": ".gitignore", - "origin": ".gitignore", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/${NameLower}_files.cmake", - "origin": "Code/${NameLower}_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/${NameLower}_shared_files.cmake", - "origin": "Code/${NameLower}_shared_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/CMakeLists.txt", - "origin": "Code/CMakeLists.txt", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/${NameLower}_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_android_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "origin": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/PAL_android.cmake", - "origin": "Code/Platform/Android/PAL_android.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/PAL_linux.cmake", - "origin": "Code/Platform/Linux/PAL_linux.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/PAL_mac.cmake", - "origin": "Code/Platform/Mac/PAL_mac.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/PAL_windows.cmake", - "origin": "Code/Platform/Windows/PAL_windows.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "origin": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/PAL_ios.cmake", - "origin": "Code/Platform/iOS/PAL_ios.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}Module.cpp", - "origin": "Code/Source/${Name}Module.cpp", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}SystemComponent.cpp", - "origin": "Code/Source/${Name}SystemComponent.cpp", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Source/${Name}SystemComponent.h", - "origin": "Code/Source/${Name}SystemComponent.h", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/enabled_gems.cmake", - "origin": "Code/enabled_gems.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/gem.json", - "origin": "Code/gem.json", - "isTemplated": true, - "isOptional": true - }, - { - "file": "Config/shader_global_build_options.json", - "origin": "Config/shader_global_build_options.json", - "isTemplated": false, - "isOptional": false + "isTemplated": true }, { "file": "cmake/EngineFinder.cmake", - "origin": "cmake/EngineFinder.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "cmake/CompilerSettings.cmake", - "origin": "cmake/CompilerSettings.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "cmake/Platform/Linux/CompilerSettings_linux.cmake", - "origin": "cmake/Platform/Linux/CompilerSettings_linux.cmake", - "isTemplated": false, - "isOptional": false + "isTemplated": false + }, + { + "file": "Config/shader_global_build_options.json", + "isTemplated": false + }, + { + "file": "Gem/${NameLower}_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/${NameLower}_shared_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/CMakeLists.txt", + "isTemplated": true + }, + { + "file": "Gem/Include/${Name}/${Name}Bus.h", + "isTemplated": true + }, + { + "file": "Gem/Platform/Android/${NameLower}_android_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Android/${NameLower}_shared_android_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Android/PAL_android.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Linux/${NameLower}_linux_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Linux/PAL_linux.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Mac/${NameLower}_mac_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Mac/PAL_mac.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Windows/${NameLower}_windows_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/Windows/PAL_windows.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/iOS/${NameLower}_ios_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/iOS/${NameLower}_shared_ios_files.cmake", + "isTemplated": true + }, + { + "file": "Gem/Platform/iOS/PAL_ios.cmake", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}Module.cpp", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}SystemComponent.cpp", + "isTemplated": true + }, + { + "file": "Gem/Source/${Name}SystemComponent.h", + "isTemplated": true + }, + { + "file": "Gem/enabled_gems.cmake", + "isTemplated": true + }, + { + "file": "Gem/gem.json", + "isTemplated": true }, { "file": "Platform/Android/android_project.cmake", - "origin": "Platform/Android/android_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Android/android_project.json", - "origin": "Platform/Android/android_project.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Linux/linux_project.cmake", - "origin": "Platform/Linux/linux_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Linux/linux_project.json", - "origin": "Platform/Linux/linux_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Mac/mac_project.cmake", - "origin": "Platform/Mac/mac_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Mac/mac_project.json", - "origin": "Platform/Mac/mac_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/Windows/windows_project.cmake", - "origin": "Platform/Windows/windows_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/Windows/windows_project.json", - "origin": "Platform/Windows/windows_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Platform/iOS/ios_project.cmake", - "origin": "Platform/iOS/ios_project.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Platform/iOS/ios_project.json", - "origin": "Platform/iOS/ios_project.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Registry/assets_scan_folders.setreg", - "origin": "Registry/assets_scan_folders.setreg", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Resources/LegacyLogoLauncher.bmp", - "origin": "Resources/LegacyLogoLauncher.bmp", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/GameSDK.ico", - "origin": "Resources/GameSDK.ico", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/Contents.json", - "origin": "Resources/Platform/Mac/Images.xcassets/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_128.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_16_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_256.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_32_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512_2x.png", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset/icon_512_2x.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/Mac/Info.plist", - "origin": "Resources/Platform/Mac/Info.plist", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Resources/Platform/iOS/Images.xcassets/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/Contents.json", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon152x152.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon152x152.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon76x76.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadAppIcon76x76.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadProAppIcon167x167.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadProAppIcon167x167.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon29x29.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon29x29.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon58x58.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSettingsIcon58x58.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon40x40.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon40x40.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon80x80.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPadSpotlightIcon80x80.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon120x120.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon120x120.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon180x180.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneAppIcon180x180.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon58x58.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon58x58.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon87x87.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSettingsIcon87x87.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon120x120.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon120x120.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon80x80.png", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset/iPhoneSpotlightIcon80x80.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Resources/Platform/iOS/Info.plist", - "origin": "Resources/Platform/iOS/Info.plist", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "ShaderLib/README.md", - "origin": "ShaderLib/README.md", - "isTemplated": false, - "isOptional": true + "isTemplated": false }, { "file": "ShaderLib/scenesrg.srgi", - "origin": "ShaderLib/scenesrg.srgi", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "ShaderLib/viewsrg.srgi", - "origin": "ShaderLib/viewsrg.srgi", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "autoexec.cfg", - "origin": "autoexec.cfg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "game.cfg", - "origin": "game.cfg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "project.json", - "origin": "project.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" }, { - "dir": "Code", - "origin": "Code" + "dir": "cmake" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "cmake/Platform" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "cmake/Platform/Linux" }, { - "dir": "Code/Platform", - "origin": "Code/Platform" + "dir": "Config" }, { - "dir": "Code/Platform/Android", - "origin": "Code/Platform/Android" + "dir": "Gem" }, { - "dir": "Code/Platform/Linux", - "origin": "Code/Platform/Linux" + "dir": "Gem/Include" }, { - "dir": "Code/Platform/Mac", - "origin": "Code/Platform/Mac" + "dir": "Gem/Include/${Name}" }, { - "dir": "Code/Platform/Windows", - "origin": "Code/Platform/Windows" + "dir": "Gem/Platform" }, { - "dir": "Code/Platform/iOS", - "origin": "Code/Platform/iOS" + "dir": "Gem/Platform/Android" }, { - "dir": "Code/Source", - "origin": "Code/Source" + "dir": "Gem/Platform/Linux" }, { - "dir": "Config", - "origin": "Config" + "dir": "Gem/Platform/Mac" }, { - "dir": "Platform", - "origin": "Platform" + "dir": "Gem/Platform/Windows" }, { - "dir": "Platform/Android", - "origin": "Platform/Android" + "dir": "Gem/Platform/iOS" }, { - "dir": "Platform/Linux", - "origin": "Platform/Linux" + "dir": "Gem/Source" }, { - "dir": "Platform/Mac", - "origin": "Platform/Mac" + "dir": "Config" }, { - "dir": "Platform/Windows", - "origin": "Platform/Windows" + "dir": "Platform" }, { - "dir": "Platform/iOS", - "origin": "Platform/iOS" + "dir": "Platform/Android" }, { - "dir": "Registry", - "origin": "Registry" + "dir": "Platform/Linux" }, { - "dir": "Resources", - "origin": "Resources" + "dir": "Platform/Mac" }, { - "dir": "Resources/Platform", - "origin": "Resources/Platform" + "dir": "Platform/Windows" }, { - "dir": "Resources/Platform/Mac", - "origin": "Resources/Platform/Mac" + "dir": "Platform/iOS" }, { - "dir": "Resources/Platform/Mac/Images.xcassets", - "origin": "Resources/Platform/Mac/Images.xcassets" + "dir": "Registry" }, { - "dir": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset", - "origin": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset" + "dir": "Resources" }, { - "dir": "Resources/Platform/iOS", - "origin": "Resources/Platform/iOS" + "dir": "Resources/Platform" }, { - "dir": "Resources/Platform/iOS/Images.xcassets", - "origin": "Resources/Platform/iOS/Images.xcassets" + "dir": "Resources/Platform/Mac" }, { - "dir": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage", - "origin": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage" + "dir": "Resources/Platform/Mac/Images.xcassets" }, { - "dir": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset", - "origin": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset" + "dir": "Resources/Platform/Mac/Images.xcassets/TestDPAppIcon.appiconset" }, { - "dir": "ShaderLib", - "origin": "ShaderLib" + "dir": "Resources/Platform/iOS" }, { - "dir": "Shaders", - "origin": "Shaders" + "dir": "Resources/Platform/iOS/Images.xcassets" }, { - "dir": "Shaders/ShaderResourceGroups", - "origin": "Shaders/ShaderResourceGroups" + "dir": "Resources/Platform/iOS/Images.xcassets/LaunchImage.launchimage" + }, + { + "dir": "Resources/Platform/iOS/Images.xcassets/TestDPAppIcon.appiconset" + }, + { + "dir": "ShaderLib" + }, + { + "dir": "Shaders" + }, + { + "dir": "Shaders/ShaderResourceGroups" } ] } diff --git a/Templates/PythonToolGem/Template/gem.json b/Templates/PythonToolGem/Template/gem.json index 84f5b65a3e..3164c7b5b8 100644 --- a/Templates/PythonToolGem/Template/gem.json +++ b/Templates/PythonToolGem/Template/gem.json @@ -2,8 +2,9 @@ "gem_name": "${Name}", "display_name": "${Name}", "license": "What license ${Name} uses goes here: i.e. Apache-2.0 Or MIT", - "license_url": "", - "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "origin": "The name of the originator goes here. i.e. XYZ Inc.", + "origin_url": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", "type": "Code", "summary": "A short description of ${Name}.", "canonical_tags": [ @@ -14,6 +15,7 @@ ], "icon_path": "preview.png", "requirements": "", + "documentation_url": "", "dependencies": [ "QtForPython" ] diff --git a/Templates/PythonToolGem/template.json b/Templates/PythonToolGem/template.json index 6dc68de3fc..3af74eb49f 100644 --- a/Templates/PythonToolGem/template.json +++ b/Templates/PythonToolGem/template.json @@ -1,12 +1,18 @@ { "template_name": "PythonToolGem", + "template_restricted_platform_relative_path": "Templates/PythonToolGem", "restricted_name": "o3de", - "restricted_platform_relative_path": "Templates", - "origin": "The primary repo for PythonToolGem goes here: i.e. http://www.mydomain.com", - "license": "What license PythonToolGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "restricted_platform_relative_path": "Templates/PythonToolGem", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "display_name": "PythonToolGem", "summary": "A gem template for a custom tool in Python that gets registered with the Editor.", - "canonical_tags": [], + "canonical_tags": [ + "Python", + "Gem" + ], "user_tags": [ "PythonToolGem" ], @@ -14,221 +20,153 @@ "copyFiles": [ { "file": ".gitignore", - "origin": ".gitignore", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_files.cmake", - "origin": "Code/${NameLower}_editor_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_shared_files.cmake", - "origin": "Code/${NameLower}_editor_shared_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/${NameLower}_editor_tests_files.cmake", - "origin": "Code/${NameLower}_editor_tests_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/CMakeLists.txt", - "origin": "Code/CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Linux/PAL_linux.cmake", - "origin": "Code/Platform/Linux/PAL_linux.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Mac/PAL_mac.cmake", - "origin": "Code/Platform/Mac/PAL_mac.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Platform/Windows/PAL_windows.cmake", - "origin": "Code/Platform/Windows/PAL_windows.cmake", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}.qrc", - "origin": "Code/Source/${Name}.qrc", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorModule.cpp", - "origin": "Code/Source/${Name}EditorModule.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.cpp", - "origin": "Code/Source/${Name}EditorSystemComponent.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}EditorSystemComponent.h", - "origin": "Code/Source/${Name}EditorSystemComponent.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/${Name}ModuleInterface.h", - "origin": "Code/Source/${Name}ModuleInterface.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Code/Source/toolbar_icon.svg", - "origin": "Code/Source/toolbar_icon.svg", - "isTemplated": false, - "isOptional": false + "isTemplated": false }, { "file": "Code/Tests/${Name}EditorTest.cpp", - "origin": "Code/Tests/${Name}EditorTest.cpp", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Editor/Scripts/__init__.py", - "origin": "Editor/Scripts/__init__.py", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Editor/Scripts/bootstrap.py", - "origin": "Editor/Scripts/bootstrap.py", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "Editor/Scripts/${NameLower}_dialog.py", - "origin": "Editor/Scripts/${NameLower}_dialog.py", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" }, { - "dir": "Code", - "origin": "Code" + "dir": "Code" }, { - "dir": "Editor", - "origin": "Editor" + "dir": "Editor" }, { - "dir": "Editor/Scripts", - "origin": "Editor/Scripts" + "dir": "Editor/Scripts" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "Code/Include" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "Code/Include/${Name}" }, { - "dir": "Code/Platform", - "origin": "Code/Platform" + "dir": "Code/Platform" }, { - "dir": "Code/Platform/Linux", - "origin": "Code/Platform/Linux" + "dir": "Code/Platform/Linux" }, { - "dir": "Code/Platform/Mac", - "origin": "Code/Platform/Mac" + "dir": "Code/Platform/Mac" }, { - "dir": "Code/Platform/Windows", - "origin": "Code/Platform/Windows" + "dir": "Code/Platform/Windows" }, { - "dir": "Code/Source", - "origin": "Code/Source" + "dir": "Code/Source" }, { - "dir": "Code/Tests", - "origin": "Code/Tests" + "dir": "Code/Tests" } ] } diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py index af29064766..1c17d6d519 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py @@ -413,7 +413,7 @@ def crash_log_watchdog(request, workspace): def _crash_log_watchdog(request, workspace, raise_on_crash): """Separate implementation to call directly during unit tests""" - error_log = os.path.join(workspace.paths.project_log(), 'error.log') + error_log = workspace.paths.crash_log() crash_log_watchdog = ly_test_tools.environment.watchdog.CrashLogWatchdog( error_log, raise_on_condition=raise_on_crash) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index fd2157d1cc..8bd4fbe29a 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -762,7 +762,7 @@ class EditorTestSuite(): cmdline = [ "--runpythontest", test_filename, "-logfile", f"@log@/{log_name}", - "-project-log-path", ly_test_tools._internal.pytest_plugin.output_path] + test_cmdline_args + "-project-log-path", editor_utils.retrieve_log_path(run_id, workspace)] + test_cmdline_args editor.args.extend(cmdline) editor.start(backupFiles = False, launch_ap = False, configure_settings=False) @@ -771,7 +771,8 @@ class EditorTestSuite(): output = editor.get_output() return_code = editor.get_returncode() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) - + # Save the editor log + workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name)) if return_code == 0: test_result = Result.Pass.create(test_spec, output, editor_log_content) else: @@ -779,6 +780,9 @@ class EditorTestSuite(): if has_crashed: test_result = Result.Crash.create(test_spec, output, return_code, editor_utils.retrieve_crash_output (run_id, workspace, self._TIMEOUT_CRASH_LOG), None) + # Save the crash log + crash_file_name = os.path.basename(workspace.paths.crash_log()) + workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), crash_file_name)) editor_utils.cycle_crash_report(run_id, workspace) else: test_result = Result.Fail.create(test_spec, output, editor_log_content) @@ -830,7 +834,7 @@ class EditorTestSuite(): cmdline = [ "--runpythontest", test_filenames_str, "-logfile", f"@log@/{log_name}", - "-project-log-path", ly_test_tools._internal.pytest_plugin.output_path] + test_cmdline_args + "-project-log-path", editor_utils.retrieve_log_path(run_id, workspace)] + test_cmdline_args editor.args.extend(cmdline) editor.start(backupFiles = False, launch_ap = False, configure_settings=False) @@ -842,7 +846,8 @@ class EditorTestSuite(): output = editor.get_output() return_code = editor.get_returncode() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) - + # Save the editor log + workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name)) if return_code == 0: # No need to scrap the output, as all the tests have passed for test_spec in test_spec_list: @@ -863,6 +868,10 @@ class EditorTestSuite(): # The first test with "Unknown" result (no data in output) is likely the one that crashed crash_error = editor_utils.retrieve_crash_output(run_id, workspace, self._TIMEOUT_CRASH_LOG) + # Save the crash log + crash_file_name = os.path.basename(workspace.paths.crash_log()) + workspace.artifact_manager.save_artifact( + os.path.join(editor_utils.retrieve_log_path(run_id, workspace), crash_file_name)) editor_utils.cycle_crash_report(run_id, workspace) results[test_spec_name] = Result.Crash.create(result.test_spec, output, return_code, crash_error, result.editor_log) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py index dd0bede4b8..7b36a82c07 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test_utils.py @@ -71,7 +71,9 @@ def retrieve_crash_output(run_id: int, workspace: AbstractWorkspaceManager, time :return str: The contents of the editor crash file (error.log) """ crash_info = "-- No crash log available --" - crash_log = os.path.join(retrieve_log_path(run_id, workspace), 'error.log') + # Grab the file name of the crash log which can be different depending on platform + crash_file_name = os.path.basename(workspace.paths.crash_log()) + crash_log = os.path.join(retrieve_log_path(run_id, workspace), crash_file_name) try: waiter.wait_for(lambda: os.path.exists(crash_log), timeout=timeout) except AssertionError: @@ -92,7 +94,7 @@ def cycle_crash_report(run_id: int, workspace: AbstractWorkspaceManager) -> None :param workspace: Workspace fixture """ log_path = retrieve_log_path(run_id, workspace) - files_to_cycle = ['error.log', 'error.dmp'] + files_to_cycle = ['crash.log', 'error.log', 'error.dmp'] for filename in files_to_cycle: filepath = os.path.join(log_path, filename) name, ext = os.path.splitext(filename) diff --git a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py index 849fa5c391..f81d2fd8e6 100644 --- a/Tools/LyTestTools/tests/unit/test_editor_test_utils.py +++ b/Tools/LyTestTools/tests/unit/test_editor_test_utils.py @@ -60,22 +60,31 @@ class TestEditorTestUtils(unittest.TestCase): assert expected == editor_test_utils.retrieve_log_path(0, mock_workspace) + @mock.patch('os.listdir') @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('os.path.join', mock.MagicMock()) + @mock.patch('os.path.basename', mock.MagicMock()) + @mock.patch('os.path.isfile', mock.MagicMock()) @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) - def test_RetrieveCrashOutput_CrashLogExists_ReturnsLogInfo(self, mock_retrieve_log_path): - mock_retrieve_log_path.return_value = 'mock_log_path' + def test_RetrieveCrashOutput_CrashLogExists_ReturnsLogInfo(self, mock_retrieve_log_path, mock_listdir): + mock_retrieve_log_path.return_value = 'mock_path' mock_workspace = mock.MagicMock() mock_log = 'mock crash info' + mock_listdir.return_value = ['mock_error_log.log'] with mock.patch('builtins.open', mock.mock_open(read_data=mock_log)) as mock_file: assert mock_log == editor_test_utils.retrieve_crash_output(0, mock_workspace, 0) + @mock.patch('os.listdir') @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') + @mock.patch('os.path.isfile', mock.MagicMock()) @mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock()) - def test_RetrieveCrashOutput_CrashLogNotExists_ReturnsError(self, mock_retrieve_log_path): + def test_RetrieveCrashOutput_CrashLogNotExists_ReturnsError(self, mock_retrieve_log_path, mock_listdir): mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() + mock_workspace.paths.crash_log.return_value = 'mock_file.log' error_message = "No crash log available" + mock_listdir.return_value = ['mock_file.log'] assert error_message in editor_test_utils.retrieve_crash_output(0, mock_workspace, 0) @@ -86,7 +95,7 @@ class TestEditorTestUtils(unittest.TestCase): @mock.patch('os.path.exists') def test_CycleCrashReport_DmpExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_strftime, mock_rename): - mock_exists.side_effect = [False, True] + mock_exists.side_effect = [False, False, True] mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() mock_strftime.return_value = 'mock_strftime' @@ -102,7 +111,7 @@ class TestEditorTestUtils(unittest.TestCase): @mock.patch('os.path.exists') def test_CycleCrashReport_LogExists_NamedCorrectly(self, mock_exists, mock_retrieve_log_path, mock_strftime, mock_rename): - mock_exists.side_effect = [True, False] + mock_exists.side_effect = [False, True, False] mock_retrieve_log_path.return_value = 'mock_log_path' mock_workspace = mock.MagicMock() mock_strftime.return_value = 'mock_strftime' diff --git a/Tools/LyTestTools/tests/unit/test_fixtures.py b/Tools/LyTestTools/tests/unit/test_fixtures.py index 32dc204bd2..eb36cf6998 100755 --- a/Tools/LyTestTools/tests/unit/test_fixtures.py +++ b/Tools/LyTestTools/tests/unit/test_fixtures.py @@ -323,20 +323,19 @@ class TestFixtures(object): @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog') def test_CrashLogWatchdog_Instantiates_CreatesWatchdog(self, under_test): mock_workspace = mock.MagicMock() - mock_path = 'C:/foo' - mock_workspace.paths.project_log.return_value = mock_path + mock_workspace.paths.crash_log.return_value = mock.MagicMock() mock_request = mock.MagicMock() mock_request.addfinalizer = mock.MagicMock() mock_raise_on_crash = mock.MagicMock() mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash) - under_test.assert_called_once_with(os.path.join(mock_path, 'error.log'), raise_on_condition=mock_raise_on_crash) + under_test.assert_called_once_with(mock_workspace.paths.crash_log.return_value, raise_on_condition=mock_raise_on_crash) @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start') def test_CrashLogWatchdog_Instantiates_StartsThread(self, under_test): mock_workspace = mock.MagicMock() mock_path = 'C:/foo' - mock_workspace.paths.project_log.return_value = mock_path + mock_workspace.paths.crash_log.return_value = mock_path mock_request = mock.MagicMock() mock_request.addfinalizer = mock.MagicMock() mock_raise_on_crash = mock.MagicMock() @@ -348,7 +347,7 @@ class TestFixtures(object): def test_CrashLogWatchdog_Instantiates_AddsTeardown(self): mock_workspace = mock.MagicMock() mock_path = 'C:/foo' - mock_workspace.paths.project_log.return_value = mock_path + mock_workspace.paths.crash_log.return_value = mock_path mock_request = mock.MagicMock() mock_request.addfinalizer = mock.MagicMock() mock_raise_on_crash = mock.MagicMock() @@ -361,7 +360,7 @@ class TestFixtures(object): def test_CrashLogWatchdog_Teardown_CallsStop(self, mock_stop): mock_workspace = mock.MagicMock() mock_path = 'C:/foo' - mock_workspace.paths.project_log.return_value = mock_path + mock_workspace.paths.crash_log.return_value = mock_path mock_request = mock.MagicMock() mock_request.addfinalizer = mock.MagicMock() mock_raise_condition = mock.MagicMock() diff --git a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py index 2b6ae5b471..054159cd16 100644 --- a/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py +++ b/Tools/LyTestTools/tests/unit/test_o3de_editor_test.py @@ -589,6 +589,7 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) def test_ExecEditorTest_TestSucceeds_ReturnsPass(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_output_results, mock_create): @@ -616,6 +617,7 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) def test_ExecEditorTest_TestFails_ReturnsFail(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_output_results, mock_create): @@ -644,6 +646,8 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) + @mock.patch('os.path.basename', mock.MagicMock()) def test_ExecEditorTest_TestCrashes_ReturnsCrash(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_output_results, mock_retrieve_crash, mock_create): @@ -699,10 +703,14 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) def test_ExecEditorMultitest_AllTestsPass_ReturnsPasses(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_create): mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() mock_workspace = mock.MagicMock() + mock_artifact_manager = mock.MagicMock() + mock_artifact_manager.save_artifact.return_value = mock.MagicMock() + mock_workspace.artifact_manager = mock_artifact_manager mock_workspace.paths.engine_root.return_value = "" mock_editor = mock.MagicMock() mock_editor.get_returncode.return_value = 0 @@ -727,6 +735,7 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) def test_ExecEditorMultitest_OneFailure_CallsCorrectFunc(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_results): mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite() @@ -752,6 +761,8 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) + @mock.patch('os.path.basename', mock.MagicMock()) def test_ExecEditorMultitest_OneCrash_ReportsOnUnknownResult(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_results, mock_retrieve_crash, mock_create): @@ -787,6 +798,8 @@ class TestRunningTests(unittest.TestCase): @mock.patch('ly_test_tools.o3de.editor_test_utils.retrieve_log_path') @mock.patch('ly_test_tools.o3de.editor_test_utils.get_testcase_module_filepath') @mock.patch('ly_test_tools.o3de.editor_test_utils.cycle_crash_report') + @mock.patch('os.path.join', mock.MagicMock()) + @mock.patch('os.path.basename', mock.MagicMock()) def test_ExecEditorMultitest_ManyUnknown_ReportsUnknownResults(self, mock_cycle_crash, mock_get_testcase_filepath, mock_retrieve_log, mock_retrieve_editor_log, mock_get_results, mock_retrieve_crash, mock_create): diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index 7d98c3ea3e..1bea5f4f67 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -186,7 +186,7 @@ function(ly_add_external_target) endif() # Check if there is a pal file - ly_get_absolute_pal_filename(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + o3de_pal_dir(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) if(NOT EXISTS ${pal_file}) set(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) endif() @@ -357,12 +357,12 @@ endfunction() # Add the 3rdParty folder to find the modules list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/3rdParty) -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) list(APPEND CMAKE_MODULE_PATH ${pal_dir}) if(NOT INSTALLED_ENGINE) # Add the 3rdParty cmake files to the IDE ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake) - ly_get_absolute_pal_filename(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) endif() diff --git a/cmake/3rdParty/BuiltInPackages.cmake b/cmake/3rdParty/BuiltInPackages.cmake index 743e2e983e..e81cfffe01 100644 --- a/cmake/3rdParty/BuiltInPackages.cmake +++ b/cmake/3rdParty/BuiltInPackages.cmake @@ -12,9 +12,9 @@ # cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake #include the platform-specific 3rd party packages. -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) -set(LY_PAL_PACKAGE_FILE_NAME ${CMAKE_CURRENT_LIST_DIR}/${pal_dir}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +set(LY_PAL_PACKAGE_FILE_NAME ${pal_dir}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) include(${LY_PAL_PACKAGE_FILE_NAME}) # add the above file to the ALLFILES list, so that they show up in IDEs diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index f7bc2721ae..d174f935e2 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -8,11 +8,10 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) -ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) +ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) @@ -21,6 +20,7 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) # platform-specific: +ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev12-linux TARGETS assimplib PACKAGE_HASH 49d32e11c594e58a9079972ad63570dd895ac61e6148e428b9c39a62feb676ee) ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af) ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-linux TARGETS TIFF PACKAGE_HASH 2377f48b2ebc2d1628d9f65186c881544c92891312abe478a20d10b85877409a) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-linux TARGETS freetype PACKAGE_HASH 3f10c703d9001ecd2bb51a3bd003d3237c02d8f947ad0161c0252fdc54cbcf97) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index ea324a5cb7..95f7c89930 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -8,11 +8,10 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) -ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) +ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) @@ -21,6 +20,7 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) # platform-specific: +ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev12-mac TARGETS assimplib PACKAGE_HASH 12db03817553f607bee0d65b690bcaae748014f3ed9266b70384f463bc98c9d1) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 3f77367dbb0342136ec4ebbd44bc1fedf7198089a0f83c5631248530769b2be6) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-mac TARGETS SPIRVCross PACKAGE_HASH 78c6376ed2fd195b9b1f5fb2b56e5267a32c3aa21fb399e905308de470eb4515) ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-mac TARGETS TIFF PACKAGE_HASH c2615ccdadcc0e1d6c5ed61e5965c4d3a82193d206591b79b805c3b3ff35a4bf) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 5441bcd76f..1f7cb8d28f 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -8,11 +8,10 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) -ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) +ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) @@ -21,6 +20,7 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) # platform-specific: +ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev12-windows TARGETS assimplib PACKAGE_HASH 5273b7661a7a247bb18e8bc928d25c9cd1bd8ce9dfcc56c50742bac8fa02f0f2) ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 803e10b94006b834cbbdd30f562a8ddf04174c2cb6956c8399ec164ef8418d1f) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index d8dd7e8134..4b99efc9d0 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -18,7 +18,7 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS gla # platform-specific: ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-ios TARGETS TIFF PACKAGE_HASH e9067e88649fb6e93a926d9ed38621a9fae360a2e6f6eb24ebca63c1bc7761ea) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-ios TARGETS freetype PACKAGE_HASH 3ac3c35e056ae4baec2e40caa023d76a7a3320895ef172b6655e9261b0dc2e29) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-ios TARGETS AWSNativeSDK PACKAGE_HASH d10e7496ca705577032821011beaf9f2507689f23817bfa0ed4d2a2758afcd02) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.9.50-rev1-ios TARGETS AWSNativeSDK PACKAGE_HASH c3c9478c259ecb569fb2ce6fcfa733647adc3b6bd2854e8eff9de64bcd18c745) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-ios TARGETS Lua PACKAGE_HASH c2d3c4e67046c293049292317a7d60fdb8f23effeea7136aefaef667163e5ffe) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev5-ios TARGETS PhysX PACKAGE_HASH 4a5e38b385837248590018eb133444b4e440190414e6756191200a10c8fa5615) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a) diff --git a/cmake/3rdPartyPackages.cmake b/cmake/3rdPartyPackages.cmake index a3f15bdb22..f9a72672c0 100644 --- a/cmake/3rdPartyPackages.cmake +++ b/cmake/3rdPartyPackages.cmake @@ -614,7 +614,7 @@ endfunction() # and ensure the path to the package root is added to the find_package search paths. # For example # ly_associate_package(TARGETS zlib PACKAGE_NAME zlib-1.2.8-multiplatform PACKAGE_HASH e6f34b8ac16acf881e3d666ef9fd0c1aee94c3f69283fb6524d35d6f858eebbb) -# - this waill cause it to automatically download and activate this package if it finds a target that +# - this will cause it to automatically download and activate this package if it finds a target that # depends on '3rdParty::zlib' in its runtime or its build time dependency list. # - note that '3rdParty' is implied, do not specify it in the TARGETS list. function(ly_associate_package) @@ -684,6 +684,7 @@ endmacro() # is associated with a package, as above. If it is, it makes sure that the package # is brought into scope (and if necessary, downloaded.) macro(ly_download_associated_package find_library_name) + unset(package_name) ly_get_package_association(${find_library_name} package_name) if (package_name) # it is an associated package. diff --git a/cmake/Configurations.cmake b/cmake/Configurations.cmake index 51dee2f07b..709c81e3d2 100644 --- a/cmake/Configurations.cmake +++ b/cmake/Configurations.cmake @@ -189,5 +189,5 @@ foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) endforeach() # flags are defined per platform, follow platform files under Platform//Configurations_.cmake -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/Configurations_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/cmake/FileUtil.cmake b/cmake/FileUtil.cmake index 4607e14452..5721cf452c 100644 --- a/cmake/FileUtil.cmake +++ b/cmake/FileUtil.cmake @@ -26,8 +26,16 @@ function(ly_include_cmake_file_list file) include(${file}) get_filename_component(file_path "${file}" PATH) if(file_path) - list(TRANSFORM FILES PREPEND ${file_path}/) + foreach(f ${FILES}) + cmake_path(IS_RELATIVE f is_relative) + if(is_relative) + string(PREPEND f ${file_path}/) + endif() + list(APPEND TRANSFORMED_FILES ${f}) + endforeach() + set(FILES ${TRANSFORMED_FILES}) endif() + foreach(f ${FILES}) get_filename_component(absolute_path ${f} ABSOLUTE) if(NOT EXISTS ${absolute_path}) @@ -41,12 +49,19 @@ function(ly_include_cmake_file_list file) list(APPEND UNITY_AUTO_EXCLUSIONS ${f}) endif() endif() - endforeach() + list(APPEND FILES ${file}) # Add the _files.cmake to the list so it shows in the IDE if(file_path) - list(TRANSFORM SKIP_UNITY_BUILD_INCLUSION_FILES PREPEND ${file_path}/) + foreach(f ${SKIP_UNITY_BUILD_INCLUSION_FILES}) + cmake_path(IS_RELATIVE f is_relative) + if(is_relative) + string(PREPEND f ${file_path}/) + endif() + list(APPEND SKIP_UNITY_BUILD_INCLUSION_TRANSFORMED_FILES ${f}) + endforeach() + set(SKIP_UNITY_BUILD_INCLUSION_FILES ${SKIP_UNITY_BUILD_INCLUSION_TRANSFORMED_FILES}) endif() # Check if there are any files to exclude from unity groupings diff --git a/cmake/Install.cmake b/cmake/Install.cmake index b558590b9e..55f56b05e8 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -30,7 +30,7 @@ function(ly_install) install(CODE "endif()\n" ALL_COMPONENTS) else() install(${ARGN}) - endif() + endif() endfunction() @@ -195,6 +195,6 @@ function(ly_install_run_script SCRIPT) endfunction() if(LY_INSTALL_ENABLED) - ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) + o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) endif() diff --git a/cmake/LYTestWrappers.cmake b/cmake/LYTestWrappers.cmake index 03146b6045..9f4cd41a47 100644 --- a/cmake/LYTestWrappers.cmake +++ b/cmake/LYTestWrappers.cmake @@ -141,7 +141,7 @@ function(ly_add_test) set(wrapper_file ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/LYTestWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(NOT EXISTS ${wrapper_file}) - ly_get_absolute_pal_filename(wrapper_file ${wrapper_file}) + o3de_pal_dir(wrapper_file ${wrapper_file} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) endif() include(${wrapper_file}) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index d4bf1d7423..a2f4359fd5 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -11,7 +11,7 @@ set(LY_UNITY_BUILD ON CACHE BOOL "UNITY builds") include(CMakeFindDependencyMacro) include(cmake/LyAutoGen.cmake) -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/LYWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # Not all platforms support unity builds diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index 67ed17b6d4..ef431ff92a 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -15,67 +15,207 @@ # PAL_PLATFORM_NAME_LOWERCASE: name of the platform in lower case (part of filenames) # -file(GLOB detection_files "cmake/Platform/*/PALDetection_*.cmake") -foreach(detection_file ${detection_files}) - include(${detection_file}) -endforeach() - - -#! o3de_restricted_id: Reads the "restricted" key from the o3de manifest +#! o3de_get_home_path: returns the home path # -# \arg:o3de_json_file name of the o3de json file to read the "restricted_name" key from -# \arg:restricted returns the restricted association element from an o3de json, otherwise engine 'o3de' is assumed -# \arg:o3de_json_file name of the o3de json file -function(o3de_restricted_id o3de_json_file restricted) - ly_file_read(${o3de_json_file} json_data) - string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted_name") +# \arg:o3de_manifest_path returns the path of the manifest +function(o3de_get_home_path o3de_home_path) + # The o3de_manifest.json is in the home directory / .o3de folder + file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_path) # Windows + if(NOT EXISTS ${home_path}) + file(TO_CMAKE_PATH "$ENV{HOME}" home_path) # Unix + if (NOT EXISTS ${home_path}) + message(FATAL_ERROR "o3de Home path not found") + endif() + endif() + set(${o3de_home_path} ${home_path} PARENT_SCOPE) +endfunction() + +#! o3de_get_manifest_path: returns the path to the manifest +# +# \arg:o3de_manifest_path returns the path of the manifest +function(o3de_get_manifest_path o3de_manifest_path) + # The o3de_manifest.json is in the home directory / .o3de folder + o3de_get_home_path(o3de_home_path) + set(${o3de_manifest_path} ${o3de_home_path}/.o3de/o3de_manifest.json PARENT_SCOPE) +endfunction() + +#! o3de_read_manifest: returns the contents of the manifest +# +# \arg:restricted_subdirs returns the restricted elements from the manifest +function(o3de_read_manifest o3de_manifest_json_data) + #get the manifest path + o3de_get_manifest_path(o3de_manifest_path) + if(EXISTS ${o3de_manifest_path}) + ly_file_read(${o3de_manifest_path} json_data) + set(${o3de_manifest_json_data} ${json_data} PARENT_SCOPE) + endif() +endfunction() + +#! o3de_recurse_gems: returns the gem paths +# +# \arg:object json path +# \arg:gems returns the gems from the external subdirectory elements from the manifest +function(o3de_recurse_gems object_json_path gems) + get_filename_component(object_json_parent_path ${object_json_path} DIRECTORY) + ly_file_read(${object_json_path} json_data) + string(JSON external_subdirectories_count ERROR_VARIABLE json_error LENGTH ${json_data} "external_subdirectories") + if(NOT json_error) + if(external_subdirectories_count GREATER 0) + math(EXPR external_subdirectories_range "${external_subdirectories_count}-1") + foreach(external_subdirectories_index RANGE ${external_subdirectories_range}) + string(JSON external_subdirectories_entry ERROR_VARIABLE json_error GET ${json_data} "external_subdirectories" "${external_subdirectories_index}") + cmake_path(IS_RELATIVE external_subdirectories_entry is_relative) + if(${is_relative}) + cmake_path(ABSOLUTE_PATH external_subdirectories_entry BASE_DIRECTORY ${object_json_parent_path} NORMALIZE OUTPUT_VARIABLE external_subdirectories_entry) + endif() + if(EXISTS ${external_subdirectories_entry}/gem.json) + list(APPEND gem_entries ${external_subdirectories_entry}) + o3de_recurse_gems(${external_subdirectories_entry}/gem.json gem_entries) + endif() + endforeach() + endif() + endif() + set(${gems} ${gem_entries} PARENT_SCOPE) +endfunction() + +#! o3de_find_gem: returns the gem path +# +# \arg:gem_name the gem name to find +# \arg:the path of the gem +function(o3de_find_gem gem_name gem_path) + o3de_get_manifest_path(manifest_path) + if(EXISTS ${manifest_path}) + o3de_recurse_gems(${manifest_path} gems) + endif() + o3de_recurse_gems(${LY_ROOT_FOLDER}/engine.json gems) + foreach(gem ${gems}) + ly_file_read(${gem}/gem.json json_data) + string(JSON gem_json_name ERROR_VARIABLE json_error GET ${json_data} "gem_name") + if(gem_json_name STREQUAL gem_name) + set(${gem_path} ${gem} PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() + +#! o3de_manifest_restricted: returns the manifests restricted paths +# +# \arg:restricted returns the restricted elements from the manifest +function(o3de_manifest_restricted restricted) + #read the manifest + o3de_read_manifest(o3de_manifest_json_data) + string(JSON restricted_count ERROR_VARIABLE json_error LENGTH ${o3de_manifest_json_data} "restricted") if(json_error) # Restricted fields can never be a requirement so no warning is issued return() endif() - if(restricted_entry) - set(${restricted} ${restricted_entry} PARENT_SCOPE) + if(restricted_count GREATER 0) + math(EXPR restricted_range "${restricted_count}-1") + foreach(restricted_index RANGE ${restricted_range}) + string(JSON restricted_entry ERROR_VARIABLE json_error GET ${o3de_manifest_json_data} "restricted" "${restricted_index}") + list(APPEND restricted_entries ${restricted_entry}) + endforeach() endif() + set(${restricted} ${restricted_entries} PARENT_SCOPE) +endfunction() + +#! o3de_json_restricted: returns the restricted element from a json +# +# \arg:restricted returns the restricted element of the json +function(o3de_json_restricted json_path restricted) + if(EXISTS ${json_path}) + ly_file_read(${json_path} json_data) + string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted") + if(json_error) + # Restricted fields can never be a requirement so no warning is issued + return() + endif() + set(${restricted} ${restricted_entry} PARENT_SCOPE) + endif() +endfunction() + +#! o3de_restricted_id: determines the restricted object for this json +# +# Find this objects restricted name. If the object has a "restricted" element +# If it does not have one it inherits its parents "restricted" element if it has one +# If the parent does not have one it inherits its parents parent "restricted" element is it has one and so on... +# We stop looking if the object or parent is in the manifest, as the manifest only has top level objects +# which means they have no children. +# +# \arg:o3de_json_file name of the o3de json file to read the "restricted" key from +# \arg:restricted returns the restricted association element from an o3de json, otherwise its doesnt change anything +# \arg:o3de_json_file name of the o3de json file +function(o3de_restricted_id o3de_json_file restricted parent_relative_path) + # read the passed in o3de json and see if "restricted" is set + o3de_json_restricted(${o3de_json_file} restricted_name) + if(restricted_name) + set(${parent_relative_path} "" PARENT_SCOPE) + set(${restricted} ${restricted_name} PARENT_SCOPE) + return() + endif() + + # This object did not have a "restricted" set, now we must look at the parent + # Stop if this is a top level object + o3de_manifest_restricted(manifest_restricted_paths) + cmake_path(GET o3de_json_file PARENT_PATH o3de_json_file_parent) + cmake_path(GET o3de_json_file_parent FILENAME relative_path) + cmake_path(GET o3de_json_file_parent PARENT_PATH o3de_json_file_parent) + if(${o3de_json_file_parent} IN_LIST manifest_restricted_paths) + set(${parent_relative_path} "" PARENT_SCOPE) + set(${restricted} "" PARENT_SCOPE) + return() + endif() + + set(is_prev_path_segment TRUE) + while(is_prev_path_segment) + if(EXISTS ${o3de_json_file_parent}/engine.json) + o3de_json_restricted(${o3de_json_file_parent}/engine.json restricted_name) + if(restricted_name) + set(${parent_relative_path} ${relative_path} PARENT_SCOPE) + set(${restricted} ${restricted_name} PARENT_SCOPE) + return() + endif() + endif() + if(EXISTS ${o3de_json_file_parent}/project.json) + o3de_json_restricted(${o3de_json_file_parent}/project.json restricted_name) + if(restricted_name) + set(${parent_relative_path} ${relative_path} PARENT_SCOPE) + set(${restricted} ${restricted_name} PARENT_SCOPE) + return() + endif() + endif() + if(EXISTS ${o3de_json_file_parent}/gem.json) + o3de_json_restricted(${o3de_json_file_parent}/gem.json restricted_name) + if(restricted_name) + set(${parent_relative_path} ${relative_path} PARENT_SCOPE) + set(${restricted} ${restricted_name} PARENT_SCOPE) + return() + endif() + endif() + + if(${o3de_json_file_parent} IN_LIST manifest_restricted_paths) + set(${parent_relative_path} "" PARENT_SCOPE) + set(${restricted} "" PARENT_SCOPE) + return() + endif() + + # Remove one path segment from the end of the o3de json candidate path + cmake_path(GET o3de_json_file_parent PARENT_PATH parent_path) + cmake_path(GET o3de_json_file_parent FILENAME path_segment) + cmake_path(COMPARE "${o3de_json_file_parent}" NOT_EQUAL "${parent_path}" is_prev_path_segment) + cmake_path(SET o3de_json_file_parent "${parent_path}") + cmake_path(SET relative_path "${path_segment}/${relative_path}") + endwhile() endfunction() #! o3de_find_restricted_folder: # -# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_path returns the path of the o3de restricted folder using the restricted_name # \arg:restricted_name name of the restricted function(o3de_find_restricted_folder restricted_name restricted_path) - # Read the restricted path from engine.json if one EXISTS - ly_file_read(${LY_ROOT_FOLDER}/engine.json engine_json_data) - string(JSON restricted_subdirs_count ERROR_VARIABLE engine_json_error LENGTH ${engine_json_data} "restricted") - if(restricted_subdirs_count GREATER 0) - string(JSON restricted_subdir ERROR_VARIABLE engine_json_error GET ${engine_json_data} "restricted" "0") - set(${restricted_path} ${restricted_subdir} PARENT_SCOPE) - return() - endif() - - - file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows - if(NOT EXISTS ${home_directory}) - file(TO_CMAKE_PATH "$ENV{HOME}" home_directory) # Unix - if (NOT EXISTS ${home_directory}) - return() - endif() - endif() - - # Examine the o3de manifest file for the list of restricted directories - set(o3de_manifest_path ${home_directory}/.o3de/o3de_manifest.json) - if(EXISTS ${o3de_manifest_path}) - ly_file_read(${o3de_manifest_path} o3de_manifest_json_data) - string(JSON restricted_subdirs_count ERROR_VARIABLE engine_json_error LENGTH ${o3de_manifest_json_data} "restricted") - if(restricted_subdirs_count GREATER 0) - math(EXPR restricted_subdirs_range "${restricted_subdirs_count}-1") - foreach(restricted_subdir_index RANGE ${restricted_subdirs_range}) - string(JSON restricted_subdir ERROR_VARIABLE engine_json_error GET ${o3de_manifest_json_data} "restricted" "${restricted_subdir_index}") - list(APPEND restricted_subdirs ${restricted_subdir}) - endforeach() - endif() - endif() + o3de_manifest_restricted(restricted_entries) # Iterate over the restricted directories from the manifest file - foreach(restricted_entry ${restricted_subdirs}) + foreach(restricted_entry ${restricted_entries}) set(restricted_json_file ${restricted_entry}/restricted.json) ly_file_read(${restricted_json_file} restricted_json) string(JSON this_restricted_name ERROR_VARIABLE json_error GET ${restricted_json} "restricted_name") @@ -94,31 +234,34 @@ endfunction() #! o3de_restricted_path: # # \arg:o3de_json_file json file to read restricted id from -# \arg:restricted_name name of the restricted object -function(o3de_restricted_path o3de_json_file restricted_path) - o3de_restricted_id(${o3de_json_file} restricted_name) +# \arg:restricted_path output path of the restricted object +# \arg:parent_relative_path optional output of the path relative to the parent +function(o3de_restricted_path o3de_json_file restricted_path) #parent_relative_path + o3de_restricted_id(${o3de_json_file} restricted_name parent_relative) + if(${ARGC} GREATER 2) + set(${ARGV2} ${parent_relative} PARENT_SCOPE) + endif() if(restricted_name) o3de_find_restricted_folder(${restricted_name} restricted_folder) if(restricted_folder) set(${restricted_path} ${restricted_folder} PARENT_SCOPE) + else() + get_filename_component(o3de_json_file_parent ${o3de_json_file} DIRECTORY) + set(${restricted_path} ${o3de_json_file_parent}/restricted PARENT_SCOPE) endif() endif() endfunction() -#! read_engine_restricted_path: Locates the restricted path within the engine from a json file -# -# \arg:output_restricted_path returns the path of the o3de restricted folder with name restricted_name -function(read_engine_restricted_path output_restricted_path) - # Set manifest path to path in the user home directory - set(manifest_path ${LY_ROOT_FOLDER}/engine.json) - if(EXISTS ${manifest_path}) - o3de_restricted_path(${manifest_path} read_restricted_path) - set(${output_restricted_path} ${read_restricted_path} PARENT_SCOPE) - endif() -endfunction() +# detect open platforms +file(GLOB detection_files "cmake/Platform/*/PALDetection_*.cmake") +foreach(detection_file ${detection_files}) + include(${detection_file}) +endforeach() -read_engine_restricted_path(O3DE_ENGINE_RESTRICTED_PATH) +# set the O3DE_ENGINE_RESTRICTED_PATH +o3de_restricted_path(${LY_ROOT_FOLDER}/engine.json O3DE_ENGINE_RESTRICTED_PATH) +# detect platforms in the restricted path file(GLOB detection_files ${O3DE_ENGINE_RESTRICTED_PATH}/*/cmake/PALDetection_*.cmake) foreach(detection_file ${detection_files}) include(${detection_file}) @@ -146,21 +289,16 @@ foreach(pal_restricted_file ${pal_restricted_files}) string(TOLOWER ${platform} platform_lower) list(APPEND PAL_RESTRICTED_PLATFORMS ${platform_lower}) endforeach() +list(REMOVE_DUPLICATES PAL_RESTRICTED_PLATFORMS) + ly_set(PAL_RESTRICTED_PLATFORMS ${PAL_RESTRICTED_PLATFORMS}) function(ly_get_absolute_pal_filename out_name in_name) - set(full_name ${in_name}) + message(DEPRECATION "ly_get_list_relative_pal_filename is being deprecated, change your code to use o3de_pal_dir instead.") + # parent relative path is optional if(${ARGC} GREATER 4) - # The object name is used to resolve ambiguities when a PAL directory is requested from - # two different external subdirectory root paths - # Such as if a PAL directory for two root object paths with same relative structure was requested to be Palified - # i.e /Platform//IO and /Platform//IO - # Normally the restricted PAL path for both gems would be "//IO". - # The object name can be used to make this path unique - # "///IO" for gem 1 and - # "///IO" for gem 2 - set(object_name ${ARGV4}) + set(parent_relative_path ${ARGV4}) endif() # The Default object path for path is the LY_ROOT_FOLDER @@ -170,14 +308,30 @@ function(ly_get_absolute_pal_filename out_name in_name) cmake_path(SET object_path NORMALIZE ${ARGV3}) endif() - # The Default restricted object path is the result of the read_engine_restricted_path function + # The default restricted object path is O3DE_ENGINE_RESTRICTED_PATH cmake_path(SET object_restricted_path NORMALIZE "${O3DE_ENGINE_RESTRICTED_PATH}") if(${ARGC} GREATER 2) # The user has supplied an object restricted path cmake_path(SET object_restricted_path NORMALIZE ${ARGV2}) endif() - # The input path must exist in order to form a PAL path + if(${ARGC} GREATER 4) + o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path} ${parent_relative_path}) + else() + o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path}) + endif() + set(${out_name} ${abs_name} PARENT_SCOPE) +endfunction() + +function(o3de_pal_dir out_name in_name object_restricted_path object_path) #parent_relative_path) + set(full_name ${in_name}) + + # parent relative path is optional + if(${ARGC} GREATER 4) + set(parent_relative_path ${ARGV4}) + endif() + + # The input path must not exist in order to form a restricted PAL path if (NOT EXISTS ${full_name}) # if the file is not in the object path then we cannot determine a PAL file for it cmake_path(IS_PREFIX object_path ${full_name} is_input_path_in_root) @@ -189,7 +343,7 @@ function(ly_get_absolute_pal_filename out_name in_name) cmake_path(GET current_object_path PARENT_PATH parent_path) cmake_path(GET current_object_path FILENAME path_segment) list(PREPEND path_segments_visited ${path_segment}) - cmake_path(COMPARE current_object_path NOT_EQUAL parent_path is_prev_path_segment) + cmake_path(COMPARE "${current_object_path}" NOT_EQUAL "${parent_path}" is_prev_path_segment) cmake_path(SET current_object_path "${parent_path}") set(is_prev_path_segment TRUE) @@ -197,7 +351,7 @@ function(ly_get_absolute_pal_filename out_name in_name) # Remove one path segment from the end of the current_object_path and prepend it to the list path_segments cmake_path(GET current_object_path PARENT_PATH parent_path) cmake_path(GET current_object_path FILENAME path_segment) - cmake_path(COMPARE current_object_path NOT_EQUAL parent_path is_prev_path_segment) + cmake_path(COMPARE "${current_object_path}" NOT_EQUAL "${parent_path}" is_prev_path_segment) cmake_path(SET current_object_path "${parent_path}") # The Path is in a PAL structure # Decompose the path into sections before "Platform" and after "Platform" @@ -222,7 +376,7 @@ function(ly_get_absolute_pal_filename out_name in_name) if(NOT EXISTS ${candidate_PAL_path}) string(TOLOWER ${candidate_platform_name} candidate_platform_name_lower) if("${candidate_platform_name_lower}" IN_LIST PAL_RESTRICTED_PLATFORMS) - cmake_path(APPEND object_restricted_path ${candidate_platform_name} ${object_name} + cmake_path(APPEND object_restricted_path ${candidate_platform_name} ${parent_relative_path} ${pre_platform_paths} OUTPUT_VARIABLE candidate_PAL_path) endif() endif() @@ -236,17 +390,43 @@ function(ly_get_absolute_pal_filename out_name in_name) endfunction() function(ly_get_list_relative_pal_filename out_name in_name) - ly_get_absolute_pal_filename(abs_name ${in_name} ${ARGN}) + message(DEPRECATION "ly_get_list_relative_pal_filename is being deprecated, change your code to use o3de_pal_dir instead.") + + # parent relative path is optional + if(${ARGC} GREATER 4) + set(parent_relative_path ${ARGV4}) + endif() + + # The Default object path for path is the LY_ROOT_FOLDER + cmake_path(SET object_path NORMALIZE "${LY_ROOT_FOLDER}") + if(${ARGC} GREATER 3) + # The user has supplied an object restricted path, the object path for consideration + cmake_path(SET object_path NORMALIZE ${ARGV3}) + endif() + + # The default restricted object path is O3DE_ENGINE_RESTRICTED_PATH + cmake_path(SET object_restricted_path NORMALIZE "${O3DE_ENGINE_RESTRICTED_PATH}") + if(${ARGC} GREATER 2) + # The user has supplied an object restricted path + cmake_path(SET object_restricted_path NORMALIZE ${ARGV2}) + endif() + + if(${ARGC} GREATER 4) + o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path} ${parent_relative_path}) + else() + o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path}) + endif() + cmake_path(RELATIVE_PATH abs_name BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE relative_name) set(${out_name} ${relative_name} PARENT_SCOPE) endfunction() -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) -ly_include_cmake_file_list(${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) +ly_include_cmake_file_list(${pal_cmake_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) -include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) -include(${pal_dir}/Toolchain_${PAL_PLATFORM_NAME_LOWERCASE}.cmake OPTIONAL) +include(${pal_cmake_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +include(${pal_cmake_dir}/Toolchain_${PAL_PLATFORM_NAME_LOWERCASE}.cmake OPTIONAL) set(LY_DISABLE_TEST_MODULES FALSE CACHE BOOL "Option to forcibly disable the inclusion of test targets in the build") diff --git a/cmake/PALTools.cmake b/cmake/PALTools.cmake index 2204abf5ae..88e827f9c2 100644 --- a/cmake/PALTools.cmake +++ b/cmake/PALTools.cmake @@ -35,14 +35,14 @@ ly_set(LY_PAL_TOOLS_DEFINES ${LY_PAL_TOOLS_DEFINES}) # Include files to the CMakeFiles project foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${enabled_platform}) + o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${enabled_platform}) ly_include_cmake_file_list(${pal_dir}/pal_tools_${enabled_platform_lowercase}_files.cmake) endforeach() function(ly_get_pal_tool_dirs out_list pal_path) set(pal_paths "") foreach(platform ${LY_PAL_TOOLS_ENABLED}) - ly_get_absolute_pal_filename(path ${pal_path}/${platform}) + o3d_pal_dir(path ${pal_path}/${platform} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) list(APPEND pal_paths ${path}) endforeach() set(${out_list} ${pal_paths} PARENT_SCOPE) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index ecef5261b1..81409369dc 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -73,7 +73,7 @@ set(CPACK_PROJECT_CONFIG_FILE ${CPACK_SOURCE_DIR}/PackagingConfig.cmake) set(CPACK_AUTO_GEN_TAG ${LY_INSTALLER_AUTO_GEN_TAG}) # attempt to apply platform specific settings -ly_get_absolute_pal_filename(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/Packaging_${PAL_HOST_PLATFORM_NAME_LOWERCASE}.cmake) # if we get here and the generator hasn't been set, then a non fatal error occurred disabling packaging support diff --git a/cmake/Platform/Linux/CompilerSettings_linux.cmake b/cmake/Platform/Linux/CompilerSettings_linux.cmake index 9bb629c53b..a1a632e957 100644 --- a/cmake/Platform/Linux/CompilerSettings_linux.cmake +++ b/cmake/Platform/Linux/CompilerSettings_linux.cmake @@ -19,7 +19,7 @@ if(NOT CMAKE_C_COMPILER AND NOT CMAKE_CXX_COMPILER AND NOT "$ENV{CC}" AND NOT "$ file(GLOB clang_versions ${path_search}) if(clang_versions) # Find and pick the highest installed version - list(SORT clang_versions COMPARE NATURAL) + list(SORT clang_versions COMPARE NATURAL ORDER DESCENDING) list(GET clang_versions 0 clang_higher_version_path) string(REGEX MATCH "clang-([0-9.]*)" clang_higher_version ${clang_higher_version_path}) if(CMAKE_MATCH_1) diff --git a/cmake/Platform/Mac/InstallUtils_mac.cmake.in b/cmake/Platform/Mac/InstallUtils_mac.cmake.in index 3db9903e48..9be6338752 100644 --- a/cmake/Platform/Mac/InstallUtils_mac.cmake.in +++ b/cmake/Platform/Mac/InstallUtils_mac.cmake.in @@ -43,7 +43,7 @@ function(fixup_python_framework framework_path) file(GLOB_RECURSE exe_file_list "${framework_path}/**/*.exe") if(exe_file_list) - file(REMOVE_RECURSE "${exe_file_list}") + file(REMOVE_RECURSE ${exe_file_list}) endif() execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink include/python@LY_PYTHON_VERSION_MAJOR_MINOR@m Headers WORKING_DIRECTORY "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@" diff --git a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in index 51e6e5830c..fff816cb3e 100644 --- a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in +++ b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in @@ -187,7 +187,7 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS") ) file(GLOB_RECURSE exe_file_list "${bundle_path}/Contents/Frameworks/Python.framework/**/*.exe") if(exe_file_list) - file(REMOVE_RECURSE "${exe_file_list}") + file(REMOVE_RECURSE ${exe_file_list}) endif() execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink include/python3.7m Headers WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7" @@ -216,7 +216,7 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS") # fixup bundle ends up removing the rpath of dxc (despite we exclude it) if(EXISTS "${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7") - execute_process(COMMAND $"{LY_INSTALL_NAME_TOOL}" -add_rpath @executable_path/../lib ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) + execute_process(COMMAND "${LY_INSTALL_NAME_TOOL}" -add_rpath @executable_path/../lib ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) endif() # misplaced .DS_Store files can cause signing to fail diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 13161c9e0f..c6aa6c382a 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -118,17 +118,27 @@ function(ly_generate_project_build_path_setreg project_real_path) file(GENERATE OUTPUT ${project_user_build_path_setreg_file} CONTENT ${project_build_path_setreg_content}) endfunction() +function(add_gem_json_external_subdirectories gem_path) + set(gem_json_path ${gem_path}/gem.json) + if(EXISTS ${gem_json_path}) + read_json_external_subdirs(gem_external_subdirs ${gem_path}/gem.json) + foreach(gem_external_subdir ${gem_external_subdirs}) + file(REAL_PATH ${gem_external_subdir} real_external_subdir BASE_DIRECTORY ${gem_path}) + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${real_external_subdir}) + add_gem_json_external_subdirectories(${real_external_subdir}) + endforeach() + endif() +endfunction() function(add_project_json_external_subdirectories project_path) set(project_json_path ${project_path}/project.json) if(EXISTS ${project_json_path}) - read_json_external_subdirs(external_subdirs ${project_path}/project.json) - foreach(external_subdir ${external_subdirs}) - file(REAL_PATH ${external_subdir} real_external_subdir BASE_DIRECTORY ${project_path}) - list(APPEND project_external_subdirs ${real_external_subdir}) + read_json_external_subdirs(project_external_subdirs ${project_path}/project.json) + foreach(project_external_subdir ${project_external_subdirs}) + file(REAL_PATH ${project_external_subdir} real_external_subdir BASE_DIRECTORY ${project_path}) + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${real_external_subdir}) + add_gem_json_external_subdirectories(${real_external_subdir}) endforeach() - - set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${project_external_subdirs}) endif() endfunction() diff --git a/cmake/RuntimeDependencies.cmake b/cmake/RuntimeDependencies.cmake index 9cc7315b08..d36789791f 100644 --- a/cmake/RuntimeDependencies.cmake +++ b/cmake/RuntimeDependencies.cmake @@ -6,6 +6,6 @@ # # -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/RuntimeDependencies_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/engine.json b/engine.json index 737ac24fea..51b6738001 100644 --- a/engine.json +++ b/engine.json @@ -1,6 +1,6 @@ { "engine_name": "o3de", - "restricted_name": "o3de", + "restricted": "o3de", "FileVersion": 1, "O3DEVersion": "0.0.0.0", "O3DECopyrightYear": 2021, diff --git a/scripts/o3de/CMakeLists.txt b/scripts/o3de/CMakeLists.txt index 79836305c0..fced0f7727 100644 --- a/scripts/o3de/CMakeLists.txt +++ b/scripts/o3de/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory(tests) -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) include(${pal_dir}/o3de_install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ly_install_files(FILES ../o3de.py diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index ec970d06f4..7a820a9677 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -235,14 +235,22 @@ def get_enabled_gem_cmake_file(project_name: str = None, enable_gem_filename = "enabled_gems.cmake" if platform == 'Common': - project_code_dir = project_path / 'Gem/Code' - if project_code_dir.is_dir(): - dependencies_file_path = project_code_dir / enable_gem_filename - return dependencies_file_path.resolve() - return (project_path / 'Code' / enable_gem_filename).resolve() + possible_project_enable_gem_filename_paths = [ + pathlib.Path(project_path / 'Gem' / enable_gem_filename), + pathlib.Path(project_path / 'Gem/Code' / enable_gem_filename), + pathlib.Path(project_path / 'Code' / enable_gem_filename) + ] + for possible_project_enable_gem_filename_path in possible_project_enable_gem_filename_paths: + if possible_project_enable_gem_filename_path.is_file(): + return possible_project_enable_gem_filename_path.resolve() + return possible_project_enable_gem_filename_paths[0].resolve() else: - project_code_dir = project_path / 'Gem/Code/Platform' / platform - if project_code_dir.is_dir(): - dependencies_file_path = project_code_dir / enable_gem_filename - return dependencies_file_path.resolve() - return (project_path / 'Code/Platform' / platform / enable_gem_filename).resolve() + possible_project_platform_enable_gem_filename_paths = [ + pathlib.Path(project_path / 'Gem/Platform' / platform / enable_gem_filename), + pathlib.Path(project_path / 'Gem/Code/Platform' / platform / enable_gem_filename), + pathlib.Path(project_path / 'Code/Platform' / platform / enable_gem_filename) + ] + for possible_project_platform_enable_gem_filename_path in possible_project_platform_enable_gem_filename_paths: + if possible_project_platform_enable_gem_filename_path.is_file(): + return possible_project_platform_enable_gem_filename_path.resolve() + return possible_project_platform_enable_gem_filename_paths[0].resolve() diff --git a/scripts/o3de/o3de/disable_gem.py b/scripts/o3de/o3de/disable_gem.py index 0b0e465d12..eecc765d32 100644 --- a/scripts/o3de/o3de/disable_gem.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -98,9 +98,6 @@ def disable_gem_in_project(gem_name: str = None, def _run_disable_gem_in_project(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - return disable_gem_in_project(args.gem_name, args.gem_path, args.project_name, @@ -133,9 +130,6 @@ def add_parser_args(parser): help='The cmake enabled gem file in which gem names are to be removed from.' 'If not specified it will assume ') - parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, - help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_disable_gem_in_project) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 8e28561e50..a7d5b56440 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -277,9 +277,6 @@ def is_o3de_restricted_update_available(restricted_name: str, local_last_updated return is_o3de_object_update_available(restricted_name, 'restricted_name', local_last_updated) def _run_download(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - if args.engine_name: return download_engine(args.engine_name, args.dest_path, @@ -331,8 +328,6 @@ def add_parser_args(parser): parser.add_argument('-f', '--force', action='store_true', required=False, default=False, help = 'Force overwrite the current object') - parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, - help='By default the home folder is the user folder, override it to this folder.') parser.set_defaults(func=_run_download) diff --git a/scripts/o3de/o3de/enable_gem.py b/scripts/o3de/o3de/enable_gem.py index fc4dc6e9cf..ea79f6c73f 100644 --- a/scripts/o3de/o3de/enable_gem.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -115,9 +115,6 @@ def enable_gem_in_project(gem_name: str = None, def _run_enable_gem_in_project(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - return enable_gem_in_project(args.gem_name, args.gem_path, args.project_name, @@ -150,9 +147,6 @@ def add_parser_args(parser): help='The cmake enabled_gem file in which the gem names are specified.' 'If not specified it will assume enabled_gems.cmake') - parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, - help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_enable_gem_in_project) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 6b2e098cf0..d9993fb5d0 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -80,10 +80,20 @@ restricted_platforms = { 'Provo', 'Salem', 'Jasper', - 'Paris' + 'Paris', + 'Xenia', + 'Lancaster' } -template_file_name = 'template.json' +O3DE_LICENSE_TEXT = \ + """'# {BEGIN_LICENSE} +# 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 +# {END_LICENSE} +""" + this_script_parent = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) @@ -165,7 +175,8 @@ def _execute_template_json(json_data: dict, destination_path: pathlib.Path, template_path: pathlib.Path, replacements: list, - keep_license_text: bool = False) -> None: + keep_license_text: bool = False, + keep_restricted_in_instance: bool = False) -> None: # create dirs first # for each createDirectory entry, transform the folder name for create_directory in json_data['createDirectories']: @@ -174,6 +185,18 @@ def _execute_template_json(json_data: dict, # transform the folder name new_dir = _transform(new_dir.as_posix(), replacements, keep_license_text) + new_dir = pathlib.Path(new_dir) + + if not keep_restricted_in_instance and 'Platform' in new_dir.parts: + try: + # the name of the Platform should follow the '/Platform/' + pattern = r'/Platform/(?P[^/:*?\"<>|\r\n]+/?)' + found_platform = re.search(pattern, new_dir.as_posix()).group('Platform') + found_platform = found_platform.replace('/', '') + if found_platform in restricted_platforms: + continue + except Exception as e: + pass # create the folder os.makedirs(new_dir, exist_ok=True) @@ -184,16 +207,23 @@ def _execute_template_json(json_data: dict, # construct the input file name in_file = template_path / 'Template' / copy_file['file'] - # the file can be marked as optional, if it is and it does not exist skip - if copy_file['isOptional'] and copy_file['isOptional'] == 'true': - if not os.path.isfile(in_file): - continue - # construct the output file name out_file = destination_path / copy_file['file'] # transform the output file name out_file = _transform(out_file.as_posix(), replacements, keep_license_text) + out_file = pathlib.Path(out_file) + + if not keep_restricted_in_instance and 'Platform' in out_file.parts: + try: + # the name of the Platform should follow the '/Platform/' + pattern = r'/Platform/(?P[^/:*?\"<>|\r\n]+/?)' + found_platform = re.search(pattern, out_file.as_posix()).group('Platform') + found_platform = found_platform.replace('/', '') + if found_platform in restricted_platforms: + continue + except Exception as e: + pass # if for some reason the output folder for this file was not created above do it now os.makedirs(os.path.dirname(out_file), exist_ok=True) @@ -205,18 +235,20 @@ def _execute_template_json(json_data: dict, shutil.copy(in_file, out_file) -def _execute_restricted_template_json(json_data: dict, +def _execute_restricted_template_json(template_json_data: dict, + json_data: dict, restricted_platform: str, destination_name, - template_name, destination_path: pathlib.Path, destination_restricted_path: pathlib.Path, + template_path: pathlib.Path, template_restricted_path: pathlib.Path, destination_restricted_platform_relative_path: pathlib.Path, template_restricted_platform_relative_path: pathlib.Path, replacements: list, keep_restricted_in_instance: bool = False, keep_license_text: bool = False) -> None: + # if we are not keeping restricted in instance make restricted.json if not present if not keep_restricted_in_instance: restricted_json = destination_restricted_path / 'restricted.json' @@ -227,50 +259,96 @@ def _execute_restricted_template_json(json_data: dict, restricted_json_data.update({"restricted_name": destination_name}) s.write(json.dumps(restricted_json_data, indent=4) + '\n') + ################################################################################### + # for each createDirectories in the template copy any entries in the json_data that are for this platform + for create_directory in template_json_data['createDirectories']: + new_dir = pathlib.Path(create_directory['dir']) + if not keep_restricted_in_instance and 'Platform' in new_dir.parts: + try: + # the name of the Platform should follow the '/Platform/' + pattern = r'/Platform/(?P[^/:*?\"<>|\r\n]+/?)' + found_platform = re.search(pattern, new_dir.as_posix()).group('Platform') + except Exception as e: + pass + else: + found_platform = found_platform.replace('/', '') + if found_platform == restricted_platform: + create_dirs = [] + if 'createDirectories' in json_data.keys(): + create_dirs = json_data['createDirectories'] + create_dirs.append(create_directory) + json_data.update({'createDirectories': create_dirs}) + + # for each copyFiles in the template copy any entries in the json_data that are for this platform + for copy_file in template_json_data['copyFiles']: + new_file = pathlib.Path(copy_file['file']) + if not keep_restricted_in_instance and 'Platform' in new_file.parts: + try: + # the name of the Platform should follow the '/Platform/' + pattern = r'/Platform/(?P[^/:*?\"<>|\r\n]+/?)' + found_platform = re.search(pattern, new_file.as_posix()).group('Platform') + except Exception as e: + pass + else: + found_platform = found_platform.replace('/', '') + if found_platform == restricted_platform: + copy_files = [] + if 'copyFiles' in json_data.keys(): + copy_files = json_data['copyFiles'] + copy_files.append(copy_file) + json_data.update({'copyFiles': copy_files}) + + ################################################################################### + + # every entry is saved in its combined location, so if not keep_restricted_in_instance + # then we need to palify into the restricted folder + # create dirs first # for each createDirectory entry, transform the folder name - for create_directory in json_data['createDirectories']: - # construct the new folder name - new_dir = destination_restricted_path / restricted_platform / destination_restricted_platform_relative_path\ - / destination_name / create_directory['dir'] - if keep_restricted_in_instance: - new_dir = destination_path / create_directory['origin'] + if 'createDirectories' in json_data: + for create_directory in json_data['createDirectories']: + # construct the new folder name + if keep_restricted_in_instance: + new_dir = destination_path / create_directory['dir'] + else: + pal_dir = create_directory['dir'].replace(f'Platform/{restricted_platform}','') + new_dir = destination_restricted_path / restricted_platform / destination_restricted_platform_relative_path / pal_dir - # transform the folder name - new_dir = _transform(new_dir.as_posix(), replacements, keep_license_text) + # transform the folder name + new_dir = _transform(new_dir.as_posix(), replacements, keep_license_text) - # create the folder - os.makedirs(new_dir, exist_ok=True) + # create the folder + os.makedirs(new_dir, exist_ok=True) # for each copyFiles entry, _transformCopy the templated source file into a concrete instance file or # regular copy if not templated - for copy_file in json_data['copyFiles']: - # construct the input file name - in_file = template_restricted_path / restricted_platform / template_restricted_platform_relative_path\ - / template_name / 'Template' / copy_file['file'] + if 'copyFiles' in json_data: + for copy_file in json_data['copyFiles']: + # construct the input file name + if template_restricted_path: + pal_file = copy_file['file'].replace(f'Platform/{restricted_platform}/', '') + in_file = template_restricted_path / restricted_platform / template_restricted_platform_relative_path / 'Template' / pal_file + else: + in_file = template_path / 'Template' / copy_file['file'] - # the file can be marked as optional, if it is and it does not exist skip - if copy_file['isOptional'] and copy_file['isOptional'] == 'true': - if not os.path.isfile(in_file): - continue + # construct the output file name + if keep_restricted_in_instance: + out_file = destination_path / copy_file['file'] + else: + pal_file = copy_file['file'].replace(f'Platform/{restricted_platform}/', '') + out_file = destination_restricted_path / restricted_platform / destination_restricted_platform_relative_path / pal_file - # construct the output file name - out_file = destination_restricted_path / restricted_platform / destination_restricted_platform_relative_path\ - / destination_name / copy_file['file'] - if keep_restricted_in_instance: - out_file = destination_path / copy_file['origin'] + # transform the output file name + out_file = _transform(out_file.as_posix(), replacements, keep_license_text) - # transform the output file name - out_file = _transform(out_file.as_posix(), replacements, keep_license_text) + # if for some reason the output folder for this file was not created above do it now + os.makedirs(os.path.dirname(out_file), exist_ok=True) - # if for some reason the output folder for this file was not created above do it now - os.makedirs(os.path.dirname(out_file), exist_ok=True) - - # if templated _transformCopy the file, if not just copy it - if copy_file['isTemplated']: - _transform_copy(in_file, out_file, replacements, keep_license_text) - else: - shutil.copy(in_file, out_file) + # if templated _transformCopy the file, if not just copy it + if copy_file['isTemplated']: + _transform_copy(in_file, out_file, replacements, keep_license_text) + else: + shutil.copy(in_file, out_file) def _instantiate_template(template_json_data: dict, @@ -309,46 +387,51 @@ def _instantiate_template(template_json_data: dict, :return: 0 for success or non 0 failure code """ # execute the template json + # this will filter out any restricted platforms in the template _execute_template_json(template_json_data, destination_path, template_path, replacements, - keep_license_text) + keep_license_text, + keep_restricted_in_instance) - # execute restricted platform jsons if any - if template_restricted_path: - for restricted_platform in os.listdir(template_restricted_path): - if os.path.isfile(restricted_platform): - continue + # we execute the jason data again if there are any restricted platforms in the main template and + # execute any restricted platform jsons if separate + + for restricted_platform in restricted_platforms: + restricted_json_data = {} + if template_restricted_path: template_restricted_platform = template_restricted_path / restricted_platform - template_restricted_platform_path_rel = template_restricted_platform / template_restricted_platform_relative_path / template_name - platform_json = template_restricted_platform_path_rel / template_file_name + template_restricted_platform_path_rel = template_restricted_platform / template_restricted_platform_relative_path + platform_json = template_restricted_platform_path_rel / 'template.json' if os.path.isfile(platform_json): if not validation.valid_o3de_template_json(platform_json): logger.error(f'Template json {platform_json} is invalid.') return 1 - # load the template json and execute it + # load the template json with open(platform_json, 'r') as s: try: - json_data = json.load(s) + restricted_json_data = json.load(s) except json.JSONDecodeError as e: logger.error(f'Failed to load {platform_json}: ' + str(e)) return 1 - else: - _execute_restricted_template_json(json_data, - restricted_platform, - destination_name, - template_name, - destination_path, - destination_restricted_path, - template_restricted_path, - destination_restricted_platform_relative_path, - template_restricted_platform_relative_path, - replacements, - keep_restricted_in_instance, - keep_license_text) + + # execute for this restricted platform + _execute_restricted_template_json(template_json_data, + restricted_json_data, + restricted_platform, + destination_name, + destination_path, + destination_restricted_path, + template_path, + template_restricted_path, + destination_restricted_platform_relative_path, + template_restricted_platform_relative_path, + replacements, + keep_restricted_in_instance, + keep_license_text) return 0 @@ -365,7 +448,8 @@ def create_template(source_path: pathlib.Path, keep_restricted_in_template: bool = False, keep_license_text: bool = False, replace: list = None, - force: bool = False) -> int: + force: bool = False, + no_register: bool = False) -> int: """ Create a template from a source directory using replacement @@ -391,6 +475,7 @@ def create_template(source_path: pathlib.Path, this controls if you want to keep the license text from the template in the new instance. It is false by default because most people will not want license text in their instances. :param force Overrides existing files even if they exist + :param no_register: whether or not after completion that the new object is registered :return: 0 for success or non 0 failure code """ @@ -401,15 +486,19 @@ def create_template(source_path: pathlib.Path, if not source_path.is_dir(): logger.error(f'Src path {source_path} is not a folder.') return 1 - source_path = source_path.resolve() - # source_name is now the last component of the source_path + + # if not specified, source_name defaults to the last component of the source_path if not source_name: source_name = os.path.basename(source_path) sanitized_source_name = utils.sanitize_identifier_for_cpp(source_name) # if no template path, use default_templates_folder path if not template_path: + logger.info(f'Template path empty. Using source name {source_name}') + template_path = source_name + # if the template_path is not an absolute path, then it default to relative from the default template folder + if not template_path.is_absolute(): default_templates_folder = manifest.get_registered(default_folder='templates') template_path = default_templates_folder / source_name logger.info(f'Template path empty. Using default templates folder {template_path}') @@ -423,7 +512,8 @@ def create_template(source_path: pathlib.Path, except ValueError: pass else: - logger.error(f'Template output path {template_path} cannot be a subdirectory of the source_path {source_path}\n') + logger.error( + f'Template output path {template_path} cannot be a subdirectory of the source_path {source_path}\n') return 1 # template name is now the last component of the template_path @@ -434,69 +524,61 @@ def create_template(source_path: pathlib.Path, logger.error(f'Template path cannot be a restricted name. {template_name}') return 1 + # if the source restricted name was given and no source restricted path, look up the restricted name to fill + # in the path if source_restricted_name and not source_restricted_path: source_restricted_path = manifest.get_registered(restricted_name=source_restricted_name) - # source_restricted_path + # if we have a source restricted path, make sure its a real restricted object if source_restricted_path: - if not os.path.isabs(source_restricted_path): - engine_json = manifest.get_this_engine_path() / 'engine.json' - if not validation.valid_o3de_engine_json(engine_json): - logger.error(f"Engine json {engine_json} is not valid.") - return 1 - with open(engine_json) as s: - try: - engine_json_data = json.load(s) - except json.JSONDecodeError as e: - logger.error(f"Failed to read engine json {engine_json}: {str(e)}") - return 1 - try: - engine_restricted = engine_json_data['restricted_name'] - except KeyError as e: - logger.error(f"Engine json {engine_json} restricted not found.") - return 1 - engine_restricted_folder = manifest.get_registered(restricted_name=engine_restricted) - new_source_restricted_path = engine_restricted_folder / source_restricted_path - logger.info(f'Source restricted path {source_restricted_path} not a full path. We must assume this engines' - f' restricted folder {new_source_restricted_path}') - if not os.path.isdir(source_restricted_path): + if not source_restricted_path.is_dir(): logger.error(f'Source restricted path {source_restricted_path} is not a folder.') return 1 + restricted_json = source_restricted_path / 'restricted.json' + if not validation.valid_o3de_restricted_json(restricted_json): + logger.error(f"Restricted json {restricted_json} is not valid.") + return 1 + with open(restricted_json, 'r') as s: + try: + restricted_json_data = json.load(s) + except json.JSONDecodeError as e: + logger.error(f'Failed to load {restricted_json}: ' + str(e)) + return 1 + try: + source_restricted_name = restricted_json_data['restricted_name'] + except KeyError as e: + logger.error(f'Failed to read restricted_name from {restricted_json}') + return 1 + # if the template restricted name was given and no template restricted path, look up the restricted name to fill + # in the path if template_restricted_name and not template_restricted_path: template_restricted_path = manifest.get_registered(restricted_name=template_restricted_name) + # if we dont have a template restricted name then set it to the templates name if not template_restricted_name: template_restricted_name = template_name - # template_restricted_path + # if we have a template restricted path, it must either not exist yet or must be a restricted object already if template_restricted_path: - if not os.path.isabs(template_restricted_path): - default_templates_restricted_folder = manifest.get_registered(restricted_name='templates') - new_template_restricted_path = default_templates_restricted_folder / template_restricted_path - logger.info(f'Template restricted path {template_restricted_path} not a full path. We must assume the' - f' default templates restricted folder {new_template_restricted_path}') - template_restricted_path = new_template_restricted_path - - if os.path.isdir(template_restricted_path): + if template_restricted_path.is_dir(): # see if this is already a restricted path, if it is get the "restricted_name" from the restricted json # so we can set "restricted_name" to it for this template restricted_json = template_restricted_path / 'restricted.json' - if os.path.isfile(restricted_json): - if not validation.valid_o3de_restricted_json(restricted_json): - logger.error(f'{restricted_json} is not valid.') + if not validation.valid_o3de_restricted_json(restricted_json): + logger.error(f'{restricted_json} is not valid.') + return 1 + with open(restricted_json, 'r') as s: + try: + restricted_json_data = json.load(s) + except json.JSONDecodeError as e: + logger.error(f'Failed to load {restricted_json}: ' + str(e)) + return 1 + try: + template_restricted_name = restricted_json_data['restricted_name'] + except KeyError as e: + logger.error(f'Failed to read restricted_name from {restricted_json}') return 1 - with open(restricted_json, 'r') as s: - try: - restricted_json_data = json.load(s) - except json.JSONDecodeError as e: - logger.error(f'Failed to load {restricted_json}: ' + str(e)) - return 1 - try: - template_restricted_name = restricted_json_data['restricted_name'] - except KeyError as e: - logger.error(f'Failed to read restricted_name from {restricted_json}') - return 1 else: os.makedirs(template_restricted_path, exist_ok=True) @@ -610,36 +692,7 @@ def create_template(source_path: pathlib.Path, else: return False, t_data - def _transform_into_template_restricted_filename(s_data: object, - platform: str) -> (bool, object): - """ - Internal function to transform a restricted platform file name into restricted template file name - :param s_data: the input data, this could be file data or file name data - :return: bool: whether or not the returned data MAY need to be transformed to instantiate it - t_data: potentially transformed data 0 for success or non 0 failure code - """ - # copy the src data to the transformed data, then operate only on transformed data - t_data = s_data - - # run all the replacements - for replacement in replacements: - t_data = t_data.replace(replacement[0], replacement[1]) - - # the name of the Platform should follow the '/Platform/{platform}' - t_data = t_data.replace(f"Platform/{platform}", '') - - # we want to send back the transformed data and whether or not this file - # may require transformation when instantiated. So if the input data is not the - # same as the output, then we transformed it which means there may be a transformation - # needed to instance it. - if s_data != t_data: - return True, t_data - else: - return False, t_data - - def _transform_restricted_into_copyfiles_and_createdirs(source_path: pathlib.Path, - restricted_platform: str, - root_abs: pathlib.Path, + def _transform_restricted_into_copyfiles_and_createdirs(root_abs: pathlib.Path, path_abs: pathlib.Path = None) -> None: """ Internal function recursively called to transform any paths files into copyfiles and create dirs relative to @@ -657,70 +710,49 @@ def create_template(source_path: pathlib.Path, # create the absolute entry by joining the path_abs and the entry entry_abs = path_abs / entry + # report what file we are processing so we have a good idea if it breaks on what file it broke on + logger.info(f'Processing file: {entry_abs}') + # create the relative entry by removing the root_abs try: entry_rel = entry_abs.relative_to(root_abs) except ValueError as err: - logger.warning(f'Unable to create relative path: {str(err)}') + logger.fatal(f'Unable to create relative path: {str(err)}') - # report what file we are processing so we have a good idea if it breaks on what file it broke on - logger.info(f'Processing file: {entry_abs}') - - # this is a restricted file, so we need to transform it, unpalify it - # restricted///some/folders/ -> - # /some/folders/Platform// - # - # C:/repo/Lumberyard/restricted/Jasper/TestDP/CMakeLists.txt -> - # C:/repo/Lumberyard/TestDP/Platform/Jasper/CMakeLists.txt - # - _, origin_entry_rel = _transform_into_template(entry_rel.as_posix()) - components = list(origin_entry_rel.parts) - num_components = len(components) - - # see how far along the source path the restricted folder matches - # then hopefully there is a Platform folder, warn if there isn't - before = [] - after = [] - relative = '' - - if os.path.isdir(entry_abs): - for x in range(0, num_components): - relative += f'{components[x]}/' - if os.path.isdir(f'{source_path}/{relative}'): - before.append(components[x]) - else: - after.append(components[x]) - else: - for x in range(0, num_components - 1): - relative += f'{components[x]}/' - if os.path.isdir(f'{source_path}/{relative}'): - before.append(components[x]) - else: - after.append(components[x]) - - after.append(components[num_components - 1]) - - before.append("Platform") - warn_if_not_platform = source_path / pathlib.Path(*before) - before.append(restricted_platform) - before.extend(after) - - origin_entry_rel = pathlib.Path(*before) - - if not os.path.isdir(warn_if_not_platform): - logger.warning( - f'{entry_abs} -> {origin_entry_rel}: Other Platforms not found in {warn_if_not_platform}') - - destination_entry_rel = origin_entry_rel - destination_entry_abs = template_path / 'Template' / origin_entry_rel + # templatize the entry relative into the destination entry relative + _, destination_entry_rel = _transform_into_template(entry_rel.as_posix()) + destination_entry_rel = pathlib.Path(destination_entry_rel) # clean up any relative leading slashes - if origin_entry_rel.as_posix().startswith('/'): - origin_entry_rel = pathlib.Path(origin_entry_rel.as_posix().lstrip('/')) if destination_entry_rel.as_posix().startswith('/'): destination_entry_rel = pathlib.Path(destination_entry_rel.as_posix().lstrip('/')) + if isinstance(destination_entry_rel, pathlib.Path): + destination_entry_rel = destination_entry_rel.as_posix() - # make sure the dst folder may or may not exist yet, make sure it does exist before we transform + if template_restricted_path: + destination_entry_abs = template_restricted_path / restricted_platform / template_restricted_platform_relative_path / 'Template' / destination_entry_rel + destination_entry_rel = pathlib.Path(destination_entry_rel) + first = True + for component in destination_entry_rel.parts: + if first: + first = False + result = pathlib.Path(component) / 'Platform' / restricted_platform + else: + result = result / component + destination_entry_rel = result.as_posix() + else: + destination_entry_rel = pathlib.Path(destination_entry_rel) + first = True + for component in destination_entry_rel.parts: + if first: + first = False + result = pathlib.Path(component) / 'Platform' / restricted_platform + else: + result = result / component + destination_entry_rel = result.as_posix() + destination_entry_abs = template_path / 'Template' / destination_entry_rel + + # the destination folder may or may not exist yet, make sure it does exist before we transform # data into it os.makedirs(os.path.dirname(destination_entry_abs), exist_ok=True) @@ -730,8 +762,8 @@ def create_template(source_path: pathlib.Path, if os.path.isfile(entry_abs): # if this file is a known binary file, there is no transformation needed and just copy it - # if not a known binary file open it and try to transform the data. if it is an unknown binary - # type it will throw and we catch copy + # if not a known binary file open it and try to transform the data. + # if it is an unknown binary type it will throw and we catch copy # if we had no known binary type it would still work, but much slower name, ext = os.path.splitext(entry) if ext in binary_file_ext: @@ -743,7 +775,7 @@ def create_template(source_path: pathlib.Path, source_data = s.read() templated, source_data = _transform_into_template(source_data, _is_cpp_file(entry_abs)) - # if the file type is a file that we expect to fins license header and we don't find any + # if the file type is a file that we expect to find a license header and we don't find any # warn that the we didn't find the license info, this makes it easy to make sure we didn't # miss any files we want to have license info in. if keep_license_text and ext in expect_license_info_ext: @@ -761,19 +793,26 @@ def create_template(source_path: pathlib.Path, shutil.copy(entry_abs, destination_entry_abs) pass - copy_files.append({ - "file": destination_entry_rel, - "origin": origin_entry_rel, - "isTemplated": templated, - "isOptional": False - }) + if keep_restricted_in_template: + copy_files.append({ + "file": destination_entry_rel, + "isTemplated": templated + }) + else: + restricted_platform_entries[restricted_platform]['copyFiles'].append({ + "file": destination_entry_rel, + "isTemplated": templated + }) else: - create_dirs.append({ - "dir": destination_entry_rel, - "origin": origin_entry_rel - }) - _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, root_abs, - entry_abs) + if keep_restricted_in_template: + create_dirs.append({ + "dir": destination_entry_rel + }) + else: + restricted_platform_entries[restricted_platform]['createDirs'].append({ + "dir": destination_entry_rel + }) + _transform_restricted_into_copyfiles_and_createdirs(root_abs, entry_abs) def _transform_dir_into_copyfiles_and_createdirs(root_abs: pathlib.Path, path_abs: pathlib.Path = None) -> None: @@ -793,18 +832,21 @@ def create_template(source_path: pathlib.Path, # create the absolute entry by joining the path_abs and the entry entry_abs = path_abs / entry - # create the relative entry by removing the root_abs - entry_rel = entry_abs - try: - entry_rel = entry_abs.relative_to(root_abs) - except ValueError as err: - logger.warning(f'Unable to create relative path: {str(err)}') - # report what file we are processing so we have a good idea if it breaks on what file it broke on logger.info(f'Processing file: {entry_abs}') - # see if the entry is a platform file, if it is then we save its copyfile data in a platform specific list - # then at the end we can save the restricted ones separately + # create the relative entry by removing the root_abs + try: + entry_rel = entry_abs.relative_to(root_abs).as_posix() + except ValueError as err: + logger.fatal(f'Unable to create relative path: {str(err)}') + + # templatize the entry relative into the origin entry relative + _, destination_entry_rel = _transform_into_template(entry_rel) + destination_entry_rel = pathlib.Path(destination_entry_rel) + + # see if the entry is a restricted platform file, if it is then we save its copyfile data in a + # platform specific list then at the end we can save the restricted ones separately found_platform = '' platform = False if not keep_restricted_in_template and 'Platform' in entry_abs.parts: @@ -812,7 +854,7 @@ def create_template(source_path: pathlib.Path, try: # the name of the Platform should follow the '/Platform/' pattern = r'/Platform/(?P[^/:*?\"<>|\r\n]+/?)' - found_platform = re.search(pattern, entry_abs).group('Platform') + found_platform = re.search(pattern, entry_abs.as_posix()).group('Platform') found_platform = found_platform.replace('/', '') except Exception as e: pass @@ -831,30 +873,35 @@ def create_template(source_path: pathlib.Path, # Now if we found a platform and still have a found_platform which is a restricted platform # then transform the entry relative name into a dst relative entry name and dst abs entry. # if not then create a normal relative and abs dst entry name - _, origin_entry_rel = _transform_into_template(entry_rel.as_posix()) if platform and found_platform in restricted_platforms: # if we don't have a template restricted path and we found restricted files... warn and skip # the file/dir if not template_restricted_path: - logger.warning("Restricted platform files found!!! {entry_rel}, {found_platform}") + logger.warning("Restricted platform file found!!! {destination_entry_rel}, {found_platform}") continue - _, destination_entry_rel = _transform_into_template_restricted_filename(entry_rel, found_platform) - destination_entry_abs = template_restricted_path / found_platform\ - / template_restricted_platform_relative_path / template_name / 'Template'\ - / destination_entry_rel + + # run all the replacements + for replacement in replacements: + destination_entry_rel = destination_entry_rel.replace(replacement[0], replacement[1]) + + # the name of the Platform should follow the '/Platform/{found_platform}' + destination_entry_rel = destination_entry_rel.replace(f"Platform/{found_platform}", '') + destination_entry_rel = destination_entry_rel.lstrip('/') + + # construct the absolute entry from the relative + if template_restricted_platform_relative_path: + destination_entry_abs = template_restricted_path / found_platform / template_restricted_platform_relative_path / template_name / 'Template' / destination_entry_rel + else: + destination_entry_abs = template_restricted_path / found_platform / 'Template' / destination_entry_rel else: - destination_entry_rel = origin_entry_rel + # construct the absolute entry from the relative destination_entry_abs = template_path / 'Template' / destination_entry_rel # clean up any relative leading slashes - if isinstance(origin_entry_rel, pathlib.Path): - origin_entry_rel = origin_entry_rel.as_posix() - if origin_entry_rel.startswith('/'): - origin_entry_rel = pathlib.Path(origin_entry_rel.lstrip('/')) if isinstance(destination_entry_rel, pathlib.Path): destination_entry_rel = destination_entry_rel.as_posix() if destination_entry_rel.startswith('/'): - destination_entry_rel = pathlib.Path(destination_entry_rel.lstrip('/')) + destination_entry_rel = destination_entry_rel.lstrip('/') # make sure the dst folder may or may not exist yet, make sure it does exist before we transform # data into it @@ -902,29 +949,23 @@ def create_template(source_path: pathlib.Path, if platform and found_platform in restricted_platforms: restricted_platform_entries[found_platform]['copyFiles'].append({ "file": destination_entry_rel, - "origin": origin_entry_rel, - "isTemplated": templated, - "isOptional": False + "isTemplated": templated }) else: copy_files.append({ "file": destination_entry_rel, - "origin": origin_entry_rel, - "isTemplated": templated, - "isOptional": False + "isTemplated": templated }) else: # if the folder was for a restricted platform add the entry to the restricted platform, otherwise add it # to the non restricted if platform and found_platform in restricted_platforms: restricted_platform_entries[found_platform]['createDirs'].append({ - "dir": destination_entry_rel, - "origin": origin_entry_rel + "dir": destination_entry_rel }) else: create_dirs.append({ - "dir": destination_entry_rel, - "origin": origin_entry_rel + "dir": destination_entry_rel }) # recurse using the same root and this folder @@ -937,11 +978,11 @@ def create_template(source_path: pathlib.Path, # when we run the transformation any restricted platforms entries we find will go in here restricted_platform_entries = {} - # Every project will have a unrestricted folder which is src_path_abs which MAY have restricted files in it, and - # each project MAY have a restricted folder which will only have restricted files in them. The process is the + # Every template will have a unrestricted folder which is src_path_abs which MAY have restricted files in it, and + # each template MAY have a restricted folder which will only have restricted files in them. The process is the # same for all of them and the result will be a separation of all restricted files from unrestricted files. We do - # this by running the transformation first over the src path abs and then on each restricted folder for this project - # we find. This will effectively combine all sources then separates all the restricted. + # this by running the transformation first over the src path abs and then on each restricted folder for this + # template we find. This will effectively combine all sources then separates all the restricted. # run the transformation on the src, which may or may not have restricted files _transform_dir_into_copyfiles_and_createdirs(source_path) @@ -950,11 +991,12 @@ def create_template(source_path: pathlib.Path, # run the transformation on each src restricted folder if source_restricted_path: for restricted_platform in os.listdir(source_restricted_path): - restricted_platform_src_path_abs = source_restricted_path / restricted_platform\ - / source_restricted_platform_relative_path / source_name + restricted_platform_src_path_abs = source_restricted_path / restricted_platform \ + / source_restricted_platform_relative_path if os.path.isdir(restricted_platform_src_path_abs): - _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, - restricted_platform_src_path_abs) + if restricted_platform not in restricted_platform_entries: + restricted_platform_entries.update({restricted_platform: {'copyFiles': [], 'createDirs': []}}) + _transform_restricted_into_copyfiles_and_createdirs(restricted_platform_src_path_abs) # sort copy_files.sort(key=lambda x: x['file']) @@ -972,39 +1014,47 @@ def create_template(source_path: pathlib.Path, json_data.update({'canonical_tags': []}) json_data.update({'user_tags': [f"{template_name}"]}) json_data.update({'icon_path': "preview.png"}) - if template_restricted_path: + if not keep_restricted_in_template and template_restricted_path: json_data.update({'restricted_name': template_restricted_name}) if template_restricted_platform_relative_path != '': - json_data.update({'template_restricted_platform_relative_path': template_restricted_platform_relative_path}) + json_data.update({'template_restricted_platform_relative_path': template_restricted_platform_relative_path.as_posix()}) json_data.update({'copyFiles': copy_files}) json_data.update({'createDirectories': create_dirs}) - json_name = template_path / template_file_name + json_name = template_path / source_restricted_platform_relative_path / 'template.json' with json_name.open('w') as s: s.write(json.dumps(json_data, indent=4) + '\n') # copy the default preview.png preview_png_src = this_script_parent / 'resources' / 'preview.png' - preview_png_dst = template_path / 'Template' / 'preview.png' + preview_png_dst = template_path / 'preview.png' if not os.path.isfile(preview_png_dst): shutil.copy(preview_png_src, preview_png_dst) # if no restricted template path was given and restricted platform files were found - if not template_restricted_path and len(restricted_platform_entries): + if not keep_restricted_in_template and not template_restricted_path and len(restricted_platform_entries): logger.info(f'Restricted platform files found!!! and no template restricted path was found...') - if template_restricted_path: + if not keep_restricted_in_template and template_restricted_path: + json_name = template_restricted_path / 'restricted.json' + if not json_name.is_file(): + json_data = {} + json_data.update({'restricted_name': template_restricted_name}) + os.makedirs(os.path.dirname(json_name), exist_ok=True) + + with json_name.open('w') as s: + s.write(json.dumps(json_data, indent=4) + '\n') + # now write out each restricted platform template json separately for restricted_platform in restricted_platform_entries: - restricted_template_path = template_restricted_path / restricted_platform\ - / template_restricted_platform_relative_path / template_name - + restricted_template_path = template_restricted_path / restricted_platform / template_restricted_platform_relative_path # sort restricted_platform_entries[restricted_platform]['copyFiles'].sort(key=lambda x: x['file']) restricted_platform_entries[restricted_platform]['createDirs'].sort(key=lambda x: x['dir']) json_data = {} + json_data.update({'restricted_name': template_name}) json_data.update({'template_name': template_name}) json_data.update( {'origin': f'The primary repo for {template_name} goes here: i.e. http://www.mydomain.com'}) @@ -1012,23 +1062,25 @@ def create_template(source_path: pathlib.Path, {'license': f'What license {template_name} uses goes here: i.e. https://opensource.org/licenses/MIT'}) json_data.update({'display_name': template_name}) json_data.update({'summary': f"A short description of {template_name}."}) - json_data.update({'canonical_tags': []}) + json_data.update({'canonical_tags': [f'{restricted_platform}']}) json_data.update({'user_tags': [f'{template_name}']}) - json_data.update({'icon_path': "preview.png"}) json_data.update({'copyFiles': restricted_platform_entries[restricted_platform]['copyFiles']}) json_data.update({'createDirectories': restricted_platform_entries[restricted_platform]['createDirs']}) - json_name = restricted_template_path / template_file_name + json_name = restricted_template_path / 'template.json' os.makedirs(os.path.dirname(json_name), exist_ok=True) with json_name.open('w') as s: s.write(json.dumps(json_data, indent=4) + '\n') - preview_png_dst = restricted_template_path / 'Template' /' preview.png' - if not os.path.isfile(preview_png_dst): - shutil.copy(preview_png_src, preview_png_dst) + # Register the restricted + if not no_register: + if register.register(restricted_path=template_restricted_path): + logger.error(f'Failed to register the restricted {template_restricted_path}.') + return 1 - return 0 + # Register the template + return register.register(template_path=template_path) if not no_register else 0 def create_from_template(destination_path: pathlib.Path, @@ -1044,7 +1096,8 @@ def create_from_template(destination_path: pathlib.Path, keep_restricted_in_instance: bool = False, keep_license_text: bool = False, replace: list = None, - force: bool = False) -> int: + force: bool = False, + no_register: bool = False) -> int: """ Generic template instantiation for non o3de object templates. This function makes NO assumptions! Assumptions are made only for specializations like create_project or create_gem etc... So this function @@ -1251,17 +1304,18 @@ def create_from_template(destination_path: pathlib.Path, # destination restricted path elif destination_restricted_path: - if os.path.isabs(destination_restricted_path): + if not os.path.isabs(destination_restricted_path): restricted_default_path = manifest.get_registered(default_folder='restricted') - new_destination_restricted_path = restricted_default_path / destination_restricted_path + new_destination_restricted_path = restricted_default_path / "Templates" / destination_restricted_path logger.info(f'{destination_restricted_path} is not a full path, making it relative' f' to default restricted path = {new_destination_restricted_path}') destination_restricted_path = new_destination_restricted_path - elif template_restricted_path: - restricted_default_path = manifest.get_registered(restricted_name='restricted') - logger.info(f'--destination-restricted-path is not specified, using default restricted path / destination name' - f' = {restricted_default_path}') - destination_restricted_path = restricted_default_path + else: + restricted_default_path = manifest.get_registered(default_folder='restricted') + new_destination_restricted_path = restricted_default_path / "Templates" / destination_name + logger.info(f'--destination-restricted-path is not specified, using default restricted path' + f' / Templates / destination name = {new_destination_restricted_path}') + destination_restricted_path = new_destination_restricted_path # destination restricted relative if not destination_restricted_platform_relative_path: @@ -1306,7 +1360,7 @@ def create_from_template(destination_path: pathlib.Path, if destination_restricted_path: os.makedirs(destination_restricted_path, exist_ok=True) - # read the restricted_name from the destination restricted.json + # write the restricted_name to the destination restricted.json restricted_json = destination_restricted_path / 'restricted.json' if not os.path.isfile(restricted_json): with open(restricted_json, 'w') as s: @@ -1314,6 +1368,12 @@ def create_from_template(destination_path: pathlib.Path, restricted_json_data.update({'restricted_name': destination_name}) s.write(json.dumps(restricted_json_data, indent=4) + '\n') + # Register the restricted + if not no_register: + if register.register(restricted_path=destination_restricted_path): + logger.error(f'Failed to register the restricted {destination_restricted_path}.') + return 1 + logger.warning(f'Instantiation successful. NOTE: This is a generic instantiation of the template. If this' f' was a template of an o3de object like a project, gem, template, etc. then the create-project' f' or create-gem command can be used to register the object type via its project.json or gem.json, etc.' @@ -1364,6 +1424,7 @@ def create_project(project_path: pathlib.Path, Ex. ${Name},TestGem,${Player},TestGemPlayer This will cause all references to ${Name} be replaced by TestGem, and all ${Player} replaced by 'TestGemPlayer' :param force Overrides existing files even if they exist + :param no_register: whether or not after completion that the new object is registered :param system_component_class_id: optionally specify a uuid for the system component class, default is random uuid :param editor_system_component_class_id: optionally specify a uuid for the editor system component class, default is random uuid @@ -1422,12 +1483,10 @@ def create_project(project_path: pathlib.Path, # see if the template itself specifies a restricted name if not template_restricted_name and not template_restricted_path: try: - template_json_restricted_name = template_json_data['restricted_name'] + template_restricted_name = template_json_data['restricted_name'] except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".') - else: - template_restricted_name = template_json_restricted_name # if no restricted name or path we continue on as if there is no template restricted files. if template_restricted_name or template_restricted_path: @@ -1523,8 +1582,13 @@ def create_project(project_path: pathlib.Path, if not project_path: logger.error('Project path cannot be empty.') return 1 - project_path = project_path.resolve() + if not os.path.isabs(project_path): + default_projects_folder = manifest.get_registered(default_folder='projects') + new_project_path = default_projects_folder / project_path + logger.info(f'Project Path {project_path} is not a full path, we must assume its relative' + f' to default projects path = {new_project_path}') + project_path = new_project_path if not force and project_path.is_dir() and len(list(project_path.iterdir())): logger.error(f'Project path {project_path} already exists and is not empty.') return 1 @@ -1536,7 +1600,8 @@ def create_project(project_path: pathlib.Path, project_name = os.path.basename(project_path) if not utils.validate_identifier(project_name): - logger.error(f'Project name must be fewer than 64 characters, contain only alphanumeric, "_" or "-" characters, and start with a letter. {project_name}') + logger.error( + f'Project name must be fewer than 64 characters, contain only alphanumeric, "_" or "-" characters, and start with a letter. {project_name}') return 1 # project name cannot be the same as a restricted platform name @@ -1546,21 +1611,19 @@ def create_project(project_path: pathlib.Path, # project restricted name if project_restricted_name and not project_restricted_path: - project_restricted_path = manifest.get_registered(restricted_name=project_restricted_name) + gem_restricted_path = manifest.get_registered(restricted_name=project_restricted_name) + if not gem_restricted_path: + logger.error(f'Project Restricted Name {project_restricted_name} cannot be found.') + return 1 # project restricted path - elif project_restricted_path: + if project_restricted_path: if not os.path.isabs(project_restricted_path): - default_projects_restricted_folder = manifest.get_registered(restricted_name='projects') - new_project_restricted_path = default_projects_restricted_folder/ project_restricted_path - logger.info(f'Project restricted path {project_restricted_path} is not a full path, we must assume its' - f' relative to default projects restricted path = {new_project_restricted_path}') - project_restricted_path = new_project_restricted_path - elif template_restricted_path: - project_restricted_default_path = manifest.get_registered(restricted_name='projects') - logger.info(f'--project-restricted-path is not specified, using default project restricted path / project name' - f' = {project_restricted_default_path}') - project_restricted_path = project_restricted_default_path + logger.error(f'Project Restricted Path {project_restricted_path} is not an absolute path.') + return 1 + # neither put it in the default restricted projects + else: + project_restricted_path = manifest.get_o3de_restricted_folder() / 'Projects' / project_name # project restricted relative path if not project_restricted_platform_relative_path: @@ -1639,7 +1702,7 @@ def create_project(project_path: pathlib.Path, os.makedirs(project_restricted_path, exist_ok=True) # read the restricted_name from the projects restricted.json - restricted_json = project_restricted_path / 'restricted.json' + restricted_json = project_restricted_path / 'restricted.json' if os.path.isfile(restricted_json): if not validation.valid_o3de_restricted_json(restricted_json): logger.error(f'Restricted json {restricted_json} is not valid.') @@ -1663,7 +1726,8 @@ def create_project(project_path: pathlib.Path, logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') return 1 - # set the "restricted_name": "restricted_name" element of the project.json + # set the "restricted": element of the project.json + project_json = project_path / 'project.json' if not validation.valid_o3de_project_json(project_json): logger.error(f'Project json {project_json} is not valid.') return 1 @@ -1675,7 +1739,7 @@ def create_project(project_path: pathlib.Path, logger.error(f'Failed to load project json {project_json}.') return 1 - project_json_data.update({"restricted_name": restricted_name}) + project_json_data.update({"restricted": restricted_name}) os.unlink(project_json) with open(project_json, 'w') as s: try: @@ -1684,20 +1748,11 @@ def create_project(project_path: pathlib.Path, logger.error(f'Failed to write project json {project_json}.') return 1 - for restricted_platform in restricted_platforms: - restricted_project = project_restricted_path / restricted_platform / project_name - os.makedirs(restricted_project, exist_ok=True) - cmakelists_file_name = restricted_project/ 'CMakeLists.txt' - if not os.path.isfile(cmakelists_file_name): - with open(cmakelists_file_name, 'w') as d: - if keep_license_text: - d.write('# {BEGIN_LICENSE}\n') - d.write('# Copyright (c) Contributors to the Open 3D Engine Project.\n') - d.write('# For complete copyright and license terms please see the LICENSE at the root of this distribution.\n') - d.write('#\n') - d.write('# SPDX-License-Identifier: Apache-2.0 OR MIT\n') - d.write('# {END_LICENSE}\n') - + # Register the restricted + if not no_register: + if register.register(restricted_path=project_restricted_path): + logger.error(f'Failed to register the restricted {project_restricted_path}.') + return 1 # Register the project with the either o3de_manifest.json or engine.json # and set the project.json "engine" field to match the @@ -1906,10 +1961,15 @@ def create_gem(gem_path: pathlib.Path, if not gem_path: logger.error('Gem path cannot be empty.') return 1 - gem_path = gem_path.resolve() + if not os.path.isabs(gem_path): + default_gems_folder = manifest.get_registered(default_folder='gems') + new_gem_path = default_gems_folder / gem_path + logger.info(f'Gem Path {gem_path} is not a full path, we must assume its relative' + f' to default gems path = {new_gem_path}') + gem_path = new_gem_path if not force and gem_path.is_dir() and len(list(gem_path.iterdir())): - logger.error(f'Gem path {gem_path} already exists and is not empty.') + logger.error(f'Gem path {gem_path} already exists.') return 1 else: os.makedirs(gem_path, exist_ok=force) @@ -1930,22 +1990,18 @@ def create_gem(gem_path: pathlib.Path, # gem restricted name if gem_restricted_name and not gem_restricted_path: gem_restricted_path = manifest.get_registered(restricted_name=gem_restricted_name) + if not gem_restricted_path: + logger.error(f'Gem Restricted Name {gem_restricted_name} cannot be found.') + return 1 # gem restricted path - elif gem_restricted_path: + if gem_restricted_path: if not os.path.isabs(gem_restricted_path): - gem_restricted_default_path = manifest.get_registered(restricted_name='gems') - if gem_restricted_default_path: - new_gem_restricted_path = gem_restricted_default_path / gem_restricted_path - logger.info(f'Gem restricted path {gem_restricted_path} is not a full path, we must assume its' - f' relative to default gems restricted path = {new_gem_restricted_path}') - gem_restricted_path = new_gem_restricted_path + logger.error(f'Gem Restricted Path {gem_restricted_path} is not an absolute path.') + return 1 + # neither put it in the default restricted gems else: - gem_restricted_default_path = manifest.get_registered(restricted_name='gems') - if gem_restricted_default_path: - logger.info(f'--gem-restricted-path is not specified, using default / ' - f' = {gem_restricted_default_path}') - gem_restricted_path = gem_restricted_default_path / gem_name + gem_restricted_path = manifest.get_o3de_restricted_folder() / "Gems" / gem_name # gem restricted relative if not gem_restricted_platform_relative_path: @@ -2035,47 +2091,49 @@ def create_gem(gem_path: pathlib.Path, logger.error(f'Failed to load restricted json {restricted_json}.') return 1 + try: + restricted_name = restricted_json_data["restricted_name"] + except KeyError as e: + logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') + return 1 + + # set the "restricted_name": element of the gem.json + gem_json = gem_path / 'gem.json' + if not validation.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + with open(gem_json, 'r') as s: try: - restricted_name = restricted_json_data["restricted_name"] - except KeyError as e: - logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') + gem_json_data = json.load(s) + except json.JSONDecodeError as e: + logger.error(f'Failed to load gem json {gem_json}.') return 1 - # set the "restricted_name": "restricted_name" element of the gem.json - gem_json = gem_path / 'gem.json' - if not validation.valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') + gem_json_data.update({"restricted": restricted_name}) + os.unlink(gem_json) + with open(gem_json, 'w') as s: + try: + s.write(json.dumps(gem_json_data, indent=4) + '\n') + except OSError as e: + logger.error(f'Failed to write project json {gem_json}.') + return 1 + ''' + for restricted_platform in restricted_platforms: + restricted_gem = gem_restricted_path / restricted_platform / gem_name + os.makedirs(restricted_gem, exist_ok=True) + cmakelists_file_name = restricted_gem / 'CMakeLists.txt' + if not os.path.isfile(cmakelists_file_name): + with open(cmakelists_file_name, 'w') as d: + if keep_license_text: + d.write(O3DE_LICENSE_TEXT) + ''' + # Register the restricted + if not no_register: + if register.register(restricted_path=gem_restricted_path): + logger.error(f'Failed to register the restricted {gem_restricted_path}.') return 1 - with open(gem_json, 'r') as s: - try: - gem_json_data = json.load(s) - except json.JSONDecodeError as e: - logger.error(f'Failed to load gem json {gem_json}.') - return 1 - - gem_json_data.update({"restricted_name": restricted_name}) - os.unlink(gem_json) - with open(gem_json, 'w') as s: - try: - s.write(json.dumps(gem_json_data, indent=4) + '\n') - except OSError as e: - logger.error(f'Failed to write project json {gem_json}.') - return 1 - - for restricted_platform in restricted_platforms: - restricted_gem = gem_restricted_path / restricted_platform/ gem_name - os.makedirs(restricted_gem, exist_ok=True) - cmakelists_file_name = restricted_gem / 'CMakeLists.txt' - if not os.path.isfile(cmakelists_file_name): - with open(cmakelists_file_name, 'w') as d: - if keep_license_text: - d.write('# {BEGIN_LICENSE}\n') - d.write('# Copyright (c) Contributors to the Open 3D Engine Project.\n') - d.write('# For complete copyright and license terms please see the LICENSE at the root of this distribution.\n') - d.write('#\n') - d.write('# SPDX-License-Identifier: Apache-2.0 OR MIT\n') - d.write('# {END_LICENSE}\n') # Register the gem with the either o3de_manifest.json, engine.json or project.json based on the gem path return register.register(gem_path=gem_path) if not no_register else 0 @@ -2093,7 +2151,8 @@ def _run_create_template(args: argparse) -> int: args.keep_restricted_in_template, args.keep_license_text, args.replace, - args.force) + args.force, + args.no_register) def _run_create_from_template(args: argparse) -> int: @@ -2110,7 +2169,8 @@ def _run_create_from_template(args: argparse) -> int: args.keep_restricted_in_instance, args.keep_license_text, args.replace, - args.force) + args.force, + args.no_register) def _run_create_project(args: argparse) -> int: @@ -2166,7 +2226,6 @@ def add_args(subparsers) -> None: call add_args and execute: python o3de.py create-gem --gem-path TestGem :param subparsers: the caller instantiates subparsers and passes it in here """ - # turn a directory into a template create_template_subparser = subparsers.add_parser('create-template') @@ -2242,7 +2301,10 @@ def add_args(subparsers) -> None: ' Note: is automatically ${NameLower}' ' Note: is automatically ${NameUpper}') create_template_subparser.add_argument('-f', '--force', action='store_true', default=False, - help='Copies to new template directory even if it exist.') + help='Copies to new template directory even if it exist.') + create_template_subparser.add_argument('--no-register', action='store_true', default=False, + help='If the template is created successfully, it will not register the' + ' template with the global or engine manifest file.') create_template_subparser.set_defaults(func=_run_create_template) # create from template @@ -2268,11 +2330,11 @@ def add_args(subparsers) -> None: ' resolve the --template-path.') create_from_template_subparser.add_argument('-dn', '--destination-name', type=str, - help='The name to use when substituting the ${Name} placeholder in instantiated template,' - ' must be alphanumeric, ' - ' and can contain _ and - characters.' - ' If no name is provided, will use last component of destination path.' - ' Ex. New_Gem') + help='The name to use when substituting the ${Name} placeholder in instantiated template,' + ' must be alphanumeric, ' + ' and can contain _ and - characters.' + ' If no name is provided, will use last component of destination path.' + ' Ex. New_Gem') group = create_from_template_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-drp', '--destination-restricted-path', type=pathlib.Path, required=False, @@ -2293,7 +2355,8 @@ def add_args(subparsers) -> None: help='The name of the registered restricted path to read from if any. If supplied this will' ' resolve the --template-restricted-path.') - create_from_template_subparser.add_argument('-drprp', '--destination-restricted-platform-relative-path', type=pathlib.Path, + create_from_template_subparser.add_argument('-drprp', '--destination-restricted-platform-relative-path', + type=pathlib.Path, required=False, default=None, help='Any path to append to the --destination-restricted-path/' @@ -2301,7 +2364,8 @@ def add_args(subparsers) -> None: ' --destination-restricted-path C:/instance' ' --destination-restricted-platform-relative-path some/folder' ' => C:/instance//some/folder/') - create_from_template_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', type=pathlib.Path, + create_from_template_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', + type=pathlib.Path, required=False, default=None, help='Any path to append to the --template-restricted-path/' @@ -2329,7 +2393,10 @@ def add_args(subparsers) -> None: ' Note: ${NameLower} is automatically ' ' Note: ${NameUpper} is automatically ') create_from_template_subparser.add_argument('-f', '--force', action='store_true', default=False, - help='Copies over instantiated template directory even if it exist.') + help='Copies over instantiated template directory even if it exist.') + create_from_template_subparser.add_argument('--no-register', action='store_true', default=False, + help='If the project template is instantiated successfully, it will not register the' + ' project with the global or engine manifest file.') create_from_template_subparser.set_defaults(func=_run_create_from_template) # creation of a project from a template (like create from template but makes project assumptions) @@ -2430,10 +2497,10 @@ def add_args(subparsers) -> None: help='The str id you want to associate with the project, default is a random uuid' ' Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') create_project_subparser.add_argument('-f', '--force', action='store_true', default=False, - help='Copies over instantiated template directory even if it exist.') + help='Copies over instantiated template directory even if it exist.') create_project_subparser.add_argument('--no-register', action='store_true', default=False, - help='If the project template is instantiated successfully, it will not register the' - ' project with the global or engine manifest file.') + help='If the project template is instantiated successfully, it will not register the' + ' project with the global or engine manifest file.') create_project_subparser.set_defaults(func=_run_create_project) # creation of a gem from a template (like create from template but makes gem assumptions) @@ -2445,11 +2512,11 @@ def add_args(subparsers) -> None: create_gem_subparser.add_argument('-gp', '--gem-path', type=pathlib.Path, required=True, help='The gem path, can be absolute or relative to the current working directory') create_gem_subparser.add_argument('-gn', '--gem-name', type=str, - help='The name to use when substituting the ${Name} placeholder for the gem,' - ' must be alphanumeric, ' - ' and can contain _ and - characters.' - ' If no name is provided, will use last component of gem path.' - ' Ex. New_Gem') + help='The name to use when substituting the ${Name} placeholder for the gem,' + ' must be alphanumeric, ' + ' and can contain _ and - characters.' + ' If no name is provided, will use last component of gem path.' + ' Ex. New_Gem') group = create_gem_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-tp', '--template-path', type=pathlib.Path, required=False, @@ -2529,7 +2596,7 @@ def add_args(subparsers) -> None: help='The uuid you want to associate with the gem module,' ' default is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') create_gem_subparser.add_argument('-f', '--force', action='store_true', default=False, - help='Copies over instantiated template directory even if it exist.') + help='Copies over instantiated template directory even if it exist.') create_gem_subparser.add_argument('--no-register', action='store_true', default=False, help='If the gem template is instantiated successfully, it will not register the' ' gem with the global, project or engine manifest file.') diff --git a/scripts/o3de/o3de/get_registration.py b/scripts/o3de/o3de/get_registration.py index d64056e8b2..1271d56804 100644 --- a/scripts/o3de/o3de/get_registration.py +++ b/scripts/o3de/o3de/get_registration.py @@ -14,9 +14,6 @@ from o3de import manifest def _run_get_registered(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - registered_path = manifest.get_registered(args.engine_name, args.project_name, args.gem_name, @@ -55,9 +52,6 @@ def add_parser_args(parser): group.add_argument('-rsn', '--restricted-name', type=str, required=False, help='Restricted name.') - parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, - help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_get_registered) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index a334109e6a..88e6ae8229 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -22,18 +22,13 @@ logger = logging.getLogger('o3de.manifest') logging.basicConfig(format=utils.LOG_FORMAT) # Directory methods -override_home_folder = None - def get_this_engine_path() -> pathlib.Path: return pathlib.Path(os.path.realpath(__file__)).parents[3].resolve() def get_home_folder() -> pathlib.Path: - if override_home_folder: - return pathlib.Path(override_home_folder).resolve() - else: - return pathlib.Path(os.path.expanduser("~")).resolve() + return pathlib.Path(os.path.expanduser("~")).resolve() def get_o3de_folder() -> pathlib.Path: @@ -42,12 +37,6 @@ def get_o3de_folder() -> pathlib.Path: return o3de_folder -def get_o3de_user_folder() -> pathlib.Path: - o3de_user_folder = get_home_folder() / 'O3DE' - o3de_user_folder.mkdir(parents=True, exist_ok=True) - return o3de_user_folder - - def get_o3de_registry_folder() -> pathlib.Path: registry_folder = get_o3de_folder() / 'Registry' registry_folder.mkdir(parents=True, exist_ok=True) @@ -73,19 +62,19 @@ def get_o3de_engines_folder() -> pathlib.Path: def get_o3de_projects_folder() -> pathlib.Path: - projects_folder = get_o3de_user_folder() / 'Projects' + projects_folder = get_o3de_folder() / 'Projects' projects_folder.mkdir(parents=True, exist_ok=True) return projects_folder def get_o3de_gems_folder() -> pathlib.Path: - gems_folder = get_o3de_user_folder() / 'Gems' + gems_folder = get_o3de_folder() / 'Gems' gems_folder.mkdir(parents=True, exist_ok=True) return gems_folder def get_o3de_templates_folder() -> pathlib.Path: - templates_folder = get_o3de_user_folder() / 'Templates' + templates_folder = get_o3de_folder() / 'Templates' templates_folder.mkdir(parents=True, exist_ok=True) return templates_folder @@ -117,6 +106,10 @@ def get_default_o3de_manifest_json_data() -> dict: username = os.path.split(get_home_folder())[-1] o3de_folder = get_o3de_folder() + default_registry_folder = get_o3de_registry_folder() + default_cache_folder = get_o3de_cache_folder() + default_downloads_folder = get_o3de_download_folder() + default_logs_folder = get_o3de_logs_folder() default_engines_folder = get_o3de_engines_folder() default_projects_folder = get_o3de_projects_folder() default_gems_folder = get_o3de_gems_folder() @@ -124,12 +117,20 @@ def get_default_o3de_manifest_json_data() -> dict: default_restricted_folder = get_o3de_restricted_folder() default_third_party_folder = get_o3de_third_party_folder() - default_projects_restricted_folder = default_projects_folder / 'Restricted' - default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) - default_gems_restricted_folder = default_gems_folder / 'Restricted' - default_gems_restricted_folder.mkdir(parents=True, exist_ok=True) - default_templates_restricted_folder = default_templates_folder / 'Restricted' - default_templates_restricted_folder.mkdir(parents=True, exist_ok=True) + default_restricted_projects_folder = default_restricted_folder / 'Projects' + default_restricted_projects_folder.mkdir(parents=True, exist_ok=True) + default_restricted_gems_folder = default_restricted_folder / 'Gems' + default_restricted_gems_folder.mkdir(parents=True, exist_ok=True) + default_restricted_engine_folder = default_restricted_folder / 'Engines' / 'o3de' + default_restricted_engine_folder.mkdir(parents=True, exist_ok=True) + default_restricted_templates_folder = default_restricted_folder / 'Templates' + default_restricted_templates_folder.mkdir(parents=True, exist_ok=True) + default_restricted_engine_folder_json = default_restricted_engine_folder / 'restricted.json' + if not default_restricted_engine_folder_json.is_file(): + with default_restricted_engine_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'o3de'}) + s.write(json.dumps(restricted_json_data, indent=4) + '\n') json_data = {} json_data.update({'o3de_manifest_name': f'{username}'}) @@ -140,45 +141,14 @@ def get_default_o3de_manifest_json_data() -> dict: json_data.update({'default_templates_folder': default_templates_folder.as_posix()}) json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()}) - - json_data.update({'engines': []}) json_data.update({'projects': []}) json_data.update({'external_subdirectories': []}) json_data.update({'templates': []}) - json_data.update({'restricted': []}) + json_data.update({'restricted': [default_restricted_engine_folder.as_posix()]}) json_data.update({'repos': []}) - - default_restricted_folder_json = default_restricted_folder / 'restricted.json' - if not default_restricted_folder_json.is_file(): - with default_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'o3de'}) - s.write(json.dumps(restricted_json_data, indent=4) + '\n') - - default_projects_restricted_folder_json = default_projects_restricted_folder / 'restricted.json' - if not default_projects_restricted_folder_json.is_file(): - with default_projects_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'projects'}) - s.write(json.dumps(restricted_json_data, indent=4) + '\n') - - default_gems_restricted_folder_json = default_gems_restricted_folder / 'restricted.json' - if not default_gems_restricted_folder_json.is_file(): - with default_gems_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'gems'}) - s.write(json.dumps(restricted_json_data, indent=4) + '\n') - - default_templates_restricted_folder_json = default_templates_restricted_folder / 'restricted.json' - if not default_templates_restricted_folder_json.is_file(): - with default_templates_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'templates'}) - s.write(json.dumps(restricted_json_data, indent=4) + '\n') - + json_data.update({'engines': []}) return json_data - def get_o3de_manifest() -> pathlib.Path: manifest_path = get_o3de_folder() / 'o3de_manifest.json' if not manifest_path.is_file(): @@ -229,12 +199,12 @@ def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> b return False -def get_gems_from_subdirectories(external_subdirs: list) -> list: - """ +def get_gems_from_external_subdirectories(external_subdirs: list) -> list: + ''' Helper Method for scanning a set of external subdirectories for gem.json files - """ + ''' def is_gem_subdirectory(subdir_files): - for name in subdir_files: + for name in files: if name == 'gem.json': return True return False @@ -250,7 +220,8 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list: return gem_directories -def get_engines() -> list: +# Data query methods +def get_manifest_engines() -> list: json_data = load_o3de_manifest() engine_list = json_data['engines'] if 'engines' in json_data else [] # Convert each engine dict entry into a string entry @@ -259,31 +230,31 @@ def get_engines() -> list: engine_list)) -def get_projects() -> list: +def get_manifest_projects() -> list: json_data = load_o3de_manifest() return json_data['projects'] if 'projects' in json_data else [] -def get_gems() -> list: - return get_gems_from_subdirectories(get_external_subdirectories()) +def get_manifest_gems() -> list: + return get_gems_from_external_subdirectories(get_manifest_external_subdirectories()) -def get_external_subdirectories() -> list: +def get_manifest_external_subdirectories() -> list: json_data = load_o3de_manifest() return json_data['external_subdirectories'] if 'external_subdirectories' in json_data else [] -def get_templates() -> list: +def get_manifest_templates() -> list: json_data = load_o3de_manifest() return json_data['templates'] if 'templates' in json_data else [] -def get_restricted() -> list: +def get_manifest_restricted() -> list: json_data = load_o3de_manifest() return json_data['restricted'] if 'restricted' in json_data else [] -def get_repos() -> list: +def get_manifest_repos() -> list: json_data = load_o3de_manifest() return json_data['repos'] if 'repos' in json_data else [] @@ -299,7 +270,7 @@ def get_engine_projects() -> list: def get_engine_gems() -> list: - return get_gems_from_subdirectories(get_engine_external_subdirectories()) + return get_gems_from_external_subdirectories(get_engine_external_subdirectories()) def get_engine_external_subdirectories() -> list: @@ -320,23 +291,9 @@ def get_engine_templates() -> list: return [] -def get_engine_restricted() -> list: - engine_path = get_this_engine_path() - engine_object = get_engine_json_data(engine_path=engine_path) - if engine_object: - return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), - engine_object['restricted'])) if 'restricted' in engine_object else [] - return [] - - # project.json queries -def get_project_engine_name(project_path: pathlib.Path) -> str or None: - project_object = get_project_json_data(project_path=project_path) - return project_object.get('engine', None) if project_object else None - - def get_project_gems(project_path: pathlib.Path) -> list: - return get_gems_from_subdirectories(get_project_external_subdirectories(project_path)) + return get_gems_from_external_subdirectories(get_project_external_subdirectories(project_path)) def get_project_external_subdirectories(project_path: pathlib.Path) -> list: @@ -355,74 +312,95 @@ def get_project_templates(project_path: pathlib.Path) -> list: return [] -def get_project_restricted(project_path: pathlib.Path) -> list: - project_object = get_project_json_data(project_path=project_path) - if project_object: - return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), - project_object['restricted'])) if 'restricted' in project_object else [] +# gem.json queries +def get_gem_gems(gem_path: pathlib.Path) -> list: + return get_gems_from_external_subdirectories(get_gem_external_subdirectories(gem_path)) + + +def get_gem_external_subdirectories(gem_path: pathlib.Path) -> list: + gem_object = get_gem_json_data(gem_path=gem_path) + if gem_object: + return list(map(lambda rel_path: (pathlib.Path(gem_path) / rel_path).as_posix(), + gem_object[ + 'external_subdirectories'])) if 'external_subdirectories' in gem_object else [] + return [] + + +def get_gem_templates(gem_path: pathlib.Path) -> list: + gem_object = get_gem_json_data(gem_path=gem_path) + if gem_object: + return list(map(lambda rel_path: (pathlib.Path(gem_path) / rel_path).as_posix(), + gem_object['templates'])) if 'templates' in gem_object else [] return [] # Combined manifest queries def get_all_projects() -> list: - projects_data = get_projects() + projects_data = get_manifest_projects() projects_data.extend(get_engine_projects()) # Remove duplicates from the list return list(dict.fromkeys(projects_data)) def get_all_gems(project_path: pathlib.Path = None) -> list: - gems_data = get_gems() - gems_data.extend(get_engine_gems()) - if project_path: - gems_data.extend(get_project_gems(project_path)) - return list(dict.fromkeys(gems_data)) + return get_gems_from_external_subdirectories(get_all_external_subdirectories(project_path)) def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list: - external_subdirectories_data = get_external_subdirectories() + external_subdirectories_data = get_manifest_external_subdirectories() external_subdirectories_data.extend(get_engine_external_subdirectories()) if project_path: external_subdirectories_data.extend(get_project_external_subdirectories(project_path)) + + def descend_gems(gem_path: pathlib.Path): + new_external_subdirectories_data = get_gem_external_subdirectories(gem_path) + external_subdirectories_data.extend(new_external_subdirectories_data) + new_gems_data = get_gems_from_external_subdirectories(new_external_subdirectories_data) + for new_gem in new_gems_data: + descend_gems(new_gem) + + gems_data = get_gems_from_external_subdirectories(external_subdirectories_data) + for gem in gems_data: + descend_gems(gem) + + # Remove duplicates from the list return list(dict.fromkeys(external_subdirectories_data)) def get_all_templates(project_path: pathlib.Path = None) -> list: - templates_data = get_templates() + templates_data = get_manifest_templates() templates_data.extend(get_engine_templates()) if project_path: templates_data.extend(get_project_templates(project_path)) + + gems_data = get_all_gems(project_path) + for gem_path in gems_data: + templates_data.extend(get_gem_templates(gem_path)) + + # Remove duplicates from the list return list(dict.fromkeys(templates_data)) -def get_all_restricted(project_path: pathlib.Path = None) -> list: - restricted_data = get_restricted() - restricted_data.extend(get_engine_restricted()) - if project_path: - restricted_data.extend(get_project_restricted(project_path)) - return list(dict.fromkeys(restricted_data)) - - # Template functions -def get_templates_for_project_creation(): +def get_templates_for_project_creation(project_path: pathlib.Path = None) -> list: project_templates = [] - for template_path in get_all_templates(): + for template_path in get_all_templates(project_path): template_path = pathlib.Path(template_path) - template_json_path = pathlib.Path(template_path) / 'template.json' + template_json_path = template_path / 'template.json' if not validation.valid_o3de_template_json(template_json_path): continue - project_json_path = template_path / 'Template' / 'project.json' if validation.valid_o3de_project_json(project_json_path): project_templates.append(template_path) + return project_templates -def get_templates_for_gem_creation(): +def get_templates_for_gem_creation(project_path: pathlib.Path = None) -> list: gem_templates = [] - for template_path in get_all_templates(): + for template_path in get_all_templates(project_path): template_path = pathlib.Path(template_path) - template_json_path = pathlib.Path(template_path) / 'template.json' + template_json_path = template_path / 'template.json' if not validation.valid_o3de_template_json(template_json_path): continue @@ -432,58 +410,20 @@ def get_templates_for_gem_creation(): return gem_templates -def get_templates_for_generic_creation(): # temporary until we have a better way to do this... maybe template_type element - def filter_project_and_gem_templates_out(template_path, - templates_for_project_creation = get_templates_for_project_creation(), - templates_for_gem_creation = get_templates_for_gem_creation()): +def get_templates_for_generic_creation(project_path: pathlib.Path = None) -> list: + generic_templates = [] + for template_path in get_all_templates(project_path): template_path = pathlib.Path(template_path) - return template_path not in templates_for_project_creation and template_path not in templates_for_gem_creation + template_json_path = template_path / 'template.json' + if not validation.valid_o3de_template_json(template_json_path): + continue + gem_json_path = template_path / 'Template' / 'gem.json' + project_json_path = template_path / 'Template' / 'project.json' + if not validation.valid_o3de_gem_json(gem_json_path) and\ + not validation.valid_o3de_project_json(project_json_path): + generic_templates.append(template_path) - return list(filter(filter_project_and_gem_templates_out, get_all_templates())) - - -def get_json_file_path(object_typename: str, - object_path: str or pathlib.Path) -> pathlib.Path: - if not object_typename or not object_path: - logger.error('Must specify an object typename and object path.') - return None - - object_path = pathlib.Path(object_path).resolve() - return object_path / f'{object_typename}.json' - - -def get_json_data_file(object_json: pathlib.Path, - object_typename: str, - object_validator: callable) -> dict or None: - if not object_typename: - logger.error('Missing object typename.') - return None - - if not object_json or not object_json.is_file(): - logger.error(f'Invalid {object_typename} json {object_json} supplied or file missing.') - return None - - if not object_validator or not object_validator(object_json): - logger.error(f'{object_typename} json {object_json} is not valid or could not be validated.') - return None - - with object_json.open('r') as f: - try: - object_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{object_json} failed to load: {e}') - else: - return object_json_data - - return None - - -def get_json_data(object_typename: str, - object_path: str or pathlib.Path, - object_validator: callable) -> dict or None: - object_json = get_json_file_path(object_typename, object_path) - - return get_json_data_file(object_json, object_typename, object_validator) + return generic_templates def get_engine_json_data(engine_name: str = None, @@ -495,7 +435,28 @@ def get_engine_json_data(engine_name: str = None, if engine_name and not engine_path: engine_path = get_registered(engine_name=engine_name) - return get_json_data('engine', engine_path, validation.valid_o3de_engine_json) + if not engine_path: + logger.error(f'Engine Path {engine_path} has not been registered.') + return None + + engine_path = pathlib.Path(engine_path).resolve() + engine_json = engine_path / 'engine.json' + if not engine_json.is_file(): + logger.error(f'Engine json {engine_json} is not present.') + return None + if not validation.valid_o3de_engine_json(engine_json): + logger.error(f'Engine json {engine_json} is not valid.') + return None + + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{engine_json} failed to load: {str(e)}') + else: + return engine_json_data + + return None def get_project_json_data(project_name: str = None, @@ -507,7 +468,28 @@ def get_project_json_data(project_name: str = None, if project_name and not project_path: project_path = get_registered(project_name=project_name) - return get_json_data('project', project_path, validation.valid_o3de_project_json) + if not project_path: + logger.error(f'Project Path {project_path} has not been registered.') + return None + + project_path = pathlib.Path(project_path).resolve() + project_json = project_path / 'project.json' + if not project_json.is_file(): + logger.error(f'Project json {project_json} is not present.') + return None + if not validation.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return None + + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{project_json} failed to load: {str(e)}') + else: + return project_json_data + + return None def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None, @@ -519,10 +501,28 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name, project_path=project_path) - if pathlib.Path(gem_path).is_file(): - return get_json_data_file(gem_path, 'gem', validation.valid_o3de_gem_json) - else: - return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) + if not gem_path: + logger.error(f'Gem Path {gem_path} has not been registered.') + return None + + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + logger.error(f'Gem json {gem_json} is not present.') + return None + if not validation.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return None + + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{gem_json} failed to load: {str(e)}') + else: + return gem_json_data + + return None def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None, @@ -534,7 +534,28 @@ def get_template_json_data(template_name: str = None, template_path: str or path if template_name and not template_path: template_path = get_registered(template_name=template_name, project_path=project_path) - return get_json_data('template', template_path, validation.valid_o3de_template_json) + if not template_path: + logger.error(f'Template Path {template_path} has not been registered.') + return None + + template_path = pathlib.Path(template_path).resolve() + template_json = template_path / 'template.json' + if not template_json.is_file(): + logger.error(f'Template json {template_json} is not present.') + return None + if not validation.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_json} is not valid.') + return None + + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{template_json} failed to load: {str(e)}') + else: + return template_json_data + + return None def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, @@ -546,26 +567,28 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path) - return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json) - - -def get_repo_json_data(repo_uri: str) -> dict or None: - if not repo_uri: - logger.error('Must specify a Repo Uri.') + if not restricted_path: + logger.error(f'Restricted Path {restricted_path} has not been registered.') return None - repo_json = get_repo_path(repo_uri=repo_uri) + restricted_path = pathlib.Path(restricted_path).resolve() + restricted_json = restricted_path / 'restricted.json' + if not restricted_json.is_file(): + logger.error(f'Restricted json {restricted_json} is not present.') + return None + if not validation.valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return None - return get_json_data_file(repo_json, "Repo", validation.valid_o3de_repo_json) + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{restricted_json} failed to load: {str(e)}') + else: + return restricted_json_data - -def get_repo_path(repo_uri: str, cache_folder: str or pathlib.Path = None) -> pathlib.Path: - if not cache_folder: - cache_folder = get_o3de_cache_folder() - - repo_manifest = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_manifest.encode()) - return cache_folder / str(repo_sha256.hexdigest() + '.json') + return None def get_registered(engine_name: str = None, @@ -604,7 +627,7 @@ def get_registered(engine_name: str = None, # check global first then this engine if isinstance(engine_name, str): - engines = get_engines() + engines = get_manifest_engines() for engine in engines: if isinstance(engine, dict): engine_path = pathlib.Path(engine['path']).resolve() @@ -633,72 +656,60 @@ def get_registered(engine_name: str = None, for project_path in projects: project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' - if not pathlib.Path(project_json).is_file(): - logger.warning(f'{project_json} does not exist') - else: - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{project_json} failed to load: {str(e)}') - else: - this_projects_name = project_json_data['project_name'] - if this_projects_name == project_name: - return project_path + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{project_json} failed to load: {str(e)}') + else: + this_projects_name = project_json_data['project_name'] + if this_projects_name == project_name: + return project_path elif isinstance(gem_name, str): gems = get_all_gems(project_path) for gem_path in gems: gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' - if not pathlib.Path(gem_json).is_file(): - logger.warning(f'{gem_json} does not exist') - else: - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{gem_json} failed to load: {str(e)}') - else: - this_gems_name = gem_json_data['gem_name'] - if this_gems_name == gem_name: - return gem_path + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{gem_json} failed to load: {str(e)}') + else: + this_gems_name = gem_json_data['gem_name'] + if this_gems_name == gem_name: + return gem_path elif isinstance(template_name, str): templates = get_all_templates(project_path) for template_path in templates: template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' - if not pathlib.Path(template_json).is_file(): - logger.warning(f'{template_json} does not exist') - else: - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{template_path} failed to load: {str(e)}') - else: - this_templates_name = template_json_data['template_name'] - if this_templates_name == template_name: - return template_path + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{template_path} failed to load: {str(e)}') + else: + this_templates_name = template_json_data['template_name'] + if this_templates_name == template_name: + return template_path elif isinstance(restricted_name, str): - restricted = get_all_restricted(project_path) + restricted = get_manifest_restricted() for restricted_path in restricted: restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' - if not pathlib.Path(restricted_json).is_file(): - logger.warning(f'{restricted_json} does not exist') - else: - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{restricted_json} failed to load: {str(e)}') - else: - this_restricted_name = restricted_json_data['restricted_name'] - if this_restricted_name == restricted_name: - return restricted_path + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{restricted_json} failed to load: {str(e)}') + else: + this_restricted_name = restricted_json_data['restricted_name'] + if this_restricted_name == restricted_name: + return restricted_path elif isinstance(default_folder, str): if default_folder == 'engines': @@ -720,7 +731,9 @@ def get_registered(engine_name: str = None, elif isinstance(repo_name, str): cache_folder = get_o3de_cache_folder() for repo_uri in json_data['repos']: - cache_file = get_repo_path(repo_uri=repo_uri, cache_folder=cache_folder) + repo_uri = pathlib.Path(repo_uri).resolve() + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') if cache_file.is_file(): repo = pathlib.Path(cache_file).resolve() with repo.open('r') as f: diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 77e098d0ba..2bd3202ca0 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -39,69 +39,68 @@ def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.P return project_path -def print_this_engine(verbose: int) -> int: +def print_this_engine(verbose: int = 0) -> int: this_engine_path = manifest.get_this_engine_path() print(f'This Engine:\n{json.dumps(str(this_engine_path), indent=4)}') if verbose > 0: return print_manifest_json_data([this_engine_path], 'This Engine', - manifest.get_engine_json_data, 'engine_path') + manifest.get_engine_json_data, 'engine_path') return 0 -def print_engines(verbose: int) -> None: - engines_data = manifest.get_engines() +def print_engines(verbose: int = 0) -> int: + engines_data = manifest.get_manifest_engines() print(f'Engine Paths:\n{json.dumps(engines_data, indent=4)}') if verbose > 0: return print_manifest_json_data(engines_data, 'Engine Jsons', - manifest.get_engine_json_data, 'engine_path') + manifest.get_engine_json_data, 'engine_path') return 0 -def print_projects(verbose: int) -> int: - projects_data = manifest.get_projects() +def print_projects(verbose: int = 0) -> int: + projects_data = manifest.get_all_projects() print(f'Project Paths:\n{json.dumps(projects_data, indent=4)}') if verbose > 0: return print_manifest_json_data(projects_data, 'Project Jsons', - manifest.get_project_json_data, 'project_path') + manifest.get_project_json_data, 'project_path') return 0 -def print_gems(verbose: int) -> int: - gems_data = manifest.get_gems() +def print_gems(verbose: int = 0) -> int: + gems_data = manifest.get_all_gems() print(f'Gem Paths:\n{json.dumps(gems_data, indent=4)}') if verbose > 0: return print_manifest_json_data(gems_data, 'Gem Jsons', - manifest.get_gem_json_data, 'gem_path') + manifest.get_gem_json_data, 'gem_path') return 0 -def print_external_subdirectories(verbose: int) -> int: - external_subdirs_data = manifest.get_external_subdirectories() +def print_external_subdirectories(verbose: int = 0) -> int: + external_subdirs_data = manifest.get_all_external_subdirectories() print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}') return 0 - def print_templates(verbose: int) -> int: - templates_data = manifest.get_templates() + templates_data = manifest.get_all_templates() print(f'Template Paths:\n{json.dumps(templates_data, indent=4)}') if verbose > 0: return print_manifest_json_data(templates_data, 'Template Jsons', - manifest.get_template_json_data, 'template_path') + manifest.get_template_json_data, 'template_path') return 0 def print_restricted(verbose: int) -> int: - restricted_data = manifest.get_restricted() + restricted_data = manifest.get_manifest_restricted() print(f'Restricted Paths:\n{json.dumps(restricted_data, indent=4)}') if verbose > 0: return print_manifest_json_data(restricted_data, 'Restricted Jsons', - manifest.get_restricted_json_data, 'restricted_path') + manifest.get_restricted_json_data, 'restricted_path') return 0 @@ -112,7 +111,7 @@ def print_engine_projects(verbose: int) -> int: if verbose > 0: return print_manifest_json_data(engine_projects_data, 'Project Jsons', - manifest.get_project_json_data, 'project_path') + manifest.get_project_json_data, 'project_path') return 0 @@ -122,7 +121,7 @@ def print_engine_gems(verbose: int) -> int: if verbose > 0: return print_manifest_json_data(engine_gems_data, 'Gem Jsons', - manifest.get_gem_json_data, 'gem_path') + manifest.get_gem_json_data, 'gem_path') return 0 @@ -132,17 +131,7 @@ def print_engine_templates(verbose: int) -> int: if verbose > 0: return print_manifest_json_data(engine_templates_data, 'Template Jsons', - manifest.get_template_json_data, 'template_path') - return 0 - - -def print_engine_restricted(verbose: int) -> int: - engine_restricted_data = manifest.get_engine_restricted() - print(f'Restricted Paths:\n{json.dumps(engine_restricted_data, indent=4)}') - - if verbose > 0: - return print_manifest_json_data(engine_restricted_data, 'Restricted Jsons', - manifest.get_restricted_json_data, 'restricted_path') + manifest.get_template_json_data, 'template_path') return 0 @@ -153,21 +142,6 @@ def print_engine_external_subdirectories(verbose: int) -> int: # Project output methods -def print_project_engine_name(verbose: int, project_path: pathlib.Path, project_name: str) -> int: - project_path = get_project_path(project_path, project_name) - if not project_path: - return 1 - - engine_name = manifest.get_project_engine_name(project_path) - if engine_name: - print(f'Project\'s engine name:\n{engine_name}') - return 0 - - if verbose > 0: - logger.info(f'project.json at path "{project_path}" contains no registered "engine" field') - return 1 - - def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: str) -> int: project_path = get_project_path(project_path, project_name) if not project_path: @@ -178,7 +152,7 @@ def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: s if verbose > 0: return print_manifest_json_data(project_gems_data, 'Gems Jsons', - manifest.get_gem_json_data, 'gem_path') + manifest.get_gem_json_data, 'gem_path') return 0 @@ -201,20 +175,7 @@ def print_project_templates(verbose: int, project_path: pathlib.Path, project_na print(f'Template Paths:\n{json.dumps(project_templates_data, indent=4)}') if verbose > 0: return print_manifest_json_data(project_templates_data, 'Template Jsons', - manifest.get_template_json_data, 'template_path') - return 0 - - -def print_project_restricted(verbose: int, project_path: pathlib.Path, project_name: str) -> int: - project_path = get_project_path(project_path, project_name) - if not project_path: - return 1 - - project_restricted_data = manifest.get_project_restricted(project_path) - print(f'Restricted Paths:\n{json.dumps(project_restricted_data, indent=4)}') - if verbose > 0: - return print_manifest_json_data(project_restricted_data, 'Restricted Jsons', - manifest.get_restricted_json_data, 'restricted_path') + manifest.get_template_json_data, 'template_path') return 0 @@ -224,12 +185,12 @@ def print_all_projects(verbose: int) -> int: if verbose > 0: return print_manifest_json_data(all_projects_data, 'Project Jsons', - manifest.get_project_json_data, 'project_path') + manifest.get_project_json_data, 'project_path') return 0 def print_all_gems(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: - all_gems = manifest.get_gems() + all_gems = manifest.get_manifest_gems() all_gems.extend(manifest.get_engine_gems()) # If a project path or project name is supplied query the gems from that project, otherwise query the gems from @@ -245,12 +206,12 @@ def print_all_gems(verbose: int, project_path: pathlib.Path = None, project_name if verbose > 0: return print_manifest_json_data(all_gems, 'Gem Jsons', - manifest.get_gem_json_data, 'gem_path') + manifest.get_gem_json_data, 'gem_path') return 0 def print_all_external_subdirectories(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: - all_external_subdirectories = manifest.get_external_subdirectories() + all_external_subdirectories = manifest.get_manifest_external_subdirectories() all_external_subdirectories.extend(manifest.get_engine_external_subdirectories()) # If a project path or project name is supplied query the external subdirectories from that project, @@ -267,7 +228,7 @@ def print_all_external_subdirectories(verbose: int, project_path: pathlib.Path = def print_all_templates(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: - all_templates = manifest.get_templates() + all_templates = manifest.get_manifest_templates() all_templates.extend(manifest.get_engine_templates()) # If a project path or project name is supplied query the templates from that project, @@ -283,31 +244,9 @@ def print_all_templates(verbose: int, project_path: pathlib.Path = None, project if verbose > 0: return print_manifest_json_data(all_templates, 'Template Jsons', - manifest.get_template_json_data, 'template_path') + manifest.get_template_json_data, 'template_path') return 0 - -def print_all_restricted(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: - all_restricted = manifest.get_restricted() - all_restricted.extend(manifest.get_engine_restricted()) - - # If a project path or project name is supplied query the restricted from that project, - # otherwise query the restricted from all projects - project_path = get_project_path(project_path, project_name) if project_path or project_name else None - projects = [project_path] if project_path else manifest.get_all_projects() - for project in projects: - all_restricted.extend(manifest.get_project_restricted(project)) - - # Filter out duplicates - all_restricted = list(dict.fromkeys(all_restricted)) - print(f'Restricted Paths:\n{json.dumps(all_restricted, indent=4)}') - - if verbose > 0: - return print_manifest_json_data(all_restricted, 'Restricted Jsons', - manifest.get_restricted_json_data, 'restricted_path') - return 0 - - def print_manifest_json_data(uri_json_data: list, print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int: print('\n') @@ -351,7 +290,7 @@ def print_repos_data(repos_data: dict) -> int: def print_repos(verbose: int) -> int: - repos_data = manifest.get_repos() + repos_data = manifest.get_manifest_repos() print(json.dumps(repos_data, indent=4)) if verbose > 0: @@ -370,16 +309,13 @@ def register_show(verbose: int, project_path: pathlib.Path = None, project_name: result = print_all_projects(verbose) or result result = print_all_gems(verbose, project_path, project_name) or result result = print_all_templates(verbose, project_path, project_name) or result - result = print_all_restricted(verbose, project_path, project_name) or result + result = print_restricted(verbose) or result result = print_repos(verbose) or result return result def _run_register_show(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - if args.this_engine: return print_this_engine(args.verbose) elif args.engines: @@ -393,7 +329,7 @@ def _run_register_show(args: argparse) -> int: elif args.templates: return print_templates(args.verbose) elif args.repos: - return register_show_repos(args.verbose) + return print_repos(args.verbose) elif args.restricted: return print_restricted(args.verbose) @@ -405,8 +341,6 @@ def _run_register_show(args: argparse) -> int: return print_engine_external_subdirectories(args.verbose) elif args.engine_templates: return print_engine_templates(args.verbose) - elif args.engine_restricted: - return print_engine_restricted(args.verbose) elif args.project_gems: return print_project_gems(args.verbose, args.project_path, args.project_name) @@ -414,8 +348,6 @@ def _run_register_show(args: argparse) -> int: return print_project_external_subdirectories(args.verbose, args.project_path, args.project_name) elif args.project_templates: return print_project_templates(args.verbose, args.project_path, args.project_name) - elif args.project_restricted: - return print_project_restricted(args.verbose, args.project_path, args.project_name) elif args.project_engine_name: return print_project_engine_name(args.verbose, args.project_path, args.project_name) @@ -427,8 +359,6 @@ def _run_register_show(args: argparse) -> int: return print_all_external_subdirectories(args.verbose, args.project_path, args.project_name) elif args.all_templates: return print_all_templates(args.verbose, args.project_path, args.project_name) - elif args.all_restricted: - return print_all_restricted(args.verbose, args.project_path, args.project_name) else: return register_show(args.verbose, args.project_path, args.project_name) @@ -538,9 +468,6 @@ def add_parser_args(parser): project_group.add_argument('-pn', '--project-name', type=str, help='The name of a project.') - parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, - help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_register_show) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index a175104997..926c413521 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -490,7 +490,7 @@ def register_repo(json_data: dict, repo_sha256 = hashlib.sha256(url.encode()) cache_file = manifest.get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') - result = utils.download_file(parsed_uri, cache_file, True) + result = utils.download_file(url, cache_file, True) if result == 0: json_data.setdefault('repos', []).insert(0, repo_uri) @@ -793,9 +793,6 @@ def register(engine_path: pathlib.Path = None, def _run_register(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - if args.update: remove_invalid_o3de_objects() return repo.refresh_repos() @@ -891,8 +888,6 @@ def add_parser_args(parser): default=False, help='Refresh the repo cache.') - parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, - help='By default the home folder is the user folder, override it to this folder.') parser.add_argument('-r', '--remove', action='store_true', required=False, default=False, help='Remove entry.') diff --git a/scripts/o3de/tests/unit_test_enable_gem.py b/scripts/o3de/tests/unit_test_enable_gem.py index c765f74731..8067fc329d 100644 --- a/scripts/o3de/tests/unit_test_enable_gem.py +++ b/scripts/o3de/tests/unit_test_enable_gem.py @@ -42,8 +42,10 @@ TEST_GEM_JSON_PAYLOAD = ''' { "gem_name": "TestGem", "display_name": "TestGem", - "license": "What license TestGem uses goes here: i.e. https://opensource.org/licenses/MIT", - "origin": "The primary repo for TestGem goes here: i.e. http://www.mydomain.com", + "license": "Apache-2.0 Or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", + "origin": "Open 3D Engine - o3de.org", + "origin_url": "https://github.com/o3de/o3de", "type": "Code", "summary": "A short description of TestGem.", "canonical_tags": [ @@ -53,7 +55,10 @@ TEST_GEM_JSON_PAYLOAD = ''' "TestGem" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "Any requirement goes here.", + "documentation_url": "The link to the documentation goes here.", + "dependencies": [ + ] } ''' diff --git a/scripts/o3de/tests/unit_test_engine_template.py b/scripts/o3de/tests/unit_test_engine_template.py index ed1c8258d3..da23ee11f1 100755 --- a/scripts/o3de/tests/unit_test_engine_template.py +++ b/scripts/o3de/tests/unit_test_engine_template.py @@ -93,37 +93,28 @@ TEST_TEMPLATE_JSON_CONTENTS = """\ "copyFiles": [ { "file": "Code/Include/${Name}/${Name}Bus.h", - "origin": "Code/Include/${Name}/${Name}Bus.h", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { - "file": "Code/Include/Platform/Salem/${Name}Bus.h", - "origin": "Code/Include/Platform/Salem/${Name}Bus.h", - "isTemplated": true, - "isOptional": false + "file": "Code/Include/Platform/Windows/${Name}Bus.h", + "isTemplated": true } ], "createDirectories": [ { - "dir": "Code", - "origin": "Code" + "dir": "Code" }, { - "dir": "Code/Include", - "origin": "Code/Include" + "dir": "Code/Include" }, { - "dir": "Code/Include/${Name}", - "origin": "Code/Include/${Name}" + "dir": "Code/Include/${Name}" }, { - "dir": "Code/Include/Platform", - "origin": "Code/Include/Platform" + "dir": "Code/Include/Platform" }, { - "dir": "Code/Include/Platform/Salem", - "origin": "Code/Include/Platform/Salem" + "dir": "Code/Include/Platform/Windows" } ] } @@ -174,10 +165,10 @@ def test_create_template(tmpdir, with gem_bus_file.open('w') as s: s.write(concrete_contents) - engine_gem_code_include_platform_salem = template_source_path / 'Code/Include/Platform/Salem' - engine_gem_code_include_platform_salem.mkdir(parents=True, exist_ok=True) + engine_gem_code_include_platform_windows = template_source_path / 'Code/Include/Platform/Windows' + engine_gem_code_include_platform_windows.mkdir(parents=True, exist_ok=True) - restricted_gem_bus_file = engine_gem_code_include_platform_salem / 'TestTemplateBus.h' + restricted_gem_bus_file = engine_gem_code_include_platform_windows / 'TestTemplateBus.h' with restricted_gem_bus_file.open('w') as s: s.write(concrete_contents) @@ -209,9 +200,9 @@ def test_create_template(tmpdir, else: assert s_data == templated_contents_without_license - platform_template_folder = engine_root / 'Salem/Templates' + platform_template_folder = engine_root / 'Windows/Templates' - new_platform_default_name_bus_file = template_content_folder / 'Code/Include/Platform/Salem/${Name}Bus.h' + new_platform_default_name_bus_file = template_content_folder / 'Code/Include/Platform/Windows/${Name}Bus.h' assert new_platform_default_name_bus_file.is_file() with new_platform_default_name_bus_file.open('r') as s: s_data = s.read() @@ -255,7 +246,7 @@ class TestCreateTemplate: s.write(templated_contents) template_content_folder = template_default_folder / 'Template' - platform_default_name_bus_dir = template_content_folder / 'Code/Include/Platform/Salem' + platform_default_name_bus_dir = template_content_folder / 'Code/Include/Platform/Windows' platform_default_name_bus_dir.mkdir(parents=True, exist_ok=True) platform_default_name_bus_file = platform_default_name_bus_dir / '${Name}Bus.h' @@ -263,10 +254,13 @@ class TestCreateTemplate: s.write(templated_contents) template_dest_path = engine_root / instantiated_name - # Skip registeration in test + # Skip registration in test with patch('uuid.uuid4', return_value=uuid.uuid5(uuid.NAMESPACE_DNS, instantiated_name)) as uuid4_mock: - result = create_from_template_func(template_dest_path, template_path=template_default_folder, force=True, - keep_license_text=keep_license_text, **create_from_template_kwargs) + result = create_from_template_func(template_dest_path, + template_path=template_default_folder, + keep_license_text=keep_license_text, + force=True, + **create_from_template_kwargs) if expect_failure: assert result != 0 else: @@ -281,7 +275,7 @@ class TestCreateTemplate: s_data = s.read() assert s_data == concrete_contents - platform_test_bus_folder = test_folder / 'Code/Include/Platform/Salem' + platform_test_bus_folder = test_folder / 'Code/Include/Platform/Windows' assert platform_test_bus_folder.is_dir() platform_default_name_bus_file = platform_test_bus_folder / f'{instantiated_name}Bus.h' @@ -338,9 +332,7 @@ class TestCreateTemplate: template_json_dict.setdefault('copyFiles', []).append( { "file": "project.json", - "origin": "project.json", - "isTemplated": True, - "isOptional": False + "isTemplated": True }) # Convert the python dictionary back into a json string template_json_contents = json.dumps(template_json_dict, indent=4) @@ -376,9 +368,7 @@ class TestCreateTemplate: template_json_dict.setdefault('copyFiles', []).append( { "file": "gem.json", - "origin": "gem.json", - "isTemplated": True, - "isOptional": False + "isTemplated": True }) #Convert dict back to string template_json_contents = json.dumps(template_json_dict, indent=4) diff --git a/scripts/o3de/tests/unit_test_gem_properties.py b/scripts/o3de/tests/unit_test_gem_properties.py index dee5811b65..6358917852 100644 --- a/scripts/o3de/tests/unit_test_gem_properties.py +++ b/scripts/o3de/tests/unit_test_gem_properties.py @@ -18,10 +18,9 @@ TEST_GEM_JSON_PAYLOAD = ''' { "gem_name": "TestGem", "display_name": "TestGem", - "license": "MIT", - "license_url": "https://opensource.org/licenses/MIT", + "license": "Apache-2.0 or MIT", + "license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt", "origin": "The primary repo for TestGem goes here: i.e. http://www.mydomain.com", - "type": "Code", "summary": "A short description of TestGem.", "canonical_tags": [ "Gem" @@ -31,7 +30,9 @@ TEST_GEM_JSON_PAYLOAD = ''' ], "icon_path": "preview.png", "requirements": "", - "documentation_url": "https://o3de.org/docs/" + "documentation_url": "https://o3de.org/docs/", + "dependencies": [ + ] } ''' diff --git a/scripts/o3de/tests/unit_test_manifest.py b/scripts/o3de/tests/unit_test_manifest.py index ad4809dc1d..c7d7a7573b 100644 --- a/scripts/o3de/tests/unit_test_manifest.py +++ b/scripts/o3de/tests/unit_test_manifest.py @@ -22,7 +22,7 @@ from o3de import manifest ]) class TestGetTemplatesForCreation: @staticmethod - def get_templates() -> list: + def get_manifest_templates() -> list: return [] @staticmethod @@ -40,20 +40,24 @@ class TestGetTemplatesForCreation: ) def test_get_templates_for_generic_creation(self, valid_project_json_paths, valid_gem_json_paths, expected_template_paths): - def validate_project_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_project_json_paths + def validate_project_json(project_json_path) -> bool: + return pathlib.Path(project_json_path) in valid_project_json_paths - def validate_gem_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_gem_json_paths + def validate_gem_json(gem_json_path) -> bool: + return pathlib.Path(gem_json_path) in valid_gem_json_paths - with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + with patch('o3de.manifest.get_manifest_templates', side_effect=self.get_manifest_templates)\ + as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates)\ as get_project_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates)\ as get_engine_templates_patch, \ - patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json,\ - patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) as validate_project_json,\ - patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + patch('o3de.validation.valid_o3de_template_json', return_value=True) \ + as validate_template_json,\ + patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ + as validate_project_json,\ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ + as validate_gem_json: templates = manifest.get_templates_for_generic_creation() assert templates == expected_template_paths @@ -64,21 +68,24 @@ class TestGetTemplatesForCreation: ) def test_get_templates_for_gem_creation(self, valid_project_json_paths, valid_gem_json_paths, expected_template_paths): - def validate_project_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_project_json_paths + def validate_project_json(project_json_path) -> bool: + return pathlib.Path(project_json_path) in valid_project_json_paths - def validate_gem_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_gem_json_paths + def validate_gem_json(gem_json_path) -> bool: + return pathlib.Path(gem_json_path) in valid_gem_json_paths - with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + with patch('o3de.manifest.get_manifest_templates', side_effect=self.get_manifest_templates)\ + as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ as get_project_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ as get_engine_templates_patch, \ - patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ - patch('o3de.validation.valid_o3de_project_json', - side_effect=validate_project_json) as validate_project_json, \ - patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + patch('o3de.validation.valid_o3de_template_json', return_value=True) \ + as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ + as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ + as validate_gem_json: templates = manifest.get_templates_for_project_creation() assert templates == expected_template_paths @@ -89,20 +96,23 @@ class TestGetTemplatesForCreation: ) def test_get_templates_for_project_creation(self, valid_project_json_paths, valid_gem_json_paths, expected_template_paths): - def validate_project_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_project_json_paths + def validate_project_json(project_json_path) -> bool: + return pathlib.Path(project_json_path) in valid_project_json_paths - def validate_gem_json(template_path) -> bool: - return pathlib.Path(template_path) in valid_gem_json_paths + def validate_gem_json(gem_json_path) -> bool: + return pathlib.Path(gem_json_path) in valid_gem_json_paths - with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + with patch('o3de.manifest.get_manifest_templates', side_effect=self.get_manifest_templates) \ + as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ as get_project_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ as get_engine_templates_patch, \ - patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ - patch('o3de.validation.valid_o3de_project_json', - side_effect=validate_project_json) as validate_project_json, \ - patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + patch('o3de.validation.valid_o3de_template_json', return_value=True) \ + as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ + as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ + as validate_gem_json: templates = manifest.get_templates_for_gem_creation() assert templates == expected_template_paths \ No newline at end of file diff --git a/scripts/o3de/tests/unit_test_print_registration.py b/scripts/o3de/tests/unit_test_print_registration.py index 7e3e75edcd..d01434c99f 100644 --- a/scripts/o3de/tests/unit_test_print_registration.py +++ b/scripts/o3de/tests/unit_test_print_registration.py @@ -90,27 +90,20 @@ TEST_TEMPLATE_JSON_PAYLOAD = ''' "copyFiles": [ { "file": "CMakeLists.txt", - "origin": "CMakeLists.txt", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "gem.json", - "origin": "gem.json", - "isTemplated": true, - "isOptional": false + "isTemplated": true }, { "file": "preview.png", - "origin": "preview.png", - "isTemplated": false, - "isOptional": false + "isTemplated": false } ], "createDirectories": [ { - "dir": "Assets", - "origin": "Assets" + "dir": "Assets" } ] } @@ -277,13 +270,9 @@ class TestPrintRegistration: # Patch the manifest.py function to locate gem.json files in external subdirectories # to just return a fake path to a single test gem - def get_gems_from_subdirectories(external_subdirs: list) -> list: - return ["D:/TestGem"] - with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ patch('o3de.manifest.get_gem_json_data', side_effect=self.get_gem_json_data) as get_json_patch, \ patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \ - patch('o3de.manifest.get_gems_from_subdirectories', side_effect=get_gems_from_subdirectories) as get_gems_from_subdirs_patch, \ patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch: result = print_registration._run_register_show(test_args) assert result == 0