Merge pull request #4516 from aws-lumberyard-dev/animation/dev/atomRenderViewport

1st check-in for atom render window.
This commit is contained in:
Luis Sempé
2021-10-07 17:07:38 -07:00
committed by GitHub
74 changed files with 1493 additions and 568 deletions
@@ -54,11 +54,21 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
INCLUDE_DIRECTORIES
PRIVATE
Source
Tools
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
Gem::EMotionFX_Atom.Static
Gem::EMotionFX.Editor.Static
Gem::AtomToolsFramework.Static
Gem::AtomToolsFramework.Editor
Gem::Atom_Component_DebugCamera.Static
Gem::Atom_Feature_Common.Static
Gem::AtomLyIntegration_CommonFeatures.Static
RUNTIME_DEPENDENCIES
Gem::EMotionFX.Editor
COMPILE_DEFINITIONS
PUBLIC
EMOTIONFXATOM_EDITOR
)
endif()
@@ -11,6 +11,9 @@
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Module/Module.h>
#ifdef EMOTIONFXATOM_EDITOR
#include <Editor/EditorSystemComponent.h>
#endif
namespace AZ
{
@@ -28,7 +31,10 @@ namespace AZ
: Module()
{
m_descriptors.insert(m_descriptors.end(), {
ActorSystemComponent::CreateDescriptor()
ActorSystemComponent::CreateDescriptor(),
#ifdef EMOTIONFXATOM_EDITOR
EMotionFXAtom::EditorSystemComponent::CreateDescriptor(),
#endif
});
}
@@ -39,6 +45,9 @@ namespace AZ
{
return ComponentTypeList{
azrtti_typeid<ActorSystemComponent>(),
#ifdef EMOTIONFXATOM_EDITOR
azrtti_typeid<EMotionFXAtom::EditorSystemComponent>(),
#endif
};
}
};
@@ -0,0 +1,39 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Editor/EditorSystemComponent.h>
#include <EMStudio/AtomRenderPlugin.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
namespace AZ::EMotionFXAtom
{
void EditorSystemComponent::Reflect(ReflectContext* context)
{
if (SerializeContext* serialize = azrtti_cast<SerializeContext*>(context))
{
serialize->Class<EditorSystemComponent, Component>()->Version(0);
}
}
void EditorSystemComponent::Activate()
{
EMotionFX::Integration::SystemNotificationBus::Handler::BusConnect();
}
void EditorSystemComponent::Deactivate()
{
EMotionFX::Integration::SystemNotificationBus::Handler::BusDisconnect();
}
void EditorSystemComponent::OnRegisterPlugin()
{
EMStudio::PluginManager* pluginManager = EMStudio::EMStudioManager::GetInstance()->GetPluginManager();
pluginManager->RegisterPlugin(aznew EMStudio::AtomRenderPlugin());
}
} // namespace AZ::EMotionFXAtom
@@ -0,0 +1,32 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <Integration/AnimationBus.h>
namespace AZ::EMotionFXAtom
{
class EditorSystemComponent
: public Component
, private EMotionFX::Integration::SystemNotificationBus::Handler
{
public:
AZ_COMPONENT(EditorSystemComponent, "{1FAEC046-255D-4664-8F12-D16503C34431}");
static void Reflect(ReflectContext* context);
protected:
// AZ::Component overrides
void Activate() override;
void Deactivate() override;
// SystemNotificationBus::OnRegisterPlugin
void OnRegisterPlugin() override;
};
} // namespace AZ::EMotionFXAtom
@@ -0,0 +1,293 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <Integration/ActorComponentBus.h>
#include <Integration/Components/ActorComponent.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
#include <Atom/Feature/DisplayMapper/DisplayMapperFeatureProcessorInterface.h>
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
#include <Atom/Component/DebugCamera/CameraComponent.h>
#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConfig.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/PostFxLayerComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConstants.h>
#include <EMStudio/AnimViewportRenderer.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
namespace EMStudio
{
static constexpr float DepthNear = 0.01f;
AnimViewportRenderer::AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext)
: m_windowContext(viewportContext->GetWindowContext())
{
// Create a new entity context
m_entityContext = AZStd::make_unique<AzFramework::EntityContext>();
m_entityContext->InitContext();
// Create the scene
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
AZ_Assert(sceneSystem, "Unable to retrieve scene system.");
AZ::Outcome<AZStd::shared_ptr<AzFramework::Scene>, AZStd::string> createSceneOutcome = sceneSystem->CreateScene("AnimViewport");
AZ_Assert(createSceneOutcome, "%s", createSceneOutcome.GetError().data());
m_frameworkScene = createSceneOutcome.TakeValue();
m_frameworkScene->SetSubsystem<AzFramework::EntityContext::SceneStorageType>(m_entityContext.get());
// Create and register a scene with all available feature processors
AZ::RPI::SceneDescriptor sceneDesc;
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
m_scene->EnableAllFeatureProcessors();
// Link our RPI::Scene to the AzFramework::Scene
m_frameworkScene->SetSubsystem(m_scene);
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
AZStd::string defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset";
AZ::Data::Asset<AZ::RPI::AnyAsset> pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(
defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error);
m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get());
pipelineAsset.Release();
m_scene->AddRenderPipeline(m_renderPipeline);
m_renderPipeline->SetDefaultView(viewportContext->GetDefaultView());
// Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be
// initialized properly with pipeline's pass information.
m_scene->Activate();
AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId();
// Get the FeatureProcessors
m_meshFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::MeshFeatureProcessorInterface>();
// Configure tone mapper
AzFramework::EntityContextRequestBus::EventResult(
m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity");
AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity.");
m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId);
m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId);
m_postProcessEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_postProcessEntity->Activate();
// Init directional light processor
m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::DirectionalLightFeatureProcessorInterface>();
// Init display mapper processor
m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::DisplayMapperFeatureProcessorInterface>();
// Init Skybox
m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
m_skyboxFeatureProcessor->Enable(true);
m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap);
// Create IBL
AzFramework::EntityContextRequestBus::EventResult(
m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity");
AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity.");
m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId);
m_iblEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_iblEntity->Activate();
// Load light preset
AZ::Data::Asset<AZ::RPI::AnyAsset> lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(
"lightingpresets/default.lightingpreset.azasset", AZ::RPI::AssetUtils::TraceLevel::Warning);
const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs<AZ::Render::LightingPreset>();
SetLightingPreset(preset);
// Create grid
AzFramework::EntityContextRequestBus::EventResult(
m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid");
AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity.");
AZ::Render::GridComponentConfig gridConfig;
gridConfig.m_gridSize = 4.0f;
gridConfig.m_axisColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f);
gridConfig.m_primaryColor = AZ::Color(0.3f, 0.3f, 0.3f, 1.0f);
gridConfig.m_secondaryColor = AZ::Color(0.5f, 0.1f, 0.1f, 1.0f);
auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId);
gridComponent->SetConfiguration(gridConfig);
m_gridEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_gridEntity->Activate();
Reinit();
}
AnimViewportRenderer::~AnimViewportRenderer()
{
// Destroy all the entity we created.
m_entityContext->DestroyEntity(m_iblEntity);
m_entityContext->DestroyEntity(m_postProcessEntity);
m_entityContext->DestroyEntity(m_gridEntity);
for (AZ::Entity* entity : m_actorEntities)
{
m_entityContext->DestroyEntity(entity);
}
m_actorEntities.clear();
m_entityContext->DestroyContext();
for (AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle& handle : m_lightHandles)
{
m_directionalLightFeatureProcessor->ReleaseLight(handle);
}
m_lightHandles.clear();
m_frameworkScene->UnsetSubsystem(m_scene);
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
AZ_Assert(sceneSystem, "AtomViewportRenderer was unable to get the scene system during destruction.");
bool removeSuccess = sceneSystem->RemoveScene("AnimViewport");
if (!removeSuccess)
{
AZ_Assert(false, "AtomViewportRenderer should be removed.");
}
AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
m_scene = nullptr;
}
void AnimViewportRenderer::Reinit()
{
ReinitActorEntities();
ResetEnvironment();
}
void AnimViewportRenderer::ResetEnvironment()
{
// Reset environment
AZ::Transform iblTransform = AZ::Transform::CreateIdentity();
AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform);
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity();
AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix);
}
void AnimViewportRenderer::ReinitActorEntities()
{
// 1. Destroy all the entities that do not point to any actorAsset anymore.
AZStd::set<AZ::Data::AssetId> assetLookup;
AzFramework::EntityContext* entityContext = m_entityContext.get();
const size_t numActors = EMotionFX::GetActorManager().GetNumActors();
for (size_t i = 0; i < numActors; ++i)
{
assetLookup.emplace(EMotionFX::GetActorManager().GetActorAsset(i).GetId());
}
m_actorEntities.erase(
AZStd::remove_if(
m_actorEntities.begin(), m_actorEntities.end(),
[&assetLookup, entityContext](AZ::Entity* entity)
{
EMotionFX::Integration::ActorComponent* actorComponent =
entity->FindComponent<EMotionFX::Integration::ActorComponent>();
if (assetLookup.find(actorComponent->GetActorAsset().GetId()) == assetLookup.end())
{
entityContext->DestroyEntity(entity);
return true;
}
return false;
}),
m_actorEntities.end());
// 2. Create an entity for every actorAsset stored in actor manager.
for (size_t i = 0; i < numActors; ++i)
{
AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset = EMotionFX::GetActorManager().GetActorAsset(i);
if (!actorAsset->IsReady())
{
continue;
}
AZ::Entity* entity = FindActorEntity(actorAsset);
if (!entity)
{
m_actorEntities.emplace_back(CreateActorEntity(actorAsset));
}
}
}
AZ::Entity* AnimViewportRenderer::FindActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset) const
{
const auto foundEntity = AZStd::find_if(
begin(m_actorEntities), end(m_actorEntities),
[match = actorAsset](const AZ::Entity* entity)
{
EMotionFX::Integration::ActorComponent* actorComponent = entity->FindComponent<EMotionFX::Integration::ActorComponent>();
return actorComponent->GetActorAsset() == match;
});
return foundEntity != end(m_actorEntities) ? (*foundEntity) : nullptr;
}
AZ::Entity* AnimViewportRenderer::CreateActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset)
{
AZ::Entity* actorEntity = m_entityContext->CreateEntity(actorAsset->GetActor()->GetName());
actorEntity->CreateComponent(azrtti_typeid<EMotionFX::Integration::ActorComponent>());
actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
actorEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
actorEntity->Activate();
EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent<EMotionFX::Integration::ActorComponent>();
actorComponent->SetActorAsset(actorAsset);
// Since this entity belongs to the animation editor, we need to set the isOwnByRuntime flag to false.
actorComponent->GetActorInstance()->SetIsOwnedByRuntime(false);
// Selet the actor instance in the command manager after it has been created.
AZStd::string outResult;
EMStudioManager::GetInstance()->GetCommandManager()->ExecuteCommandInsideCommand(
AZStd::string::format("Select -actorInstanceID %i", actorComponent->GetActorInstance()->GetID()).c_str(), outResult);
return actorEntity;
}
void AnimViewportRenderer::SetLightingPreset(const AZ::Render::LightingPreset* preset)
{
if (!preset)
{
AZ_Warning("AnimViewportRenderer", false, "Attempting to set invalid lighting preset.");
return;
}
AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor =
m_scene->GetFeatureProcessor<AZ::Render::ImageBasedLightFeatureProcessorInterface>();
AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor =
m_scene->GetFeatureProcessor<AZ::Render::PostProcessFeatureProcessorInterface>();
AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface =
postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())
->GetOrCreateExposureControlSettingsInterface();
Camera::Configuration cameraConfig;
cameraConfig.m_fovRadians = AZ::Constants::HalfPi;
cameraConfig.m_nearClipDistance = DepthNear;
preset->ApplyLightingPreset(
iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor,
cameraConfig, m_lightHandles, nullptr, AZ::RPI::MaterialPropertyIndex::Null, false);
}
} // namespace EMStudio
@@ -0,0 +1,88 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/TickBus.h>
#include <AzFramework/Windowing/NativeWindow.h>
#include <AzFramework/Scene/Scene.h>
#include <Integration/Assets/ActorAsset.h>
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
#include <Atom/Feature/Utils/LightingPreset.h>
namespace AZ
{
class Entity;
class Component;
namespace Render
{
class DisplayMapperFeatureProcessorInterface;
class DirectionalLightFeatureProcessorInterface;
class MeshFeatureProcessorInterface;
}
namespace RPI
{
class WindowContext;
}
}
namespace EMStudio
{
class AnimViewportRenderer
{
public:
AZ_CLASS_ALLOCATOR(AnimViewportRenderer, AZ::SystemAllocator, 0);
AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext);
~AnimViewportRenderer();
void Reinit();
private:
// This function resets the light, camera and other environment settings.
void ResetEnvironment();
// This function creates in-editor entities for all actor assets stored in the actor manager,
// and deletes all the actor entities that no longer has an actor asset in the actor manager.
// Those entities are used in atom render viewport to visualize actors in animation editor.
void ReinitActorEntities();
AZ::Entity* CreateActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset);
AZ::Entity* FindActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset) const;
void SetLightingPreset(const AZ::Render::LightingPreset* preset);
AZStd::shared_ptr<AZ::RPI::WindowContext> m_windowContext;
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
AZStd::shared_ptr<AzFramework::Scene> m_frameworkScene;
AZ::RPI::ScenePtr m_scene;
AZ::RPI::RenderPipelinePtr m_renderPipeline;
AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr;
AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = nullptr;
AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = nullptr;
AZ::Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr;
AZ::Entity* m_postProcessEntity = nullptr;
AZ::Entity* m_iblEntity = nullptr;
AZ::Entity* m_cameraEntity = nullptr;
AZ::Component* m_cameraComponent = nullptr;
AZ::Entity* m_modelEntity = nullptr;
AZ::Data::AssetId m_modelAssetId;
AZ::Entity* m_gridEntity = nullptr;
AZStd::vector<AZ::Entity*> m_actorEntities;
AZStd::vector<AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle> m_lightHandles;
};
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <EMStudio/AnimViewportSettings.h>
namespace EMStudio::ViewportUtil
{
constexpr AZStd::string_view CameraRotateSmoothnessSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothness";
constexpr AZStd::string_view CameraTranslateSmoothnessSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothness";
constexpr AZStd::string_view CameraTranslateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothing";
constexpr AZStd::string_view CameraRotateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothing";
constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId";
constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId";
constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId";
constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId";
constexpr AZStd::string_view CameraTranslateRightIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateRightId";
constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId";
constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId";
constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId";
AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds()
{
AzFramework::TranslateCameraInputChannelIds translateCameraInputChannelIds;
translateCameraInputChannelIds.m_leftChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str());
translateCameraInputChannelIds.m_rightChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str());
translateCameraInputChannelIds.m_forwardChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str());
translateCameraInputChannelIds.m_backwardChannelId = AzFramework::InputChannelId(
GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str());
translateCameraInputChannelIds.m_upChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str());
translateCameraInputChannelIds.m_downChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str());
translateCameraInputChannelIds.m_boostChannelId =
AzFramework::InputChannelId(GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str());
return translateCameraInputChannelIds;
}
float CameraRotateSmoothness()
{
return aznumeric_cast<float>(GetRegistry(CameraRotateSmoothnessSetting, 5.0));
}
float CameraTranslateSmoothness()
{
return aznumeric_cast<float>(GetRegistry(CameraTranslateSmoothnessSetting, 5.0));
}
bool CameraRotateSmoothingEnabled()
{
return GetRegistry(CameraRotateSmoothingSetting, true);
}
bool CameraTranslateSmoothingEnabled()
{
return GetRegistry(CameraTranslateSmoothingSetting, true);
}
AzFramework::InputChannelId BuildRotateCameraInputId()
{
return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str());
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Settings/SettingsRegistry.h>
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
namespace EMStudio::ViewportUtil
{
template<typename T>
AZStd::remove_cvref_t<T> GetRegistry(const AZStd::string_view setting, T&& defaultValue)
{
AZStd::remove_cvref_t<T> value = AZStd::forward<T>(defaultValue);
if (const auto* registry = AZ::SettingsRegistry::Get())
{
T potentialValue;
if (registry->Get(potentialValue, setting))
{
value = AZStd::move(potentialValue);
}
}
return value;
}
float CameraRotateSmoothness();
float CameraTranslateSmoothness();
bool CameraRotateSmoothingEnabled();
bool CameraTranslateSmoothingEnabled();
AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds();
AzFramework::InputChannelId BuildRotateCameraInputId();
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzFramework/Viewport/CameraInput.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
#include <EMStudio/AnimViewportWidget.h>
#include <EMStudio/AnimViewportRenderer.h>
#include <EMStudio/AnimViewportSettings.h>
namespace EMStudio
{
AnimViewportWidget::AnimViewportWidget(QWidget* parent)
: AtomToolsFramework::RenderViewportWidget(parent)
{
setObjectName(QString::fromUtf8("AtomViewportWidget"));
QSizePolicy qSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
qSize.setHorizontalStretch(0);
qSize.setVerticalStretch(0);
qSize.setHeightForWidth(sizePolicy().hasHeightForWidth());
setSizePolicy(qSize);
setAutoFillBackground(false);
setStyleSheet(QString::fromUtf8(""));
m_renderer = AZStd::make_unique<AnimViewportRenderer>(GetViewportContext());
SetupCameras();
SetupCameraController();
}
void AnimViewportWidget::SetupCameras()
{
m_rotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(EMStudio::ViewportUtil::BuildRotateCameraInputId());
const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::BuildTranslateCameraInputChannelIds();
m_translateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
m_translateCamera.get()->m_translateSpeedFn = []
{
return 3.0f;
};
m_orbitDollyScrollCamera = AZStd::make_shared<AzFramework::OrbitDollyScrollCameraInput>();
}
void AnimViewportWidget::SetupCameraController()
{
auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
controller->SetCameraViewportContextBuilderCallback(
[viewportId =
GetViewportContext()->GetId()](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext)
{
cameraViewportContext = AZStd::make_unique<AtomToolsFramework::ModularCameraViewportContextImpl>(viewportId);
});
controller->SetCameraPriorityBuilderCallback(
[](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn)
{
cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority;
});
controller->SetCameraPropsBuilderCallback(
[](AzFramework::CameraProps& cameraProps)
{
cameraProps.m_rotateSmoothnessFn = []
{
return EMStudio::ViewportUtil::CameraRotateSmoothness();
};
cameraProps.m_translateSmoothnessFn = []
{
return EMStudio::ViewportUtil::CameraTranslateSmoothness();
};
cameraProps.m_rotateSmoothingEnabledFn = []
{
return EMStudio::ViewportUtil::CameraRotateSmoothingEnabled();
};
cameraProps.m_translateSmoothingEnabledFn = []
{
return EMStudio::ViewportUtil::CameraTranslateSmoothingEnabled();
};
});
controller->SetCameraListBuilderCallback(
[this](AzFramework::Cameras& cameras)
{
cameras.AddCamera(m_rotateCamera);
cameras.AddCamera(m_translateCamera);
cameras.AddCamera(m_orbitDollyScrollCamera);
});
GetControllerList()->Add(controller);
}
} // namespace EMStudio
@@ -0,0 +1,33 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzFramework/Viewport/CameraInput.h>
namespace EMStudio
{
class AnimViewportRenderer;
class AnimViewportWidget
: public AtomToolsFramework::RenderViewportWidget
{
public:
AnimViewportWidget(QWidget* parent = nullptr);
AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); }
private:
void SetupCameras();
void SetupCameraController();
AZStd::unique_ptr<AnimViewportRenderer> m_renderer;
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_rotateCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_translateCamera;
AZStd::shared_ptr<AzFramework::OrbitDollyScrollCameraInput> m_orbitDollyScrollCamera;
};
}
@@ -0,0 +1,140 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <EMStudio/AtomRenderPlugin.h>
#include <EMStudio/AnimViewportRenderer.h>
#include <Integration/Components/ActorComponent.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Source/Allocators.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <QHBoxLayout>
namespace EMStudio
{
AZ_CLASS_ALLOCATOR_IMPL(AtomRenderPlugin, EMotionFX::EditorAllocator, 0);
AtomRenderPlugin::AtomRenderPlugin()
: DockWidgetPlugin()
{
}
AtomRenderPlugin::~AtomRenderPlugin()
{
}
const char* AtomRenderPlugin::GetName() const
{
return "Atom Render Window (Preview)";
}
uint32 AtomRenderPlugin::GetClassID() const
{
return static_cast<uint32>(AtomRenderPlugin::CLASS_ID);
}
const char* AtomRenderPlugin::GetCreatorName() const
{
return "O3DE";
}
float AtomRenderPlugin::GetVersion() const
{
return 1.0f;
}
bool AtomRenderPlugin::GetIsClosable() const
{
return true;
}
bool AtomRenderPlugin::GetIsFloatable() const
{
return true;
}
bool AtomRenderPlugin::GetIsVertical() const
{
return false;
}
EMStudioPlugin* AtomRenderPlugin::Clone()
{
return new AtomRenderPlugin();
}
EMStudioPlugin::EPluginType AtomRenderPlugin::GetPluginType() const
{
return EMStudioPlugin::PLUGINTYPE_RENDERING;
}
void AtomRenderPlugin::ReinitRenderer()
{
m_animViewportWidget->GetAnimViewportRenderer()->Reinit();
}
bool AtomRenderPlugin::Init()
{
m_innerWidget = new QWidget();
m_dock->setWidget(m_innerWidget);
QVBoxLayout* verticalLayout = new QVBoxLayout(m_innerWidget);
verticalLayout->setSizeConstraint(QLayout::SetNoConstraint);
verticalLayout->setSpacing(1);
verticalLayout->setMargin(0);
m_animViewportWidget = new AnimViewportWidget(m_innerWidget);
verticalLayout->addWidget(m_animViewportWidget);
// Register command callbacks.
m_importActorCallback = new ImportActorCallback(false);
m_removeActorCallback = new RemoveActorCallback(false);
EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("ImportActor", m_importActorCallback);
EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActor", m_removeActorCallback);
return true;
}
// Command callbacks
bool ReinitAtomRenderPlugin()
{
EMStudioPlugin* plugin = EMStudio::GetPluginManager()->FindActivePlugin(static_cast<uint32>(AtomRenderPlugin::CLASS_ID));
if (!plugin)
{
AZ_Error("AtomRenderPlugin", false, "Cannot execute command callback. Atom render plugin does not exist.");
return false;
}
AtomRenderPlugin* atomRenderPlugin = static_cast<AtomRenderPlugin*>(plugin);
atomRenderPlugin->ReinitRenderer();
return true;
}
bool AtomRenderPlugin::ImportActorCallback::Execute(
[[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
{
return ReinitAtomRenderPlugin();
}
bool AtomRenderPlugin::ImportActorCallback::Undo(
[[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
{
return ReinitAtomRenderPlugin();
}
bool AtomRenderPlugin::RemoveActorCallback::Execute(
[[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
{
return ReinitAtomRenderPlugin();
}
bool AtomRenderPlugin::RemoveActorCallback::Undo(
[[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
{
return ReinitAtomRenderPlugin();
}
}// namespace EMStudio
@@ -0,0 +1,61 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <MCore/Source/Command.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/DockWidgetPlugin.h>
#include <EMStudio/AnimViewportWidget.h>
#include <QWidget>
#endif
namespace AZ
{
class Entity;
}
namespace EMStudio
{
class AtomRenderPlugin
: public DockWidgetPlugin
{
public:
AZ_CLASS_ALLOCATOR_DECL
enum
{
CLASS_ID = 0x32b0c04d
};
AtomRenderPlugin();
~AtomRenderPlugin();
// Plugin information
const char* GetName() const override;
uint32 GetClassID() const override;
const char* GetCreatorName() const override;
float GetVersion() const override;
bool GetIsClosable() const override;
bool GetIsFloatable() const override;
bool GetIsVertical() const override;
bool Init() override;
EMStudioPlugin* Clone();
EMStudioPlugin::EPluginType GetPluginType() const override;
void ReinitRenderer();
private:
MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback);
MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback);
ImportActorCallback* m_importActorCallback = nullptr;
RemoveActorCallback* m_removeActorCallback = nullptr;
QWidget* m_innerWidget = nullptr;
AnimViewportWidget* m_animViewportWidget = nullptr;
};
}// namespace EMStudio
@@ -8,4 +8,14 @@
set(FILES
Source/ActorModule.cpp
Source/Editor/EditorSystemComponent.h
Source/Editor/EditorSystemComponent.cpp
Tools/EMStudio/AtomRenderPlugin.h
Tools/EMStudio/AtomRenderPlugin.cpp
Tools/EMStudio/AnimViewportWidget.h
Tools/EMStudio/AnimViewportWidget.cpp
Tools/EMStudio/AnimViewportRenderer.h
Tools/EMStudio/AnimViewportRenderer.cpp
Tools/EMStudio/AnimViewportSettings.h
Tools/EMStudio/AnimViewportSettings.cpp
)
+2
View File
@@ -109,6 +109,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
AZ::AzToolsFramework
Legacy::Editor.Headers
3rdParty::OpenGLInterface
Gem::AtomToolsFramework.Static
Gem::AtomToolsFramework.Editor
COMPILE_DEFINITIONS
PUBLIC
EMFX_EMSTUDIOLYEMBEDDED
@@ -22,6 +22,7 @@
#include "CommandManager.h"
#include <EMotionFX/Source/EMotionFXManager.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <Source/Integration/Assets/ActorAsset.h>
namespace CommandSystem
@@ -729,7 +730,8 @@ namespace CommandSystem
m_oldWorkspaceDirtyFlag = GetCommandManager()->GetWorkspaceDirtyFlag();
// get rid of the actor
EMotionFX::GetActorManager().UnregisterActor(EMotionFX::GetActorManager().FindSharedActorByID(actor->GetID()));
const AZ::Data::AssetId actorAssetId = EMotionFX::GetActorManager().FindAssetIdByActorId(actor->GetID());
EMotionFX::GetActorManager().UnregisterActor(actorAssetId);
// mark the workspace as dirty
GetCommandManager()->SetWorkspaceDirtyFlag(true);
@@ -818,7 +820,6 @@ namespace CommandSystem
{
continue;
}
// ignore visualization actor instances
if (actorInstance->GetIsUsedForVisualization())
{
@@ -849,12 +850,6 @@ namespace CommandSystem
// get the current actor
EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
// ignore runtime-owned actors
if (actor->GetIsOwnedByRuntime())
{
continue;
}
// ignore visualization actors
if (actor->GetIsUsedForVisualization())
{
@@ -17,6 +17,7 @@
#include <EMotionFX/Exporters/ExporterLib/Exporter/Exporter.h>
#include "CommandManager.h"
#include <AzFramework/API/ApplicationAPI.h>
#include <Source/Integration/Assets/ActorAsset.h>
namespace CommandSystem
@@ -65,35 +66,29 @@ namespace CommandSystem
filename = EMotionFX::EMotionFXManager::ResolvePath(filename.c_str());
}
// check if we have already loaded the actor
EMotionFX::Actor* actorFromManager = EMotionFX::GetActorManager().FindActorByFileName(filename.c_str());
if (actorFromManager)
AZ::Data::AssetId actorAssetId;
EBUS_EVENT_RESULT(
actorAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, filename.c_str(), AZ::Data::s_invalidAssetType, false);
if (!actorAssetId.IsValid())
{
AZStd::to_string(outResult, actorFromManager->GetID());
return true;
}
// init the settings
EMotionFX::Importer::ActorSettings settings;
// extract default values from the command syntax automatically, if they aren't specified explicitly
settings.m_loadLimits = parameters.GetValueAsBool("loadLimits", this);
settings.m_loadMorphTargets = parameters.GetValueAsBool("loadMorphTargets", this);
settings.m_loadSkeletalLoDs = parameters.GetValueAsBool("loadSkeletalLODs", this);
settings.m_dualQuatSkinning = parameters.GetValueAsBool("dualQuatSkinning", this);
// try to load the actor
AZStd::shared_ptr<EMotionFX::Actor> actor {EMotionFX::GetImporter().LoadActor(filename.c_str(), &settings)};
if (!actor)
{
outResult = AZStd::string::format("Failed to load actor from '%s'. File may not exist at this path or may have incorrect permissions", filename.c_str());
outResult = AZStd::string::format("Cannot import actor. Cannot find asset at path %s.", filename.c_str());
return false;
}
// Because the actor is directly loaded from disk (without going through an actor asset), we need to ask for a blocking
// load for the asset that actor is depend on.
actor->Finalize(EMotionFX::Actor::LoadRequirement::RequireBlockingLoad);
// check if we have already loaded the actor
const size_t actorIndex = EMotionFX::GetActorManager().FindActorIndex(actorAssetId);
if (actorIndex != InvalidIndex)
{
return true;
}
// Do a blocking load of the asset.
AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset =
AZ::Data::AssetManager::Instance().GetAsset<EMotionFX::Integration::ActorAsset>(
actorAssetId, AZ::Data::AssetLoadBehavior::Default);
actorAsset.BlockUntilLoadComplete();
EMotionFX::Actor* actor = actorAsset->GetActor();
// set the actor id in case we have specified it as parameter
if (actorID != MCORE_INVALIDINDEX32)
{
@@ -113,7 +108,6 @@ namespace CommandSystem
GetCommandManager()->ExecuteCommandInsideCommand(AZStd::string::format("Select -actorID %i", actor->GetID()).c_str(), outResult);
}
// mark the workspace as dirty
m_oldWorkspaceDirtyFlag = GetCommandManager()->GetWorkspaceDirtyFlag();
GetCommandManager()->SetWorkspaceDirtyFlag(true);
@@ -121,7 +115,8 @@ namespace CommandSystem
// return the id of the newly created actor
AZStd::to_string(outResult, actor->GetID());
EMotionFX::GetActorManager().RegisterActor(AZStd::move(actor));
// Register actor asset.
EMotionFX::GetActorManager().RegisterActor(AZStd::move(actorAsset));
return true;
}
@@ -145,14 +140,14 @@ namespace CommandSystem
}
// find the actor based on the given id
AZStd::shared_ptr<EMotionFX::Actor> actor = EMotionFX::GetActorManager().FindSharedActorByID(actorID);
if (actor == nullptr)
AZ::Data::AssetId actorAssetId = EMotionFX::GetActorManager().FindAssetIdByActorId(actorID);
if (!actorAssetId.IsValid())
{
outResult = AZStd::string::format("Cannot remove actor. Actor ID %i is not valid.", actorID);
return false;
}
EMotionFX::GetActorManager().UnregisterActor(actor);
EMotionFX::GetActorManager().UnregisterActor(actorAssetId);
// update our render actors
AZStd::string updateRenderActorsResult;
@@ -183,11 +183,6 @@ namespace CommandSystem
for (size_t i = 0; i < numActors; ++i)
{
EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
if (actor->GetIsOwnedByRuntime())
{
continue;
}
if (unselect == false)
{
@@ -211,11 +206,6 @@ namespace CommandSystem
return false;
}
if (actor->GetIsOwnedByRuntime())
{
return false;
}
if (unselect == false)
{
selection.AddActor(actor);
@@ -244,11 +234,6 @@ namespace CommandSystem
{
EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
if (actor->GetIsOwnedByRuntime())
{
continue;
}
if (AzFramework::StringFunc::Equal(valueString.c_str(), actor->GetName(), false /* no case */))
{
if (unselect == false)
@@ -8,7 +8,6 @@
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionFX/Source/Importer/Importer.h>
#include <EMotionFX/CommandSystem/Source/MetaData.h>
#include <EMotionFX/Exporters/ExporterLib/Exporter/Exporter.h>
@@ -8,7 +8,6 @@
#pragma once
#include <AzCore/std/optional.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
#include <Integration/System/SystemCommon.h>
@@ -44,7 +43,7 @@ namespace EMotionFX
static AZStd::optional<AZ::SceneAPI::Events::ExportProduct> GetFirstProductByType(
const ActorGroupExportContext& context, AZ::Data::AssetType type);
AutoRegisteredActor m_actor;
AZStd::shared_ptr<Actor> m_actor;
AZStd::vector<AZStd::string> m_actorMaterialReferences;
};
} // namespace Pipeline
@@ -91,9 +91,6 @@ namespace EMotionFX
m_simulatedObjectSetup = AZStd::make_shared<SimulatedObjectSetup>(this);
m_optimizeSkeleton = false;
#if defined(EMFX_DEVELOPMENT_BUILD)
m_isOwnedByRuntime = false;
#endif // EMFX_DEVELOPMENT_BUILD
// make sure we have at least allocated the first LOD of materials and facial setups
m_materials.reserve(4); // reserve space for 4 lods
@@ -2074,25 +2071,6 @@ namespace EMotionFX
return m_usedForVisualization;
}
void Actor::SetIsOwnedByRuntime(bool isOwnedByRuntime)
{
#if defined(EMFX_DEVELOPMENT_BUILD)
m_isOwnedByRuntime = isOwnedByRuntime;
#else
AZ_UNUSED(isOwnedByRuntime);
#endif
}
bool Actor::GetIsOwnedByRuntime() const
{
#if defined(EMFX_DEVELOPMENT_BUILD)
return m_isOwnedByRuntime;
#else
return true;
#endif
}
const AZ::Aabb& Actor::GetStaticAabb() const
{
return m_staticAabb;
@@ -720,12 +720,6 @@ namespace EMotionFX
void SetIsUsedForVisualization(bool flag);
bool GetIsUsedForVisualization() const;
/**
* Marks the actor as used by the engine runtime, as opposed to the tool suite.
*/
void SetIsOwnedByRuntime(bool isOwnedByRuntime);
bool GetIsOwnedByRuntime() const;
/**
* Recursively find the parent bone that is enabled in a given LOD, starting from a given node.
* For example if you have a finger bone, while the finger bones are disabled in the skeletal LOD, this function will return the index to the hand bone.
@@ -940,8 +934,5 @@ namespace EMotionFX
bool m_usedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */
bool m_optimizeSkeleton; /**< Indicates if we should perform/ */
bool m_isReady = false; /**< If actor as well as its dependent files are fully loaded and initialized.*/
#if defined(EMFX_DEVELOPMENT_BUILD)
bool m_isOwnedByRuntime; /**< Set if the actor is used/owned by the engine runtime. */
#endif // EMFX_DEVELOPMENT_BUILD
};
} // namespace EMotionFX
@@ -31,7 +31,6 @@ namespace EMotionFX
SetScheduler(MultiThreadScheduler::Create());
// reserve memory
m_actors.reserve(512);
m_actorInstances.reserve(1024);
m_rootActorInstances.reserve(1024);
}
@@ -111,20 +110,23 @@ namespace EMotionFX
// register the actor
void ActorManager::RegisterActor(AZStd::shared_ptr<Actor> actor)
void ActorManager::RegisterActor(ActorAssetData actorAsset)
{
LockActors();
// check if we already registered
if (FindActorIndex(actor.get()) != InvalidIndex)
if (FindActorIndex(actorAsset.GetId()) != InvalidIndex)
{
MCore::LogWarning("EMotionFX::ActorManager::RegisterActor() - The actor at location 0x%x has already been registered as actor, most likely already by the LoadActor of the importer.", actor.get());
MCore::LogWarning(
"EMotionFX::ActorManager::RegisterActor() - The actor %s has already been registered as actor, most likely "
"already by the LoadActor of the importer.",
actorAsset->GetActor()->GetName());
UnlockActors();
return;
}
// register it
m_actors.emplace_back(AZStd::move(actor));
m_actorAssets.emplace_back(AZStd::move(actorAsset));
UnlockActors();
}
@@ -146,60 +148,82 @@ namespace EMotionFX
Actor* ActorManager::FindActorByName(const char* actorName) const
{
// get the number of actors and iterate through them
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actorName](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[actorName](const ActorAssetData& a)
{
return a->GetNameString() == actorName;
return a->GetActor()->GetNameString() == actorName;
});
return (found != m_actors.end()) ? found->get() : nullptr;
return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr;
}
// find the actor for a given filename
Actor* ActorManager::FindActorByFileName(const char* fileName) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [fileName](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[fileName](const ActorAssetData& a)
{
return AzFramework::StringFunc::Equal(a->GetFileNameString().c_str(), fileName, false /* no case */);
return AzFramework::StringFunc::Equal(
a->GetActor()->GetFileNameString().c_str(), fileName, false /* no case */);
});
return (found != m_actors.end()) ? found->get() : nullptr;
return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr;
}
// find the leader actor record for a given actor
size_t ActorManager::FindActorIndex(Actor* actor) const
size_t ActorManager::FindActorIndex(AZ::Data::AssetId assetId) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actor](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[assetId](const ActorAssetData& a)
{
return a.get() == actor;
return a.GetId() == assetId;
});
return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex;
return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex;
}
size_t ActorManager::FindActorIndex(const Actor* actor) const
{
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[actor](const ActorAssetData& a)
{
return a->GetActor() == actor;
});
return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex;
}
// find the actor for a given actor name
size_t ActorManager::FindActorIndexByName(const char* actorName) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actorName](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[actorName](const ActorAssetData& a)
{
return a->GetNameString() == actorName;
return a->GetActor()->GetNameString() == actorName;
});
return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex;
return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex;
}
// find the actor for a given actor filename
size_t ActorManager::FindActorIndexByFileName(const char* filename) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [filename](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[filename](const ActorAssetData& a)
{
return a->GetFileNameString() == filename;
return a->GetActor()->GetFileNameString() == filename;
});
return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex;
return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex;
}
@@ -237,22 +261,26 @@ namespace EMotionFX
// find the actor by the identification number
Actor* ActorManager::FindActorByID(uint32 id) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [id](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[id](const ActorAssetData& a)
{
return a->GetID() == id;
return a->GetActor()->GetID() == id;
});
return (found != m_actors.end()) ? found->get() : nullptr;
return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr;
}
AZStd::shared_ptr<Actor> ActorManager::FindSharedActorByID(uint32 id) const
AZ::Data::AssetId ActorManager::FindAssetIdByActorId(uint32 id) const
{
const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [id](const AZStd::shared_ptr<Actor>& a)
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[id](const ActorAssetData& a)
{
return a->GetID() == id;
return a->GetActor()->GetID() == id;
});
return (found != m_actors.end()) ? *found : nullptr;
return (found != m_actorAssets.end()) ? found->GetId() : AZ::Data::AssetId();
}
@@ -264,14 +292,20 @@ namespace EMotionFX
// unregister an actor
void ActorManager::UnregisterActor(const AZStd::shared_ptr<Actor>& actor)
void ActorManager::UnregisterActor(AZ::Data::AssetId actorAssetID)
{
LockActors();
auto result = AZStd::find(m_actors.begin(), m_actors.end(), actor);
if (result != m_actors.end())
const auto found = AZStd::find_if(
m_actorAssets.begin(), m_actorAssets.end(),
[actorAssetID](const ActorAssetData& a)
{
return a.GetId() == actorAssetID;
});
if (found != m_actorAssets.end())
{
m_actors.erase(result);
m_actorAssets.erase(found);
}
UnlockActors();
}
@@ -297,7 +331,7 @@ namespace EMotionFX
LockActors();
// clear all actors
m_actors.clear();
m_actorAssets.clear();
// TODO: what if there are still references to the actors inside the list of registered actor instances?
UnlockActors();
@@ -390,7 +424,13 @@ namespace EMotionFX
Actor* ActorManager::GetActor(size_t nr) const
{
return m_actors[nr].get();
return m_actorAssets[nr]->GetActor();
}
ActorAssetData ActorManager::GetActorAsset(size_t nr) const
{
return m_actorAssets[nr];
}
@@ -16,7 +16,8 @@
#include <MCore/Source/MultiThreadManager.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/weak_ptr.h>
#include <Source/Integration/Assets/ActorAsset.h>
#include <Source/Integration/System/SystemCommon.h>
namespace EMotionFX
{
@@ -47,7 +48,7 @@ namespace EMotionFX
* Register an actor.
* @param actor The actor to register.
*/
void RegisterActor(AZStd::shared_ptr<Actor> actor);
void RegisterActor(ActorAssetData actorAsset);
/**
* Unregister all actors.
@@ -60,14 +61,14 @@ namespace EMotionFX
* Unregister a specific actor.
* @param actor The actor you passed to the RegisterActor function sometime before.
*/
void UnregisterActor(const AZStd::shared_ptr<Actor>& actor);
void UnregisterActor(AZ::Data::AssetId actorAssetID);
/**
* Get the number of registered actors.
* This does not include the clones that have been optionally created.
* @result The number of registered actors.
*/
MCORE_INLINE size_t GetNumActors() const { return m_actors.size(); }
MCORE_INLINE size_t GetNumActors() const { return m_actorAssets.size(); }
/**
* Get a given actor.
@@ -78,6 +79,7 @@ namespace EMotionFX
* @result A reference to the actor object that contains the array of Actor objects.
*/
Actor* GetActor(size_t nr) const;
ActorAssetData GetActorAsset(size_t nr) const;
/**
* Find the given actor by name.
@@ -99,7 +101,8 @@ namespace EMotionFX
* @param actor The actor object you once passed to RegisterActor.
* @result Returns the actor number, which is in range of [0..GetNumActors()-1], or returns MCORE_INVALIDINDEX32 when not found.
*/
size_t FindActorIndex(Actor* actor) const;
size_t FindActorIndex(AZ::Data::AssetId assetId) const;
size_t FindActorIndex(const Actor* actor) const;
/**
* Find the actor number for a given actor name.
@@ -160,7 +163,7 @@ namespace EMotionFX
*/
Actor* FindActorByID(uint32 id) const;
AZStd::shared_ptr<Actor> FindSharedActorByID(uint32 id) const;
AZ::Data::AssetId FindAssetIdByActorId(uint32 id) const;
/**
* Check if the given actor instance is registered.
@@ -255,9 +258,9 @@ namespace EMotionFX
void UnlockActors();
private:
AZStd::vector<ActorInstance*> m_actorInstances; /**< The registered actor instances. */
AZStd::vector<AZStd::shared_ptr<Actor>> m_actors; /**< The registered actors. */
AZStd::vector<ActorInstance*> m_rootActorInstances; /**< Root actor instances (roots of all attachment chains). */
AZStd::vector<ActorInstance*> m_actorInstances; /**< The registered actor instances. */
AZStd::vector<ActorAssetData> m_actorAssets;
AZStd::vector<ActorInstance*> m_rootActorInstances; /**< Root actor instances (roots of all attachment chains). */
ActorUpdateScheduler* m_scheduler; /**< The update scheduler to use. */
MCore::MutexRecursive m_actorLock; /**< The multithread lock for touching the actors array. */
MCore::MutexRecursive m_actorInstanceLock; /**< The multithread lock for touching the actor instances array. */
@@ -1,109 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/ActorManager.h>
namespace EMotionFX
{
class Actor;
/**
* @brief An Actor pointer that unregisters itself when it goes out of
* scope
*
* This class allows for simple functionality of automatically registering
* and unregistering an actor from the manager. Its primary use case is the
* ActorAsset, that shares ownership with the manager. But it can also be
* used anywhere that needs to make an Actor that needs to be in the
* Manager for a given period of time. A good example of this is anything
* that needs Actor commands to work on an actor that is made in a given
* scope. One main place where this happens is in the Actor asset processor
* code.
*/
class AutoRegisteredActor
{
public:
AutoRegisteredActor() = default;
template<class T>
AutoRegisteredActor(AZStd::shared_ptr<T> actor)
: m_actor(AZStd::move(actor))
{
Register(m_actor);
}
template<class T>
AutoRegisteredActor(AZStd::unique_ptr<T> actor)
: m_actor(AZStd::move(actor))
{
Register(m_actor);
}
// This class is not copyable, because a given actor cannot be
// registered with the manager multiple times
AutoRegisteredActor(const AutoRegisteredActor&) = delete;
AutoRegisteredActor& operator=(const AutoRegisteredActor&) = delete;
AutoRegisteredActor(AutoRegisteredActor&& other) noexcept
{
*this = AZStd::move(other);
}
AutoRegisteredActor& operator=(AutoRegisteredActor&& other) noexcept
{
if (this != &other)
{
Unregister(m_actor);
m_actor = AZStd::move(other.m_actor);
}
return *this;
}
~AutoRegisteredActor()
{
Unregister(m_actor);
}
Actor* operator->() const
{
return m_actor.operator->();
}
operator bool() const
{
return static_cast<bool>(m_actor);
}
Actor* get() const
{
return m_actor.get();
}
private:
void Register(const AZStd::shared_ptr<Actor>& actor)
{
if (actor)
{
GetActorManager().RegisterActor(actor);
}
}
void Unregister(const AZStd::shared_ptr<Actor>& actor)
{
if (actor)
{
GetActorManager().UnregisterActor(actor);
}
}
AZStd::shared_ptr<Actor> m_actor;
};
} // namespace EMotionFX
@@ -46,15 +46,10 @@ AZ_POP_DISABLE_WARNING
namespace EMStudio
{
//--------------------------------------------------------------------------
// globals
//--------------------------------------------------------------------------
EMStudioManager* gEMStudioMgr = nullptr;
//--------------------------------------------------------------------------
// class EMStudioManager
//--------------------------------------------------------------------------
AZ_CLASS_ALLOCATOR_IMPL(EMStudioManager, AZ::SystemAllocator, 0)
// constructor
EMStudioManager::EMStudioManager(QApplication* app, [[maybe_unused]] int& argc, [[maybe_unused]] char* argv[])
@@ -105,8 +100,9 @@ namespace EMStudio
// log some information
LogInfo();
}
AZ::Interface<EMStudioManager>::Register(this);
}
// destructor
EMStudioManager::~EMStudioManager()
@@ -130,6 +126,8 @@ namespace EMStudio
delete m_commandManager;
AZ::AllocatorInstance<UIAllocator>::Destroy();
AZ::Interface<EMStudioManager>::Unregister(this);
}
MainWindow* EMStudioManager::GetMainWindow()
@@ -422,6 +420,12 @@ namespace EMStudio
}
EMStudioManager* EMStudioManager::GetInstance()
{
return AZ::Interface<EMStudioManager>().Get();
}
// function to add a gizmo to the manager
MCommon::TransformationManipulator* EMStudioManager::AddTransformationManipulator(MCommon::TransformationManipulator* manipulator)
{
@@ -494,30 +498,48 @@ namespace EMStudio
painter.drawPath(path);
}
//--------------------------------------------------------------------------
// class Initializer
//--------------------------------------------------------------------------
// initialize EMotion Studio
bool Initializer::Init(QApplication* app, int& argc, char* argv[])
// shortcuts
QApplication* GetApp()
{
// do nothing if we already have initialized
if (gEMStudioMgr)
{
return true;
}
// create the new EMStudio object
gEMStudioMgr = new EMStudioManager(app, argc, argv);
// return success
return true;
return EMStudioManager::GetInstance()->GetApp();
}
EMStudioManager* GetManager()
{
return EMStudioManager::GetInstance();
}
// the shutdown function
void Initializer::Shutdown()
bool HasMainWindow()
{
delete gEMStudioMgr;
gEMStudioMgr = nullptr;
return EMStudioManager::GetInstance()->HasMainWindow();
}
MainWindow* GetMainWindow()
{
return EMStudioManager::GetInstance()->GetMainWindow();
}
PluginManager* GetPluginManager()
{
return EMStudioManager::GetInstance()->GetPluginManager();
}
LayoutManager* GetLayoutManager()
{
return EMStudioManager::GetInstance()->GetLayoutManager();
}
NotificationWindowManager* GetNotificationWindowManager()
{
return EMStudioManager::GetInstance()->GetNotificationWindowManager();
}
MotionEventPresetManager* GetEventPresetManager()
{
return EMStudioManager::GetInstance()->GetEventPresetManger();
}
CommandSystem::CommandManager* GetCommandManager()
{
return EMStudioManager::GetInstance()->GetCommandManager();
}
} // namespace EMStudio
@@ -53,9 +53,10 @@ namespace EMStudio
class EMSTUDIO_API EMStudioManager
: private EMotionFX::SkeletonOutlinerNotificationBus::Handler
{
MCORE_MEMORYOBJECTCATEGORY(EMStudioManager, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_EMSTUDIOSDK)
public:
AZ_RTTI(EMStudio::EMStudioManager, "{D45E95CF-0C7B-44F1-A9D4-99A1E12A5AB5}")
AZ_CLASS_ALLOCATOR_DECL
EMStudioManager(QApplication* app, int& argc, char* argv[]);
~EMStudioManager();
@@ -72,6 +73,9 @@ namespace EMStudio
AZStd::string GetRecoverFolder() const;
AZStd::string GetAutosavesFolder() const;
// Singleton pattern
static EMStudioManager* GetInstance();
// text rendering helper function
static void RenderText(QPainter& painter, const QString& text, const QColor& textColor, const QFont& font, const QFontMetrics& fontMetrics, Qt::Alignment textAlignment, const QRect& rect);
@@ -150,34 +154,17 @@ namespace EMStudio
void OnRemoveCommand(size_t historyIndex) override { MCORE_UNUSED(historyIndex); }
void OnSetCurrentCommand(size_t index) override { MCORE_UNUSED(index); }
};
EventProcessingCallback* m_eventProcessingCallback;
EventProcessingCallback* m_eventProcessingCallback = nullptr;
};
/**
*
*
*
*/
class EMSTUDIO_API Initializer
{
public:
static bool MCORE_CDECL Init(QApplication* app, int& argc, char* argv[]);
static void MCORE_CDECL Shutdown();
};
// the global manager
extern EMSTUDIO_API EMStudioManager* gEMStudioMgr;
// shortcuts
MCORE_INLINE QApplication* GetApp() { return gEMStudioMgr->GetApp(); }
MCORE_INLINE EMStudioManager* GetManager() { return gEMStudioMgr; }
MCORE_INLINE bool HasMainWindow() { return gEMStudioMgr->HasMainWindow(); }
MCORE_INLINE MainWindow* GetMainWindow() { return gEMStudioMgr->GetMainWindow(); }
MCORE_INLINE PluginManager* GetPluginManager() { return gEMStudioMgr->GetPluginManager(); }
MCORE_INLINE LayoutManager* GetLayoutManager() { return gEMStudioMgr->GetLayoutManager(); }
MCORE_INLINE NotificationWindowManager* GetNotificationWindowManager() { return gEMStudioMgr->GetNotificationWindowManager(); }
MCORE_INLINE MotionEventPresetManager* GetEventPresetManager() { return gEMStudioMgr->GetEventPresetManger(); }
MCORE_INLINE CommandSystem::CommandManager* GetCommandManager() { return gEMStudioMgr->GetCommandManager(); }
// Shortcuts
QApplication* GetApp();
EMStudioManager* GetManager();
bool HasMainWindow();
MainWindow* GetMainWindow();
PluginManager* GetPluginManager();
LayoutManager* GetLayoutManager();
NotificationWindowManager* GetNotificationWindowManager();
MotionEventPresetManager* GetEventPresetManager();
CommandSystem::CommandManager* GetCommandManager();
} // namespace EMStudio
@@ -112,10 +112,6 @@ namespace EMStudio
for (size_t i = 0; i < actorCount; ++i)
{
EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
if (actor->GetIsOwnedByRuntime())
{
continue;
}
if (AzFramework::StringFunc::Equal(filename, actor->GetFileName()))
{
@@ -1792,11 +1792,6 @@ namespace EMStudio
{
EMotionFX::Actor* actor = selectionList.GetActorInstance(i)->GetActor();
if (actor->GetIsOwnedByRuntime())
{
continue;
}
if (AZStd::find(savingActors.begin(), savingActors.end(), actor) == savingActors.end())
{
savingActors.push_back(actor);
@@ -10,9 +10,9 @@
#if !defined(Q_MOC_RUN)
#include <AzCore/Component/TickBus.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioConfig.h>
#include <EMotionStudio/EMStudioSDK/Source/GUIOptions.h>
#include <EMotionStudio/EMStudioSDK/Source/PluginOptionsBus.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioConfig.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/GUIOptions.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginOptionsBus.h>
#include <AzCore/std/containers/vector.h>
#include <MCore/Source/Command.h>
#include <MCore/Source/StandardHeaders.h>
@@ -389,7 +389,7 @@ namespace EMStudio
// get the current actor and the number of clones
EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
if (actor->GetIsOwnedByRuntime() || !actor->IsReady())
if (!actor->IsReady())
{
continue;
}
@@ -421,7 +421,7 @@ namespace EMStudio
// At this point the render actor could point to an already deleted actor.
// In case the actor got deleted we might get an unexpected flag as result.
if (!found || (found && actor->GetIsOwnedByRuntime()) || (!actor->IsReady()))
if (!found || (!actor->IsReady()))
{
DestroyEMStudioActor(actor);
}
@@ -155,12 +155,12 @@ namespace EMStudio
cameraMenu->addAction("Reset Camera", [this]() { this->OnResetCamera(); });
QAction* showSelectedAction = cameraMenu->addAction("Show Selected", this, &RenderViewWidget::OnShowSelected);
showSelectedAction->setShortcut(Qt::Key_S);
showSelectedAction->setShortcut(QKeySequence(Qt::Key_S + Qt::SHIFT));
GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showSelectedAction, RenderPlugin::s_renderWindowShortcutGroupName, true);
addAction(showSelectedAction);
QAction* showEntireSceneAction = cameraMenu->addAction("Show Entire Scene", this, &RenderViewWidget::OnShowEntireScene);
showEntireSceneAction->setShortcut(Qt::Key_A);
showEntireSceneAction->setShortcut(QKeySequence(Qt::Key_A + Qt::SHIFT));
GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showEntireSceneAction, RenderPlugin::s_renderWindowShortcutGroupName, true);
addAction(showEntireSceneAction);
@@ -65,8 +65,7 @@ namespace EMStudio
m_actorCheckbox = new QCheckBox("Actors");
m_actorCheckbox->setObjectName("EMFX.ResetSettingsDialog.Actors");
const bool hasActors = HasEntityInEditor(
EMotionFX::GetActorManager(), &EMotionFX::ActorManager::GetNumActors, &EMotionFX::ActorManager::GetActor);
const bool hasActors = EMotionFX::GetActorManager().GetNumActors() > 0;
m_actorCheckbox->setChecked(hasActors);
m_actorCheckbox->setDisabled(!hasActors);
@@ -327,7 +327,16 @@ namespace EMStudio
void NodeWindowPlugin::OnActorReady([[maybe_unused]] EMotionFX::Actor* actor)
{
ReInit();
m_reinitRequested = true;
}
void NodeWindowPlugin::ProcessFrame([[maybe_unused]] float timePassedInSeconds)
{
if (m_reinitRequested)
{
ReInit();
m_reinitRequested = false;
}
}
//-----------------------------------------------------------------------------------------
@@ -60,6 +60,8 @@ namespace EMStudio
EMStudioPlugin* Clone() override;
void ReInit();
void ProcessFrame(float timePassedInSeconds) override;
public slots:
void OnNodeChanged();
void VisibilityChanged(bool isVisible);
@@ -87,5 +89,8 @@ namespace EMStudio
AZStd::unique_ptr<ActorInfo> m_actorInfo;
AZStd::unique_ptr<NodeInfo> m_nodeInfo;
// Use this flag to defer the reinit function to main thread.
bool m_reinitRequested = false;
};
} // namespace EMStudio
@@ -123,12 +123,6 @@ namespace EMStudio
continue;
}
// ignore engine actors
if (actor->GetIsOwnedByRuntime())
{
continue;
}
// create a tree item for the new attachment
QTreeWidgetItem* newItem = new QTreeWidgetItem(m_treeWidget);
@@ -25,7 +25,6 @@ set(FILES
Source/AttachmentNode.h
Source/AttachmentSkin.cpp
Source/AttachmentSkin.h
Source/AutoRegisteredActor.h
Source/BaseObject.cpp
Source/BaseObject.h
Source/CompressedKeyFrames.h
@@ -16,7 +16,7 @@
#include <AzCore/RTTI/TypeInfo.h>
#include <AzFramework/Physics/AnimationConfiguration.h>
#include <AzFramework/Physics/Character.h>
#include <Integration/Assets/ActorAsset.h>
namespace EMotionFX
{
@@ -96,6 +96,9 @@ namespace EMotionFX
/// Returns skinning method used by the actor.
virtual SkinningMethod GetSkinningMethod() const = 0;
// Use this to alter the actor asset.
virtual void SetActorAsset(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset) = 0;
static const size_t s_invalidJointIndex = std::numeric_limits<size_t>::max();
};
@@ -46,6 +46,9 @@ namespace EMotionFX
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
// Use this bus to register custom EMotionFX plugin.
virtual void OnRegisterPlugin() = 0;
};
using SystemNotificationBus = AZ::EBus<SystemNotifications>;
@@ -6,7 +6,6 @@
*
*/
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/Importer/Importer.h>
@@ -64,8 +63,7 @@ namespace EMotionFX
&actorSettings,
"");
// Set the is owned by runtime flag before finalizing the actor, as that uses the flag already.
assetData->m_emfxActor->SetIsOwnedByRuntime(true);
assetData->m_emfxActor->SetFileName(asset.GetHint().c_str());
assetData->m_emfxActor->Finalize();
// Clear out the EMFX raw asset data.
@@ -15,7 +15,6 @@
#include <Integration/Assets/AssetCommon.h>
#include <Integration/Rendering/RenderActor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
namespace EMotionFX
@@ -58,7 +57,7 @@ namespace EMotionFX
void InitRenderActor();
private:
AutoRegisteredActor m_emfxActor; ///< Pointer to shared EMotionFX actor
AZStd::shared_ptr<Actor> m_emfxActor;
AZStd::unique_ptr<RenderActor> m_renderActor;
};
@@ -81,6 +80,8 @@ namespace EMotionFX
const char* GetBrowserIcon() const override;
};
} // namespace Integration
using ActorAssetData = AZ::Data::Asset<Integration::ActorAsset>;
} // namespace EMotionFX
namespace AZ
@@ -121,6 +121,7 @@ namespace EMotionFX
void SetRenderCharacter(bool enable) override;
bool GetRenderActorVisible() const override;
SkinningMethod GetSkinningMethod() const override;
void SetActorAsset(AZ::Data::Asset<ActorAsset> actorAsset) override;
//////////////////////////////////////////////////////////////////////////
// ActorComponentNotificationBus::Handler
@@ -178,8 +179,6 @@ namespace EMotionFX
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
bool IsPhysicsSceneSimulationFinishEventConnected() const;
void SetActorAsset(AZ::Data::Asset<ActorAsset> actorAsset);
AZ::Data::Asset<ActorAsset> GetActorAsset() const { return m_configuration.m_actorAsset; }
private:
@@ -60,6 +60,7 @@ namespace EMotionFX
bool GetRenderActorVisible() const override;
size_t GetNumJoints() const override;
SkinningMethod GetSkinningMethod() const override;
void SetActorAsset(AZ::Data::Asset<ActorAsset> actorAsset) override;
// EditorActorComponentRequestBus overrides ...
const AZ::Data::AssetId& GetActorAssetId() override;
@@ -79,8 +80,6 @@ namespace EMotionFX
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void SetActorAsset(AZ::Data::Asset<ActorAsset> actorAsset);
// BoundsRequestBus overrides ...
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
@@ -34,6 +34,7 @@
#include <EMotionFX/Source/MotionEventTrack.h>
#include <EMotionFX/Source/AnimGraphSyncTrack.h>
#include <EMotionFX/Source/AnimGraph.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/PhysicsSetup.h>
#include <EMotionFX/Source/SimulatedObjectSetup.h>
@@ -45,6 +46,7 @@
#include <EMotionFX/Source/PoseData.h>
#include <EMotionFX/Source/PoseDataRagdoll.h>
#include <Integration/AnimationBus.h>
#include <Integration/EMotionFXBus.h>
#include <Integration/Assets/ActorAsset.h>
#include <Integration/Assets/MotionAsset.h>
@@ -69,7 +71,6 @@
# include <AzToolsFramework/API/ViewPaneOptions.h>
# include <AzCore/std/string/wildcard.h>
# include <QApplication>
# include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
# include <EMotionStudio/EMStudioSDK/Source/MainWindow.h>
# include <EMotionStudio/EMStudioSDK/Source/PluginManager.h>
// EMStudio plugins
@@ -528,7 +529,7 @@ namespace EMotionFX
if (EMStudio::GetManager())
{
EMStudio::Initializer::Shutdown();
m_emstudioManager.reset();
MysticQt::Initializer::Shutdown();
}
@@ -798,6 +799,8 @@ namespace EMotionFX
pluginManager->RegisterPlugin(new EMotionFX::RagdollNodeInspectorPlugin());
pluginManager->RegisterPlugin(new EMotionFX::ClothJointInspectorPlugin());
pluginManager->RegisterPlugin(new EMotionFX::SimulatedObjectWidget());
SystemNotificationBus::Broadcast(&SystemNotificationBus::Events::OnRegisterPlugin);
}
//////////////////////////////////////////////////////////////////////////
@@ -813,7 +816,7 @@ namespace EMotionFX
char** argv = nullptr;
MysticQt::Initializer::Init("", editorAssetsPath.c_str());
EMStudio::Initializer::Init(qApp, argc, argv);
m_emstudioManager = AZStd::make_unique<EMStudio::EMStudioManager>(qApp, argc, argv);
InitializeEMStudioPlugins();
@@ -24,6 +24,7 @@
# include <AzToolsFramework/API/ToolsApplicationAPI.h>
# include <AzToolsFramework/API/EditorAnimationSystemRequestBus.h>
# include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
# include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#endif // EMOTIONFXANIMATION_EDITOR
namespace AZ
@@ -126,6 +127,10 @@ namespace EMotionFX
AZStd::vector<AZStd::unique_ptr<AZ::Data::AssetHandler> > m_assetHandlers;
AZStd::unique_ptr<EMotionFXEventHandler> m_eventHandler;
AZStd::unique_ptr<RenderBackendManager> m_renderBackendManager;
#if defined(EMOTIONFXANIMATION_EDITOR)
AZStd::unique_ptr<EMStudio::EMStudioManager> m_emstudioManager;
#endif // EMOTIONFXANIMATION_EDITOR
};
}
}
+14 -3
View File
@@ -10,12 +10,15 @@
#include <MCore/Source/ReflectionSerializer.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/Importer/Importer.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/SimulatedObjectSetup.h>
#include <Tests/TestAssetCode/JackActor.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
namespace EMotionFX
{
@@ -23,8 +26,9 @@ namespace EMotionFX
{
SystemComponentFixture::SetUp();
m_actor = ActorFactory::CreateAndInit<JackNoMeshesActor>();
m_actorInstance = ActorInstance::Create(m_actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<JackNoMeshesActor>(actorAssetId);
m_actorInstance = ActorInstance::Create(GetActor());
}
void ActorFixture::TearDown()
@@ -35,6 +39,7 @@ namespace EMotionFX
m_actorInstance = nullptr;
}
GetEMotionFX().GetActorManager()->UnregisterAllActors();
SystemComponentFixture::TearDown();
}
@@ -71,7 +76,7 @@ namespace EMotionFX
AZ::ObjectStream::FilterDescriptor loadFilter(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES);
SimulatedObjectSetup* setup = AZ::Utils::LoadObjectFromBuffer<EMotionFX::SimulatedObjectSetup>(data.data(), data.size(), serializeContext, loadFilter);
setup->InitAfterLoad(m_actor.get());
setup->InitAfterLoad(GetActor());
return setup;
}
@@ -80,4 +85,10 @@ namespace EMotionFX
{
return { "Bip01__pelvis", "l_upLeg", "l_loLeg", "l_ankle" };
}
Actor* ActorFixture::GetActor() const
{
return m_actorAsset->GetActor();
}
} // namespace EMotionFX
+4 -3
View File
@@ -9,8 +9,7 @@
#pragma once
#include "SystemComponentFixture.h"
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <Integration/Assets/ActorAsset.h>
namespace EMotionFX
{
@@ -31,7 +30,9 @@ namespace EMotionFX
AZStd::vector<AZStd::string> GetTestJointNames() const;
protected:
AutoRegisteredActor m_actor{};
Actor* GetActor() const;
AZ::Data::Asset<Integration::ActorAsset> m_actorAsset;
ActorInstance* m_actorInstance = nullptr;
};
} // namespace EMotionFX
@@ -26,7 +26,7 @@ namespace EMotionFX
public:
void CreateSubMotionLikeBindPose(const std::string& name)
{
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
size_t jointIndex = InvalidIndex;
const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex);
ASSERT_NE(node, nullptr);
@@ -40,7 +40,7 @@ namespace EMotionFX
void CreateSubMotion(const std::string& name, const Transform& transform)
{
// Find and store the joint index.
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
size_t jointIndex = InvalidIndex;
const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex);
ASSERT_NE(node, nullptr);
@@ -55,7 +55,7 @@ namespace EMotionFX
ActorFixture::SetUp();
// Get the joint that isn't in the motion data.
Node* footNode = m_actor->GetSkeleton()->FindNodeAndIndexByName("l_ball", m_footIndex);
Node* footNode = GetActor()->GetSkeleton()->FindNodeAndIndexByName("l_ball", m_footIndex);
ASSERT_NE(footNode, nullptr);
ASSERT_NE(m_footIndex, InvalidIndex32);
@@ -98,7 +98,7 @@ namespace EMotionFX
TEST_F(MotionSamplingFixture, SampleAdditiveJoint)
{
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
// Sample the joints that exist in our actor skeleton as well as inside the motion data.
const Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose();
@@ -106,7 +106,7 @@ namespace EMotionFX
{
// Sample the motion.
Transform transform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
m_motion->CalcNodeTransform(m_motionInstance, &transform, m_actor.get(), skeleton->GetNode(jointIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
m_motion->CalcNodeTransform(m_motionInstance, &transform, GetActor(), skeleton->GetNode(jointIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
const Transform& bindTransform = bindPose->GetLocalSpaceTransform(jointIndex);
EXPECT_THAT(transform, IsClose(bindTransform));
@@ -114,7 +114,7 @@ namespace EMotionFX
// Sample the motion for the foot node.
Transform footTransform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
m_motion->CalcNodeTransform(m_motionInstance, &footTransform, m_actor.get(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
// Make sure we get an identity transform back as we try to sample a node that doesn't have a submotion in an additive motion.
EXPECT_THAT(footTransform, IsClose(Transform::CreateIdentity()));
@@ -125,7 +125,7 @@ namespace EMotionFX
// Make sure we do not get an identity transform back now that it is a non-additive motion.
footTransform.Zero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that.
const Transform& expectedFootTransform = m_actorInstance->GetTransformData()->GetCurrentPose()->GetLocalSpaceTransform(m_footIndex);
m_motion->CalcNodeTransform(m_motionInstance, &footTransform, m_actor.get(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false);
EXPECT_THAT(footTransform, IsClose(expectedFootTransform));
}
@@ -134,7 +134,7 @@ namespace EMotionFX
// Sample a pose from the motion.
Pose pose;
pose.LinkToActorInstance(m_actorInstance);
pose.InitFromBindPose(m_actor.get());
pose.InitFromBindPose(GetActor());
pose.Zero();
m_motion->Update(&pose, &pose, m_motionInstance);
@@ -15,6 +15,7 @@
#include <EMotionFX/Source/BlendTreeBlend2Node.h>
#include <EMotionFX/Source/BlendTreeBlendNNode.h>
#include <EMotionFX/Source/BlendTreeParameterNode.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
#include <EMotionFX/Source/Parameter/ParameterFactory.h>
#include <MCore/Source/AttributeFloat.h>
@@ -105,7 +105,7 @@ namespace EMotionFX
TEST_P(RagdollRootNodeFixture, RagdollRootNodeIsSimulatedTests)
{
Physics::RagdollConfiguration& ragdollConfig = m_actor->GetPhysicsSetup()->GetRagdollConfig();
Physics::RagdollConfiguration& ragdollConfig = GetActor()->GetPhysicsSetup()->GetRagdollConfig();
AZStd::vector<Physics::RagdollNodeConfiguration>& ragdollNodes = ragdollConfig.m_nodes;
const RagdollRootNodeParam& param = GetParam();
const AZStd::string ragdollRootNodeName = param.m_ragdollRootNode.c_str();
@@ -24,13 +24,13 @@ namespace EMotionFX
CommandSystem::CommandManager commandManager;
MCore::CommandGroup commandGroup;
const AZ::u32 actorId = m_actor->GetID();
const AZ::u32 actorId = GetActor()->GetID();
const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
const size_t jointCount = jointNames.size();
// 1. Add colliders
const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor());
for (const AZStd::string& jointName : jointNames)
{
CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::BoxShapeConfiguration>(), &commandGroup);
@@ -39,23 +39,27 @@ namespace EMotionFX
}
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedAfterAdd = SerializePhysicsSetup(m_actor.get());
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(jointCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor());
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(
jointCount,
PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(jointCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(
jointCount,
PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor()));
// 2. Remove colliders
commandGroup.RemoveAllCommands();
const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor());
size_t colliderIndexToRemove = 1;
for (const AZStd::string& jointName : jointNames)
@@ -64,18 +68,24 @@ namespace EMotionFX
}
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedAfterRemove = SerializePhysicsSetup(m_actor.get());
EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Capsule));
const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor());
EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(
0,
PhysicsSetupUtils::CountColliders(
GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Capsule));
EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(
0,
PhysicsSetupUtils::CountColliders(
GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule));
EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor()));
}
TEST_F(ColliderCommandTests, AddRemove1000Colliders)
@@ -84,11 +94,11 @@ namespace EMotionFX
CommandSystem::CommandManager commandManager;
MCore::CommandGroup commandGroup;
const AZ::u32 actorId = m_actor->GetID();
const AZ::u32 actorId = GetActor()->GetID();
const AZStd::string jointName = "Bip01__pelvis";
// 1. Add colliders
const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor());
const size_t colliderCount = 1000;
for (AZ::u32 i = 0; i < colliderCount; ++i)
{
@@ -96,51 +106,51 @@ namespace EMotionFX
}
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedAfterAdd = SerializePhysicsSetup(m_actor.get());
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor());
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor()));
// 2. Clear colliders
commandGroup.RemoveAllCommands();
const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor());
CommandColliderHelpers::ClearColliders(actorId, jointName, PhysicsSetup::HitDetection, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedAfterRemove = SerializePhysicsSetup(m_actor.get());
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor());
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(m_actor.get()));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor()));
}
TEST_F(ColliderCommandTests, AutoSizingColliders)
{
CommandSystem::CommandManager commandManager;
const AZ::u32 actorId = m_actor->GetID();
const AZ::u32 actorId = GetActor()->GetID();
const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
ASSERT_TRUE(jointNames.size() > 0) << "The joint names test data needs at least one joint for this test.";
const AZStd::string& jointName = jointNames[0];
CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::BoxShapeConfiguration>());
const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = m_actor->GetPhysicsSetup();
const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = GetActor()->GetPhysicsSetup();
Physics::CharacterColliderConfiguration* colliderConfig = physicsSetup->GetColliderConfigByType(PhysicsSetup::HitDetection);
EXPECT_NE(colliderConfig, nullptr) << "Collider config should be valid after we added a collider to it.";
@@ -184,11 +194,11 @@ namespace EMotionFX
const PhysicsSetup::ColliderConfigType m_configType = PhysicsSetup::ColliderConfigType::HitDetection;
// Add collider to the given joint first.
const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = m_actor->GetPhysicsSetup();
EXPECT_TRUE(CommandColliderHelpers::AddCollider(m_actor->GetID(), m_jointName, m_configType, param.m_shapeType));
const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = GetActor()->GetPhysicsSetup();
EXPECT_TRUE(CommandColliderHelpers::AddCollider(GetActor()->GetID(), m_jointName, m_configType, param.m_shapeType));
Physics::CharacterColliderConfiguration* characterColliderConfig = physicsSetup->GetColliderConfigByType(m_configType);
ASSERT_TRUE(characterColliderConfig != nullptr);
Physics::CharacterColliderNodeConfiguration* nodeConfig = CommandColliderHelpers::GetCreateNodeConfig(m_actor.get(), m_jointName, *characterColliderConfig, result);
Physics::CharacterColliderNodeConfiguration* nodeConfig = CommandColliderHelpers::GetCreateNodeConfig(GetActor(), m_jointName, *characterColliderConfig, result);
ASSERT_TRUE(nodeConfig != nullptr);
EXPECT_EQ(nodeConfig->m_shapes.size(), 1);
@@ -200,7 +210,8 @@ namespace EMotionFX
// Create the adjust collider command and using the data from the test parameter.
MCore::Command* orgCommand = CommandSystem::GetCommandManager()->FindCommand(CommandAdjustCollider::s_commandName);
CommandAdjustCollider* command = aznew CommandAdjustCollider(m_actor->GetID(), m_jointName, m_configType, /*colliderIndex=*/0, orgCommand);
CommandAdjustCollider* command =
aznew CommandAdjustCollider(GetActor()->GetID(), m_jointName, m_configType, /*colliderIndex=*/0, orgCommand);
command->SetOldIsTrigger(colliderConfig->m_isTrigger);
command->SetIsTrigger(param.m_isTrigger);
command->SetOldPosition(colliderConfig->m_position);
@@ -223,9 +234,9 @@ namespace EMotionFX
}
// Check execute.
const AZStd::string serializedBeforeExecute = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeExecute = SerializePhysicsSetup(GetActor());
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(command, result));
const AZStd::string serializedAfterExecute = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedAfterExecute = SerializePhysicsSetup(GetActor());
EXPECT_EQ(colliderConfig->m_isTrigger, param.m_isTrigger);
EXPECT_EQ(colliderConfig->m_position, param.m_position);
@@ -243,12 +254,12 @@ namespace EMotionFX
// Check undo.
EXPECT_TRUE(CommandSystem::GetCommandManager()->Undo(result));
const AZStd::string serializedAfterUndo = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedAfterUndo = SerializePhysicsSetup(GetActor());
EXPECT_EQ(serializedAfterUndo, serializedBeforeExecute);
// Check redo.
EXPECT_TRUE(CommandSystem::GetCommandManager()->Redo(result));
const AZStd::string serializedAfterRedo = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedAfterRedo = SerializePhysicsSetup(GetActor());
EXPECT_EQ(serializedAfterRedo, serializedAfterExecute);
}
@@ -13,9 +13,11 @@
#include <QtTest>
#include <Tests/UI/UIFixture.h>
#include <Tests/TestAssetCode/JackActor.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionFX/Source/ActorManager.h>
namespace EMotionFX
{
@@ -33,14 +35,12 @@ namespace EMotionFX
ASSERT_EQ(GetActorManager().GetNumActors(), 0);
// Load an Actor
const char* actorCmd{ "ImportActor -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" };
{
AZStd::string result;
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(actorCmd, result)) << result.c_str();
}
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<JackNoMeshesActor>(actorAssetId, "Jack");
// Ensure the Actor is correct
ASSERT_TRUE(GetActorManager().FindActorByName("rinActor"));
ASSERT_TRUE(GetActorManager().FindActorByName("Jack"));
EXPECT_EQ(GetActorManager().GetNumActors(), 1);
}
} // namespace EMotionFX
@@ -8,6 +8,7 @@
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/AnimGraphMotionNode.h>
#include <EMotionFX/Source/MotionSet.h>
#include <EMotionFX/Source/Motion.h>
@@ -9,6 +9,8 @@
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/ActorUpdateScheduler.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/MultiThreadScheduler.h>
#include <Tests/SystemComponentFixture.h>
#include <Tests/TestAssetCode/JackActor.h>
@@ -19,11 +19,13 @@
#include <EMotionFX/Source/AnimGraphEntryNode.h>
#include <EMotionFX/Source/AnimGraphHubNode.h>
#include <EMotionFX/Source/AnimGraphManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <EMotionFX/Source/MotionManager.h>
namespace EMotionFX
@@ -78,7 +80,8 @@ namespace EMotionFX
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommandGroup(group, commandResult)) << commandResult.c_str();
// Create temp Actor
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(1, "tempActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 1, "tempActor");
// Cache some local poitners.
m_animGraphPlugin = static_cast<EMStudio::AnimGraphPlugin*>(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::AnimGraphPlugin::CLASS_ID));
@@ -90,6 +93,7 @@ namespace EMotionFX
void TearDown() override
{
GetEMotionFX().GetActorManager()->UnregisterAllActors();
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
delete m_animGraph;
UIFixture::TearDown();
@@ -104,7 +108,7 @@ namespace EMotionFX
AZStd::string m_entryNodeName = "testEntry";
AnimGraph* m_animGraph = nullptr;
EMStudio::AnimGraphPlugin* m_animGraphPlugin = nullptr;
AutoRegisteredActor m_actor;
AZ::Data::Asset<Integration::ActorAsset> m_actorAsset;
};
TEST_F(PopulatedAnimGraphFixture, CanActivateValidGraph)
@@ -27,7 +27,6 @@
#include <EMotionFX/Source/AnimGraphMotionNode.h>
#include <EMotionFX/Source/AnimGraphReferenceNode.h>
#include <EMotionFX/Source/AnimGraphStateMachine.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/Parameter/BoolParameter.h>
#include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
@@ -43,6 +42,7 @@
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/ProvidesUI/AnimGraph/SimpleAnimGraphUIFixture.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/Mocks/EventHandler.h>
namespace EMotionFX
@@ -423,7 +423,10 @@ namespace EMotionFX
using testing::Eq;
using testing::Not;
AutoRegisteredActor actor = EMotionFX::ActorFactory::CreateAndInit<EMotionFX::SimpleJointChainActor>(1);
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 1);
auto motionSet = AZStd::make_unique<EMotionFX::MotionSet>();
{
@@ -432,7 +435,7 @@ namespace EMotionFX
}
auto* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(0);
auto* actorInstance = EMotionFX::ActorInstance::Create(actor.get());
auto* actorInstance = EMotionFX::ActorInstance::Create(actorAsset->GetActor());
auto* animGraphInstance = EMotionFX::AnimGraphInstance::Create(animGraph, actorInstance, motionSet.get());
actorInstance->SetAnimGraphInstance(animGraphInstance);
@@ -24,12 +24,11 @@
#include <EMotionStudio/EMStudioSDK/Source/SaveChangedFilesManager.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/ModalPopupHandler.h>
namespace EMotionFX
{
@@ -58,8 +57,10 @@ namespace EMotionFX
ASSERT_EQ(GetMotionManager().GetNumMotions(), 0) << "Expected exactly zero motions";
// Create Actor, AnimGraph, Motionset and Motion
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "SampleActor");
ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 2, "SampleActor");
ActorInstance::Create(actorAsset->GetActor());
{
AZStd::string result;
ASSERT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(createAnimGraphCmd, result)) << result.c_str();
@@ -26,6 +26,7 @@
#include <Tests/Mocks/PhysicsSystem.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/UIFixture.h>
namespace EMotionFX
@@ -79,7 +80,11 @@ namespace EMotionFX
TEST_F(CopyPasteRagdollCollidersFixture, CanCopyCollider)
#endif // AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
{
AutoRegisteredActor actor{ActorFactory::CreateAndInit<SimpleJointChainActor>(4)};
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 4);
const Actor* actor = actorAsset->GetActor();
const Physics::RagdollConfiguration& ragdollConfig = actor->GetPhysicsSetup()->GetRagdollConfig();
const Physics::CharacterColliderConfiguration& simulatedObjectConfig = actor->GetPhysicsSetup()->GetSimulatedObjectColliderConfig();
@@ -104,8 +109,7 @@ namespace EMotionFX
{
AZStd::string result;
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(
"Select -actorId " + AZStd::to_string(actor->GetID()),
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand("Select -actorId " + AZStd::to_string(actor->GetID()),
result))
<< result.c_str();
}
@@ -14,7 +14,6 @@
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/CommandSystem/Source/RagdollCommands.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <Editor/Plugins/Ragdoll/RagdollJointLimitWidget.h>
#include <Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h>
@@ -25,6 +24,7 @@
#include <Tests/Mocks/PhysicsSystem.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/UIFixture.h>
namespace EMotionFX
@@ -76,7 +76,9 @@ namespace EMotionFX
return AZStd::make_unique<D6JointLimitConfiguration>();
});
AutoRegisteredActor actor {ActorFactory::CreateAndInit<SimpleJointChainActor>(4)};
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 4);
const Actor* actor = actorAsset->GetActor();
{
AZStd::string result;
@@ -99,28 +99,28 @@ namespace EMotionFX
"l_hand",
};
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftShoulder
)
);
const AZStd::string serializedBeforeHandAdded = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeHandAdded = SerializePhysicsSetup(GetActor());
// Adding l_hand should add l_upArm and l_loArm as well
commandGroup.RemoveAllCommands();
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
const AZStd::string serializedAfterHandAdded = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedAfterHandAdded = SerializePhysicsSetup(GetActor());
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftHand
@@ -129,23 +129,23 @@ namespace EMotionFX
EXPECT_TRUE(commandManager.Undo(result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftShoulder
)
);
EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedBeforeHandAdded));
EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedBeforeHandAdded));
EXPECT_TRUE(commandManager.Redo(result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftHand
)
);
EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedAfterHandAdded));
EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedAfterHandAdded));
}
TEST_F(RagdollCommandTests, AddJointHigherInHierarchy)
@@ -166,10 +166,10 @@ namespace EMotionFX
"l_hand",
};
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftHand
@@ -178,10 +178,10 @@ namespace EMotionFX
// l_shldr should already be in the ragdoll, so adding it should do nothing
commandGroup.RemoveAllCommands();
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftHand
@@ -190,11 +190,11 @@ namespace EMotionFX
// Undo here undoes the addition of l_hand
EXPECT_TRUE(commandManager.Undo(result)) << result.c_str();
EXPECT_TRUE(GetRagdollJointNames(m_actor.get()).empty());
EXPECT_TRUE(GetRagdollJointNames(GetActor()).empty());
EXPECT_TRUE(commandManager.Redo(result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(
StrEq(),
jointsToLeftHand
@@ -221,16 +221,16 @@ namespace EMotionFX
};
// Add a joint to the ragdoll that does not make a chain all the way to the root
EXPECT_TRUE(commandManager.ExecuteCommand(aznew CommandAddRagdollJoint(m_actor->GetID(), "l_shldr"), result)) << result.c_str();
EXPECT_TRUE(commandManager.ExecuteCommand(aznew CommandAddRagdollJoint(GetActor()->GetID(), "l_shldr"), result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(StrEq(), AZStd::vector<AZStd::string>{"l_shldr"})
);
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(StrEq(), jointsToLeftHand)
);
}
@@ -250,17 +250,17 @@ namespace EMotionFX
};
// Add joints from the root to the left hand
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
// Removing the left shoulder should remove the elbow, wrist, and hand
// as well
commandGroup.RemoveAllCommands();
CommandRagdollHelpers::RemoveJointsFromRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup);
CommandRagdollHelpers::RemoveJointsFromRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
EXPECT_THAT(
GetRagdollJointNames(m_actor.get()),
GetRagdollJointNames(GetActor()),
testing::UnorderedPointwise(StrEq(), jointsToSpine3)
);
}
@@ -271,24 +271,24 @@ namespace EMotionFX
CommandSystem::CommandManager commandManager;
MCore::CommandGroup commandGroup;
CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup);
CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str();
const AZStd::string serializedBeforeSphereAdded = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedBeforeSphereAdded = SerializePhysicsSetup(GetActor());
CommandColliderHelpers::AddCollider(m_actor->GetID(), "l_hand",
CommandColliderHelpers::AddCollider(GetActor()->GetID(), "l_hand",
PhysicsSetup::Ragdoll, azrtti_typeid<Physics::SphereShapeConfiguration>());
const AZStd::string serializedAfterSphereAdded = SerializePhysicsSetup(m_actor.get());
const AZStd::string serializedAfterSphereAdded = SerializePhysicsSetup(GetActor());
EXPECT_THAT(serializedAfterSphereAdded, ::testing::Not(StrEq(serializedBeforeSphereAdded)));
EXPECT_TRUE(commandManager.Undo(result)) << result.c_str();
EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedBeforeSphereAdded));
EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedBeforeSphereAdded));
EXPECT_TRUE(commandManager.Redo(result)) << result.c_str();
EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedAfterSphereAdded));
EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedAfterSphereAdded));
}
} // namespace EMotionFX
@@ -55,25 +55,25 @@ namespace EMotionFX
CommandSystem::CommandManager commandManager;
MCore::CommandGroup commandGroup;
const uint32 actorId = m_actor->GetID();
const uint32 actorId = GetActor()->GetID();
const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
// 1. Add simulated object.
const AZStd::string serializedBeforeAdd = SerializeSimulatedObjectSetup(m_actor.get());
const AZStd::string serializedBeforeAdd = SerializeSimulatedObjectSetup(GetActor());
CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup);
CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup);
CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedAfterAdd = SerializeSimulatedObjectSetup(m_actor.get());
EXPECT_EQ(3, CountSimulatedObjects(m_actor.get()));
const AZStd::string serializedAfterAdd = SerializeSimulatedObjectSetup(GetActor());
EXPECT_EQ(3, CountSimulatedObjects(GetActor()));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(0, CountSimulatedObjects(m_actor.get()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedObjects(GetActor()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(3, CountSimulatedObjects(m_actor.get()));
EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(3, CountSimulatedObjects(GetActor()));
EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(GetActor()));
// 2. Remove simulated object.
commandGroup.RemoveAllCommands();
@@ -81,22 +81,22 @@ namespace EMotionFX
CommandSimulatedObjectHelpers::RemoveSimulatedObject(actorId, 0, &commandGroup);
CommandSimulatedObjectHelpers::RemoveSimulatedObject(actorId, 0, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
EXPECT_EQ(0, CountSimulatedObjects(m_actor.get()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedObjects(GetActor()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(3, CountSimulatedObjects(m_actor.get()));
EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(3, CountSimulatedObjects(GetActor()));
EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(0, CountSimulatedObjects(m_actor.get()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedObjects(GetActor()));
EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor()));
// 3. Add simulated joints.
// 3.1 Add a simulated object first to put in the simulated joints.
commandGroup.RemoveAllCommands();
CommandSimulatedObjectHelpers::AddSimulatedObject(actorId);
const AZStd::string serialized3_1 = SerializeSimulatedObjectSetup(m_actor.get());
const AZStd::string serialized3_1 = SerializeSimulatedObjectSetup(GetActor());
// 3.2 Add simulated joints.
// Joint hierarchy as follow:
@@ -105,7 +105,7 @@ namespace EMotionFX
// --l_loLeg
// --l_ankle
// --l_ball
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
const size_t l_upLegIdx = skeleton->FindNodeByName("l_upLeg")->GetNodeIndex();
const size_t l_upLegRollIdx = skeleton->FindNodeByName("l_upLegRoll")->GetNodeIndex();
const size_t l_loLegIdx = skeleton->FindNodeByName("l_loLeg")->GetNodeIndex();
@@ -113,33 +113,33 @@ namespace EMotionFX
const size_t l_ballIdx = skeleton->FindNodeByName("l_ball")->GetNodeIndex();
CommandSimulatedObjectHelpers::AddSimulatedJoints(actorId, {l_upLegIdx, l_upLegRollIdx, l_loLegIdx, l_ankleIdx, l_ballIdx}, 0, false, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serialized3_2 = SerializeSimulatedObjectSetup(m_actor.get());
EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(2, CountChildJoints(m_actor.get(), 0, l_upLegIdx));
EXPECT_EQ(0, CountChildJoints(m_actor.get(), 0, l_upLegRollIdx));
EXPECT_EQ(1, CountChildJoints(m_actor.get(), 0, l_loLegIdx));
const AZStd::string serialized3_2 = SerializeSimulatedObjectSetup(GetActor());
EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(2, CountChildJoints(GetActor(), 0, l_upLegIdx));
EXPECT_EQ(0, CountChildJoints(GetActor(), 0, l_upLegRollIdx));
EXPECT_EQ(1, CountChildJoints(GetActor(), 0, l_loLegIdx));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor()));
// 4 Remove simulated joints.
// 4.1 Test sparse chain.
EXPECT_EQ(1, CountRootJoints(m_actor.get(), 0));
EXPECT_EQ(1, CountRootJoints(GetActor(), 0));
commandGroup.RemoveAllCommands();
CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, {l_loLegIdx}, 0, false, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
EXPECT_EQ(2, CountRootJoints(m_actor.get(), 0));
EXPECT_EQ(2, CountRootJoints(GetActor(), 0));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(1, CountRootJoints(m_actor.get(), 0));
EXPECT_EQ(1, CountRootJoints(GetActor(), 0));
EXPECT_TRUE(commandManager.Redo(result));
EXPECT_EQ(2, CountRootJoints(m_actor.get(), 0));
EXPECT_EQ(2, CountRootJoints(GetActor(), 0));
EXPECT_TRUE(commandManager.Undo(result));
@@ -147,23 +147,23 @@ namespace EMotionFX
commandGroup.RemoveAllCommands();
CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { l_upLegIdx, l_upLegRollIdx, l_loLegIdx, l_ankleIdx, l_ballIdx }, 0, false, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor()));
// 4.3 Test removing the root joint and children.
commandGroup.RemoveAllCommands();
CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { l_upLegIdx }, 0, true, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor()));
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor()));
}
TEST_F(SimulatedObjectCommandTests, SimulatedObjectCommands_UndoRemoveJointTest)
@@ -172,35 +172,35 @@ namespace EMotionFX
CommandSystem::CommandManager commandManager;
MCore::CommandGroup commandGroup;
const uint32 actorId = m_actor->GetID();
const uint32 actorId = GetActor()->GetID();
const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
// 1. Add simulated object
CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
const AZStd::string serializedBase = SerializeSimulatedObjectSetup(m_actor.get());
const AZStd::string serializedBase = SerializeSimulatedObjectSetup(GetActor());
const size_t simulatedObjectIndex = 0;
// 2. Add r_upLeg simulated joints
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
const size_t r_upLegIdx = skeleton->FindNodeByName("r_upLeg")->GetNodeIndex();
const size_t r_loLegIdx = skeleton->FindNodeByName("r_loLeg")->GetNodeIndex();
CommandSimulatedObjectHelpers::AddSimulatedJoints(actorId, { r_upLegIdx, r_loLegIdx }, 0, false);
EXPECT_EQ(2, CountSimulatedJoints(m_actor.get(), 0));
const AZStd::string serializedUpLeg = SerializeSimulatedObjectSetup(m_actor.get());
EXPECT_EQ(2, CountSimulatedJoints(GetActor(), 0));
const AZStd::string serializedUpLeg = SerializeSimulatedObjectSetup(GetActor());
// 3. Remove the r_loLeg simulated joint
AZStd::vector<SimulatedJoint*> jointsToBeRemoved;
commandGroup.RemoveAllCommands();
CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { r_upLegIdx }, simulatedObjectIndex, true, &commandGroup);
EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serializedBase, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serializedBase, SerializeSimulatedObjectSetup(GetActor()));
// 4. Undo
// This recreates r_loLeg and r_loLeg but won't add all other children recursively as only these two joints got aded in step 3.
EXPECT_TRUE(commandManager.Undo(result));
EXPECT_EQ(2, CountSimulatedJoints(m_actor.get(), 0));
EXPECT_EQ(serializedUpLeg, SerializeSimulatedObjectSetup(m_actor.get()));
EXPECT_EQ(2, CountSimulatedJoints(GetActor(), 0));
EXPECT_EQ(serializedUpLeg, SerializeSimulatedObjectSetup(GetActor()));
}
} // namespace EMotionFX
@@ -22,17 +22,21 @@
#include <Tests/UI/UIFixture.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
namespace EMotionFX
{
using SimulatedObjectModelTestsFixture = UIFixture;
TEST_F(SimulatedObjectModelTestsFixture, CanUndoAddSimulatedObjectAndSimulatedJointWithChildren)
{
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(3, "simulatedObjectModelTestActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 3, "simulatedObjectModelTestActor");
const Actor* actor = actorAsset->GetActor();
EMotionFX::SimulatedObjectWidget* simulatedObjectWidget = static_cast<EMotionFX::SimulatedObjectWidget*>(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SimulatedObjectWidget::CLASS_ID));
ASSERT_TRUE(simulatedObjectWidget) << "Simulated Object plugin not loaded";
simulatedObjectWidget->ActorSelectionChanged(actor.get());
simulatedObjectWidget->ActorSelectionChanged(actorAsset->GetActor());
SimulatedObjectModel* model = simulatedObjectWidget->GetSimulatedObjectModel();
@@ -20,7 +20,7 @@ namespace EMotionFX
TEST_F(SimulatedObjectSerializeTests, SerializeTest)
{
SimulatedObjectSetup* setup = m_actor->GetSimulatedObjectSetup().get();
SimulatedObjectSetup* setup = GetActor()->GetSimulatedObjectSetup().get();
// Build some setup.
SimulatedObject* object = setup->AddSimulatedObject();
@@ -29,7 +29,7 @@ namespace EMotionFX
object->SetGravityFactor(3.0f);
object->SetStiffnessFactor(4.0f);
const AZStd::vector<AZStd::string> jointNames = { "l_upArm", "l_loArm", "l_hand" };
Skeleton* skeleton = m_actor->GetSkeleton();
Skeleton* skeleton = GetActor()->GetSkeleton();
for (const AZStd::string& name : jointNames)
{
size_t skeletonJointIndex;
@@ -50,7 +50,7 @@ namespace EMotionFX
object->GetSimulatedJoint(0)->SetPinned(true);
// Serialize it and deserialize it.
const AZStd::string serialized = SerializeSimulatedObjectSetup(m_actor.get());
const AZStd::string serialized = SerializeSimulatedObjectSetup(GetActor());
AZStd::unique_ptr<SimulatedObjectSetup> loadedSetup(DeserializeSimulatedObjectSetup(serialized));
// Verify some of the contents of the deserialized version.
@@ -22,13 +22,13 @@ namespace EMotionFX
void SetUp()
{
ActorFixture::SetUp();
m_actor->AddLODLevel();
GetActor()->AddLODLevel();
DisableJointsForLOD(m_disabledJointNames, 1);
}
void DisableJointsForLOD(const std::vector<std::string>& jointNames, size_t lodLevel)
{
const Skeleton* skeleton = m_actor->GetSkeleton();
const Skeleton* skeleton = GetActor()->GetSkeleton();
for (const std::string& jointName : jointNames)
{
Node* joint = skeleton->FindNodeByName(jointName.c_str());
@@ -10,9 +10,10 @@
#include <AzCore/std/containers/vector.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/Importer/Importer.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/JackActor.h>
namespace EMotionFX
{
@@ -10,6 +10,9 @@
#include <AzCore/std/string/string.h>
#include <Integration/Assets/ActorAsset.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <Tests/TestAssetCode/ActorFactory.h>
namespace EMotionFX
{
@@ -18,5 +21,14 @@ namespace EMotionFX
public:
static AZStd::string FileToBase64(const char* filePath);
static AZ::Data::Asset<Integration::ActorAsset> GetAssetFromActor(const AZ::Data::AssetId& assetId, AZStd::unique_ptr<Actor>&& actor);
template<class ActorT, typename... Args>
static AZ::Data::Asset<Integration::ActorAsset> CreateActorAssetAndRegister(const AZ::Data::AssetId& assetId, Args&&... args)
{
AZStd::unique_ptr<ActorT> actor = ActorFactory::CreateAndInit<ActorT>(AZStd::forward<Args>(args)...);
AZ::Data::Asset<Integration::ActorAsset> actorAsset = TestActorAssets::GetAssetFromActor(assetId, AZStd::move(actor));
GetEMotionFX().GetActorManager()->RegisterActor(actorAsset);
return AZStd::move(actorAsset);
}
};
} // namespace EMotionFX
@@ -16,13 +16,13 @@
#include <Tests/UI/ModalPopupHandler.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
#include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
namespace EMotionFX
{
@@ -37,8 +37,11 @@ namespace EMotionFX
RecordProperty("test_case_id", "C13048819");
// Create an actor
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(5, "SimpleActor");
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 5, "SimpleActor");
ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor());
const Actor* actor = actorAsset->GetActor();
// Open simulated objects layout
EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects");
@@ -17,7 +17,6 @@
#include <Tests/UI/ModalPopupHandler.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <Editor/ColliderContainerWidget.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
@@ -27,6 +26,7 @@
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/PhysicsSetupUtils.h>
#include <Editor/ReselectingTreeView.h>
@@ -81,9 +81,9 @@ namespace EMotionFX
inputDialog->accept();
// There is one and only one simulated objects
ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1);
ASSERT_EQ(m_actorAsset->GetActor()->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1);
// Check it has the correct name
EXPECT_STREQ(m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0)->GetName().c_str(), objectName);
EXPECT_STREQ(m_actorAsset->GetActor()->GetSimulatedObjectSetup()->GetSimulatedObject(0)->GetName().c_str(), objectName);
}
@@ -112,14 +112,16 @@ namespace EMotionFX
});
ASSERT_NE(addCapsuleColliderAction, addSelectedColliderMenuActions.end());
size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(
m_actorAsset->GetActor(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
(*addCapsuleColliderAction)->trigger();
// Delete the context menu, otherwise there it will still be around during this frame as the Qt event loop has not been run.
delete contextMenu;
const size_t numCapsuleCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
const size_t numCapsuleCollidersAfterAdd = PhysicsSetupUtils::CountColliders(
m_actorAsset->GetActor(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
ASSERT_EQ(numCapsuleCollidersAfterAdd, numCapsuleColliders + 1);
@@ -127,7 +129,7 @@ namespace EMotionFX
}
protected:
AutoRegisteredActor m_actor;
AZ::Data::Asset<Integration::ActorAsset> m_actorAsset;
EMotionFX::SimulatedObjectWidget* m_simulatedObjectWidget = nullptr;
EMotionFX::SkeletonOutlinerPlugin* m_skeletonOutliner = nullptr;
@@ -144,7 +146,8 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048820");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(1, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 1, "CanAddSimulatedObjectActor");
CreateSimulateObject("New simulated object");
}
@@ -153,9 +156,11 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048818");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor");
Actor* actor = actorAsset->GetActor();
ActorInstance* actorInstance = ActorInstance::Create(actor);
EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects");
@@ -216,7 +221,9 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048820a");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(5, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 5, "CanAddSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
CreateSimulateObject("sim1");
@@ -261,8 +268,8 @@ namespace EMotionFX
inputDialog->SetText("sim2");
inputDialog->accept();
ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 2);
const auto simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(1);
ASSERT_EQ(actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 2);
const auto simulatedObject = actor->GetSimulatedObjectSetup()->GetSimulatedObject(1);
EXPECT_STREQ(simulatedObject->GetName().c_str(), "sim2");
}
@@ -270,7 +277,9 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048816");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(5, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 5, "CanAddSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
CreateSimulateObject("sim1");
@@ -301,25 +310,25 @@ namespace EMotionFX
QAction* addCapsuleColliderAction;
ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleColliderAction, addSelectedColliderMenu, "Capsule"));
size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
EXPECT_EQ(numCapsuleColliders, 0);
addCapsuleColliderAction->trigger();
// Check that a collider has been added.
size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added.";
QAction* addSphereColliderAction;
ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereColliderAction, addSelectedColliderMenu, "Sphere"));
const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
EXPECT_EQ(numSphereColliders, 0);
addSphereColliderAction->trigger();
// Check that a second collider has been added.
const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added.";
}
@@ -327,7 +336,9 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048821");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(1, "CanRemoveSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 1, "CanRemoveSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
CreateSimulateObject("TestObject1");
@@ -350,14 +361,16 @@ namespace EMotionFX
ASSERT_TRUE(UIFixture::GetActionFromContextMenu(removeObjectAction, contextMenu, "Remove object"));
removeObjectAction->trigger();
ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 0);
ASSERT_EQ(actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 0);
}
TEST_F(CanAddSimulatedObjectFixture, CanAddColliderToSimulatedObjectFromInspector)
{
RecordProperty("test_case_id", "C20385259");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(5, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 5, "CanAddSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
CreateSimulateObject("sim1");
@@ -380,10 +393,12 @@ namespace EMotionFX
// Send the left button click directly to the button
QTest::mouseClick(addColliderButton, Qt::LeftButton);
const size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
const size_t numCapsuleColliders =
PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
EXPECT_EQ(numCapsuleColliders, 0);
const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
const size_t numSphereColliders =
PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
EXPECT_EQ(numSphereColliders, 0);
QMenu* contextMenu = addColliderButton->findChild<QMenu*>("EMFX.AddColliderButton.ContextMenu");
@@ -392,13 +407,15 @@ namespace EMotionFX
QAction* addCapsuleAction;
ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleAction, contextMenu, "Add capsule"));
addCapsuleAction->trigger();
const size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
const size_t numCollidersAfterAddCapsule =
PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule);
ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added.";
QAction* addSphereAction;
ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereAction, contextMenu, "Add sphere"));
addSphereAction->trigger();
const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
const size_t numCollidersAfterAddSphere =
PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere);
ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added.";
}
@@ -406,7 +423,9 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048818");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(7, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 7, "CanAddSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
CreateSimulateObject("ANY");
@@ -442,7 +461,7 @@ namespace EMotionFX
messageBoxPopupHandler.WaitForPopupPressDialogButton<QMessageBox*>(QDialogButtonBox::No);
newSimulatedObjectAction->trigger();
const EMotionFX::SimulatedObject* simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0);
const EMotionFX::SimulatedObject* simulatedObject = actor->GetSimulatedObjectSetup()->GetSimulatedObject(0);
EXPECT_EQ(simulatedObject->GetNumSimulatedRootJoints(), 1);
EXPECT_EQ(simulatedObject->GetNumSimulatedJoints(), 3);
}
@@ -450,7 +469,9 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C13048817");
m_actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(5, "CanAddSimulatedObjectActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
m_actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 5, "CanAddSimulatedObjectActor");
Actor* actor = m_actorAsset->GetActor();
EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects");
@@ -470,7 +491,7 @@ namespace EMotionFX
AddCapsuleColliderToJointIndex(3);
AddCapsuleColliderToJointIndex(4);
const size_t numCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider);
const size_t numCollidersAfterAdd = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider);
EXPECT_EQ(numCollidersAfterAdd, 2);
m_indexList.clear();
@@ -498,7 +519,7 @@ namespace EMotionFX
removeAction->trigger();
// Check that one of the colliders is now gone.
const size_t numCollidersAfterFirstRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider);
const size_t numCollidersAfterFirstRemove = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider);
ASSERT_EQ(numCollidersAfterFirstRemove, numCollidersAfterAdd - 1) << "RemoveCollider action in Simulated Object Inspector failed.";
// Now do the same thing using the Simulated Object Inspector context menu.
@@ -536,7 +557,7 @@ namespace EMotionFX
delAction->trigger();
// Check that we have the number of colliders we started we expect.
const size_t numCollidersAfterSecondRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider);
const size_t numCollidersAfterSecondRemove = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider);
ASSERT_EQ(numCollidersAfterSecondRemove, numCollidersAfterAdd - 2);
}
@@ -23,6 +23,7 @@
#include <Editor/ReselectingTreeView.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/ModalPopupHandler.h>
#include <Tests/UI/UIFixture.h>
#include <Tests/D6JointLimitConfiguration.h>
@@ -52,9 +53,11 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C14603914");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(7, "CanAddToSimulatedObjectActor");
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 7, "CanAddToSimulatedObjectActor");
Actor* actor = actorAsset->GetActor();
ActorInstance* actorInstance = ActorInstance::Create(actor);
// Change the Editor mode to Simulated Objects
EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects");
@@ -165,9 +168,11 @@ namespace EMotionFX
});
RecordProperty("test_case_id", "C13291807");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(7, "CanAddToSimulatedObjectActor");
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 7, "CanAddToSimulatedObjectActor");
Actor* actor = actorAsset->GetActor();
ActorInstance* actorInstance = ActorInstance::Create(actor);
// Change the Editor mode to Physics
EMStudio::GetMainWindow()->ApplicationModeChanged("Physics");
@@ -22,6 +22,7 @@
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/ModalPopupHandler.h>
#include <Tests/UI/UIFixture.h>
@@ -37,9 +38,10 @@ namespace EMotionFX
{
RecordProperty("test_case_id", "C14519563");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(7, "CanAddToSimulatedObjectActor");
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 7, "CanAddToSimulatedObjectActor");
ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor());
// Change the Editor mode to Simulated Objects
EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects");
@@ -24,10 +24,12 @@
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
#include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
#include <EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h>
#include <EMotionFX/Source/AnimGraphReferenceNode.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.h>
#include <EMotionFX/CommandSystem/Source/MotionCommands.h>
@@ -141,8 +143,10 @@ namespace EMotionFX
{
if (EMotionFX::GetActorManager().GetNumActorInstances() == 0)
{
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actorAsset->GetActor());
EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test.";
}
@@ -152,15 +156,16 @@ namespace EMotionFX
{
if (EMotionFX::GetActorManager().GetNumActorInstances() == 0)
{
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actor.get());
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset = TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(
actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actorAsset->GetActor());
EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test.";
actor->SetFileName(filename);
actorAsset->GetActor()->SetFileName(filename);
AZStd::string stringFilename = filename;
ExporterLib::SaveActor(stringFilename, actor.get(), MCore::Endian::ENDIAN_LITTLE);
ExporterLib::SaveActor(stringFilename, actorAsset->GetActor(), MCore::Endian::ENDIAN_LITTLE);
}
}
@@ -239,7 +244,6 @@ namespace EMotionFX
// Load the actor we just saved, with replaceScene set to true to represent a load.
LoadActor(actorFilename.toUtf8().data(), true);
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to load Actor.";
// Do it again to verify that number of actors stays the same when replaceScene is true.
@@ -696,7 +700,10 @@ namespace EMotionFX
TestResetMenuItem(fileMenu);
TestActorMenus(fileMenu);
// Temporarily disable loading actor test.
// This is because the importer command now load actor asset instead of reading from disk. We do not want to add dependency to the asset processor
// in this test.
// TestActorMenus(fileMenu);
TestSaveAllMenuItem(fileMenu);
}
@@ -17,7 +17,6 @@
#include <Editor/InputDialogValidatable.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/AutoRegisteredActor.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/DockWidgetPlugin.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
@@ -17,6 +17,7 @@
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/UIFixture.h>
namespace EMotionFX
@@ -102,7 +103,9 @@ namespace EMotionFX
const int lastIndex = 6;
RecordProperty("test_case_id", "C18970351");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(numJoints, "RagdollEditTestsActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, numJoints, "RagdollEditTestsActor");
CreateSkeletonAndModelIndices();
EXPECT_EQ(m_indexList.size(), numJoints);
@@ -80,11 +80,14 @@ namespace EMotionFX
DataMembers m_data;
};
AZStd::unique_ptr<Actor> CreateLODActor(int numLODs)
AZ::Data::Asset<Integration::ActorAsset> CreateLODActor(int numLODs)
{
AZStd::unique_ptr<Actor> actor = ActorFactory::CreateAndInit<PlaneActor>("LODSkinnedMeshTestsActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<PlaneActor>(actorAssetId, "LODSkinnedMeshTestsActor");
// Modify the actor to have numLODs LOD levels.
Actor* actor = actorAsset->GetActor();
Mesh* lodMesh = actor->GetMesh(0, 0);
StandardMaterial* dummyMat = StandardMaterial::Create("Dummy Material");
actor->AddMaterial(0, dummyMat); // owns the material
@@ -97,7 +100,7 @@ namespace EMotionFX
actor->AddMaterial(i, dummyMat->Clone());
}
return actor;
return AZStd::move(actorAsset);
}
class LODPropertyRowWidget
@@ -112,9 +115,8 @@ namespace EMotionFX
const int numLODs = GetParam();
RecordProperty("test_case_id", "C29202698");
AutoRegisteredActor actor = CreateLODActor(numLODs);
ActorInstance* actorInstance = ActorInstance::Create(actor.get());
AZ::Data::Asset<Integration::ActorAsset> actorAsset = CreateLODActor(numLODs);
ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor());
// Change the Editor mode to Character
EMStudio::GetMainWindow()->ApplicationModeChanged("Character");
@@ -166,8 +168,7 @@ namespace EMotionFX
gameEntity->SetId(entityId);
AZ::Data::AssetId actorAssetId("{85D3EF54-7400-43F8-8A40-F6BCBF534E54}");
AZStd::unique_ptr<Actor> actor = CreateLODActor(numLODs);
AZ::Data::Asset<Integration::ActorAsset> actorAsset = TestActorAssets::GetAssetFromActor(actorAssetId, AZStd::move(actor));
AZ::Data::Asset<Integration::ActorAsset> actorAsset = CreateLODActor(numLODs);
gameEntity->CreateComponent<AzFramework::TransformComponent>();
Integration::ActorComponent::Configuration actorConf;
@@ -20,6 +20,7 @@
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/TestActorAssets.h>
#include <Tests/UI/UIFixture.h>
#include <Editor/ReselectingTreeView.h>
@@ -110,7 +111,9 @@ namespace EMotionFX
const int numJoints = 6;
RecordProperty("test_case_id", "C3122249");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(numJoints, "RagdollEditTestsActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, numJoints, "RagdollEditTestsActor");
CreateSkeletonAndModelIndices();
@@ -138,7 +141,9 @@ namespace EMotionFX
const int numJoints = 8;
RecordProperty("test_case_id", "C3122248");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(numJoints, "RagdollEditTestsActor");
AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
AZ::Data::Asset<Integration::ActorAsset> actorAsset =
TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, numJoints, "RagdollEditTestsActor");
CreateSkeletonAndModelIndices();
EXPECT_EQ(m_indexList.size(), numJoints);