Merge branch 'stabilization/2106' of https://github.com/aws-lumberyard/o3de into Atom/gallowj/stabilization/2106

This commit is contained in:
gallowj
2021-06-14 09:02:46 -05:00
36 changed files with 10251 additions and 10925 deletions
+7 -6
View File
@@ -105,24 +105,25 @@ endforeach()
# Post-processing
################################################################################
# The following steps have to be done after all targets are registered:
# Defer generation of the StaticModules.inl file which is needed to create the AZ::Module derived class in monolithic
# builds until after all the targets are known
ly_delayed_generate_static_modules_inl()
# 1. Add any dependencies registered via ly_enable_gems
ly_enable_gems_delayed()
# 2. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls
# 2. Defer generation of the StaticModules.inl file which is needed to create the AZ::Module derived class in monolithic
# builds until after all the targets are known and all the gems are enabled
ly_delayed_generate_static_modules_inl()
# 3. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls
# to provide applications with the filenames of gem modules to load
# This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIES as MANUALLY_ADDED_DEPENDENCIES
# if the build dependency is a MODULE_LIBRARY. That would cause a false load dependency to be generated
ly_delayed_generate_settings_registry()
# 3. link targets where the dependency was yet not declared, we need to have the declaration so we do different
# 4. link targets where the dependency was yet not declared, we need to have the declaration so we do different
# linking logic depending on the type of target
ly_delayed_target_link_libraries()
# 4. generate a registry file for unit testing for platforms that support unit testing
# 5. generate a registry file for unit testing for platforms that support unit testing
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_delayed_generate_unit_test_module_registry()
endif()
@@ -292,8 +292,13 @@ namespace AZ
const typename VecType::FloatType cmp2 = VecType::AndNot(cmp0, cmp1);
// -1/x
// this step is calculated for all values of x, but only used if x > Sqrt(2) + 1
// in order to avoid a division by zero, detect if xabs is zero here and replace it with an arbitrary value
// if xabs does equal zero, the value here doesn't matter because the result will be thrown away
typename VecType::FloatType xabsSafe =
VecType::Add(xabs, VecType::And(VecType::CmpEq(xabs, VecType::ZeroFloat()), FastLoadConstant<VecType>(Simd::g_vec1111)));
const typename VecType::FloatType y0 = VecType::And(cmp0, FastLoadConstant<VecType>(Simd::g_HalfPi));
typename VecType::FloatType x0 = VecType::Div(FastLoadConstant<VecType>(Simd::g_vec1111), xabs);
typename VecType::FloatType x0 = VecType::Div(FastLoadConstant<VecType>(Simd::g_vec1111), xabsSafe);
x0 = VecType::Xor(x0, VecType::CastToFloat(FastLoadConstant<VecType>(Simd::g_negateMask)));
const typename VecType::FloatType y1 = VecType::And(cmp2, FastLoadConstant<VecType>(Simd::g_QuarterPi));
@@ -368,8 +373,12 @@ namespace AZ
typename VecType::FloatType offset = VecType::And(x_lt_0, offset1);
// the result of this part of the computation is thrown away if x equals 0,
// but if x does equal 0, it will cause a division by zero
// so replace zero by an arbitrary value here in that case
typename VecType::FloatType xSafe = VecType::Add(x, VecType::And(x_eq_0, FastLoadConstant<VecType>(Simd::g_vec1111)));
const typename VecType::FloatType atan_mask = VecType::Not(VecType::Or(x_eq_0, y_eq_0));
const typename VecType::FloatType atan_arg = VecType::Div(y, x);
const typename VecType::FloatType atan_arg = VecType::Div(y, xSafe);
typename VecType::FloatType atan_result = VecType::Atan(atan_arg);
atan_result = VecType::Add(atan_result, offset);
atan_result = VecType::AndNot(pio2_mask, atan_result);
@@ -471,6 +471,7 @@ namespace AZ
AZ_MATH_INLINE Vec2::FloatType Vec2::Reciprocal(FloatArgType value)
{
value = Sse::ReplaceFourth(Sse::ReplaceThird(value, 1.0f), 1.0f);
return Sse::Reciprocal(value);
}
@@ -513,6 +514,7 @@ namespace AZ
AZ_MATH_INLINE Vec2::FloatType Vec2::SqrtInv(FloatArgType value)
{
value = Sse::ReplaceFourth(Sse::ReplaceThird(value, 1.0f), 1.0f);
return Sse::SqrtInv(value);
}
@@ -507,6 +507,7 @@ namespace AZ
AZ_MATH_INLINE Vec3::FloatType Vec3::Reciprocal(FloatArgType value)
{
value = Sse::ReplaceFourth(value, 1.0f);
return Sse::Reciprocal(value);
}
@@ -549,6 +550,7 @@ namespace AZ
AZ_MATH_INLINE Vec3::FloatType Vec3::SqrtInv(FloatArgType value)
{
value = Sse::ReplaceFourth(value, 1.0f);
return Sse::SqrtInv(value);
}
@@ -693,11 +693,11 @@ namespace AzFramework
// set the __index so we can read values in case we change the script
// after we export the component
lua_pushliteral(lua, "__index");
lua_pushcclosure(lua, &Internal::Properties__Index, 1);
lua_pushcclosure(lua, &Internal::Properties__Index, 0);
lua_rawset(lua, -3);
lua_pushliteral(lua, "__newindex");
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 1);
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 0);
lua_rawset(lua, -3);
}
lua_pop(lua, 1); // pop the properties table (or the nil value)
@@ -900,11 +900,11 @@ namespace AzFramework
// Ensure that this instance of Properties table has the proper __index and __newIndex metamethods.
lua_newtable(lua); // This new table will become the Properties instance metatable. Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {}
lua_pushliteral(lua, "__index"); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index
lua_pushcclosure(lua, &Internal::Properties__Index, 1); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index function
lua_pushcclosure(lua, &Internal::Properties__Index, 0); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index function
lua_rawset(lua, -3); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {__index=Internal::Properties__Index}
lua_pushliteral(lua, "__newindex");
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 1);
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 0);
lua_rawset(lua, -3); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {__index=Internal::Properties__Index __newindex=Internal::Properties__NewIndex}
lua_setmetatable(lua, -2); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {Meta{__index=Internal::Properties__Index __newindex=Internal::Properties__NewIndex} }
+22 -20
View File
@@ -8,25 +8,27 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AzTest STATIC
NAMESPACE AZ
FILES_CMAKE
AzTest/aztest_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
${pal_dir}
BUILD_DEPENDENCIES
PUBLIC
3rdParty::googletest::GMock
3rdParty::googletest::GTest
3rdParty::GoogleBenchmark
AZ::AzCore
PLATFORM_INCLUDE_FILES
if(NOT LY_MONOLITHIC_GAME)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AzTest/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AzTest STATIC
NAMESPACE AZ
FILES_CMAKE
AzTest/aztest_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
${pal_dir}
BUILD_DEPENDENCIES
PUBLIC
3rdParty::googletest::GMock
3rdParty::googletest::GTest
3rdParty::GoogleBenchmark
AZ::AzCore
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
)
)
endif()
@@ -252,13 +252,20 @@ namespace AzToolsFramework
}
AZStd::string out;
if (m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
if (!m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
{
const size_t bytesToWrite = out.size();
const size_t bytesWritten = stream.Write(bytesToWrite, out.data());
return bytesWritten == bytesToWrite;
return false;
}
return false;
const size_t bytesToWrite = out.size();
const size_t bytesWritten = stream.Write(bytesToWrite, out.data());
if(bytesWritten != bytesToWrite)
{
return false;
}
m_prefabSystemComponent->SetTemplateDirtyFlag(templateId, false);
return true;
}
void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename)
@@ -58,8 +58,17 @@ namespace AzToolsFramework
if (!path.empty())
{
infoString =
QObject::tr("<span style=\"font-style: italic; font-weight: 400;\">(%1)</span>").arg(path.Filename().Native().data());
QString saveFlag = "";
auto dirtyOutcome = m_prefabPublicInterface->HasUnsavedChanges(path);
if (dirtyOutcome.IsSuccess() && dirtyOutcome.GetValue() == true)
{
saveFlag = "*";
}
infoString = QObject::tr("<span style=\"font-style: italic; font-weight: 400;\">(%1%2)</span>")
.arg(path.Filename().Native().data())
.arg(saveFlag);
}
return infoString;
@@ -28,6 +28,7 @@
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
#include <QApplication>
#include <QFileDialog>
@@ -588,15 +589,6 @@ namespace AzToolsFramework
bool PrefabIntegrationManager::QueryUserForPrefabFilePath(AZStd::string& outPrefabFilePath)
{
QWidget* mainWindow = nullptr;
EditorRequests::Bus::BroadcastResult(mainWindow, &EditorRequests::Bus::Events::GetMainWindow);
if (mainWindow == nullptr)
{
AZ_Assert(false, "Prefab - Could not detect Editor main window to generate the asset picker.");
return false;
}
AssetSelectionModel selection;
// Note, stringfilter will match every source file CONTAINING ".prefab".
@@ -624,7 +616,7 @@ namespace AzToolsFramework
selection.SetDisplayFilter(compositeFilterPtr);
selection.SetSelectionFilter(compositeFilterPtr);
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, mainWindow);
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, AzToolsFramework::GetActiveWindow());
if (!selection.IsValid())
{
@@ -983,12 +975,7 @@ namespace AzToolsFramework
includedEntities.c_str(),
referencedEntities.c_str());
QWidget* mainWindow = nullptr;
AzToolsFramework::EditorRequests::Bus::BroadcastResult(
mainWindow,
&AzToolsFramework::EditorRequests::Bus::Events::GetMainWindow);
QMessageBox msgBox(mainWindow);
QMessageBox msgBox(AzToolsFramework::GetActiveWindow());
msgBox.setWindowTitle("External Entity References");
msgBox.setText("The prefab contains references to external entities that are not selected.");
msgBox.setInformativeText("You can move the referenced entities into this prefab or retain the external references.");
@@ -196,6 +196,16 @@ function(ly_delayed_generate_static_modules_inl)
ly_get_gem_load_dependencies(all_game_gem_dependencies ${project_name}.GameLauncher)
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
# 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)
if(${target_type} STREQUAL "INTERFACE_LIBRARY")
continue()
endif()
endif()
# To match the convention on how gems targets vs gem modules are named,
# we remove the ".Static" from the suffix
# Replace "." with "_"
@@ -224,6 +234,14 @@ function(ly_delayed_generate_static_modules_inl)
list(APPEND all_server_gem_dependencies ${server_gem_load_dependencies} ${server_gem_dependency})
endforeach()
foreach(server_gem_dependency ${all_server_gem_dependencies})
# Skip interface libraries
if(TARGET ${server_gem_dependency})
get_target_property(target_type ${server_gem_dependency} TYPE)
if(${target_type} STREQUAL "INTERFACE_LIBRARY")
continue()
endif()
endif()
# Replace "." with "_"
string(REPLACE "." "_" server_gem_dependency ${server_gem_dependency})
+1 -1
View File
@@ -13,7 +13,7 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${P
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
if(PAL_TRAIT_AZTESTRUNNER_SUPPORTED)
if(PAL_TRAIT_AZTESTRUNNER_SUPPORTED AND NOT LY_MONOLITHIC_GAME)
ly_add_target(
NAME AzTestRunner ${PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE}
@@ -122,29 +122,22 @@ namespace AWSMetrics
//! @return Outcome of the operation.
AZ::Outcome<void, AZStd::string> SendMetricsToFile(AZStd::shared_ptr<MetricsQueue> metricsQueue);
//! Check whether the consumer should flush the metrics queue.
//! @return whether the limit is hit.
bool ShouldSendMetrics();
//! Push metrics events to the front of the queue for retry.
//! @param metricsEventsForRetry Metrics events for retry.
void PushMetricsForRetry(MetricsQueue& metricsEventsForRetry);
void SubmitLocalMetricsAsync();
////////////////////////////////////////////
// These data are protected by m_metricsMutex.
AZStd::mutex m_metricsMutex;
AZStd::chrono::system_clock::time_point m_lastSendMetricsTime;
MetricsQueue m_metricsQueue;
////////////////////////////////////////////
AZStd::mutex m_metricsMutex; //!< Mutex to protect the metrics queue
MetricsQueue m_metricsQueue; //!< Queue fo buffering the metrics events
AZStd::mutex m_metricsFileMutex; //!< Local metrics file is protected by m_metricsFileMutex
AZStd::mutex m_metricsFileMutex; //!< Mutex to protect the local metrics file
AZStd::atomic<int> m_sendMetricsId;//!< Request ID for sending metrics
AZStd::thread m_consumerThread; //!< Thread to monitor and consume the metrics queue
AZStd::atomic<bool> m_consumerTerminated;
AZStd::thread m_monitorThread; //!< Thread to monitor and consume the metrics queue
AZStd::atomic<bool> m_monitorTerminated;
AZStd::binary_semaphore m_waitEvent;
// Client Configurations.
AZStd::unique_ptr<ClientConfiguration> m_clientConfiguration;
+28 -37
View File
@@ -29,7 +29,7 @@ namespace AWSMetrics
MetricsManager::MetricsManager()
: m_clientConfiguration(AZStd::make_unique<ClientConfiguration>())
, m_clientIdProvider(IdentityProvider::CreateIdentityProvider())
, m_consumerTerminated(true)
, m_monitorTerminated(true)
, m_sendMetricsId(0)
{
}
@@ -53,31 +53,27 @@ namespace AWSMetrics
void MetricsManager::StartMetrics()
{
if (!m_consumerTerminated)
if (!m_monitorTerminated)
{
// The background thread has been started.
return;
}
m_consumerTerminated = false;
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_lastSendMetricsTime = AZStd::chrono::system_clock::now();
m_monitorTerminated = false;
// Start a separate thread to monitor and consume the metrics queue.
// Avoid using the job system since the worker is long-running over multiple frames
m_consumerThread = AZStd::thread(AZStd::bind(&MetricsManager::MonitorMetricsQueue, this));
m_monitorThread = AZStd::thread(AZStd::bind(&MetricsManager::MonitorMetricsQueue, this));
}
void MetricsManager::MonitorMetricsQueue()
{
while (!m_consumerTerminated)
// Continue to loop until the monitor is terminated.
while (!m_monitorTerminated)
{
if (ShouldSendMetrics())
{
// Flush the metrics queue when the accumulated metrics size or time period hits the limit
FlushMetricsAsync();
}
// The thread will wake up either when the metrics event queue is full (try_acquire_for call returns true),
// or the flush period limit is hit (try_acquire_for call returns false).
m_waitEvent.try_acquire_for(AZStd::chrono::seconds(m_clientConfiguration->GetQueueFlushPeriodInSeconds()));
FlushMetricsAsync();
}
}
@@ -114,6 +110,12 @@ namespace AWSMetrics
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_metricsQueue.AddMetrics(metricsEvent);
if (m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
// Flush the metrics queue when the accumulated metrics size hits the limit
m_waitEvent.release();
}
return true;
}
@@ -348,9 +350,6 @@ namespace AWSMetrics
void MetricsManager::FlushMetricsAsync()
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_lastSendMetricsTime = AZStd::chrono::system_clock::now();
if (m_metricsQueue.GetNumMetrics() == 0)
{
return;
@@ -363,34 +362,20 @@ namespace AWSMetrics
SendMetricsAsync(metricsToFlush);
}
bool MetricsManager::ShouldSendMetrics()
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
auto secondsSinceLastFlush = AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now() - m_lastSendMetricsTime);
if (secondsSinceLastFlush >= AZStd::chrono::seconds(m_clientConfiguration->GetQueueFlushPeriodInSeconds()) ||
m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
return true;
}
return false;
}
void MetricsManager::ShutdownMetrics()
{
if (m_consumerTerminated)
if (m_monitorTerminated)
{
return;
}
// Terminate the consumer thread
m_consumerTerminated = true;
FlushMetricsAsync();
// Terminate the monitor thread
m_monitorTerminated = true;
m_waitEvent.release();
if (m_consumerThread.joinable())
if (m_monitorThread.joinable())
{
m_consumerThread.join();
m_monitorThread.join();
}
}
@@ -449,6 +434,12 @@ namespace AWSMetrics
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_metricsQueue.AddMetrics(offlineRecords[index]);
if (m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
// Flush the metrics queue when the accumulated metrics size hits the limit
m_waitEvent.release();
}
}
// Remove the local metrics file after reading all its content.
@@ -355,6 +355,9 @@ namespace AWSMetrics
TEST_F(MetricsManagerTest, FlushMetrics_NonEmptyQueue_Success)
{
ResetClientConfig(true, (double)TestMetricsEventSizeInBytes * (MaxNumMetricsEvents + 1) / MbToBytes,
DefaultFlushPeriodInSeconds, 1);
for (int index = 0; index < MaxNumMetricsEvents; ++index)
{
AZStd::vector<MetricsAttribute> metricsAttributes;
@@ -377,7 +380,7 @@ namespace AWSMetrics
TEST_F(MetricsManagerTest, ResetOfflineRecordingStatus_ResubmitLocalMetrics_Success)
{
// Disable offline recording in the config file.
ResetClientConfig(false, 0.0, 0, 0);
ResetClientConfig(false, (double)TestMetricsEventSizeInBytes * 2 / MbToBytes, 0, 0);
// Enable offline recording after initialize the metric manager.
m_metricsManager->UpdateOfflineRecordingStatus(true);
@@ -265,6 +265,12 @@ namespace AZ
// Update all bindings on this pass that are connected to bindings on other passes
void UpdateConnectedBindings();
// Update input and input/output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedInputBindings();
// Update output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedOutputBindings();
protected:
explicit Pass(const PassDescriptor& descriptor);
@@ -1036,6 +1036,26 @@ namespace AZ
}
}
void Pass::UpdateConnectedInputBindings()
{
for (uint8_t idx : m_inputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
for (uint8_t idx : m_inputOutputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
}
void Pass::UpdateConnectedOutputBindings()
{
for (uint8_t idx : m_outputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
}
// --- Queuing functions with PassSystem ---
void Pass::QueueForBuildAndInitialization()
@@ -1264,7 +1284,7 @@ namespace AZ
AZ_Assert(m_state == PassState::Idle, "Pass::FrameBegin - Pass [%s] is attempting to render, but is not in the Idle state.", m_path.GetCStr());
m_state = PassState::Rendering;
UpdateConnectedBindings();
UpdateConnectedInputBindings();
UpdateOwnedAttachments();
CreateTransientAttachments(params.m_frameGraphBuilder->GetAttachmentDatabase());
@@ -1273,6 +1293,8 @@ namespace AZ
// FrameBeginInternal needs to be the last function be called in FrameBegin because its implementation expects
// all the attachments are imported to database (for example, ImageAttachmentPreview)
FrameBeginInternal(params);
UpdateConnectedOutputBindings();
}
void Pass::FrameEnd()
@@ -20,10 +20,12 @@ namespace CommandSystem
SelectionList::SelectionList()
{
EMotionFX::ActorNotificationBus::Handler::BusConnect();
EMotionFX::ActorInstanceNotificationBus::Handler::BusConnect();
}
SelectionList::~SelectionList()
{
EMotionFX::ActorInstanceNotificationBus::Handler::BusDisconnect();
EMotionFX::ActorNotificationBus::Handler::BusDisconnect();
}
@@ -378,4 +380,9 @@ namespace CommandSystem
RemoveActor(actor);
}
void SelectionList::OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance)
{
RemoveActorInstance(actorInstance);
}
} // namespace CommandSystem
@@ -15,6 +15,7 @@
#include "CommandSystemConfig.h"
#include <EMotionFX/Source/ActorBus.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/ActorInstanceBus.h>
#include <EMotionFX/Source/Motion.h>
#include <EMotionFX/Source/Node.h>
#include <EMotionFX/Source/MotionInstance.h>
@@ -27,7 +28,8 @@ namespace CommandSystem
* specific time stamp in a scene.
*/
class COMMANDSYSTEM_API SelectionList
: EMotionFX::ActorNotificationBus::Handler
: private EMotionFX::ActorNotificationBus::Handler
, private EMotionFX::ActorInstanceNotificationBus::Handler
{
MCORE_MEMORYOBJECTCATEGORY(SelectionList, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_COMMANDSYSTEM);
@@ -400,6 +402,9 @@ namespace CommandSystem
// ActorNotificationBus overrides
void OnActorDestroyed(EMotionFX::Actor* actor) override;
// ActorInstanceNotificationBus overrides
void OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance) override;
AZStd::vector<EMotionFX::Node*> mSelectedNodes; /**< Array of selected nodes. */
AZStd::vector<EMotionFX::Actor*> mSelectedActors; /**< The selected actors. */
AZStd::vector<EMotionFX::ActorInstance*> mSelectedActorInstances; /**< Array of selected actor instances. */
@@ -34,6 +34,7 @@
#include "NodeGroup.h"
#include "Recorder.h"
#include "TransformData.h"
#include <EMotionFX/Source/ActorInstanceBus.h>
#include <EMotionFX/Source/DebugDraw.h>
#include <EMotionFX/Source/RagdollInstance.h>
@@ -153,20 +154,14 @@ namespace EMotionFX
// register it
GetActorManager().RegisterActorInstance(this);
// automatically register the actor instance
GetEventManager().OnCreateActorInstance(this);
GetActorManager().GetScheduler()->RecursiveInsertActorInstance(this);
ActorInstanceNotificationBus::Broadcast(&ActorInstanceNotificationBus::Events::OnActorInstanceCreated, this);
}
// the destructor
ActorInstance::~ActorInstance()
{
// trigger the OnDeleteActorInstance event
GetEventManager().OnDeleteActorInstance(this);
// remove it from the recording
GetRecorder().RemoveActorInstanceFromRecording(this);
ActorInstanceNotificationBus::Broadcast(&ActorInstanceNotificationBus::Events::OnActorInstanceDestroyed, this);
// get rid of the motion system
if (mMotionSystem)
@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace EMotionFX
{
class ActorInstance;
/**
* EMotion FX Actor Instance Request Bus
* Used for making requests to actor instances.
*/
class ActorInstanceRequests
: public AZ::EBusTraits
{
public:
};
using ActorInstanceRequestBus = AZ::EBus<ActorInstanceRequests>;
/**
* EMotion FX Actor Instance Notification Bus
* Used for monitoring events from actor instances.
*/
class ActorInstanceNotifications
: public AZ::EBusTraits
{
public:
// Enable multi-threaded access by locking primitive using a mutex when connecting handlers to the EBus or executing events.
using MutexType = AZStd::recursive_mutex;
virtual void OnActorInstanceCreated([[maybe_unused]] ActorInstance* actorInstance) {}
/**
* Called when any of the actor instances gets destructed.
* @param actorInstance The actorInstance that gets destructed.
*/
virtual void OnActorInstanceDestroyed([[maybe_unused]] ActorInstance* actorInstance) {}
};
using ActorInstanceNotificationBus = AZ::EBus<ActorInstanceNotifications>;
} // namespace EMotionFX
@@ -51,7 +51,6 @@ namespace EMotionFX
EVENT_TYPE_MOTION_INSTANCE_LAST_EVENT = EVENT_TYPE_ON_QUEUE_MOTION_INSTANCE,
EVENT_TYPE_ON_DELETE_ACTOR,
EVENT_TYPE_ON_DELETE_ACTOR_INSTANCE,
EVENT_TYPE_ON_SIMULATE_PHYSICS,
EVENT_TYPE_ON_CUSTOM_EVENT,
EVENT_TYPE_ON_DRAW_LINE,
@@ -64,7 +63,6 @@ namespace EMotionFX
EVENT_TYPE_ON_CREATE_MOTION_INSTANCE,
EVENT_TYPE_ON_CREATE_MOTION_SYSTEM,
EVENT_TYPE_ON_CREATE_ACTOR,
EVENT_TYPE_ON_CREATE_ACTOR_INSTANCE,
EVENT_TYPE_ON_POST_CREATE_ACTOR,
EVENT_TYPE_ON_DELETE_ANIM_GRAPH,
EVENT_TYPE_ON_DELETE_ANIM_GRAPH_INSTANCE,
@@ -298,15 +296,6 @@ namespace EMotionFX
*/
virtual void OnDeleteActor(Actor* actor) { MCORE_UNUSED(actor); }
/**
* The event that gets triggered once an ActorInstance object is being deleted.
* You could for example use this event to delete any allocations you have done inside the
* custom user data object linked with the ActorInstance object.
* You can get and set this data object with the ActorInstance::GetCustomData() and ActorInstance::SetCustomData(...) methods.
* @param actorInstance The actorInstance that is being deleted.
*/
virtual void OnDeleteActorInstance(ActorInstance* actorInstance) { MCORE_UNUSED(actorInstance); }
virtual void OnSimulatePhysics(float timeDelta) { MCORE_UNUSED(timeDelta); }
virtual void OnCustomEvent(uint32 eventType, void* data) { MCORE_UNUSED(eventType); MCORE_UNUSED(data); }
@@ -321,7 +310,6 @@ namespace EMotionFX
virtual void OnCreateMotionInstance(MotionInstance* motionInstance) { MCORE_UNUSED(motionInstance); }
virtual void OnCreateMotionSystem(MotionSystem* motionSystem) { MCORE_UNUSED(motionSystem); }
virtual void OnCreateActor(Actor* actor) { MCORE_UNUSED(actor); }
virtual void OnCreateActorInstance(ActorInstance* actorInstance) { MCORE_UNUSED(actorInstance); }
virtual void OnPostCreateActor(Actor* actor) { MCORE_UNUSED(actor); }
// delete callbacks
@@ -305,16 +305,6 @@ namespace EMotionFX
}
void EventManager::OnDeleteActorInstance(ActorInstance* actorInstance)
{
const EventHandlerVector& eventHandlers = m_eventHandlersByEventType[EVENT_TYPE_ON_DELETE_ACTOR_INSTANCE];
for (EventHandler* eventHandler : eventHandlers)
{
eventHandler->OnDeleteActorInstance(actorInstance);
}
}
// draw a debug triangle
void EventManager::OnDrawTriangle(const AZ::Vector3& posA, const AZ::Vector3& posB, const AZ::Vector3& posC, const AZ::Vector3& normalA, const AZ::Vector3& normalB, const AZ::Vector3& normalC, uint32 color)
{
@@ -670,17 +660,6 @@ namespace EMotionFX
}
// create an actor instance
void EventManager::OnCreateActorInstance(ActorInstance* actorInstance)
{
const EventHandlerVector& eventHandlers = m_eventHandlersByEventType[EVENT_TYPE_ON_CREATE_ACTOR_INSTANCE];
for (EventHandler* eventHandler : eventHandlers)
{
eventHandler->OnCreateActorInstance(actorInstance);
}
}
// on post create actor
void EventManager::OnPostCreateActor(Actor* actor)
{
@@ -286,15 +286,6 @@ namespace EMotionFX
*/
void OnDeleteActor(Actor* actor);
/**
* The event that gets triggered once an ActorInstance object is being deleted.
* You could for example use this event to delete any allocations you have done inside the
* custom user data object linked with the ActorInstance object.
* You can get and set this data object with the ActorInstance::GetCustomData() and ActorInstance::SetCustomData(...) methods.
* @param actorInstance The actorInstance that is being deleted.
*/
void OnDeleteActorInstance(ActorInstance* actorInstance);
void OnSimulatePhysics(float timeDelta);
void OnCustomEvent(uint32 eventType, void* data);
void OnDrawTriangle(const AZ::Vector3& posA, const AZ::Vector3& posB, const AZ::Vector3& posC, const AZ::Vector3& normalA, const AZ::Vector3& normalB, const AZ::Vector3& normalC, uint32 color);
@@ -343,7 +334,6 @@ namespace EMotionFX
void OnCreateMotionInstance(MotionInstance* motionInstance);
void OnCreateMotionSystem(MotionSystem* motionSystem);
void OnCreateActor(Actor* actor);
void OnCreateActorInstance(ActorInstance* actorInstance);
void OnPostCreateActor(Actor* actor);
// delete callbacks
@@ -106,16 +106,12 @@ namespace EMotionFX
mCurrentPlayTime = 0.0f;
mObjects.SetMemoryCategory(EMFX_MEMCATEGORY_RECORDER);
GetEMotionFX().GetEventManager()->AddEventHandler(this);
EMotionFX::ActorInstanceNotificationBus::Handler::BusConnect();
}
Recorder::~Recorder()
{
if (EventManager* eventManager = GetEMotionFX().GetEventManager())
{
eventManager->RemoveEventHandler(this);
}
EMotionFX::ActorInstanceNotificationBus::Handler::BusDisconnect();
Clear();
}
@@ -1448,7 +1444,7 @@ namespace EMotionFX
Unlock();
}
void Recorder::OnDeleteActorInstance(ActorInstance* actorInstance)
void Recorder::OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance)
{
// Actor instances created by actor components do not use the command system and don't call a ClearRecorder command.
// Thus, these actor instances will have to be removed from the recorder to avoid dangling data.
@@ -23,6 +23,7 @@
#include <MCore/Source/File.h>
#include <MCore/Source/Vector.h>
#include <MCore/Source/MultiThreadManager.h>
#include <EMotionFX/Source/ActorInstanceBus.h>
#include <EMotionFX/Source/AnimGraphObjectIds.h>
#include <EMotionFX/Source/EventHandler.h>
#include <EMotionFX/Source/EventInfo.h>
@@ -47,7 +48,7 @@ namespace EMotionFX
class EMFX_API Recorder
: public BaseObject
, public EventHandler
, private EMotionFX::ActorInstanceNotificationBus::Handler
{
public:
AZ_CLASS_ALLOCATOR_DECL
@@ -319,9 +320,8 @@ namespace EMotionFX
void RemoveActorInstanceFromRecording(ActorInstance* actorInstance);
void RemoveAnimGraphFromRecording(AnimGraph* animGraph);
// EventHandler overrides
const AZStd::vector<EventTypes> GetHandledEventTypes() const override { return {EMotionFX::EVENT_TYPE_ON_DELETE_ACTOR_INSTANCE}; }
void OnDeleteActorInstance(ActorInstance* actorInstance) override;
// ActorInstanceNotificationBus overrides
void OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance) override;
void SampleAndApplyTransforms(float timeInSeconds, ActorInstance* actorInstance) const;
void SampleAndApplyMainTransform(float timeInSeconds, ActorInstance* actorInstance) const;
@@ -17,25 +17,26 @@
#include "../../../../EMStudioSDK/Source/EMStudioCore.h"
#include <MCore/Source/LogManager.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/MorphSetup.h>
#include "../../../../EMStudioSDK/Source/EMStudioManager.h"
namespace EMStudio
{
// constructor
MorphTargetsWindowPlugin::MorphTargetsWindowPlugin()
: EMStudio::DockWidgetPlugin()
{
mDialogStack = nullptr;
mCurrentActorInstance = nullptr;
mDialogStack = nullptr;
mCurrentActorInstance = nullptr;
mStaticTextWidget = nullptr;
EMotionFX::ActorInstanceNotificationBus::Handler::BusConnect();
}
// destructor
MorphTargetsWindowPlugin::~MorphTargetsWindowPlugin()
{
EMotionFX::ActorInstanceNotificationBus::Handler::BusDisconnect();
// unregister the command callbacks and get rid of the memory
for (auto callback : m_callbacks)
{
@@ -110,14 +111,16 @@ namespace EMStudio
mMorphTargetGroups.clear();
}
// reinit the morph target dialog, e.g. if selection changes
void MorphTargetsWindowPlugin::ReInit(bool forceReInit)
{
// get the selected actorinstance
const CommandSystem::SelectionList& selection = GetCommandManager()->GetCurrentSelection();
EMotionFX::ActorInstance* actorInstance = selection.GetSingleActorInstance();
const CommandSystem::SelectionList& selection = GetCommandManager()->GetCurrentSelection();
EMotionFX::ActorInstance* actorInstance = selection.GetSingleActorInstance();
ReInit(actorInstance, forceReInit);
}
void MorphTargetsWindowPlugin::ReInit(EMotionFX::ActorInstance* actorInstance, bool forceReInit)
{
// show hint if no/multiple actor instances is/are selected
if (actorInstance == nullptr)
{
@@ -135,10 +138,7 @@ namespace EMStudio
return;
}
// get our selected actor instance and the corresponding actor
EMotionFX::Actor* actor = actorInstance->GetActor();
// only reinit the morph targets if actorinstance changed
// only reinit the morph targets if actor instance changed
if (mCurrentActorInstance != actorInstance || forceReInit)
{
// set the current actor instance in any case
@@ -150,7 +150,7 @@ namespace EMStudio
AZStd::vector<EMotionFX::MorphSetupInstance::MorphTarget*> phonemeInstances;
AZStd::vector<EMotionFX::MorphSetupInstance::MorphTarget*> defaultMorphTargetInstances;
// get the morph target setup
EMotionFX::Actor* actor = actorInstance->GetActor();
EMotionFX::MorphSetup* morphSetup = actor->GetMorphSetup(actorInstance->GetLODLevel());
if (morphSetup == nullptr)
{
@@ -278,6 +278,13 @@ namespace EMStudio
}
}
void MorphTargetsWindowPlugin::OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance)
{
if (mCurrentActorInstance == actorInstance)
{
ReInit(/*actorInstance=*/nullptr);
}
}
//-----------------------------------------------------------------------------------------
// Command callbacks
@@ -16,6 +16,7 @@
#include <MysticQt/Source/DialogStack.h>
#include "../../../../EMStudioSDK/Source/DockWidgetPlugin.h"
#include <EMotionFX/CommandSystem/Source/SelectionCommands.h>
#include <EMotionFX/Source/ActorInstanceBus.h>
#include "MorphTargetGroupWidget.h"
#include <QVBoxLayout>
#include <QLabel>
@@ -26,6 +27,7 @@ namespace EMStudio
{
class MorphTargetsWindowPlugin
: public EMStudio::DockWidgetPlugin
, private EMotionFX::ActorInstanceNotificationBus::Handler
{
Q_OBJECT
MCORE_MEMORYOBJECTCATEGORY(MorphTargetsWindowPlugin, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_STANDARDPLUGINS);
@@ -54,6 +56,7 @@ namespace EMStudio
EMStudioPlugin* Clone() override;
// update the morph targets window based on the current selection
void ReInit(EMotionFX::ActorInstance* actorInstance, bool forceReInit = false);
void ReInit(bool forceReInit = false);
// clear all widgets from the window
@@ -70,6 +73,9 @@ namespace EMStudio
void WindowReInit(bool visible);
private:
// ActorInstanceNotificationBus overrides
void OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance) override;
// declare the callbacks
MCORE_DEFINECOMMANDCALLBACK(CommandSelectCallback);
MCORE_DEFINECOMMANDCALLBACK(CommandUnselectCallback);
@@ -15,6 +15,7 @@ set(FILES
Source/ActorBus.h
Source/ActorInstance.cpp
Source/ActorInstance.h
Source/ActorInstanceBus.h
Source/ActorManager.cpp
Source/ActorManager.h
Source/ActorUpdateScheduler.h
File diff suppressed because it is too large Load Diff
@@ -360,6 +360,8 @@ namespace ScriptCanvasEditor
}
}
AzToolsFramework::ScopedUndoBatch undo("Update Entity With New SC Graph");
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, GetEntityId());
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
}
+1
View File
@@ -24,6 +24,7 @@ ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED FALSE)
# Test library support
ly_set(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_PYTEST_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_TARGET_TYPE MODULE)
+1
View File
@@ -24,6 +24,7 @@ ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED FALSE)
# Test library support
ly_set(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_PYTEST_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_TARGET_TYPE MODULE)
+1
View File
@@ -24,6 +24,7 @@ ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED FALSE)
# Test library support
ly_set(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_PYTEST_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_TARGET_TYPE MODULE)
+1
View File
@@ -24,6 +24,7 @@ ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED TRUE)
# Test library support
ly_set(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_PYTEST_SUPPORTED TRUE)
ly_set(PAL_TRAIT_TEST_TARGET_TYPE MODULE)
+1
View File
@@ -24,6 +24,7 @@ ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED FALSE)
# Test library support
ly_set(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_PYTEST_SUPPORTED FALSE)
ly_set(PAL_TRAIT_TEST_TARGET_TYPE MODULE)
+15 -13
View File
@@ -20,20 +20,22 @@ endif()
# Tests
################################################################################
foreach(suite_name ${LY_TEST_GLOBAL_KNOWN_SUITE_NAMES})
ly_add_pytest(
NAME pytest_sanity_${suite_name}_no_gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/sanity_test.py
TEST_SUITE ${suite_name}
)
if(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED)
foreach(suite_name ${LY_TEST_GLOBAL_KNOWN_SUITE_NAMES})
ly_add_pytest(
NAME pytest_sanity_${suite_name}_no_gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/sanity_test.py
TEST_SUITE ${suite_name}
)
ly_add_pytest(
NAME pytest_sanity_${suite_name}_requires_gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/sanity_test.py
TEST_SUITE ${suite_name}
TEST_REQUIRES gpu
)
endforeach()
ly_add_pytest(
NAME pytest_sanity_${suite_name}_requires_gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/sanity_test.py
TEST_SUITE ${suite_name}
TEST_REQUIRES gpu
)
endforeach()
endif()
# EPB Sanity test is being registered here to validate that the ly_add_editor_python_test function works.
#if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_TARGET_NAME)