/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace EMotionFX { class LODSkinnedMeshFixture : public ::testing::WithParamInterface , public UIFixture { public: }; class LODSystemMock : public SystemMock { public: CCamera& GetViewCamera() override { return m_camera; } void SetViewCameraPosition(Vec3& vec) { m_camera.SetPosition(vec); } protected: CCamera m_camera; }; class LODSkinnedMeshColorFixture : public UIFixture { public: void SetUp() override { UIFixture::SetUp(); m_app.RegisterComponentDescriptor(Integration::SimpleLODComponent::CreateDescriptor()); m_app.RegisterComponentDescriptor(Integration::ActorComponent::CreateDescriptor()); m_app.RegisterComponentDescriptor(AzFramework::TransformComponent::CreateDescriptor()); } struct DataMembers { testing::NiceMock m_renderer; testing::NiceMock m_system; }; }; AZStd::unique_ptr CreateLODActor(int numLODs) { AZStd::unique_ptr actor = ActorFactory::CreateAndInit("LODSkinnedMeshTestsActor"); // Modify the actor to have numLODs LOD levels. Mesh* lodMesh = actor->GetMesh(0, 0); StandardMaterial* dummyMat = StandardMaterial::Create("Dummy Material"); actor->AddMaterial(0, dummyMat); for (int i = 1; i < numLODs; ++i) { actor->InsertLODLevel(i); actor->SetMesh(i, 0, lodMesh); dummyMat->SetAmbient(MCore::RGBAColor{ i * 20.f }); actor->AddMaterial(i, dummyMat); } return actor; } class LODPropertyRowWidget : public AzToolsFramework::PropertyRowWidget { public: QLabel* GetDefaultLabel() { return m_defaultLabel; } }; TEST_P(LODSkinnedMeshFixture, CheckLODLevels) { const int numLODs = GetParam(); RecordProperty("test_case_id", "C29202698"); AutoRegisteredActor actor = CreateLODActor(numLODs); ActorInstance* actorInstance = ActorInstance::Create(actor.get()); // Change the Editor mode to Character EMStudio::GetMainWindow()->ApplicationModeChanged("Character"); // Find the NodeWindowPlugin auto nodeWindow = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::NodeWindowPlugin::CLASS_ID)); EXPECT_TRUE(nodeWindow) << "NodeWidow plugin not found!"; // Select the newly created actor instance AZStd::string result; EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(AZStd::string{ "Select -actorInstanceID " } +AZStd::to_string(actorInstance->GetID()), result)) << result.c_str(); QTreeWidget* treeWidget = nodeWindow->GetDockWidget()->findChild("EMFX.NodeWindowPlugin.NodeHierarchyWidget.HierarchyWidget")->GetTreeWidget(); EXPECT_TRUE(treeWidget); // Select the node containing the mesh const QTreeWidgetItem* meshNodeItem = treeWidget->topLevelItem(0)->child(0); EXPECT_TRUE(meshNodeItem); const QRect rect = treeWidget->visualItemRect(meshNodeItem); QTest::mouseClick(treeWidget->viewport(), Qt::LeftButton, Qt::NoModifier, rect.center()); // Get the property widget that holds ReflectedPropertyEditor AzToolsFramework::ReflectedPropertyEditor* propertyWidget = nodeWindow->GetDockWidget()->findChild("EMFX.NodeWindowPlugin.ReflectedPropertyEditor.PropertyWidget"); LODPropertyRowWidget* finalRowWidget = reinterpret_cast(GetNamedPropertyRowWidgetFromReflectedPropertyEditor(propertyWidget, "Meshes by lod")); EXPECT_TRUE(finalRowWidget); // The default label holds the number of LODs found. const QString defaultString = finalRowWidget->GetDefaultLabel()->text(); const QString testString = QString("%1 elements").arg(numLODs); EXPECT_TRUE(testString == defaultString); } INSTANTIATE_TEST_CASE_P(LODSkinnedMeshFixtureTests, LODSkinnedMeshFixture, ::testing::Range(1, 7)); TEST_F(LODSkinnedMeshColorFixture, CheckLODDistanceChange) { const int numLODs = 6; RecordProperty("test_case_id", "C29202698"); SSystemGlobalEnvironment env{}; env.p3DEngine = nullptr; AZStd::unique_ptr data; data = AZStd::make_unique(); env.pRenderer = &data->m_renderer; env.pSystem = &data->m_system; gEnv = &env; AZ::EntityId entityId(740216387); auto gameEntity = AZStd::make_unique(); gameEntity->SetId(entityId); AzFramework::TransformComponent* transformComponent = gameEntity->CreateComponent(); Integration::ActorComponent* actorComponent = gameEntity->CreateComponent(); Integration::SimpleLODComponent::Configuration conf; conf.GenerateDefaultValue(numLODs); Integration::SimpleLODComponent* simpleLODComponent = gameEntity->CreateComponent(&conf); gameEntity->Init(); gameEntity->Activate(); AZ::Data::AssetId actorAssetId("{85D3EF54-7400-43F8-8A40-F6BCBF534E54}"); AZStd::unique_ptr actor = CreateLODActor(numLODs); AZ::Data::Asset actorAsset = TestActorAssets::GetAssetFromActor(actorAssetId, AZStd::move(actor)); actorComponent->OnAssetReady(actorAsset); ActorInstance* actorInstance = actorComponent->GetActorInstance(); EXPECT_TRUE(actorInstance); // Tick! AZ::TickBus::Broadcast(&AZ::TickBus::Events::OnTick, 0.0f, AZ::ScriptTimePoint{}); EXPECT_EQ(actorInstance->GetLODLevel(), 0); Vec3 newVec{ 0,30,0 }; data->m_system.SetViewCameraPosition(newVec); // Tick! AZ::TickBus::Broadcast(&AZ::TickBus::Events::OnTick, 0.0f, AZ::ScriptTimePoint{}); actorInstance->UpdateTransformations(0.0f); EXPECT_EQ(actorInstance->GetLODLevel(), 3); newVec.y = 50; data->m_system.SetViewCameraPosition(newVec); // Tick! AZ::TickBus::Broadcast(&AZ::TickBus::Events::OnTick, 0.0f, AZ::ScriptTimePoint{}); actorInstance->UpdateTransformations(0.0f); EXPECT_EQ(actorInstance->GetLODLevel(), 5); gameEntity->Deactivate(); } }