You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp

406 lines
22 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "FastNoise_precompiled.h"
#include "FastNoiseGradientComponent.h"
#include <AzCore/Math/MathUtils.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <External/FastNoise/FastNoise.h>
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
namespace FastNoiseGem
{
AZ::u32 FastNoiseGradientConfig::GetCellularParameterVisibility() const
{
return m_noiseType == FastNoise::NoiseType::Cellular ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
}
AZ::u32 FastNoiseGradientConfig::GetFractalParameterVisbility() const
{
switch (m_noiseType)
{
case FastNoise::NoiseType::CubicFractal:
case FastNoise::NoiseType::PerlinFractal:
case FastNoise::NoiseType::SimplexFractal:
case FastNoise::NoiseType::ValueFractal:
return AZ::Edit::PropertyVisibility::Show;
}
return AZ::Edit::PropertyVisibility::Hide;
}
AZ::u32 FastNoiseGradientConfig::GetFrequencyParameterVisbility() const
{
return m_noiseType != FastNoise::NoiseType::WhiteNoise ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
}
AZ::u32 FastNoiseGradientConfig::GetInterpParameterVisibility() const
{
switch (m_noiseType)
{
case FastNoise::NoiseType::Value:
case FastNoise::NoiseType::ValueFractal:
case FastNoise::NoiseType::Perlin:
case FastNoise::NoiseType::PerlinFractal:
return AZ::Edit::PropertyVisibility::Show;
}
return AZ::Edit::PropertyVisibility::Hide;
}
void FastNoiseGradientConfig::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<FastNoiseGradientConfig, AZ::ComponentConfig>()
->Version(0)
->Field("NoiseType", &FastNoiseGradientConfig::m_noiseType)
->Field("Seed", &FastNoiseGradientConfig::m_seed)
->Field("Frequency", &FastNoiseGradientConfig::m_frequency)
->Field("Octaves", &FastNoiseGradientConfig::m_octaves)
->Field("Lacunarity", &FastNoiseGradientConfig::m_lacunarity)
->Field("Gain", &FastNoiseGradientConfig::m_gain)
->Field("Interp", &FastNoiseGradientConfig::m_interp)
->Field("FractalType", &FastNoiseGradientConfig::m_fractalType)
->Field("CellularDistanceFunction", &FastNoiseGradientConfig::m_cellularDistanceFunction)
->Field("CellularReturnType", &FastNoiseGradientConfig::m_cellularReturnType)
->Field("CellularJitter", &FastNoiseGradientConfig::m_cellularJitter)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<FastNoiseGradientConfig>(
"FastNoise Gradient", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_seed, "Random Seed", "Using different seeds will cause the noise output to change")
->Attribute(AZ::Edit::Attributes::Min, 1)
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<int>::max())
->Attribute(AZ::Edit::Attributes::SoftMin, 1)
->Attribute(AZ::Edit::Attributes::SoftMax, 100)
->Attribute(AZ::Edit::Attributes::Step, 10)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &FastNoiseGradientConfig::m_noiseType, "Noise Type", "Sets the type of noise generator used")
->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits<int>::min())
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<int>::max())
->EnumAttribute(FastNoise::NoiseType::Value, "Value")
->EnumAttribute(FastNoise::NoiseType::ValueFractal, "Value Fractal")
->EnumAttribute(FastNoise::NoiseType::Perlin, "Perlin")
->EnumAttribute(FastNoise::NoiseType::PerlinFractal, "Perlin Fractal")
->EnumAttribute(FastNoise::NoiseType::Simplex, "Simplex")
->EnumAttribute(FastNoise::NoiseType::SimplexFractal, "Simplex Fractal")
->EnumAttribute(FastNoise::NoiseType::Cellular, "Cellular")
->EnumAttribute(FastNoise::NoiseType::WhiteNoise, "White Noise")
->EnumAttribute(FastNoise::NoiseType::Cubic, "Cubic")
->EnumAttribute(FastNoise::NoiseType::CubicFractal, "Cubic Fractal")
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_frequency, "Frequency", "Higher frequencies are more coarse")
->Attribute(AZ::Edit::Attributes::DisplayDecimals, 4)
->Attribute(AZ::Edit::Attributes::Min, 0.0001f)
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<float>::max())
->Attribute(AZ::Edit::Attributes::SoftMax, 8.0f)
->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.25) // Give the frequency a non-linear scale slider with higher precision at the low end
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetFrequencyParameterVisbility)
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_octaves, "Octaves", "Number of recursions in the pattern generation, higher octaves refine the pattern")
->Attribute(AZ::Edit::Attributes::Min, 0)
->Attribute(AZ::Edit::Attributes::Max, 8)
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetFractalParameterVisbility)
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_lacunarity, "Lacunarity", "The frequency multiplier between each octave")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<float>::max())
->Attribute(AZ::Edit::Attributes::SoftMax, 5.f)
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetFractalParameterVisbility)
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_gain, "Gain", "The relative strength of noise from each layer when compared to the last")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<float>::max())
->Attribute(AZ::Edit::Attributes::SoftMax, 5.f)
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetFractalParameterVisbility)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &FastNoiseGradientConfig::m_cellularDistanceFunction, "Distance Function", "Sets the distance function used to calculate the cell for a given point")
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetCellularParameterVisibility)
->EnumAttribute(FastNoise::CellularDistanceFunction::Euclidean, "Euclidean")
->EnumAttribute(FastNoise::CellularDistanceFunction::Manhattan, "Manhattan")
->EnumAttribute(FastNoise::CellularDistanceFunction::Natural, "Natural")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &FastNoiseGradientConfig::m_cellularReturnType, "Return Type", "Alters the value type the cellular function returns from its calculation")
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetCellularParameterVisibility)
->EnumAttribute(FastNoise::CellularReturnType::CellValue, "CellValue")
->EnumAttribute(FastNoise::CellularReturnType::Distance, "Distance")
->EnumAttribute(FastNoise::CellularReturnType::Distance2, "Distance2")
->EnumAttribute(FastNoise::CellularReturnType::Distance2Add, "Distance2Add")
->EnumAttribute(FastNoise::CellularReturnType::Distance2Sub, "Distance2Sub")
->EnumAttribute(FastNoise::CellularReturnType::Distance2Mul, "Distance2Mul")
->EnumAttribute(FastNoise::CellularReturnType::Distance2Div, "Distance2Div")
->DataElement(AZ::Edit::UIHandlers::Slider, &FastNoiseGradientConfig::m_cellularJitter, "Jitter", "Sets the maximum distance a cellular point can move from its grid position")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits<float>::max())
->Attribute(AZ::Edit::Attributes::SoftMax, 10.f)
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetCellularParameterVisibility)
->ClassElement(AZ::Edit::ClassElements::Group, "FastNoise Advanced Settings")
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &FastNoiseGradientConfig::m_interp, "Interpolation", "Changes the interpolation method used to smooth between noise values")
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetInterpParameterVisibility)
->EnumAttribute(FastNoise::Interp::Linear, "Linear")
->EnumAttribute(FastNoise::Interp::Hermite, "Hermite")
->EnumAttribute(FastNoise::Interp::Quintic, "Quintic")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &FastNoiseGradientConfig::m_fractalType, "Fractal Type", "Sets how the fractal is combined")
->Attribute(AZ::Edit::Attributes::Visibility, &FastNoiseGradientConfig::GetFractalParameterVisbility)
->EnumAttribute(FastNoise::FractalType::FBM, "FBM")
->EnumAttribute(FastNoise::FractalType::Billow, "Billow")
->EnumAttribute(FastNoise::FractalType::RigidMulti, "Rigid Multi")
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<FastNoiseGradientConfig>()
->Constructor()
->Attribute(AZ::Script::Attributes::Category, "Vegetation")
->Property("randomSeed", BehaviorValueProperty(&FastNoiseGradientConfig::m_seed))
->Property("frequency", BehaviorValueProperty(&FastNoiseGradientConfig::m_frequency))
->Property("octaves", BehaviorValueProperty(&FastNoiseGradientConfig::m_octaves))
->Property("lacunarity", BehaviorValueProperty(&FastNoiseGradientConfig::m_lacunarity))
->Property("gain", BehaviorValueProperty(&FastNoiseGradientConfig::m_gain))
->Property("noiseType",
[](FastNoiseGradientConfig* config) { return (int&)(config->m_noiseType); },
[](FastNoiseGradientConfig* config, const int& i) { config->m_noiseType = (FastNoise::NoiseType)i; })
->Property("interpolation",
[](FastNoiseGradientConfig* config) { return (int&)(config->m_interp); },
[](FastNoiseGradientConfig* config, const int& i) { config->m_interp = (FastNoise::Interp)i; })
->Property("fractalType",
[](FastNoiseGradientConfig* config) { return (int&)(config->m_fractalType); },
[](FastNoiseGradientConfig* config, const int& i) { config->m_fractalType = (FastNoise::FractalType)i; })
;
}
}
void FastNoiseGradientComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("GradientService", 0x21c18d23));
}
void FastNoiseGradientComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("GradientService", 0x21c18d23));
}
void FastNoiseGradientComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("GradientTransformService", 0x8c8c5ecc));
}
void FastNoiseGradientComponent::Reflect(AZ::ReflectContext* context)
{
FastNoiseGradientConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<FastNoiseGradientComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &FastNoiseGradientComponent::m_configuration)
;
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Constant("FastNoiseGradientComponentTypeId", BehaviorConstant(FastNoiseGradientComponentTypeId));
behaviorContext->Class<FastNoiseGradientComponent>()->RequestBus("FastNoiseGradientRequestBus");
behaviorContext->EBus<FastNoiseGradientRequestBus>("FastNoiseGradientRequestBus")
->Attribute(AZ::Script::Attributes::Category, "Vegetation")
->Event("GetRandomSeed", &FastNoiseGradientRequestBus::Events::GetRandomSeed)
->Event("SetRandomSeed", &FastNoiseGradientRequestBus::Events::SetRandomSeed)
->VirtualProperty("RandomSeed", "GetRandomSeed", "SetRandomSeed")
->Event("GetFrequency", &FastNoiseGradientRequestBus::Events::GetFrequency)
->Event("SetFrequency", &FastNoiseGradientRequestBus::Events::SetFrequency)
->VirtualProperty("Frequency", "GetFrequency", "SetFrequency")
->Event("GetInterpolation", &FastNoiseGradientRequestBus::Events::GetInterpolation)
->Event("SetInterpolation", &FastNoiseGradientRequestBus::Events::SetInterpolation)
->VirtualProperty("Interpolation", "GetInterpolation", "SetInterpolation")
->Event("GetNoiseType", &FastNoiseGradientRequestBus::Events::GetNoiseType)
->Event("SetNoiseType", &FastNoiseGradientRequestBus::Events::SetNoiseType)
->VirtualProperty("NoiseType", "GetNoiseType", "SetNoiseType")
->Event("GetOctaves", &FastNoiseGradientRequestBus::Events::GetOctaves)
->Event("SetOctaves", &FastNoiseGradientRequestBus::Events::SetOctaves)
->VirtualProperty("Octaves", "GetOctaves", "SetOctaves")
->Event("GetLacunarity", &FastNoiseGradientRequestBus::Events::GetLacunarity)
->Event("SetLacunarity", &FastNoiseGradientRequestBus::Events::SetLacunarity)
->VirtualProperty("Lacunarity", "GetLacunarity", "SetLacunarity")
->Event("GetGain", &FastNoiseGradientRequestBus::Events::GetGain)
->Event("SetGain", &FastNoiseGradientRequestBus::Events::SetGain)
->VirtualProperty("Gain", "GetGain", "SetGain")
->Event("GetFractalType", &FastNoiseGradientRequestBus::Events::GetFractalType)
->Event("SetFractalType", &FastNoiseGradientRequestBus::Events::SetFractalType)
->VirtualProperty("FractalType", "GetFractalType", "SetFractalType")
;
}
}
FastNoiseGradientComponent::FastNoiseGradientComponent(const FastNoiseGradientConfig& configuration)
: m_configuration(configuration)
{
}
void FastNoiseGradientComponent::Activate()
{
// Some platforms require random seeds to be > 0. Clamp to a positive range to ensure we're always safe.
m_generator.SetSeed(AZ::GetMax(m_configuration.m_seed, 1));
m_generator.SetFrequency(m_configuration.m_frequency);
m_generator.SetInterp(m_configuration.m_interp);
m_generator.SetNoiseType(m_configuration.m_noiseType);
m_generator.SetFractalOctaves(m_configuration.m_octaves);
m_generator.SetFractalLacunarity(m_configuration.m_lacunarity);
m_generator.SetFractalGain(m_configuration.m_gain);
m_generator.SetFractalType(m_configuration.m_fractalType);
m_generator.SetCellularDistanceFunction(m_configuration.m_cellularDistanceFunction);
m_generator.SetCellularReturnType(m_configuration.m_cellularReturnType);
m_generator.SetCellularJitter(m_configuration.m_cellularJitter);
GradientSignal::GradientRequestBus::Handler::BusConnect(GetEntityId());
FastNoiseGradientRequestBus::Handler::BusConnect(GetEntityId());
}
void FastNoiseGradientComponent::Deactivate()
{
GradientSignal::GradientRequestBus::Handler::BusDisconnect();
FastNoiseGradientRequestBus::Handler::BusDisconnect();
}
bool FastNoiseGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const FastNoiseGradientConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool FastNoiseGradientComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<FastNoiseGradientConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const
{
AZ::Vector3 uvw = sampleParams.m_position;
bool wasPointRejected = false;
const bool shouldNormalizeOutput = false;
GradientSignal::GradientTransformRequestBus::Event(
GetEntityId(), &GradientSignal::GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, shouldNormalizeOutput, wasPointRejected);
if (!wasPointRejected)
{
// Generator returns a range between [-1, 1], map that to [0, 1]
return AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
}
return 0.0f;
}
template <typename TValueType, TValueType FastNoiseGradientConfig::*TConfigMember, void (FastNoise::*TMethod)(TValueType)>
void FastNoiseGradientComponent::SetConfigValue(TValueType value)
{
m_configuration.*TConfigMember = value;
((&m_generator)->*TMethod)(value);
LmbrCentral::DependencyNotificationBus::Event(GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
}
int FastNoiseGradientComponent::GetRandomSeed() const
{
return m_configuration.m_seed;
}
void FastNoiseGradientComponent::SetRandomSeed(int seed)
{
// Some platforms require random seeds to be > 0. Clamp to a positive range to ensure we're always safe.
SetConfigValue<int, &FastNoiseGradientConfig::m_seed, &FastNoise::SetSeed>(AZ::GetMax(seed, 1));
}
float FastNoiseGradientComponent::GetFrequency() const
{
return m_configuration.m_frequency;
}
void FastNoiseGradientComponent::SetFrequency(float freq)
{
SetConfigValue<float, &FastNoiseGradientConfig::m_frequency, &FastNoise::SetFrequency>(freq);
}
FastNoise::Interp FastNoiseGradientComponent::GetInterpolation() const
{
return m_configuration.m_interp;
}
void FastNoiseGradientComponent::SetInterpolation(FastNoise::Interp interp)
{
SetConfigValue<FastNoise::Interp, &FastNoiseGradientConfig::m_interp, &FastNoise::SetInterp>(interp);
}
FastNoise::NoiseType FastNoiseGradientComponent::GetNoiseType() const
{
return m_configuration.m_noiseType;
}
void FastNoiseGradientComponent::SetNoiseType(FastNoise::NoiseType type)
{
SetConfigValue<FastNoise::NoiseType, &FastNoiseGradientConfig::m_noiseType, &FastNoise::SetNoiseType>(type);
}
int FastNoiseGradientComponent::GetOctaves() const
{
return m_configuration.m_octaves;
}
void FastNoiseGradientComponent::SetOctaves(int octaves)
{
SetConfigValue<int, &FastNoiseGradientConfig::m_octaves, &FastNoise::SetFractalOctaves>(octaves);
}
float FastNoiseGradientComponent::GetLacunarity() const
{
return m_configuration.m_lacunarity;
}
void FastNoiseGradientComponent::SetLacunarity(float lacunarity)
{
SetConfigValue<float, &FastNoiseGradientConfig::m_lacunarity, &FastNoise::SetFractalLacunarity>(lacunarity);
}
float FastNoiseGradientComponent::GetGain() const
{
return m_configuration.m_gain;
}
void FastNoiseGradientComponent::SetGain(float gain)
{
SetConfigValue<float, &FastNoiseGradientConfig::m_gain, &FastNoise::SetFractalGain>(gain);
}
FastNoise::FractalType FastNoiseGradientComponent::GetFractalType() const
{
return m_configuration.m_fractalType;
}
void FastNoiseGradientComponent::SetFractalType(FastNoise::FractalType type)
{
SetConfigValue<FastNoise::FractalType, &FastNoiseGradientConfig::m_fractalType, &FastNoise::SetFractalType>(type);
}
} // namespace FastNoiseGem