/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include <gtest/gtest.h> #include <EMotionFX/Source/EMotionFXManager.h> #include <Integration/Assets/ActorAsset.h> #include <Integration/Rendering/RenderBackend.h> #include <Integration/Rendering/RenderActor.h> #include <Integration/Rendering/RenderActorInstance.h> #include <Integration/Rendering/RenderBackendManager.h> #include <Integration/System/SystemCommon.h> #include <Tests/SystemComponentFixture.h> #include <Tests/TestAssetCode/ActorFactory.h> #include <Tests/TestAssetCode/JackActor.h> #include <Tests/TestAssetCode/TestActorAssets.h> namespace EMotionFX { namespace Integration { class TestRenderActor : public RenderActor { public: AZ_RTTI(TestRenderActor, "{560849A4-7767-4654-8C61-EDA9A0059BE1}", RenderActor) AZ_CLASS_ALLOCATOR(TestRenderActor, EMotionFXAllocator, 0) TestRenderActor(ActorAsset* actorAsset) : RenderActor() , m_actorAsset(actorAsset) { } public: ActorAsset* m_actorAsset = nullptr; }; class TestRenderActorInstance : public RenderActorInstance { public: AZ_RTTI(TestRenderActorInstance, "{8F5CD404-9661-4A71-9583-EB8E66F3C0E8}", RenderActorInstance) AZ_CLASS_ALLOCATOR(TestRenderActorInstance, EMotionFXAllocator, 0) TestRenderActorInstance(AZ::EntityId entityId, const EMotionFXPtr<EMotionFX::ActorInstance>& actorInstance, const AZ::Data::Asset<ActorAsset>& asset, const ActorAsset::MaterialList& materialPerLOD, SkinningMethod skinningMethod, const AZ::Transform& worldTransform) : RenderActorInstance(asset, actorInstance.get(), entityId) , m_entityId(entityId) , m_actorAsset(asset) , m_actorInstance(actorInstance) , m_materialPerLOD(materialPerLOD) , m_skinningMethod(skinningMethod) , m_worldTransform(worldTransform) { } MOCK_METHOD1(OnTick, void(float)); MOCK_METHOD1(DebugDraw, void(const DebugOptions&)); MOCK_CONST_METHOD0(IsVisible, bool()); MOCK_METHOD1(SetIsVisible, void(bool)); MOCK_METHOD1(SetMaterials, void(const ActorAsset::MaterialList&)); MOCK_METHOD0(UpdateBounds, void()); MOCK_METHOD0(GetWorldBounds, AZ::Aabb()); MOCK_METHOD0(GetLocalBounds, AZ::Aabb()); public: AZ::EntityId m_entityId; AZ::Data::Asset<ActorAsset> m_actorAsset; EMotionFXPtr<EMotionFX::ActorInstance> m_actorInstance; ActorAsset::MaterialList m_materialPerLOD; SkinningMethod m_skinningMethod = SkinningMethod::Linear; AZ::Transform m_worldTransform = AZ::Transform::CreateIdentity(); }; class TestRenderBackend : public RenderBackend { public: AZ_RTTI(TestRenderBackend, "{22CC2C55-8019-4302-8DFD-E08E0CA48114}", RenderBackend) AZ_CLASS_ALLOCATOR(TestRenderBackend, EMotionFXAllocator, 0) RenderActor* CreateActor(ActorAsset* actorAsset) override { return aznew TestRenderActor(actorAsset); } RenderActorInstance* CreateActorInstance(AZ::EntityId entityId, const EMotionFXPtr<EMotionFX::ActorInstance>& actorInstance, const AZ::Data::Asset<ActorAsset>& asset, const ActorAsset::MaterialList& materialPerLOD, SkinningMethod skinningMethod, const AZ::Transform& worldTransform) override { return aznew TestRenderActorInstance(entityId, actorInstance, asset, materialPerLOD, skinningMethod, worldTransform); } }; class RenderBackendManagerFixture : public SystemComponentFixture { public: void SetUp() override { SystemComponentFixture::SetUp(); EXPECT_NE(AZ::Interface<RenderBackendManager>::Get(), nullptr); } public: TestRenderBackend* m_renderBackend = nullptr; }; TEST_F(RenderBackendManagerFixture, AdjustRenderBackend) { RenderBackendManager* renderBackendManager = AZ::Interface<RenderBackendManager>::Get(); EXPECT_NE(renderBackendManager, nullptr); m_renderBackend = aznew TestRenderBackend(); AZ::Interface<RenderBackendManager>::Get()->SetRenderBackend(m_renderBackend); RenderBackend* renderBackend = renderBackendManager->GetRenderBackend(); EXPECT_NE(renderBackend, nullptr); EXPECT_EQ(renderBackend->RTTI_GetType(), azrtti_typeid<TestRenderBackend>()); } class RenderBackendActorTestComponent : public AZ::Component { public: AZ_COMPONENT(RenderBackendActorTestComponent, "{699DE64B-ADD1-4B27-AC54-3D041AF82938}"); RenderBackendActorTestComponent() : AZ::Component() { } static void Reflect(AZ::ReflectContext* context) { auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); if (serializeContext) { serializeContext->Class<RenderBackendActorTestComponent, AZ::Component>() ->Version(1); } } void Activate() override { m_actorInstance = m_actorAsset->CreateInstance(GetEntity()); EXPECT_NE(m_actorInstance, nullptr); RenderBackend* renderBackend = AZ::Interface<RenderBackendManager>::Get()->GetRenderBackend(); m_renderActorInstance.reset(renderBackend->CreateActorInstance(GetEntityId(), m_actorInstance, m_actorAsset, /*materialPerLOD=*/{}, SkinningMethod::Linear, /*transform=*/{})); } void Deactivate() override { m_actorAsset.Release(); m_actorInstance.reset(); m_renderActorInstance.reset(); } public: AZ::Data::Asset<ActorAsset> m_actorAsset; ActorAsset::ActorInstancePtr m_actorInstance; AZStd::unique_ptr<RenderActorInstance> m_renderActorInstance; }; TEST_F(RenderBackendManagerFixture, RenderActorComponentTest) { m_app.RegisterComponentDescriptor(RenderBackendActorTestComponent::CreateDescriptor()); RenderBackendManager* renderBackendManager = AZ::Interface<RenderBackendManager>::Get(); ASSERT_NE(renderBackendManager, nullptr); m_renderBackend = aznew TestRenderBackend(); AZ::Interface<RenderBackendManager>::Get()->SetRenderBackend(m_renderBackend); RenderBackend* renderBackend = renderBackendManager->GetRenderBackend(); ASSERT_NE(renderBackend, nullptr); EXPECT_EQ(renderBackend->RTTI_GetType(), azrtti_typeid<TestRenderBackend>()); AZ::Data::AssetId actorAssetId("{D568F319-49E9-47BA-9E1C-24F949EF28DD}"); AZStd::unique_ptr<Actor> actor = ActorFactory::CreateAndInit<JackNoMeshesActor>(); AZ::Data::Asset<Integration::ActorAsset> actorAsset = TestActorAssets::GetAssetFromActor(actorAssetId, AZStd::move(actor)); // Create render actor. AZStd::unique_ptr<RenderActor> renderActor(renderBackend->CreateActor(actorAsset.Get())); EXPECT_EQ(renderActor->RTTI_GetType(), azrtti_typeid<TestRenderActor>()); TestRenderActor* testRenderActor = azdynamic_cast<TestRenderActor*>(renderActor.get()); ASSERT_NE(testRenderActor, nullptr); // Create entity with a test actor component (that creates a render actor instance). AZ::EntityId entityId(42); auto gameEntity = AZStd::make_unique<AZ::Entity>(); gameEntity->SetId(entityId); auto testActorComponent = gameEntity->CreateComponent<RenderBackendActorTestComponent>(); testActorComponent->m_actorAsset = actorAsset; gameEntity->Init(); gameEntity->Activate(); EXPECT_EQ(testActorComponent->m_actorAsset, actorAsset); EXPECT_NE(testActorComponent->m_actorInstance, nullptr); TestRenderActorInstance* renderActorInstance = azdynamic_cast<TestRenderActorInstance*>(testActorComponent->m_renderActorInstance.get()); ASSERT_NE(renderActorInstance, nullptr); EXPECT_EQ(renderActorInstance->RTTI_GetType(), azrtti_typeid<TestRenderActorInstance>()); EXPECT_EQ(renderActorInstance->m_entityId, entityId); EXPECT_EQ(renderActorInstance->m_actorInstance, testActorComponent->m_actorInstance); EXPECT_EQ(renderActorInstance->GetActor(), actorAsset->GetActor()); } } // namespace Integration } // namespace EMotionFX