From 1a0805efb8b1e57968ec2fbdff6f5ceb54da404c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pe=C5=82ka?= Date: Tue, 30 Jul 2024 18:21:19 +0200 Subject: [PATCH 1/2] Smoothing gem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gem allows user to smooth movement of the entity. It provides two types of smoothing: simple and damping. Co-authored-by: Patryk Antosz Signed-off-by: Michał Pełka --- Gems/Smoothing/.gitignore | 0 Gems/Smoothing/CMakeLists.txt | 22 ++ Gems/Smoothing/Code/CMakeLists.txt | 249 +++++++++++++++++ .../Code/Include/Smoothing/SmoothingTypeIds.h | 25 ++ .../Code/Platform/Android/PAL_android.cmake | 4 + .../Android/smoothing_api_files.cmake | 3 + .../Android/smoothing_private_files.cmake | 8 + .../Android/smoothing_shared_files.cmake | 8 + .../Clang/ros2_static_editor_clang.cmake | 11 + .../Common/GCC/ros2_static_editor_gcc.cmake | 11 + .../Common/msvc/ros2_static_editor_msvc.cmake | 11 + .../Code/Platform/Linux/PAL_linux.cmake | 4 + .../Platform/Linux/smoothing_api_files.cmake | 3 + .../Linux/smoothing_editor_api_files.cmake | 3 + .../Linux/smoothing_private_files.cmake | 8 + .../Linux/smoothing_shared_files.cmake | 8 + .../Smoothing/Code/Platform/Mac/PAL_mac.cmake | 4 + .../Platform/Mac/smoothing_api_files.cmake | 3 + .../Mac/smoothing_editor_api_files.cmake | 3 + .../Mac/smoothing_private_files.cmake | 8 + .../Platform/Mac/smoothing_shared_files.cmake | 8 + .../Code/Platform/Windows/PAL_windows.cmake | 4 + .../Windows/smoothing_api_files.cmake | 3 + .../Windows/smoothing_editor_api_files.cmake | 3 + .../Windows/smoothing_private_files.cmake | 8 + .../Windows/smoothing_shared_files.cmake | 8 + .../Smoothing/Code/Platform/iOS/PAL_ios.cmake | 4 + .../Platform/iOS/smoothing_api_files.cmake | 3 + .../iOS/smoothing_private_files.cmake | 8 + .../Platform/iOS/smoothing_shared_files.cmake | 8 + .../Source/Clients/SmoothingComponent.cpp | 258 ++++++++++++++++++ .../Code/Source/Clients/SmoothingComponent.h | 92 +++++++ .../Code/Source/Clients/SmoothingModule.cpp | 20 ++ .../Clients/SmoothingSystemComponent.cpp | 50 ++++ .../Source/Clients/SmoothingSystemComponent.h | 34 +++ Gems/Smoothing/Code/Source/Clients/Utils.cpp | 81 ++++++ Gems/Smoothing/Code/Source/Clients/Utils.h | 41 +++ .../Code/Source/SmoothingModuleInterface.cpp | 36 +++ .../Code/Source/SmoothingModuleInterface.h | 23 ++ .../Source/Tools/SmoothingEditorComponent.cpp | 46 ++++ .../Source/Tools/SmoothingEditorComponent.h | 27 ++ .../Source/Tools/SmoothingEditorModule.cpp | 45 +++ .../Tools/SmoothingEditorSystemComponent.cpp | 58 ++++ .../Tools/SmoothingEditorSystemComponent.h | 35 +++ .../Code/Tests/Clients/SmoothingTest.cpp | 4 + .../Code/Tests/Tools/SmoothingEditorTest.cpp | 4 + Gems/Smoothing/Code/smoothing_api_files.cmake | 4 + .../Code/smoothing_editor_api_files.cmake | 4 + .../Code/smoothing_editor_private_files.cmake | 7 + .../Code/smoothing_editor_shared_files.cmake | 4 + .../Code/smoothing_editor_tests_files.cmake | 4 + .../Code/smoothing_private_files.cmake | 11 + .../Code/smoothing_shared_files.cmake | 4 + .../Code/smoothing_tests_files.cmake | 4 + .../Registry/assetprocessor_settings.setreg | 18 ++ Gems/Smoothing/gem.json | 28 ++ Gems/Smoothing/preview.png | Bin 0 -> 4475 bytes doc/Smoothing.png | Bin 0 -> 21706 bytes readme.md | 8 +- 59 files changed, 1402 insertions(+), 1 deletion(-) create mode 100644 Gems/Smoothing/.gitignore create mode 100644 Gems/Smoothing/CMakeLists.txt create mode 100644 Gems/Smoothing/Code/CMakeLists.txt create mode 100644 Gems/Smoothing/Code/Include/Smoothing/SmoothingTypeIds.h create mode 100644 Gems/Smoothing/Code/Platform/Android/PAL_android.cmake create mode 100644 Gems/Smoothing/Code/Platform/Android/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Android/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Android/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Common/Clang/ros2_static_editor_clang.cmake create mode 100644 Gems/Smoothing/Code/Platform/Common/GCC/ros2_static_editor_gcc.cmake create mode 100644 Gems/Smoothing/Code/Platform/Common/msvc/ros2_static_editor_msvc.cmake create mode 100644 Gems/Smoothing/Code/Platform/Linux/PAL_linux.cmake create mode 100644 Gems/Smoothing/Code/Platform/Linux/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Linux/smoothing_editor_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Linux/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Linux/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Mac/PAL_mac.cmake create mode 100644 Gems/Smoothing/Code/Platform/Mac/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Mac/smoothing_editor_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Mac/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Mac/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Windows/PAL_windows.cmake create mode 100644 Gems/Smoothing/Code/Platform/Windows/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Windows/smoothing_editor_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Windows/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/Windows/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/iOS/PAL_ios.cmake create mode 100644 Gems/Smoothing/Code/Platform/iOS/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/iOS/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/Platform/iOS/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp create mode 100644 Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h create mode 100644 Gems/Smoothing/Code/Source/Clients/SmoothingModule.cpp create mode 100644 Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.cpp create mode 100644 Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.h create mode 100644 Gems/Smoothing/Code/Source/Clients/Utils.cpp create mode 100644 Gems/Smoothing/Code/Source/Clients/Utils.h create mode 100644 Gems/Smoothing/Code/Source/SmoothingModuleInterface.cpp create mode 100644 Gems/Smoothing/Code/Source/SmoothingModuleInterface.h create mode 100644 Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp create mode 100644 Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h create mode 100644 Gems/Smoothing/Code/Source/Tools/SmoothingEditorModule.cpp create mode 100644 Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.cpp create mode 100644 Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.h create mode 100644 Gems/Smoothing/Code/Tests/Clients/SmoothingTest.cpp create mode 100644 Gems/Smoothing/Code/Tests/Tools/SmoothingEditorTest.cpp create mode 100644 Gems/Smoothing/Code/smoothing_api_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_editor_api_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_editor_private_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_editor_shared_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_editor_tests_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_private_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_shared_files.cmake create mode 100644 Gems/Smoothing/Code/smoothing_tests_files.cmake create mode 100644 Gems/Smoothing/Registry/assetprocessor_settings.setreg create mode 100644 Gems/Smoothing/gem.json create mode 100644 Gems/Smoothing/preview.png create mode 100644 doc/Smoothing.png diff --git a/Gems/Smoothing/.gitignore b/Gems/Smoothing/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/Gems/Smoothing/CMakeLists.txt b/Gems/Smoothing/CMakeLists.txt new file mode 100644 index 0000000..655246b --- /dev/null +++ b/Gems/Smoothing/CMakeLists.txt @@ -0,0 +1,22 @@ + +# Query the gem name from the gem.json file if possible +# otherwise fallback to using SensorDebug +o3de_find_ancestor_gem_root(gem_path gem_name "${CMAKE_CURRENT_SOURCE_DIR}") +if (NOT gem_name) + set(gem_name "Smoothing") +endif() + +# Fallback to using the current source CMakeLists.txt directory as the gem root path +if (NOT gem_path) + set(gem_path ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +set(gem_json ${gem_path}/gem.json) + +o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) + +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}") + +ly_add_external_target_path(${CMAKE_CURRENT_SOURCE_DIR}/3rdParty) + +add_subdirectory(Code) diff --git a/Gems/Smoothing/Code/CMakeLists.txt b/Gems/Smoothing/Code/CMakeLists.txt new file mode 100644 index 0000000..d9cbeec --- /dev/null +++ b/Gems/Smoothing/Code/CMakeLists.txt @@ -0,0 +1,249 @@ + +# 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: 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/Smoothing/Code/Platform/ or +# //Gems/Smoothing/Code +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 gem +# is supported by this platform. +include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + +# Check to see if building the Gem Modules are supported for the current platform +if(NOT PAL_TRAIT_SMOOTHING_SUPPORTED) + return() +endif() + +# The ${gem_name}.API target declares the common interface that users of this gem should depend on in their targets +ly_add_target( + NAME ${gem_name}.API INTERFACE + NAMESPACE Gem + FILES_CMAKE + smoothing_api_files.cmake + ${pal_dir}/smoothing_api_files.cmake + INCLUDE_DIRECTORIES + INTERFACE + Include + BUILD_DEPENDENCIES + INTERFACE + AZ::AzCore +) + +# The ${gem_name}.Private.Object target is an internal target +# It should not be used outside of this Gems CMakeLists.txt +ly_add_target( + NAME ${gem_name}.Private.Object STATIC + NAMESPACE Gem + FILES_CMAKE + smoothing_private_files.cmake + ${pal_dir}/smoothing_private_files.cmake + TARGET_PROPERTIES + O3DE_PRIVATE_TARGET TRUE + INCLUDE_DIRECTORIES + PRIVATE + Include + Source + Source/3rdParty/ + BUILD_DEPENDENCIES + PUBLIC + AZ::AzCore + AZ::AzFramework +) + +# Here add ${gem_name} target, it depends on the Private Object library and Public API interface +ly_add_target( + NAME ${gem_name} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} + NAMESPACE Gem + FILES_CMAKE + smoothing_shared_files.cmake + ${pal_dir}/smoothing_shared_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + Include + PRIVATE + Source + BUILD_DEPENDENCIES + PUBLIC + Gem::${gem_name}.API + PRIVATE + Gem::${gem_name}.Private.Object +) +find_package (Eigen3 3.3 NO_MODULE) + +target_link_libraries(${gem_name}.Private.Object PUBLIC Eigen3::Eigen) + + # Include the gem name into the Client Module source file +# for use with the AZ_DECLARE_MODULE_CLASS macro +# This is to allow renaming of the gem to also cause +# the CreateModuleClass_Gem_ function which +# is used to bootstrap the gem in monolithic builds to link to the new gem name +ly_add_source_properties( +SOURCES + Source/Clients/SmoothingModule.cpp +PROPERTY COMPILE_DEFINITIONS + VALUES + O3DE_GEM_NAME=${gem_name} + O3DE_GEM_VERSION=${gem_version}) + +# By default, we will specify that the above target ${gem_name} would be used by +# Client and Server type targets when this gem is enabled. If you don't want it +# active in Clients or Servers by default, delete one of both of the following lines: +ly_create_alias(NAME ${gem_name}.Clients NAMESPACE Gem TARGETS Gem::${gem_name}) +ly_create_alias(NAME ${gem_name}.Servers NAMESPACE Gem TARGETS Gem::${gem_name}) +ly_create_alias(NAME ${gem_name}.Unified NAMESPACE Gem TARGETS Gem::${gem_name}) + +# For the Client and Server variants of ${gem_name} Gem, an alias to the ${gem_name}.API target will be made +ly_create_alias(NAME ${gem_name}.Clients.API NAMESPACE Gem TARGETS Gem::${gem_name}.API) +ly_create_alias(NAME ${gem_name}.Servers.API NAMESPACE Gem TARGETS Gem::${gem_name}.API) +ly_create_alias(NAME ${gem_name}.Unified.API NAMESPACE Gem TARGETS Gem::${gem_name}.API) + +# Add in CMake dependencies for each gem dependency listed in this gem's gem.json file +# for the Clients, Servers, Unified gem variants +o3de_add_variant_dependencies_for_gem_dependencies(GEM_NAME ${gem_name} VARIANTS Clients Servers Unified) + +# If we are on a host platform, we want to add the host tools targets like the ${gem_name}.Editor MODULE target +if(PAL_TRAIT_BUILD_HOST_TOOLS) + # The ${gem_name}.Editor.API target can be used by other gems that want to interact with the ${gem_name}.Editor module + ly_add_target( + NAME ${gem_name}.Editor.API INTERFACE + NAMESPACE Gem + FILES_CMAKE + smoothing_editor_api_files.cmake + ${pal_dir}/smoothing_editor_api_files.cmake + INCLUDE_DIRECTORIES + INTERFACE + Include + BUILD_DEPENDENCIES + INTERFACE + AZ::AzToolsFramework + ) + + # The ${gem_name}.Editor.Private.Object target is an internal target + # which is only to be used by this gems CMakeLists.txt and any subdirectories + # Other gems should not use this target + ly_add_target( + NAME ${gem_name}.Editor.Private.Object STATIC + NAMESPACE Gem + FILES_CMAKE + smoothing_editor_private_files.cmake + TARGET_PROPERTIES + O3DE_PRIVATE_TARGET TRUE + INCLUDE_DIRECTORIES + PRIVATE + Include + Source + BUILD_DEPENDENCIES + PUBLIC + AZ::AzToolsFramework + ${gem_name}.Private.Object + ) + + ly_add_target( + NAME ${gem_name}.Editor GEM_MODULE + NAMESPACE Gem + AUTOMOC + FILES_CMAKE + smoothing_editor_shared_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + Gem::${gem_name}.Editor.API + PRIVATE + Gem::${gem_name}.Editor.Private.Object + ) + + # Include the gem name into the Editor Module source file + # for use with the AZ_DECLARE_MODULE_CLASS macro + # This is to allow renaming of the gem to also cause + # the CreateModuleClass_Gem_ function which + # is used to bootstrap the gem in monolithic builds to link to the new gem name + ly_add_source_properties( + SOURCES + Source/Tools/SmoothingEditorModule.cpp + PROPERTY COMPILE_DEFINITIONS + VALUES + O3DE_GEM_NAME=${gem_name} + O3DE_GEM_VERSION=${gem_version}) + + # By default, we will specify that the above target ${gem_name} would be used by + # Tool and Builder type targets when this gem is enabled. If you don't want it + # active in Tools or Builders by default, delete one of both of the following lines: + ly_create_alias(NAME ${gem_name}.Tools NAMESPACE Gem TARGETS Gem::${gem_name}.Editor) + ly_create_alias(NAME ${gem_name}.Builders NAMESPACE Gem TARGETS Gem::${gem_name}.Editor) + + # For the Tools and Builders variants of ${gem_name} Gem, an alias to the ${gem_name}.Editor API target will be made + ly_create_alias(NAME ${gem_name}.Tools.API NAMESPACE Gem TARGETS Gem::${gem_name}.Editor.API) + ly_create_alias(NAME ${gem_name}.Builders.API NAMESPACE Gem TARGETS Gem::${gem_name}.Editor.API) + + # Add in CMake dependencies for each gem dependency listed in this gem's gem.json file + # for the Tools and Builders gem variants + o3de_add_variant_dependencies_for_gem_dependencies(GEM_NAME ${gem_name} VARIANTS Tools Builders) +endif() + +################################################################################ +# Tests +################################################################################ +# See if globally, tests are supported +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + # We globally support tests, see if we support tests on this platform for ${gem_name}.Tests + if(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED) + # We support ${gem_name}.Tests on this platform, add dependency on the Private Object target + ly_add_target( + NAME ${gem_name}.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + smoothing_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzFramework + Gem::${gem_name}.Private.Object + ) + + # Add ${gem_name}.Tests to googletest + ly_add_googletest( + NAME Gem::${gem_name}.Tests + ) + endif() + + # If we are a host platform we want to add tools test like editor tests here + if(PAL_TRAIT_BUILD_HOST_TOOLS) + # We are a host platform, see if Editor tests are supported on this platform + if(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED) + # We support ${gem_name}.Editor.Tests on this platform, add ${gem_name}.Editor.Tests target which depends on + # private ${gem_name}.Editor.Private.Object target + ly_add_target( + NAME ${gem_name}.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + smoothing_editor_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + Gem::${gem_name}.Editor.Private.Object + ) + + # Add ${gem_name}.Editor.Tests to googletest + ly_add_googletest( + NAME Gem::${gem_name}.Editor.Tests + ) + endif() + endif() +endif() diff --git a/Gems/Smoothing/Code/Include/Smoothing/SmoothingTypeIds.h b/Gems/Smoothing/Code/Include/Smoothing/SmoothingTypeIds.h new file mode 100644 index 0000000..fde44ff --- /dev/null +++ b/Gems/Smoothing/Code/Include/Smoothing/SmoothingTypeIds.h @@ -0,0 +1,25 @@ + +#pragma once + +namespace Smoothing +{ + // System Component TypeIds + inline constexpr const char* SmoothingSystemComponentTypeId = "{FC39BBB4-C723-4994-9923-6EAF200891C1}"; + inline constexpr const char* SmoothingEditorSystemComponentTypeId = "{5B96FFF8-A18E-4373-B96A-56250A4ABA8B}"; + + // Components, controllers and configs TypeIds + inline constexpr const char* SmoothingComponentTypeId = "{2FAF0D38-4EEE-4351-96D5-089242B5D5B5}"; + inline constexpr const char* SmoothingComponentEditorComponentTypeId = "{A27AA1A4-9178-40B3-8079-F8486A7CE544}"; + inline constexpr const char* SmoothingComponentControllerTypeId = "{5A0DD7CE-1651-4751-8EEB-46FFFAD8E9EB}"; + inline constexpr const char* SmoothingConfigTypeId = "{142F6B91-F088-40DB-8409-7C2BE07E0286}"; + + // Module derived classes TypeIds + inline constexpr const char* SmoothingModuleInterfaceTypeId = "{86F9681F-2F29-486B-ABA7-B2152FB8A08C}"; + inline constexpr const char* SmoothingModuleTypeId = "{2B284F2F-270D-4CB2-956C-EC2B835D144E}"; + // The Editor Module by default is mutually exclusive with the Client Module + // so they use the Same TypeId + inline constexpr const char* SmoothingEditorModuleTypeId = SmoothingModuleTypeId; + + // Interface TypeIds + inline constexpr const char* SmoothingRequestsTypeId = "{897472A7-6396-476D-82E2-CD05FDCD681E}"; +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Platform/Android/PAL_android.cmake b/Gems/Smoothing/Code/Platform/Android/PAL_android.cmake new file mode 100644 index 0000000..5d03e28 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Android/PAL_android.cmake @@ -0,0 +1,4 @@ + +set(PAL_TRAIT_SMOOTHING_SUPPORTED TRUE) +set(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED FALSE) +set(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Gems/Smoothing/Code/Platform/Android/smoothing_api_files.cmake b/Gems/Smoothing/Code/Platform/Android/smoothing_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Android/smoothing_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Android/smoothing_private_files.cmake b/Gems/Smoothing/Code/Platform/Android/smoothing_private_files.cmake new file mode 100644 index 0000000..c4d6049 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Android/smoothing_private_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Android +# i.e. ../Source/Android/SmoothingAndroid.cpp +# ../Source/Android/SmoothingAndroid.h +# ../Include/Android/SmoothingAndroid.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Android/smoothing_shared_files.cmake b/Gems/Smoothing/Code/Platform/Android/smoothing_shared_files.cmake new file mode 100644 index 0000000..c4d6049 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Android/smoothing_shared_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Android +# i.e. ../Source/Android/SmoothingAndroid.cpp +# ../Source/Android/SmoothingAndroid.h +# ../Include/Android/SmoothingAndroid.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Common/Clang/ros2_static_editor_clang.cmake b/Gems/Smoothing/Code/Platform/Common/Clang/ros2_static_editor_clang.cmake new file mode 100644 index 0000000..c4f61a0 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Common/Clang/ros2_static_editor_clang.cmake @@ -0,0 +1,11 @@ +# +# 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 +# + +set(LY_COMPILE_OPTIONS + PRIVATE + -fexceptions +) diff --git a/Gems/Smoothing/Code/Platform/Common/GCC/ros2_static_editor_gcc.cmake b/Gems/Smoothing/Code/Platform/Common/GCC/ros2_static_editor_gcc.cmake new file mode 100644 index 0000000..c4f61a0 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Common/GCC/ros2_static_editor_gcc.cmake @@ -0,0 +1,11 @@ +# +# 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 +# + +set(LY_COMPILE_OPTIONS + PRIVATE + -fexceptions +) diff --git a/Gems/Smoothing/Code/Platform/Common/msvc/ros2_static_editor_msvc.cmake b/Gems/Smoothing/Code/Platform/Common/msvc/ros2_static_editor_msvc.cmake new file mode 100644 index 0000000..ffd4387 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Common/msvc/ros2_static_editor_msvc.cmake @@ -0,0 +1,11 @@ +# +# 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 +# + +set(LY_COMPILE_OPTIONS + PRIVATE + /EHsc +) diff --git a/Gems/Smoothing/Code/Platform/Linux/PAL_linux.cmake b/Gems/Smoothing/Code/Platform/Linux/PAL_linux.cmake new file mode 100644 index 0000000..5d03e28 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Linux/PAL_linux.cmake @@ -0,0 +1,4 @@ + +set(PAL_TRAIT_SMOOTHING_SUPPORTED TRUE) +set(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED FALSE) +set(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Gems/Smoothing/Code/Platform/Linux/smoothing_api_files.cmake b/Gems/Smoothing/Code/Platform/Linux/smoothing_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Linux/smoothing_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Linux/smoothing_editor_api_files.cmake b/Gems/Smoothing/Code/Platform/Linux/smoothing_editor_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Linux/smoothing_editor_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Linux/smoothing_private_files.cmake b/Gems/Smoothing/Code/Platform/Linux/smoothing_private_files.cmake new file mode 100644 index 0000000..93d260f --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Linux/smoothing_private_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Linux +# i.e. ../Source/Linux/SmoothingLinux.cpp +# ../Source/Linux/SmoothingLinux.h +# ../Include/Linux/SmoothingLinux.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Linux/smoothing_shared_files.cmake b/Gems/Smoothing/Code/Platform/Linux/smoothing_shared_files.cmake new file mode 100644 index 0000000..93d260f --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Linux/smoothing_shared_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Linux +# i.e. ../Source/Linux/SmoothingLinux.cpp +# ../Source/Linux/SmoothingLinux.h +# ../Include/Linux/SmoothingLinux.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Mac/PAL_mac.cmake b/Gems/Smoothing/Code/Platform/Mac/PAL_mac.cmake new file mode 100644 index 0000000..5d03e28 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Mac/PAL_mac.cmake @@ -0,0 +1,4 @@ + +set(PAL_TRAIT_SMOOTHING_SUPPORTED TRUE) +set(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED FALSE) +set(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Gems/Smoothing/Code/Platform/Mac/smoothing_api_files.cmake b/Gems/Smoothing/Code/Platform/Mac/smoothing_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Mac/smoothing_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Mac/smoothing_editor_api_files.cmake b/Gems/Smoothing/Code/Platform/Mac/smoothing_editor_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Mac/smoothing_editor_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Mac/smoothing_private_files.cmake b/Gems/Smoothing/Code/Platform/Mac/smoothing_private_files.cmake new file mode 100644 index 0000000..d0e80fc --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Mac/smoothing_private_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Mac +# i.e. ../Source/Mac/SmoothingMac.cpp +# ../Source/Mac/SmoothingMac.h +# ../Include/Mac/SmoothingMac.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Mac/smoothing_shared_files.cmake b/Gems/Smoothing/Code/Platform/Mac/smoothing_shared_files.cmake new file mode 100644 index 0000000..d0e80fc --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Mac/smoothing_shared_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Mac +# i.e. ../Source/Mac/SmoothingMac.cpp +# ../Source/Mac/SmoothingMac.h +# ../Include/Mac/SmoothingMac.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Windows/PAL_windows.cmake b/Gems/Smoothing/Code/Platform/Windows/PAL_windows.cmake new file mode 100644 index 0000000..5d03e28 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Windows/PAL_windows.cmake @@ -0,0 +1,4 @@ + +set(PAL_TRAIT_SMOOTHING_SUPPORTED TRUE) +set(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED FALSE) +set(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Gems/Smoothing/Code/Platform/Windows/smoothing_api_files.cmake b/Gems/Smoothing/Code/Platform/Windows/smoothing_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Windows/smoothing_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Windows/smoothing_editor_api_files.cmake b/Gems/Smoothing/Code/Platform/Windows/smoothing_editor_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Windows/smoothing_editor_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Windows/smoothing_private_files.cmake b/Gems/Smoothing/Code/Platform/Windows/smoothing_private_files.cmake new file mode 100644 index 0000000..bd2fcda --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Windows/smoothing_private_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Windows +# i.e. ../Source/Windows/SmoothingWindows.cpp +# ../Source/Windows/SmoothingWindows.h +# ../Include/Windows/SmoothingWindows.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/Windows/smoothing_shared_files.cmake b/Gems/Smoothing/Code/Platform/Windows/smoothing_shared_files.cmake new file mode 100644 index 0000000..bd2fcda --- /dev/null +++ b/Gems/Smoothing/Code/Platform/Windows/smoothing_shared_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for Windows +# i.e. ../Source/Windows/SmoothingWindows.cpp +# ../Source/Windows/SmoothingWindows.h +# ../Include/Windows/SmoothingWindows.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/iOS/PAL_ios.cmake b/Gems/Smoothing/Code/Platform/iOS/PAL_ios.cmake new file mode 100644 index 0000000..5d03e28 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/iOS/PAL_ios.cmake @@ -0,0 +1,4 @@ + +set(PAL_TRAIT_SMOOTHING_SUPPORTED TRUE) +set(PAL_TRAIT_SMOOTHING_TEST_SUPPORTED FALSE) +set(PAL_TRAIT_SMOOTHING_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Gems/Smoothing/Code/Platform/iOS/smoothing_api_files.cmake b/Gems/Smoothing/Code/Platform/iOS/smoothing_api_files.cmake new file mode 100644 index 0000000..f5526ee --- /dev/null +++ b/Gems/Smoothing/Code/Platform/iOS/smoothing_api_files.cmake @@ -0,0 +1,3 @@ + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/iOS/smoothing_private_files.cmake b/Gems/Smoothing/Code/Platform/iOS/smoothing_private_files.cmake new file mode 100644 index 0000000..1edade7 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/iOS/smoothing_private_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for iOS +# i.e. ../Source/iOS/SmoothingiOS.cpp +# ../Source/iOS/SmoothingiOS.h +# ../Include/iOS/SmoothingiOS.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Platform/iOS/smoothing_shared_files.cmake b/Gems/Smoothing/Code/Platform/iOS/smoothing_shared_files.cmake new file mode 100644 index 0000000..1edade7 --- /dev/null +++ b/Gems/Smoothing/Code/Platform/iOS/smoothing_shared_files.cmake @@ -0,0 +1,8 @@ + +# Platform specific files for iOS +# i.e. ../Source/iOS/SmoothingiOS.cpp +# ../Source/iOS/SmoothingiOS.h +# ../Include/iOS/SmoothingiOS.h + +set(FILES +) diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp new file mode 100644 index 0000000..82a8458 --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp @@ -0,0 +1,258 @@ +#include "SmoothingComponent.h" +#include "Utils.h" +#include +#include +#include +namespace Smoothing +{ + void SmoothingConfig::Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("m_entityToTrack", &SmoothingConfig::m_entityToTrack) + ->Field("m_lockZAxis", &SmoothingConfig::m_lockZAxis) + ->Field("m_smoothBufferLen", &SmoothingConfig::m_smoothBufferLen) + ->Field("m_smoothingMethod", &SmoothingConfig::m_smoothingMethod) + ->Field("m_dampingFactor", &SmoothingConfig::m_dampingFactor) + ->Field("m_springFactor", &SmoothingConfig::m_springFactor); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("SmoothingConfig", "An example of a component that does something") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SmoothingConfig::m_entityToTrack, + "Entity to Track", + "The entity to track for smoothing") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SmoothingConfig::m_lockZAxis, + "Lock Z Axis", + "Lock the Z axis of the entity to track") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &SmoothingConfig::OnSmoothMethodChanged) + ->DataElement( + AZ::Edit::UIHandlers::ComboBox, + &SmoothingConfig::m_smoothingMethod, + "Smoothing method", + "A method to smooth the entity's position") + ->EnumAttribute(SmoothingConfig::SmoothingAlgorithm::NoSmoothing, "No Smoothing") + ->EnumAttribute(SmoothingConfig::SmoothingAlgorithm::AverageSmoothing, "Average Smoothing") + ->EnumAttribute(SmoothingConfig::SmoothingAlgorithm::DampingSmoothing, "Damping Smoothing") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &SmoothingConfig::OnSmoothMethodChanged) + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SmoothingConfig::m_smoothBufferLen, + "Smooth Buffer Length", + "The length of the buffer to smooth the entity's position") + ->Attribute(AZ::Edit::Attributes::Visibility, &SmoothingConfig::SmoothBufferVisibility) + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SmoothingConfig::m_dampingFactor, + "Damping Factor", + "The damping factor to smooth the entity's position") + ->Attribute(AZ::Edit::Attributes::Visibility, &SmoothingConfig::DampingFactorVisibility) + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SmoothingConfig::m_springFactor, + "Spring Factor", + "The spring factor to smooth the entity's position") + ->Attribute(AZ::Edit::Attributes::Visibility, &SmoothingConfig::DampingFactorVisibility) + ->UIElement(AZ::Edit::UIHandlers::Label, "", "") + ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "") + ->Attribute( + AZ::Edit::Attributes::ValueText, "It is recommended to use damping smoothing with lock Z axis for better results.") + ->Attribute(AZ::Edit::Attributes::Visibility, &SmoothingConfig::DampingFactorVisibilityWarning); + } + } + } + + AZ::Crc32 SmoothingConfig::OnSmoothMethodChanged() + { + return AZ::Edit::PropertyRefreshLevels::EntireTree; + } + + AZ::Crc32 SmoothingConfig::SmoothBufferVisibility() const + { + return m_smoothingMethod == SmoothingAlgorithm::AverageSmoothing ? AZ::Edit::PropertyVisibility::Show + : AZ::Edit::PropertyVisibility::Hide; + } + + AZ::Crc32 SmoothingConfig::DampingFactorVisibility() const + { + return m_smoothingMethod == SmoothingAlgorithm::DampingSmoothing ? AZ::Edit::PropertyVisibility::Show + : AZ::Edit::PropertyVisibility::Hide; + } + AZ::Crc32 SmoothingConfig::DampingFactorVisibilityWarning() const + { + return m_smoothingMethod == SmoothingAlgorithm::DampingSmoothing && !m_lockZAxis ? AZ::Edit::PropertyVisibility::Show + : AZ::Edit::PropertyVisibility::Hide; + } + + void SmoothingComponentController::Reflect(AZ::ReflectContext* context) + { + SmoothingConfig::Reflect(context); + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("Configuration", &SmoothingComponentController::m_config) + ->Version(1); + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("SmoothingComponentController", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Smoothing") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &SmoothingComponentController::m_config); + } + } + } + + SmoothingComponentController::SmoothingComponentController(const SmoothingConfig& config) + : m_config(config) + { + } + + void SmoothingComponentController::Activate(AZ::EntityId entityId) + { + m_ourLastVelocity = AZ::Vector3::CreateZero(); + m_ourLastAngularVelocity = AZ::Vector3::CreateZero(); + m_entityId = entityId; + m_lastTargetTransform.reset(); + AZ::TickBus::Handler::BusConnect(); + } + + void SmoothingComponentController::Deactivate() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void SmoothingComponentController::OnTick(float deltaTime, AZ::ScriptTimePoint time) + { + AZ_UNUSED(time); + // get transform of entity to track + AZ::Transform targetTransform = AZ::Transform::CreateIdentity(); + AZ::Transform ourTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(targetTransform, m_config.m_entityToTrack, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(ourTransform, m_entityId, &AZ::TransformBus::Events::GetWorldTM); + + AZ::Transform newTransform = AZ::Transform::CreateIdentity(); + // lock Z axis if needed + if (m_config.m_lockZAxis) + { + targetTransform = SmoothingUtils::RemoveTiltFromTransform(targetTransform); + } + + if (m_config.m_smoothingMethod == SmoothingConfig::SmoothingAlgorithm::NoSmoothing) + { + newTransform = targetTransform; + } + else if (m_config.m_smoothingMethod == SmoothingConfig::SmoothingAlgorithm::AverageSmoothing) + { + if (m_config.m_smoothBufferLen > 0) + { + SmoothingUtils::CacheTransform(m_smoothingCache, targetTransform, deltaTime, m_config.m_smoothBufferLen); + const auto positionSmooth = SmoothingUtils::SmoothTranslation(m_smoothingCache); + newTransform.SetTranslation(positionSmooth); + const auto rotationSmooth = SmoothingUtils::SmoothRotation(m_smoothingCache); + newTransform.SetRotation(rotationSmooth); + } + } + else if (m_config.m_smoothingMethod == SmoothingConfig::SmoothingAlgorithm::DampingSmoothing) + { + // clip delta time to avoid big jumps + deltaTime = AZStd::min(deltaTime, 0.1f); + if (m_isFirstTick) + { + m_lastTargetTransform = targetTransform; + newTransform = targetTransform; + } + if (m_ourLastTransform.has_value() && m_lastTargetTransform.has_value()) + { + // easy part - linear damping + { + const AZ::Vector3 targetPosition = targetTransform.GetTranslation(); + const AZ::Vector3 ourPosition = ourTransform.GetTranslation(); + + // simplified mass-spring-damper model where damping is proportional to our velocity + const AZ::Vector3 force = + m_config.m_springFactor * (targetPosition - ourPosition) - m_config.m_dampingFactor * m_ourLastVelocity; + m_ourLastVelocity += force * deltaTime; + newTransform.SetTranslation(ourPosition + m_ourLastVelocity * deltaTime); + } + // harder part - rotation + { + // The cross product of two vectors is a vector that is perpendicular to both vector, so it can be used to calculate the + // torque response. + // We compute sum of cross products of target and our direction X and Y vectors. + // We need two cross products to get the torque response in all three axes. + // We can imagine a system as three rubbers bands that attached to the target and our entity and we are trying to align + // them. The first is attached to the target and our entity's X axis, the second is attached to the target and our + // entity's Y axis. + auto diff = ourTransform.GetBasisX().Cross(targetTransform.GetBasisX()) + + ourTransform.GetBasisY().Cross(targetTransform.GetBasisY()); + + const AZ::Vector3 torque = m_config.m_springFactor * (diff)-m_config.m_dampingFactor * m_ourLastAngularVelocity; + m_ourLastAngularVelocity += torque * deltaTime; + // to be on safe side we lock Z axis for velocity + if (m_config.m_lockZAxis) + { + m_ourLastAngularVelocity.SetX(.0f); + m_ourLastAngularVelocity.SetY(.0f); + } + newTransform.SetRotation( + ourTransform.GetRotation() * AZ::Quaternion::CreateFromScaledAxisAngle(m_ourLastAngularVelocity * deltaTime)); + } + } + } + m_isFirstTick = false; + m_lastTargetTransform = targetTransform; + m_ourLastTransform = newTransform; + AZ::TransformBus::Event(m_entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform); + } + + int SmoothingComponentController::GetTickOrder() + { + return AZ::TICK_DEFAULT; + } + + void SmoothingComponentController::Init() + { + } + + void SmoothingComponentController::SetConfiguration(const SmoothingConfig& config) + { + m_config = config; + } + + const SmoothingConfig& SmoothingComponentController::GetConfiguration() const + { + return m_config; + } + + SmoothingComponent::SmoothingComponent(const SmoothingConfig& config) + : SmoothingComponentBase(config) + { + } + + void SmoothingComponent::Reflect(AZ::ReflectContext* context) + { + SmoothingComponentBase::Reflect(context); + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(1); + } + } + + void SmoothingComponent::Activate() + { + SmoothingComponentBase::Activate(); + } + + void SmoothingComponent::Deactivate() + { + SmoothingComponentBase::Deactivate(); + } +} // namespace Smoothing \ No newline at end of file diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h new file mode 100644 index 0000000..984b6ea --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h @@ -0,0 +1,92 @@ +#pragma once + +#include "Utils.h" +#include +#include +#include +#include +#include + +namespace Smoothing +{ + struct SmoothingConfig : public AZ::ComponentConfig + { + AZ_RTTI(SmoothingConfig, SmoothingConfigTypeId, AZ::ComponentConfig); + + static void Reflect(AZ::ReflectContext* context); + + AZ::EntityId m_entityToTrack; + + enum class SmoothingAlgorithm : AZ::u8 + { + NoSmoothing = 0, + AverageSmoothing, + DampingSmoothing, + }; + + SmoothingAlgorithm m_smoothingMethod = SmoothingAlgorithm::DampingSmoothing; + bool m_lockZAxis = false; + + // config for average smoothing + int m_smoothBufferLen = 10; + + // config for damping smoothing + float m_dampingFactor = 10.f; + float m_springFactor = 10.f; + + private: + AZ::Crc32 SmoothBufferVisibility() const; + AZ::Crc32 DampingFactorVisibility() const; + AZ::Crc32 DampingFactorVisibilityWarning() const; + + AZ::Crc32 OnSmoothMethodChanged(); + }; + + class SmoothingComponentController : public AZ::TickBus::Handler + { + public: + AZ_TYPE_INFO(SmoothingComponentController, SmoothingComponentControllerTypeId); + + static void Reflect(AZ::ReflectContext* context); + + SmoothingComponentController() = default; + SmoothingComponentController(const SmoothingConfig& config); + + // Controller component ... + void Init(); + void Activate(AZ::EntityId entityId); + void Deactivate(); + void SetConfiguration(const SmoothingConfig& config); + const SmoothingConfig& GetConfiguration() const; + + // TickBus interface implementation + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + int GetTickOrder() override; + + protected: + SmoothingConfig m_config; + SmoothingUtils::SmoothingCache m_smoothingCache; + AZ::EntityId m_entityId; + AZStd::optional m_lastTargetTransform; + AZStd::optional m_ourLastTransform; + AZ::Vector3 m_ourLastVelocity; + AZ::Vector3 m_ourLastAngularVelocity; + bool m_isFirstTick = true; + }; + using SmoothingComponentBase = AzFramework::Components::ComponentAdapter; + + class SmoothingComponent : public SmoothingComponentBase + { + public: + AZ_COMPONENT(SmoothingComponent, SmoothingComponentTypeId, AZ::Component); + static void Reflect(AZ::ReflectContext* context); + + SmoothingComponent(const SmoothingConfig& config); + SmoothingComponent() = default; + ~SmoothingComponent() = default; + + // Component overrides... + void Activate() override; + void Deactivate() override; + }; +} // namespace Smoothing \ No newline at end of file diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingModule.cpp b/Gems/Smoothing/Code/Source/Clients/SmoothingModule.cpp new file mode 100644 index 0000000..a0ebffd --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingModule.cpp @@ -0,0 +1,20 @@ + +#include "SmoothingSystemComponent.h" +#include +#include + +namespace Smoothing +{ + class SmoothingModule : public SmoothingModuleInterface + { + public: + AZ_RTTI(SmoothingModule, SmoothingModuleTypeId, SmoothingModuleInterface); + AZ_CLASS_ALLOCATOR(SmoothingModule, AZ::SystemAllocator); + }; +} // namespace Smoothing + +#if defined(O3DE_GEM_NAME) +AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME), Smoothing::SmoothingModule) +#else +AZ_DECLARE_MODULE_CLASS(Gem_Smoothing, Smoothing::SmoothingModule) +#endif diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.cpp b/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.cpp new file mode 100644 index 0000000..9d3db4e --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.cpp @@ -0,0 +1,50 @@ + +#include "SmoothingSystemComponent.h" + +#include + +#include + +namespace Smoothing +{ + AZ_COMPONENT_IMPL(SmoothingSystemComponent, "SmoothingSystemComponent", SmoothingSystemComponentTypeId); + + void SmoothingSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(0); + } + } + + void SmoothingSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("SmoothingService")); + } + + void SmoothingSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("SmoothingService")); + } + + void SmoothingSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + } + + void SmoothingSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void SmoothingSystemComponent::Init() + { + } + + void SmoothingSystemComponent::Activate() + { + } + + void SmoothingSystemComponent::Deactivate() + { + } + +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.h b/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.h new file mode 100644 index 0000000..8a061e8 --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingSystemComponent.h @@ -0,0 +1,34 @@ + +#pragma once + +#include +#include + +namespace Smoothing +{ + + class SmoothingSystemComponent : public AZ::Component + { + public: + AZ_COMPONENT_DECL(SmoothingSystemComponent); + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + SmoothingSystemComponent() = default; + ~SmoothingSystemComponent() = default; + + protected: + //////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Init() override; + void Activate() override; + void Deactivate() override; + //////////////////////////////////////////////////////////////////////// + }; + +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Clients/Utils.cpp b/Gems/Smoothing/Code/Source/Clients/Utils.cpp new file mode 100644 index 0000000..38c6203 --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/Utils.cpp @@ -0,0 +1,81 @@ + +#include "Utils.h" +#include + +AZ::Transform SmoothingUtils::RemoveTiltFromTransform(AZ::Transform transform) +{ + const AZ::Vector3 axisX = transform.GetBasisX(); + const AZ::Vector3 axisY = transform.GetBasisY(); + + const AZ::Matrix3x3 projectionOnXY{ AZ::Matrix3x3::CreateFromColumns( + AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateZero()) }; + + const AZ::Vector3 newAxisZ = AZ::Vector3::CreateAxisZ(); // new axis Z points up + + // project axisX on the XY plane + const AZ::Vector3 projectedAxisX = (projectionOnXY * axisX); + const AZ::Vector3 projectedAxisY = (projectionOnXY * axisY); + + AZ::Vector3 newAxisX = AZ::Vector3::CreateZero(); + AZ::Vector3 newAxisY = AZ::Vector3::CreateZero(); + + // get 3rd vector of the new basis from the cross product of the projected vectors. + // Primarily we want to use the projectedAxisX as the newAxisX, but if it is zero-length, we use the projectedAxisY as the newAxisY. + if (!projectedAxisX.IsZero()) + { + newAxisX = projectedAxisX.GetNormalized(); + newAxisY = newAxisZ.Cross(newAxisX); + } + else + { + newAxisY = projectedAxisY.GetNormalized(); + newAxisX = newAxisY.Cross(newAxisZ); + } + // apply rotation using created basis + transform.SetRotation(AZ::Quaternion::CreateFromBasis(newAxisX, newAxisY, newAxisZ)); + return transform; +} + +AZ::Vector3 SmoothingUtils::AverageVector(const AZStd::deque>& buffer) +{ + AZ::Vector3 sum{ 0 }; + float normalization{ 0 }; + for (const auto& p : buffer) + { + sum += p.first * p.second; + normalization += p.second; + } + return sum / normalization; +} + +AZ::Vector3 SmoothingUtils::SmoothTranslation(const SmoothingUtils::SmoothingCache& cache) +{ + return SmoothingUtils::AverageVector(cache.m_lastTranslationsBuffer); +} + +AZ::Quaternion SmoothingUtils::SmoothRotation(const SmoothingUtils::SmoothingCache& cache) +{ + AZ::Quaternion q = cache.m_lastRotationsBuffer.front().first; + for (int i = 1; i < cache.m_lastRotationsBuffer.size(); i++) + { + q = q.Slerp(cache.m_lastRotationsBuffer[i].first, cache.m_lastRotationsBuffer[i].second); + } + return q; +} + +void SmoothingUtils::CacheTransform( + SmoothingUtils::SmoothingCache& cache, const AZ::Transform& transform, float deltaTime, int smoothBufferLen) +{ + // update the smoothing buffer + cache.m_lastTranslationsBuffer.push_back(AZStd::make_pair(transform.GetTranslation(), deltaTime)); + cache.m_lastRotationsBuffer.push_back(AZStd::make_pair(transform.GetRotation(), deltaTime)); + + if (cache.m_lastTranslationsBuffer.size() > smoothBufferLen) + { + cache.m_lastTranslationsBuffer.pop_front(); + } + if (cache.m_lastRotationsBuffer.size() > smoothBufferLen) + { + cache.m_lastRotationsBuffer.pop_front(); + } +} diff --git a/Gems/Smoothing/Code/Source/Clients/Utils.h b/Gems/Smoothing/Code/Source/Clients/Utils.h new file mode 100644 index 0000000..cdcce7f --- /dev/null +++ b/Gems/Smoothing/Code/Source/Clients/Utils.h @@ -0,0 +1,41 @@ + +#pragma once + +#include + +namespace SmoothingUtils +{ + //! Remove the tilt from the transform. + //! The tilt is removed by projecting the transform basis of rotation matrix to the ground plane. + //! @param transform The transform to remove the tilt. + //! @return The transform without tilt. + AZ::Transform RemoveTiltFromTransform(AZ::Transform transform); + + struct SmoothingCache + { + //! The smoothing buffer for translation, the first element is the translation, the second element is the weight. + AZStd::deque> m_lastTranslationsBuffer; + //! The smoothing buffer for rotation, the first element is the tangential vector, the second element is the weight. + AZStd::deque> m_lastRotationsBuffer; + }; + //! Compute weighted average of the vectors in the buffer. + //! @param buffer The buffer to compute the average. + //! @return The average vector. + AZ::Vector3 AverageVector(const AZStd::deque>& buffer); + + //! Cache the transform in smoothing buffer. + //! @param cache The cache to store the transform. + //! @param transform The transform to cache. + //! @param deltaTime The time between the last frame and the current frame. + //! @param smoothBufferLen The length of the buffer to smooth the entity's position. + void CacheTransform(SmoothingUtils::SmoothingCache& cache, const AZ::Transform& transform, float deltaTime, int smoothBufferLen); + + //! Compute weighted average of translation in the buffer. + //! @return The average translation. + AZ::Vector3 SmoothTranslation(const SmoothingCache& cache); + + //! Compute weighted average of rotation in the buffer. + //! @return The average rotation. + AZ::Quaternion SmoothRotation(const SmoothingCache& cache); + +} // namespace SmoothingUtils diff --git a/Gems/Smoothing/Code/Source/SmoothingModuleInterface.cpp b/Gems/Smoothing/Code/Source/SmoothingModuleInterface.cpp new file mode 100644 index 0000000..e274426 --- /dev/null +++ b/Gems/Smoothing/Code/Source/SmoothingModuleInterface.cpp @@ -0,0 +1,36 @@ + +#include "SmoothingModuleInterface.h" +#include + +#include + +#include "Clients/SmoothingComponent.h" +#include + +namespace Smoothing +{ + AZ_TYPE_INFO_WITH_NAME_IMPL(SmoothingModuleInterface, "SmoothingModuleInterface", SmoothingModuleInterfaceTypeId); + AZ_RTTI_NO_TYPE_INFO_IMPL(SmoothingModuleInterface, AZ::Module); + AZ_CLASS_ALLOCATOR_IMPL(SmoothingModuleInterface, AZ::SystemAllocator); + + SmoothingModuleInterface::SmoothingModuleInterface() + { + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. + // This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert( + m_descriptors.end(), + { + SmoothingSystemComponent::CreateDescriptor(), + SmoothingComponent::CreateDescriptor(), + }); + } + + AZ::ComponentTypeList SmoothingModuleInterface::GetRequiredSystemComponents() const + { + return AZ::ComponentTypeList{ + azrtti_typeid(), + }; + } +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/SmoothingModuleInterface.h b/Gems/Smoothing/Code/Source/SmoothingModuleInterface.h new file mode 100644 index 0000000..0901550 --- /dev/null +++ b/Gems/Smoothing/Code/Source/SmoothingModuleInterface.h @@ -0,0 +1,23 @@ + +#include +#include +#include +#include + +namespace Smoothing +{ + class SmoothingModuleInterface : public AZ::Module + { + public: + AZ_TYPE_INFO_WITH_NAME_DECL(SmoothingModuleInterface) + AZ_RTTI_NO_TYPE_INFO_DECL() + AZ_CLASS_ALLOCATOR_DECL + + SmoothingModuleInterface(); + + /** + * Add required SystemComponents to the SystemEntity. + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override; + }; +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp new file mode 100644 index 0000000..e5e9132 --- /dev/null +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp @@ -0,0 +1,46 @@ +#include "SmoothingEditorComponent.h" + +namespace Smoothing +{ + + SmoothingComponentEditorComponent::SmoothingComponentEditorComponent(const SmoothingConfig& configuration) + : SmoothingComponentEditorBase(configuration) + { + } + + void SmoothingComponentEditorComponent::Reflect(AZ::ReflectContext* context) + { + SmoothingComponentEditorBase::Reflect(context); + AZ::SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class()->Version(1); + + AZ::EditContext* editContext = serializeContext->GetEditContext(); + if (editContext) + { + editContext->Class("Smoothing Editor Component", "Smoothing Component") + ->ClassElement( + AZ::Edit::ClassElements::EditorData, "Components allows to follow movement of the another entity with smoothing.") + ->Attribute(AZ::Edit::Attributes::Category, "Smoothing") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); + } + } + } + + void SmoothingComponentEditorComponent::Activate() + { + SmoothingComponentEditorBase::Activate(); + } + + void SmoothingComponentEditorComponent::Deactivate() + { + SmoothingComponentEditorBase::Deactivate(); + } + + bool SmoothingComponentEditorComponent::ShouldActivateController() const + { + return true; + }; +} // namespace Smoothing \ No newline at end of file diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h new file mode 100644 index 0000000..c971916 --- /dev/null +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include + +namespace Smoothing +{ + using SmoothingComponentEditorBase = + AzToolsFramework::Components::EditorComponentAdapter; + + class SmoothingComponentEditorComponent : public SmoothingComponentEditorBase + { + public: + SmoothingComponentEditorComponent() = default; + explicit SmoothingComponentEditorComponent(const SmoothingConfig& configuration); + + AZ_EDITOR_COMPONENT(SmoothingComponentEditorComponent, SmoothingComponentEditorComponentTypeId, SmoothingComponentEditorBase); + static void Reflect(AZ::ReflectContext* context); + + // SmoothingComponentEditorBase interface overrides... + void Activate() override; + void Deactivate() override; + bool ShouldActivateController() const override; + }; +} // namespace Smoothing \ No newline at end of file diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorModule.cpp b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorModule.cpp new file mode 100644 index 0000000..a78ed5f --- /dev/null +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorModule.cpp @@ -0,0 +1,45 @@ + +#include "SmoothingEditorComponent.h" +#include "SmoothingEditorSystemComponent.h" +#include +#include +namespace Smoothing +{ + class SmoothingEditorModule : public SmoothingModuleInterface + { + public: + AZ_RTTI(SmoothingEditorModule, SmoothingEditorModuleTypeId, SmoothingModuleInterface); + AZ_CLASS_ALLOCATOR(SmoothingEditorModule, AZ::SystemAllocator); + + SmoothingEditorModule() + { + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and + // EditContext. This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert( + m_descriptors.end(), + { + SmoothingEditorSystemComponent::CreateDescriptor(), + SmoothingComponentEditorComponent::CreateDescriptor(), + }); + } + + /** + * Add required SystemComponents to the SystemEntity. + * Non-SystemComponents should not be added here + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList{ + azrtti_typeid(), + }; + } + }; +} // namespace Smoothing + +#if defined(O3DE_GEM_NAME) +AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME, _Editor), Smoothing::SmoothingEditorModule) +#else +AZ_DECLARE_MODULE_CLASS(Gem_Smoothing_Editor, Smoothing::SmoothingEditorModule) +#endif diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.cpp b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.cpp new file mode 100644 index 0000000..04c068d --- /dev/null +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.cpp @@ -0,0 +1,58 @@ + +#include "SmoothingEditorSystemComponent.h" +#include + +#include + +namespace Smoothing +{ + AZ_COMPONENT_IMPL( + SmoothingEditorSystemComponent, "SmoothingEditorSystemComponent", SmoothingEditorSystemComponentTypeId, BaseSystemComponent); + + void SmoothingEditorSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(0); + } + } + + SmoothingEditorSystemComponent::SmoothingEditorSystemComponent() = default; + + SmoothingEditorSystemComponent::~SmoothingEditorSystemComponent() = default; + + void SmoothingEditorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + BaseSystemComponent::GetProvidedServices(provided); + provided.push_back(AZ_CRC_CE("SmoothingEditorService")); + } + + void SmoothingEditorSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + BaseSystemComponent::GetIncompatibleServices(incompatible); + incompatible.push_back(AZ_CRC_CE("SmoothingEditorService")); + } + + void SmoothingEditorSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + BaseSystemComponent::GetRequiredServices(required); + } + + void SmoothingEditorSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + BaseSystemComponent::GetDependentServices(dependent); + } + + void SmoothingEditorSystemComponent::Activate() + { + SmoothingSystemComponent::Activate(); + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + } + + void SmoothingEditorSystemComponent::Deactivate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + SmoothingSystemComponent::Deactivate(); + } + +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.h b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.h new file mode 100644 index 0000000..6d8676f --- /dev/null +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorSystemComponent.h @@ -0,0 +1,35 @@ + +#pragma once + +#include + +#include + +namespace Smoothing +{ + /// System component for Smoothing editor + class SmoothingEditorSystemComponent + : public SmoothingSystemComponent + , protected AzToolsFramework::EditorEvents::Bus::Handler + { + using BaseSystemComponent = SmoothingSystemComponent; + + public: + AZ_COMPONENT_DECL(SmoothingEditorSystemComponent); + + static void Reflect(AZ::ReflectContext* context); + + SmoothingEditorSystemComponent(); + ~SmoothingEditorSystemComponent(); + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // AZ::Component + void Activate() override; + void Deactivate() override; + }; +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Tests/Clients/SmoothingTest.cpp b/Gems/Smoothing/Code/Tests/Clients/SmoothingTest.cpp new file mode 100644 index 0000000..274a990 --- /dev/null +++ b/Gems/Smoothing/Code/Tests/Clients/SmoothingTest.cpp @@ -0,0 +1,4 @@ + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/Smoothing/Code/Tests/Tools/SmoothingEditorTest.cpp b/Gems/Smoothing/Code/Tests/Tools/SmoothingEditorTest.cpp new file mode 100644 index 0000000..274a990 --- /dev/null +++ b/Gems/Smoothing/Code/Tests/Tools/SmoothingEditorTest.cpp @@ -0,0 +1,4 @@ + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/Smoothing/Code/smoothing_api_files.cmake b/Gems/Smoothing/Code/smoothing_api_files.cmake new file mode 100644 index 0000000..aa18669 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_api_files.cmake @@ -0,0 +1,4 @@ + +set(FILES + Include/Smoothing/SmoothingTypeIds.h +) diff --git a/Gems/Smoothing/Code/smoothing_editor_api_files.cmake b/Gems/Smoothing/Code/smoothing_editor_api_files.cmake new file mode 100644 index 0000000..8cd37a5 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_editor_api_files.cmake @@ -0,0 +1,4 @@ + + +set(FILES +) diff --git a/Gems/Smoothing/Code/smoothing_editor_private_files.cmake b/Gems/Smoothing/Code/smoothing_editor_private_files.cmake new file mode 100644 index 0000000..07a0cd3 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_editor_private_files.cmake @@ -0,0 +1,7 @@ + +set(FILES + Source/Tools/SmoothingEditorSystemComponent.cpp + Source/Tools/SmoothingEditorSystemComponent.h + Source/Tools/SmoothingEditorComponent.cpp + Source/Tools/SmoothingEditorComponent.h +) diff --git a/Gems/Smoothing/Code/smoothing_editor_shared_files.cmake b/Gems/Smoothing/Code/smoothing_editor_shared_files.cmake new file mode 100644 index 0000000..6213a5d --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_editor_shared_files.cmake @@ -0,0 +1,4 @@ + +set(FILES + Source/Tools/SmoothingEditorModule.cpp +) diff --git a/Gems/Smoothing/Code/smoothing_editor_tests_files.cmake b/Gems/Smoothing/Code/smoothing_editor_tests_files.cmake new file mode 100644 index 0000000..463841b --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_editor_tests_files.cmake @@ -0,0 +1,4 @@ + +set(FILES + Tests/Tools/SmoothingEditorTest.cpp +) diff --git a/Gems/Smoothing/Code/smoothing_private_files.cmake b/Gems/Smoothing/Code/smoothing_private_files.cmake new file mode 100644 index 0000000..6d00221 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_private_files.cmake @@ -0,0 +1,11 @@ + +set(FILES + Source/SmoothingModuleInterface.cpp + Source/SmoothingModuleInterface.h + Source/Clients/SmoothingSystemComponent.cpp + Source/Clients/SmoothingSystemComponent.h + Source/Clients/SmoothingComponent.h + Source/Clients/SmoothingComponent.cpp + Source/Clients/Utils.cpp + Source/Clients/Utils.h +) diff --git a/Gems/Smoothing/Code/smoothing_shared_files.cmake b/Gems/Smoothing/Code/smoothing_shared_files.cmake new file mode 100644 index 0000000..822c4e6 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_shared_files.cmake @@ -0,0 +1,4 @@ + +set(FILES + Source/Clients/SmoothingModule.cpp +) diff --git a/Gems/Smoothing/Code/smoothing_tests_files.cmake b/Gems/Smoothing/Code/smoothing_tests_files.cmake new file mode 100644 index 0000000..5d13366 --- /dev/null +++ b/Gems/Smoothing/Code/smoothing_tests_files.cmake @@ -0,0 +1,4 @@ + +set(FILES + Tests/Clients/SmoothingTest.cpp +) diff --git a/Gems/Smoothing/Registry/assetprocessor_settings.setreg b/Gems/Smoothing/Registry/assetprocessor_settings.setreg new file mode 100644 index 0000000..840c33b --- /dev/null +++ b/Gems/Smoothing/Registry/assetprocessor_settings.setreg @@ -0,0 +1,18 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "ScanFolder Smoothing/Assets": { + "watch": "@GEMROOT:Smoothing@/Assets", + "recursive": 1, + "order": 101 + }, + "ScanFolder Smoothing/Registry": { + "watch": "@GEMROOT:Smoothing@/Registry", + "recursive": 1, + "order": 102 + } + } + } + } +} diff --git a/Gems/Smoothing/gem.json b/Gems/Smoothing/gem.json new file mode 100644 index 0000000..27c9940 --- /dev/null +++ b/Gems/Smoothing/gem.json @@ -0,0 +1,28 @@ +{ + "gem_name": "Smoothing", + "version": "1.0.0", + "display_name": "Smoothing", + "license": "Apache-2.0", + "license_url": " https://opensource.org/licenses/Apache-2.0", + "origin": "RobotecAI", + "origin_url": "https://github.com/RobotecAI/robotec-o3de-tools", + "type": "Code", + "summary": "Tool gem to smooth movement of the entity", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "Smoothing" + ], + "platforms": [ + "" + ], + "icon_path": "preview.png", + "requirements": "N/A", + "documentation_url": "", + "dependencies": [], + "repo_uri": "", + "compatible_engines": [], + "engine_api_dependencies": [], + "restricted": "Smoothing" +} diff --git a/Gems/Smoothing/preview.png b/Gems/Smoothing/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..83afae48b97f808914d4b210c578441b7cdfdcdd GIT binary patch literal 4475 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 l Date: Wed, 21 Aug 2024 11:57:17 +0200 Subject: [PATCH 2/2] Apply suggestions from code review --- Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp | 2 +- Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h | 2 +- Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp | 2 +- Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp index 82a8458..0404b4a 100644 --- a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.cpp @@ -255,4 +255,4 @@ namespace Smoothing { SmoothingComponentBase::Deactivate(); } -} // namespace Smoothing \ No newline at end of file +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h index 984b6ea..8070e91 100644 --- a/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h +++ b/Gems/Smoothing/Code/Source/Clients/SmoothingComponent.h @@ -89,4 +89,4 @@ namespace Smoothing void Activate() override; void Deactivate() override; }; -} // namespace Smoothing \ No newline at end of file +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp index e5e9132..f68d092 100644 --- a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.cpp @@ -43,4 +43,4 @@ namespace Smoothing { return true; }; -} // namespace Smoothing \ No newline at end of file +} // namespace Smoothing diff --git a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h index c971916..6c3eb34 100644 --- a/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h +++ b/Gems/Smoothing/Code/Source/Tools/SmoothingEditorComponent.h @@ -24,4 +24,4 @@ namespace Smoothing void Deactivate() override; bool ShouldActivateController() const override; }; -} // namespace Smoothing \ No newline at end of file +} // namespace Smoothing