Files
o3de/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp
T
Mike Balfour 48260486fb Change gradients to use cached GradientTransform instance (#6591)
* Change flow so that TerrainSystem stops responding during deactivation.
Some systems might accidentally try to call back to the TerrainSystem inside a DestroyBegin notification, so make sure it stops listening before sending out the notification.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Change gradients to cache and use a GradientTransform instance.
In my local test case, calling EBus on every call took 337 ms, using a lambda to wrap the calls took 197 ms, and using the fully cached version took 170 ms.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Remove the wrappingTransform function and go back to the switch statement.
There was a bit of overhead to each function call due to using AZStd::function that just isn't necessary for this use case.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Add profile markers to the heightfield updates so that they're more visible.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Cleared state while component is deactivated.
The state was getting refreshed even while the component was in a deactivated state, which meant that it wasn't properly notifying of state changes when it became active since it wasn't detecting an actual change.  By clearing the state when deactivated, and ensuring the state isn't getting refreshed *while* deactivated, the notifications work properly.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Fixed compile warning on unit test.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Addressed PR feedback - changed comments, reduced mutex scope

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
2021-12-30 12:43:00 -06:00

261 lines
9.9 KiB
C++

/*
* 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 <AzTest/AzTest.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Math/Random.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/std/chrono/clocks.h>
#include <FastNoiseSystemComponent.h>
#include <FastNoiseGradientComponent.h>
#include <FastNoiseModule.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformModifierRequestBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
class MockGradientTransformComponent
: public AZ::Component
, private GradientSignal::GradientTransformRequestBus::Handler
, private GradientSignal::GradientTransformModifierRequestBus::Handler
{
public:
AZ_COMPONENT(MockGradientTransformComponent, "{464CF47B-7E10-4E1B-BD06-79BD2AC91399}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("GradientTransformService", 0x8c8c5ecc));
}
static void Reflect([[maybe_unused]] AZ::ReflectContext* context) {}
MockGradientTransformComponent() = default;
~MockGradientTransformComponent() = default;
// AZ::Component interface
void Activate() override {}
void Deactivate() override {}
////////////////////////////////////////////////////////////////////////////
//// GradientTransformRequestBus
const GradientSignal::GradientTransform& GetGradientTransform() const override
{
return m_gradientTransform;
}
//////////////////////////////////////////////////////////////////////////
// GradientTransformModifierRequestBus
bool GetAllowReference() const override { return false; }
void SetAllowReference([[maybe_unused]] bool value) override {}
AZ::EntityId GetShapeReference() const override { return AZ::EntityId(); }
void SetShapeReference([[maybe_unused]] AZ::EntityId shapeReference) override {}
bool GetOverrideBounds() const override { return false; }
void SetOverrideBounds([[maybe_unused]] bool value) override {}
AZ::Vector3 GetBounds() const override { return AZ::Vector3(); }
void SetBounds([[maybe_unused]] AZ::Vector3 bounds) override {}
GradientSignal::TransformType GetTransformType() const override { return static_cast<GradientSignal::TransformType>(0); }
void SetTransformType([[maybe_unused]] GradientSignal::TransformType type) override {}
bool GetOverrideTranslate() const override { return false; }
void SetOverrideTranslate([[maybe_unused]] bool value) override {}
AZ::Vector3 GetTranslate() const override { return AZ::Vector3(); }
void SetTranslate([[maybe_unused]] AZ::Vector3 translate) override {}
bool GetOverrideRotate() const override { return false; }
void SetOverrideRotate([[maybe_unused]] bool value) override {}
AZ::Vector3 GetRotate() const override { return AZ::Vector3(); }
void SetRotate([[maybe_unused]] AZ::Vector3 rotate) override {}
bool GetOverrideScale() const override { return false; }
void SetOverrideScale([[maybe_unused]] bool value) override {}
AZ::Vector3 GetScale() const override { return AZ::Vector3(); }
void SetScale([[maybe_unused]] AZ::Vector3 scale) override {}
float GetFrequencyZoom() const override { return false; }
void SetFrequencyZoom([[maybe_unused]] float frequencyZoom) override {}
GradientSignal::WrappingType GetWrappingType() const override { return static_cast<GradientSignal::WrappingType>(0); }
void SetWrappingType([[maybe_unused]] GradientSignal::WrappingType type) override {}
bool GetIs3D() const override { return false; }
void SetIs3D([[maybe_unused]] bool value) override {}
bool GetAdvancedMode() const override { return false; }
void SetAdvancedMode([[maybe_unused]] bool value) override {}
GradientSignal::GradientTransform m_gradientTransform;
};
TEST(FastNoiseTest, ComponentsWithComponentApplication)
{
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
appDesc.m_stackRecordLevels = 20;
AZ::ComponentApplication app;
AZ::Entity* systemEntity = app.Create(appDesc);
ASSERT_TRUE(systemEntity != nullptr);
app.RegisterComponentDescriptor(FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor());
systemEntity->CreateComponent<FastNoiseGem::FastNoiseSystemComponent>();
systemEntity->Init();
systemEntity->Activate();
AZ::Entity* noiseEntity = aznew AZ::Entity("fastnoise_entity");
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
app.AddEntity(noiseEntity);
app.Destroy();
ASSERT_TRUE(true);
}
class FastNoiseTestApp
: public ::testing::Test
{
public:
FastNoiseTestApp()
: m_application()
, m_systemEntity(nullptr)
{
}
void SetUp() override
{
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
appDesc.m_stackRecordLevels = 20;
AZ::ComponentApplication::StartupParameters appStartup;
appStartup.m_createStaticModulesCallback =
[](AZStd::vector<AZ::Module*>& modules)
{
modules.emplace_back(new FastNoiseGem::FastNoiseModule);
};
m_systemEntity = m_application.Create(appDesc, appStartup);
m_application.RegisterComponentDescriptor(MockGradientTransformComponent::CreateDescriptor());
m_systemEntity->Init();
m_systemEntity->Activate();
}
void TearDown() override
{
m_application.Destroy();
}
AZ::ComponentApplication m_application;
AZ::Entity* m_systemEntity;
};
//////////////////////////////////////////////////////////////////////////
// testing class to inspect protected data members in the FastNoiseGradientComponent
struct FastNoiseGradientComponentTester : public FastNoiseGem::FastNoiseGradientComponent
{
const FastNoiseGem::FastNoiseGradientConfig& GetConfig() const { return m_configuration; }
void AssertTrue(const FastNoiseGem::FastNoiseGradientConfig& cfg)
{
ASSERT_TRUE(m_configuration.m_cellularDistanceFunction == cfg.m_cellularDistanceFunction);
ASSERT_TRUE(m_configuration.m_cellularJitter == cfg.m_cellularJitter);
ASSERT_TRUE(m_configuration.m_cellularReturnType == cfg.m_cellularReturnType);
ASSERT_TRUE(m_configuration.m_fractalType == cfg.m_fractalType);
ASSERT_TRUE(m_configuration.m_frequency == cfg.m_frequency);
ASSERT_TRUE(m_configuration.m_gain == cfg.m_gain);
ASSERT_TRUE(m_configuration.m_interp == cfg.m_interp);
ASSERT_TRUE(m_configuration.m_lacunarity == cfg.m_lacunarity);
ASSERT_TRUE(m_configuration.m_noiseType == cfg.m_noiseType);
ASSERT_TRUE(m_configuration.m_octaves == cfg.m_octaves);
ASSERT_TRUE(m_configuration.m_seed == cfg.m_seed);
}
};
TEST_F(FastNoiseTestApp, FastNoise_Component)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
m_application.AddEntity(noiseEntity);
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
}
TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
noiseEntity->CreateComponent<MockGradientTransformComponent>();
noiseEntity->Init();
noiseEntity->Activate();
GradientSignal::GradientSampleParams params;
float sample = -1.0f;
GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params);
ASSERT_TRUE(sample >= 0.0f);
ASSERT_TRUE(sample <= 1.0f);
}
TEST_F(FastNoiseTestApp, FastNoise_ComponentMatchesConfiguration)
{
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
ASSERT_TRUE(noiseEntity != nullptr);
AZ::SimpleLcgRandom rand(AZStd::GetTimeNowMicroSecond());
FastNoiseGem::FastNoiseGradientConfig cfg;
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
noiseEntity->CreateComponent<MockGradientTransformComponent>();
m_application.AddEntity(noiseEntity);
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
}
#if FASTNOISE_EDITOR
#include <EditorFastNoiseGradientComponent.h>
TEST_F(FastNoiseTestApp, FastNoise_EditorCreateGameEntity)
{
AZStd::unique_ptr<AZ::Entity> noiseEntity(aznew AZ::Entity("editor_noise_entity"));
ASSERT_TRUE(noiseEntity != nullptr);
FastNoiseGem::EditorFastNoiseGradientComponent editor;
auto* editorBase = static_cast<AzToolsFramework::Components::EditorComponentBase*>(&editor);
editorBase->BuildGameEntity(noiseEntity.get());
// the new game entity's ocean component should look like the default one
FastNoiseGem::FastNoiseGradientConfig cfg;
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
ASSERT_TRUE(noiseComp != nullptr);
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
}
#endif
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);