Added FastNoiseLite

master
Marc Gilleron 2021-01-02 00:59:12 +00:00
parent 3e31140ed8
commit c8dcbc55e3
9 changed files with 3664 additions and 0 deletions

2
SCsub
View File

@ -16,6 +16,7 @@ files = [
"generators/graph/*.cpp",
"generators/simple/*.cpp",
"util/*.cpp",
"util/noise/*.cpp",
"terrain/*.cpp",
"server/*.cpp",
"math/*.cpp",
@ -29,6 +30,7 @@ if env["tools"]:
"editor/*.cpp",
"editor/graph/*.cpp",
"editor/terrain/*.cpp",
"editor/fast_noise_lite/*.cpp",
]
files += editor_files

View File

@ -0,0 +1,185 @@
#include "fast_noise_lite_editor_plugin.h"
#include "../../util/noise/fast_noise_lite.h"
#include "../../util/noise/fast_noise_lite_gradient.h"
#include <core/core_string_names.h>
#include <editor/editor_scale.h>
class FastNoiseLiteViewer : public Control {
GDCLASS(FastNoiseLiteViewer, Control)
public:
static const int PREVIEW_WIDTH = 300;
static const int PREVIEW_HEIGHT = 150;
FastNoiseLiteViewer() {
set_custom_minimum_size(Vector2(0, EDSCALE * PREVIEW_HEIGHT));
_texture_rect = memnew(TextureRect);
_texture_rect->set_anchors_and_margins_preset(Control::PRESET_WIDE);
_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED);
add_child(_texture_rect);
}
// ~FastNoiseLiteViewer() {
// }
void set_noise(Ref<FastNoiseLite> noise) {
if (_noise == noise) {
return;
}
if (_noise.is_valid()) {
_noise->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_noise_changed");
}
_noise = noise;
if (_noise.is_valid()) {
set_noise_gradient(Ref<FastNoiseLiteGradient>());
_noise->connect(CoreStringNames::get_singleton()->changed, this, "_on_noise_changed");
set_process(true);
update_preview();
} else {
set_process(false);
_time_before_update = -1.f;
}
}
void set_noise_gradient(Ref<FastNoiseLiteGradient> noise_gradient) {
if (_noise_gradient == noise_gradient) {
return;
}
if (_noise_gradient.is_valid()) {
_noise_gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_noise_changed");
}
_noise_gradient = noise_gradient;
if (_noise_gradient.is_valid()) {
set_noise(Ref<FastNoiseLite>());
_noise_gradient->connect(CoreStringNames::get_singleton()->changed, this, "_on_noise_changed");
set_process(true);
update_preview();
} else {
set_process(false);
_time_before_update = -1.f;
}
}
private:
void _on_noise_changed() {
_time_before_update = 0.5f;
}
void _notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PROCESS: {
if (_time_before_update > 0.f) {
_time_before_update -= get_process_delta_time();
if (_time_before_update <= 0.f) {
update_preview();
}
}
} break;
}
}
// TODO Use thread?
void update_preview() {
const Vector2i preview_size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
Ref<Image> im;
im.instance();
im->create(preview_size.x, preview_size.y, false, Image::FORMAT_RGB8);
im->lock();
if (_noise.is_valid()) {
for (int y = 0; y < preview_size.y; ++y) {
for (int x = 0; x < preview_size.x; ++x) {
// Assuming -1..1 output. Some noise types can have different range though.
const float v = _noise->get_noise_2d(x, y);
const float g = 0.5f * v + 0.5f;
im->set_pixel(x, y, Color(g, g, g));
}
}
} else if (_noise_gradient.is_valid()) {
const float amp = _noise_gradient->get_amplitude();
float m = (amp == 0.f ? 1.f : 1.f / amp);
for (int y = 0; y < preview_size.y; ++y) {
for (int x = 0; x < preview_size.x; ++x) {
const float x0 = x;
const float y0 = y;
float x1 = x0;
float y1 = y0;
_noise_gradient->warp_2d(x1, y1);
const float dx = x1 - x0;
const float dy = y1 - y0;
const float r = 0.5f * m * dx + 0.5f;
const float g = 0.5f * m * dy + 0.5f;
im->set_pixel(x, y, Color(r, g, 0.0f));
}
}
}
im->unlock();
Ref<ImageTexture> tex;
tex.instance();
tex->create_from_image(im);
_texture_rect->set_texture(tex);
}
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("_on_noise_changed"), &FastNoiseLiteViewer::_on_noise_changed);
}
Ref<FastNoiseLite> _noise;
Ref<FastNoiseLiteGradient> _noise_gradient;
float _time_before_update = -1.f;
TextureRect *_texture_rect = nullptr;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FastNoiseLiteEditorInspectorPlugin : public EditorInspectorPlugin {
GDCLASS(FastNoiseLiteEditorInspectorPlugin, EditorInspectorPlugin)
public:
bool can_handle(Object *p_object) override {
return Object::cast_to<FastNoiseLite>(p_object) != NULL ||
Object::cast_to<FastNoiseLiteGradient>(p_object);
}
void parse_begin(Object *p_object) override {
FastNoiseLite *noise_ptr = Object::cast_to<FastNoiseLite>(p_object);
if (noise_ptr) {
Ref<FastNoiseLite> noise(noise_ptr);
FastNoiseLiteViewer *viewer = memnew(FastNoiseLiteViewer);
viewer->set_noise(noise);
add_custom_control(viewer);
return;
}
FastNoiseLiteGradient *noise_gradient_ptr = Object::cast_to<FastNoiseLiteGradient>(p_object);
if (noise_gradient_ptr) {
Ref<FastNoiseLiteGradient> noise_gradient(noise_gradient_ptr);
FastNoiseLiteViewer *viewer = memnew(FastNoiseLiteViewer);
viewer->set_noise_gradient(noise_gradient);
add_custom_control(viewer);
return;
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FastNoiseLiteEditorPlugin::FastNoiseLiteEditorPlugin(EditorNode *p_node) {
Ref<FastNoiseLiteEditorInspectorPlugin> plugin;
plugin.instance();
add_inspector_plugin(plugin);
}

View File

@ -0,0 +1,14 @@
#ifndef FAST_NOISE_LITE_EDITOR_PLUGIN_H
#define FAST_NOISE_LITE_EDITOR_PLUGIN_H
#include <editor/editor_plugin.h>
class FastNoiseLiteEditorPlugin : public EditorPlugin {
GDCLASS(FastNoiseLiteEditorPlugin, EditorPlugin)
public:
virtual String get_name() const { return "FastNoiseLite"; }
FastNoiseLiteEditorPlugin(EditorNode *p_node);
};
#endif // FAST_NOISE_LITE_EDITOR_PLUGIN_H

View File

@ -2,6 +2,7 @@
#include "edition/voxel_tool.h"
#include "edition/voxel_tool_terrain.h"
#include "editor/editor_plugin.h"
#include "editor/fast_noise_lite/fast_noise_lite_editor_plugin.h"
#include "editor/graph/voxel_graph_editor_plugin.h"
#include "editor/terrain/voxel_terrain_editor_plugin.h"
#include "generators/graph/voxel_generator_graph.h"
@ -31,7 +32,10 @@
#include "terrain/voxel_terrain.h"
#include "terrain/voxel_viewer.h"
#include "util/macros.h"
#include "util/noise/fast_noise_lite.h"
#include "util/noise/fast_noise_lite_gradient.h"
#include "voxel_string_names.h"
#include <core/engine.h>
#ifdef TOOLS_ENABLED
@ -87,6 +91,8 @@ void register_voxel_types() {
ClassDB::register_class<VoxelToolTerrain>();
ClassDB::register_class<VoxelBlockSerializer>();
ClassDB::register_class<VoxelVoxLoader>();
ClassDB::register_class<FastNoiseLite>();
ClassDB::register_class<FastNoiseLiteGradient>();
// Meshers
ClassDB::register_virtual_class<VoxelMesher>();
@ -104,6 +110,7 @@ void register_voxel_types() {
#ifdef TOOLS_ENABLED
EditorPlugins::add_by_type<VoxelGraphEditorPlugin>();
EditorPlugins::add_by_type<VoxelTerrainEditorPlugin>();
EditorPlugins::add_by_type<FastNoiseLiteEditorPlugin>();
#endif
}

2589
thirdparty/fast_noise/FastNoiseLite.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,360 @@
#include "fast_noise_lite.h"
#include "../utility.h"
#include <core/core_string_names.h>
FastNoiseLite::FastNoiseLite() {
_fn.SetNoiseType(static_cast<_FastNoise::NoiseType>(_noise_type));
_fn.SetSeed(_seed);
_fn.SetFrequency(1.f / _period);
_fn.SetFractalType(static_cast<_FastNoise::FractalType>(_fractal_type));
_fn.SetFractalOctaves(_fractal_octaves);
_fn.SetFractalLacunarity(_fractal_lacunarity);
_fn.SetFractalPingPongStrength(_fractal_ping_pong_strength);
_fn.SetFractalGain(_fractal_gain);
_fn.SetFractalWeightedStrength(_fractal_weighted_strength);
_fn.SetCellularDistanceFunction(static_cast<_FastNoise::CellularDistanceFunction>(_cellular_distance_function));
_fn.SetCellularReturnType(static_cast<_FastNoise::CellularReturnType>(_cellular_return_type));
_fn.SetCellularJitter(_cellular_jitter);
_fn.SetRotationType3D(static_cast<_FastNoise::RotationType3D>(_rotation_type_3d));
}
void FastNoiseLite::set_noise_type(NoiseType type) {
if (_noise_type == type) {
return;
}
_noise_type = type;
_fn.SetNoiseType(static_cast<_FastNoise::NoiseType>(_noise_type));
emit_changed();
}
FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const {
return _noise_type;
}
void FastNoiseLite::set_seed(int seed) {
if (_seed == seed) {
return;
}
_seed = seed;
_fn.SetSeed(seed);
emit_changed();
}
int FastNoiseLite::get_seed() const {
return _seed;
}
void FastNoiseLite::set_period(float p) {
if (p < 0.0001f) {
p = 0.0001f;
}
if (_period == p) {
return;
}
_period = p;
_fn.SetFrequency(1.f / _period);
emit_changed();
}
float FastNoiseLite::get_period() const {
return _period;
}
void FastNoiseLite::set_warp_noise(Ref<FastNoiseLiteGradient> warp_noise) {
if (_warp_noise == warp_noise) {
return;
}
if (_warp_noise.is_valid()) {
_warp_noise->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_warp_noise_changed");
}
_warp_noise = warp_noise;
if (_warp_noise.is_valid()) {
_warp_noise->connect(CoreStringNames::get_singleton()->changed, this, "_on_warp_noise_changed");
}
emit_changed();
}
Ref<FastNoiseLiteGradient> FastNoiseLite::get_warp_noise() const {
return _warp_noise;
}
void FastNoiseLite::set_fractal_type(FractalType type) {
if (_fractal_type == type) {
return;
}
_fractal_type = type;
_fn.SetFractalType(static_cast<_FastNoise::FractalType>(_fractal_type));
emit_changed();
}
FastNoiseLite::FractalType FastNoiseLite::get_fractal_type() const {
return _fractal_type;
}
void FastNoiseLite::set_fractal_octaves(int octaves) {
ERR_FAIL_COND(octaves <= 0);
if (octaves > _MAX_OCTAVES) {
octaves = _MAX_OCTAVES;
}
if (_fractal_octaves == octaves) {
return;
}
_fractal_octaves = octaves;
_fn.SetFractalOctaves(octaves);
emit_changed();
}
int FastNoiseLite::get_fractal_octaves() const {
return _fractal_octaves;
}
void FastNoiseLite::set_fractal_lacunarity(float lacunarity) {
if (_fractal_lacunarity == lacunarity) {
return;
}
_fractal_lacunarity = lacunarity;
_fn.SetFractalLacunarity(lacunarity);
emit_changed();
}
float FastNoiseLite::get_fractal_lacunarity() const {
return _fractal_lacunarity;
}
void FastNoiseLite::set_fractal_gain(float gain) {
if (_fractal_gain == gain) {
return;
}
_fractal_gain = gain;
_fn.SetFractalGain(gain);
emit_changed();
}
float FastNoiseLite::get_fractal_gain() const {
return _fractal_gain;
}
void FastNoiseLite::set_fractal_ping_pong_strength(float s) {
if (_fractal_ping_pong_strength == s) {
return;
}
_fractal_ping_pong_strength = s;
_fn.SetFractalPingPongStrength(s);
emit_changed();
}
float FastNoiseLite::get_fractal_ping_pong_strength() const {
return _fractal_ping_pong_strength;
}
void FastNoiseLite::set_fractal_weighted_strength(float s) {
if (_fractal_weighted_strength == s) {
return;
}
_fractal_weighted_strength = s;
_fn.SetFractalWeightedStrength(s);
emit_changed();
}
float FastNoiseLite::get_fractal_weighted_strength() const {
return _fractal_weighted_strength;
}
void FastNoiseLite::set_cellular_distance_function(CellularDistanceFunction cdf) {
if (cdf == _cellular_distance_function) {
return;
}
_cellular_distance_function = cdf;
_fn.SetCellularDistanceFunction(static_cast<_FastNoise::CellularDistanceFunction>(_cellular_distance_function));
emit_changed();
}
FastNoiseLite::CellularDistanceFunction FastNoiseLite::get_cellular_distance_function() const {
return _cellular_distance_function;
}
void FastNoiseLite::set_cellular_return_type(CellularReturnType rt) {
if (_cellular_return_type == rt) {
return;
}
_cellular_return_type = rt;
_fn.SetCellularReturnType(static_cast<_FastNoise::CellularReturnType>(_cellular_return_type));
emit_changed();
}
FastNoiseLite::CellularReturnType FastNoiseLite::get_cellular_return_type() const {
return _cellular_return_type;
}
void FastNoiseLite::set_cellular_jitter(float jitter) {
jitter = clamp(jitter, 0.f, 1.f);
if (_cellular_jitter == jitter) {
return;
}
_cellular_jitter = jitter;
_fn.SetCellularJitter(_cellular_jitter);
emit_changed();
}
float FastNoiseLite::get_cellular_jitter() const {
return _cellular_jitter;
}
void FastNoiseLite::set_rotation_type_3d(RotationType3D type) {
if (_rotation_type_3d == type) {
return;
}
_rotation_type_3d = type;
_fn.SetRotationType3D(static_cast<_FastNoise::RotationType3D>(_rotation_type_3d));
emit_changed();
}
FastNoiseLite::RotationType3D FastNoiseLite::get_rotation_type_3d() const {
return _rotation_type_3d;
}
void FastNoiseLite::_on_warp_noise_changed() {
emit_changed();
}
void FastNoiseLite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLite::set_noise_type);
ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLite::get_noise_type);
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed);
ClassDB::bind_method(D_METHOD("set_period", "period"), &FastNoiseLite::set_period);
ClassDB::bind_method(D_METHOD("get_period"), &FastNoiseLite::get_period);
ClassDB::bind_method(D_METHOD("set_warp_noise", "gradient_noise"), &FastNoiseLite::set_warp_noise);
ClassDB::bind_method(D_METHOD("get_warp_noise"), &FastNoiseLite::get_warp_noise);
ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLite::set_fractal_type);
ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLite::get_fractal_type);
ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octaves"), &FastNoiseLite::set_fractal_octaves);
ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves);
ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoiseLite::set_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLite::get_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLite::set_fractal_gain);
ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLite::get_fractal_gain);
ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "strength"),
&FastNoiseLite::set_fractal_ping_pong_strength);
ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength);
ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "strength"),
&FastNoiseLite::set_fractal_weighted_strength);
ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength);
ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "cell_distance_func"),
&FastNoiseLite::set_cellular_distance_function);
ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function);
ClassDB::bind_method(D_METHOD("set_cellular_return_type", "return_type"), &FastNoiseLite::set_cellular_return_type);
ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type);
ClassDB::bind_method(D_METHOD("set_cellular_jitter", "return_type"), &FastNoiseLite::set_cellular_jitter);
ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter);
ClassDB::bind_method(D_METHOD("set_rotation_type_3d", "type"), &FastNoiseLite::set_rotation_type_3d);
ClassDB::bind_method(D_METHOD("get_rotation_type_3d"), &FastNoiseLite::get_rotation_type_3d);
ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &FastNoiseLite::_b_get_noise_2d);
ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &FastNoiseLite::_b_get_noise_3d);
ClassDB::bind_method(D_METHOD("get_noise_2dv", "position"), &FastNoiseLite::_b_get_noise_2dv);
ClassDB::bind_method(D_METHOD("get_noise_3dv", "position"), &FastNoiseLite::_b_get_noise_3dv);
// TODO This is an internal method, it should be hidden from scripts
ClassDB::bind_method(D_METHOD("_on_warp_noise_changed"), &FastNoiseLite::_on_warp_noise_changed);
ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM,
"OpenSimplex2,OpenSimplex2S,Cellular,Perlin,ValueCubic,Value"),
"set_noise_type", "get_noise_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "period", PROPERTY_HINT_EXP_RANGE, "0.0001,10000.0"),
"set_period", "get_period");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "warp_noise", PROPERTY_HINT_RESOURCE_TYPE, "FastNoiseLiteGradient"),
"set_warp_noise", "get_warp_noise");
ADD_GROUP("Fractal", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM,
"None,FBm,Ridged,PingPong"),
"set_fractal_type", "get_fractal_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, vformat("1,%d,1", _MAX_OCTAVES)),
"set_fractal_octaves", "get_fractal_octaves");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_ping_pong_strength"),
"set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_weighted_strength"),
"set_fractal_weighted_strength", "get_fractal_weighted_strength");
ADD_GROUP("Cellular", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM,
"DistanceEuclidean,DistanceEuclideanSq,Manhattan,Hybrid"),
"set_cellular_distance_function", "get_cellular_distance_function");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM,
"CellValue,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"),
"set_cellular_return_type", "get_cellular_return_type");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cellular_jitter", PROPERTY_HINT_RANGE, "0.0,1.0"),
"set_cellular_jitter", "get_cellular_jitter");
ADD_GROUP("Advanced", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_type_3d", PROPERTY_HINT_ENUM,
"None,ImproveXYPlanes,ImproveXZPlanes"),
"set_rotation_type_3d", "get_rotation_type_3d");
BIND_ENUM_CONSTANT(TYPE_OPEN_SIMPLEX_2);
BIND_ENUM_CONSTANT(TYPE_OPEN_SIMPLEX_2S);
BIND_ENUM_CONSTANT(TYPE_CELLULAR);
BIND_ENUM_CONSTANT(TYPE_PERLIN);
BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC);
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(FRACTAL_NONE);
BIND_ENUM_CONSTANT(FRACTAL_FBM);
BIND_ENUM_CONSTANT(FRACTAL_RIDGED);
BIND_ENUM_CONSTANT(FRACTAL_PING_PONG);
BIND_ENUM_CONSTANT(ROTATION_3D_NONE);
BIND_ENUM_CONSTANT(ROTATION_3D_IMPROVE_XY_PLANES);
BIND_ENUM_CONSTANT(ROTATION_3D_IMPROVE_XZ_PLANES);
BIND_ENUM_CONSTANT(CELLULAR_DISTANCE_EUCLIDEAN);
BIND_ENUM_CONSTANT(CELLULAR_DISTANCE_EUCLIDEAN_SQ);
BIND_ENUM_CONSTANT(CELLULAR_DISTANCE_MANHATTAN);
BIND_ENUM_CONSTANT(CELLULAR_DISTANCE_HYBRID);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_CELL_VALUE);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE_2);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE_2_ADD);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE_2_SUB);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE_2_MUL);
BIND_ENUM_CONSTANT(CELLULAR_RETURN_DISTANCE_2_DIV);
}

View File

@ -0,0 +1,158 @@
#ifndef FAST_NOISE_LITE_H
#define FAST_NOISE_LITE_H
#include <core/resource.h>
#include "fast_noise_lite_gradient.h"
class FastNoiseLite : public Resource {
GDCLASS(FastNoiseLite, Resource)
typedef fast_noise_lite::FastNoiseLite _FastNoise;
public:
// TODO Had to prefix it because of https://github.com/godotengine/godot/issues/44860
static const int _MAX_OCTAVES = 32;
enum NoiseType {
TYPE_OPEN_SIMPLEX_2 = _FastNoise::NoiseType_OpenSimplex2,
TYPE_OPEN_SIMPLEX_2S = _FastNoise::NoiseType_OpenSimplex2S,
TYPE_CELLULAR = _FastNoise::NoiseType_Cellular,
TYPE_PERLIN = _FastNoise::NoiseType_Perlin,
TYPE_VALUE_CUBIC = _FastNoise::NoiseType_ValueCubic,
TYPE_VALUE = _FastNoise::NoiseType_Value
};
enum FractalType {
FRACTAL_NONE = _FastNoise::FractalType_None,
FRACTAL_FBM = _FastNoise::FractalType_FBm,
FRACTAL_RIDGED = _FastNoise::FractalType_Ridged,
FRACTAL_PING_PONG = _FastNoise::FractalType_PingPong
};
enum RotationType3D {
ROTATION_3D_NONE = _FastNoise::RotationType3D_None,
ROTATION_3D_IMPROVE_XY_PLANES = _FastNoise::RotationType3D_ImproveXYPlanes,
ROTATION_3D_IMPROVE_XZ_PLANES = _FastNoise::RotationType3D_ImproveXZPlanes
};
enum CellularDistanceFunction {
CELLULAR_DISTANCE_EUCLIDEAN = _FastNoise::CellularDistanceFunction_Euclidean,
CELLULAR_DISTANCE_EUCLIDEAN_SQ = _FastNoise::CellularDistanceFunction_EuclideanSq,
CELLULAR_DISTANCE_MANHATTAN = _FastNoise::CellularDistanceFunction_Manhattan,
CELLULAR_DISTANCE_HYBRID = _FastNoise::CellularDistanceFunction_Hybrid
};
enum CellularReturnType {
CELLULAR_RETURN_CELL_VALUE = _FastNoise::CellularReturnType_CellValue,
CELLULAR_RETURN_DISTANCE = _FastNoise::CellularReturnType_Distance,
CELLULAR_RETURN_DISTANCE_2 = _FastNoise::CellularReturnType_Distance2,
CELLULAR_RETURN_DISTANCE_2_ADD = _FastNoise::CellularReturnType_Distance2Add,
CELLULAR_RETURN_DISTANCE_2_SUB = _FastNoise::CellularReturnType_Distance2Sub,
CELLULAR_RETURN_DISTANCE_2_MUL = _FastNoise::CellularReturnType_Distance2Mul,
CELLULAR_RETURN_DISTANCE_2_DIV = _FastNoise::CellularReturnType_Distance2Div
};
FastNoiseLite();
void set_noise_type(NoiseType type);
NoiseType get_noise_type() const;
void set_seed(int seed);
int get_seed() const;
void set_period(float p);
float get_period() const;
void set_warp_noise(Ref<FastNoiseLiteGradient> warp_noise);
Ref<FastNoiseLiteGradient> get_warp_noise() const;
void set_fractal_type(FractalType type);
FractalType get_fractal_type() const;
void set_fractal_octaves(int octaves);
int get_fractal_octaves() const;
void set_fractal_lacunarity(float lacunarity);
float get_fractal_lacunarity() const;
void set_fractal_gain(float gain);
float get_fractal_gain() const;
void set_fractal_ping_pong_strength(float s);
float get_fractal_ping_pong_strength() const;
void set_fractal_weighted_strength(float s);
float get_fractal_weighted_strength() const;
void set_cellular_distance_function(CellularDistanceFunction cdf);
CellularDistanceFunction get_cellular_distance_function() const;
void set_cellular_return_type(CellularReturnType rt);
CellularReturnType get_cellular_return_type() const;
void set_cellular_jitter(float jitter);
float get_cellular_jitter() const;
void set_rotation_type_3d(RotationType3D type);
RotationType3D get_rotation_type_3d() const;
inline float get_noise_2d(float x, float y) {
if (_warp_noise.is_valid()) {
_warp_noise->warp_2d(x, y);
}
return _fn.GetNoise(x, y);
}
inline float get_noise_3d(float x, float y, float z) {
if (_warp_noise.is_valid()) {
_warp_noise->warp_3d(x, y, z);
}
return _fn.GetNoise(x, y, z);
}
// TODO Bounds access
// TODO Interval range analysis
private:
static void _bind_methods();
void _on_warp_noise_changed();
float _b_get_noise_2d(float x, float y) { return get_noise_2d(x, y); }
float _b_get_noise_3d(float x, float y, float z) { return get_noise_3d(x, y, z); }
float _b_get_noise_2dv(Vector2 p) { return get_noise_2d(p.x, p.y); }
float _b_get_noise_3dv(Vector3 p) { return get_noise_3d(p.x, p.y, p.z); }
fast_noise_lite::FastNoiseLite _fn;
// TODO FastNoiseLite should rather have getters
NoiseType _noise_type = TYPE_OPEN_SIMPLEX_2;
int _seed = 0;
float _period = 64.f;
FractalType _fractal_type = FRACTAL_FBM;
int _fractal_octaves = 3;
float _fractal_lacunarity = 2.f;
float _fractal_ping_pong_strength = 2.f;
float _fractal_gain = 0.5f;
float _fractal_weighted_strength = 0.f;
CellularDistanceFunction _cellular_distance_function = CELLULAR_DISTANCE_EUCLIDEAN_SQ;
CellularReturnType _cellular_return_type = CELLULAR_RETURN_DISTANCE;
float _cellular_jitter = 1.f;
RotationType3D _rotation_type_3d = ROTATION_3D_NONE;
Ref<FastNoiseLiteGradient> _warp_noise;
};
VARIANT_ENUM_CAST(FastNoiseLite::NoiseType);
VARIANT_ENUM_CAST(FastNoiseLite::FractalType);
VARIANT_ENUM_CAST(FastNoiseLite::RotationType3D);
VARIANT_ENUM_CAST(FastNoiseLite::CellularDistanceFunction);
VARIANT_ENUM_CAST(FastNoiseLite::CellularReturnType);
#endif // FAST_NOISE_LITE_H

View File

@ -0,0 +1,225 @@
#include "fast_noise_lite_gradient.h"
static fast_noise_lite::FastNoiseLite::FractalType to_fnl_fractal_type(FastNoiseLiteGradient::FractalType type) {
switch (type) {
case FastNoiseLiteGradient::FRACTAL_NONE:
return fast_noise_lite::FastNoiseLite::FractalType_None;
case FastNoiseLiteGradient::FRACTAL_DOMAIN_WARP_PROGRESSIVE:
return fast_noise_lite::FastNoiseLite::FractalType_DomainWarpProgressive;
case FastNoiseLiteGradient::FRACTAL_DOMAIN_WARP_INDEPENDENT:
return fast_noise_lite::FastNoiseLite::FractalType_DomainWarpIndependent;
default:
ERR_PRINT("Unknown type");
break;
}
return fast_noise_lite::FastNoiseLite::FractalType_None;
}
FastNoiseLiteGradient::FastNoiseLiteGradient() {
_fn.SetDomainWarpType(static_cast<_FastNoise::DomainWarpType>(_noise_type));
_fn.SetSeed(_seed);
_fn.SetFrequency(1.f / _period);
_fn.SetDomainWarpAmp(_amplitude);
_fn.SetFractalType(to_fnl_fractal_type(_fractal_type));
_fn.SetFractalOctaves(_fractal_octaves);
_fn.SetFractalLacunarity(_fractal_lacunarity);
_fn.SetFractalGain(_fractal_gain);
_fn.SetRotationType3D(static_cast<_FastNoise::RotationType3D>(_rotation_type_3d));
}
void FastNoiseLiteGradient::set_noise_type(NoiseType type) {
if (_noise_type == type) {
return;
}
_noise_type = type;
_fn.SetDomainWarpType(static_cast<_FastNoise::DomainWarpType>(_noise_type));
emit_changed();
}
FastNoiseLiteGradient::NoiseType FastNoiseLiteGradient::get_noise_type() const {
return _noise_type;
}
void FastNoiseLiteGradient::set_seed(int seed) {
if (_seed == seed) {
return;
}
_seed = seed;
_fn.SetSeed(seed);
emit_changed();
}
int FastNoiseLiteGradient::get_seed() const {
return _seed;
}
void FastNoiseLiteGradient::set_period(float p) {
if (p < 0.0001f) {
p = 0.0001f;
}
if (_period == p) {
return;
}
_period = p;
_fn.SetFrequency(1.f / _period);
emit_changed();
}
float FastNoiseLiteGradient::get_period() const {
return _period;
}
void FastNoiseLiteGradient::set_amplitude(float amp) {
if (amp == _amplitude) {
return;
}
_amplitude = amp;
_fn.SetDomainWarpAmp(amp);
emit_changed();
}
float FastNoiseLiteGradient::get_amplitude() const {
return _amplitude;
}
void FastNoiseLiteGradient::set_fractal_type(FractalType type) {
if (type == _fractal_type) {
return;
}
_fractal_type = type;
_fn.SetFractalType(to_fnl_fractal_type(_fractal_type));
emit_changed();
}
FastNoiseLiteGradient::FractalType FastNoiseLiteGradient::get_fractal_type() const {
return _fractal_type;
}
void FastNoiseLiteGradient::set_fractal_octaves(int octaves) {
if (_fractal_octaves == octaves) {
return;
}
_fractal_octaves = octaves;
_fn.SetFractalOctaves(octaves);
emit_changed();
}
int FastNoiseLiteGradient::get_fractal_octaves() const {
return _fractal_octaves;
}
void FastNoiseLiteGradient::set_fractal_lacunarity(float lacunarity) {
if (_fractal_lacunarity == lacunarity) {
return;
}
_fractal_lacunarity = lacunarity;
_fn.SetFractalLacunarity(lacunarity);
emit_changed();
}
float FastNoiseLiteGradient::get_fractal_lacunarity() const {
return _fractal_lacunarity;
}
void FastNoiseLiteGradient::set_fractal_gain(float gain) {
if (_fractal_gain == gain) {
return;
}
_fractal_gain = gain;
_fn.SetFractalGain(gain);
emit_changed();
}
float FastNoiseLiteGradient::get_fractal_gain() const {
return _fractal_gain;
}
void FastNoiseLiteGradient::set_rotation_type_3d(RotationType3D type) {
if (_rotation_type_3d == type) {
return;
}
_rotation_type_3d = type;
_fn.SetRotationType3D(static_cast<_FastNoise::RotationType3D>(_rotation_type_3d));
emit_changed();
}
FastNoiseLiteGradient::RotationType3D FastNoiseLiteGradient::get_rotation_type_3d() const {
return _rotation_type_3d;
}
void FastNoiseLiteGradient::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLiteGradient::set_noise_type);
ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLiteGradient::get_noise_type);
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLiteGradient::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLiteGradient::get_seed);
ClassDB::bind_method(D_METHOD("set_period", "period"), &FastNoiseLiteGradient::set_period);
ClassDB::bind_method(D_METHOD("get_period"), &FastNoiseLiteGradient::get_period);
ClassDB::bind_method(D_METHOD("set_amplitude", "amplitude"), &FastNoiseLiteGradient::set_amplitude);
ClassDB::bind_method(D_METHOD("get_amplitude"), &FastNoiseLiteGradient::get_amplitude);
ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLiteGradient::set_fractal_type);
ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLiteGradient::get_fractal_type);
ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octaves"), &FastNoiseLiteGradient::set_fractal_octaves);
ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLiteGradient::get_fractal_octaves);
ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"),
&FastNoiseLiteGradient::set_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLiteGradient::get_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLiteGradient::set_fractal_gain);
ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLiteGradient::get_fractal_gain);
ClassDB::bind_method(D_METHOD("set_rotation_type_3d", "type"), &FastNoiseLiteGradient::set_rotation_type_3d);
ClassDB::bind_method(D_METHOD("get_rotation_type_3d"), &FastNoiseLiteGradient::get_rotation_type_3d);
ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM,
"OpenSimplex2,OpenSimplex2Reduced,Value"),
"set_noise_type", "get_noise_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "period", PROPERTY_HINT_EXP_RANGE, "0.0001,10000.0"),
"set_period", "get_period");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "amplitude", PROPERTY_HINT_EXP_RANGE, "0.0001,10000.0"),
"set_amplitude", "get_amplitude");
ADD_GROUP("Fractal", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM,
"None,DomainWarpProgressive,DomainWarpIndependent"),
"set_fractal_type", "get_fractal_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, vformat("1,%d,1", _MAX_OCTAVES)),
"set_fractal_octaves", "get_fractal_octaves");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
ADD_GROUP("Advanced", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_type_3d", PROPERTY_HINT_ENUM,
"None,ImproveXYPlanes,ImproveXZPlanes"),
"set_rotation_type_3d", "get_rotation_type_3d");
BIND_ENUM_CONSTANT(TYPE_OPEN_SIMPLEX_2);
BIND_ENUM_CONSTANT(TYPE_OPEN_SIMPLEX_2_REDUCED);
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(FRACTAL_NONE);
BIND_ENUM_CONSTANT(FRACTAL_DOMAIN_WARP_PROGRESSIVE);
BIND_ENUM_CONSTANT(FRACTAL_DOMAIN_WARP_INDEPENDENT);
BIND_ENUM_CONSTANT(ROTATION_3D_NONE);
BIND_ENUM_CONSTANT(ROTATION_3D_IMPROVE_XY_PLANES);
BIND_ENUM_CONSTANT(ROTATION_3D_IMPROVE_XZ_PLANES);
}

View File

@ -0,0 +1,124 @@
#ifndef FAST_NOISE_LITE_GRADIENT_H
#define FAST_NOISE_LITE_GRADIENT_H
#include <core/resource.h>
#include "../../thirdparty/fast_noise/FastNoiseLite.h"
// Domain warp is a transformation of coordinates before sampling the actual noise.
// It can be done with another instance of noise, however it needs a sample for each coordinate,
// so FastNoiseLite provides specialized versions of this using gradients.
// This is faster and produces higher-quality results.
//
// Note: FastNoiseLite provides this with the same class, but then its unclear which applies to what,
// so I made two classes, each with a specific purpose.
//
class FastNoiseLiteGradient : public Resource {
GDCLASS(FastNoiseLiteGradient, Resource)
typedef fast_noise_lite::FastNoiseLite _FastNoise;
public:
// TODO Had to prefix it because of https://github.com/godotengine/godot/issues/44860
static const int _MAX_OCTAVES = 32;
enum NoiseType {
TYPE_OPEN_SIMPLEX_2 = _FastNoise::DomainWarpType_OpenSimplex2,
TYPE_OPEN_SIMPLEX_2_REDUCED = _FastNoise::DomainWarpType_OpenSimplex2Reduced,
TYPE_VALUE = _FastNoise::DomainWarpType_BasicGrid
};
// This one does not map directly to FastNoise unfortunately,
// because Godot's UI wants consecutive values starting from 0...
enum FractalType {
FRACTAL_NONE,
FRACTAL_DOMAIN_WARP_PROGRESSIVE,
FRACTAL_DOMAIN_WARP_INDEPENDENT
};
enum RotationType3D {
ROTATION_3D_NONE = _FastNoise::RotationType3D_None,
ROTATION_3D_IMPROVE_XY_PLANES = _FastNoise::RotationType3D_ImproveXYPlanes,
ROTATION_3D_IMPROVE_XZ_PLANES = _FastNoise::RotationType3D_ImproveXZPlanes
};
FastNoiseLiteGradient();
void set_noise_type(NoiseType type);
NoiseType get_noise_type() const;
void set_seed(int seed);
int get_seed() const;
void set_period(float p);
float get_period() const;
void set_amplitude(float amp);
float get_amplitude() const;
void set_fractal_type(FractalType type);
FractalType get_fractal_type() const;
void set_fractal_octaves(int octaves);
int get_fractal_octaves() const;
void set_fractal_lacunarity(float lacunarity);
float get_fractal_lacunarity() const;
void set_fractal_gain(float gain);
float get_fractal_gain() const;
void set_rotation_type_3d(RotationType3D type);
RotationType3D get_rotation_type_3d() const;
// These are inline to ensure inlining actually happens. If they were bound directly to the script API,
// it means they would need to have an address, in which case I'm not sure they would be inlined?
inline void warp_2d(float &x, float &y) {
return _fn.DomainWarp(x, y);
}
inline void warp_3d(float &x, float &y, float &z) {
return _fn.DomainWarp(x, y, z);
}
// TODO Bounds access
// TODO Interval range analysis
private:
static void _bind_methods();
// TODO Getting the gradient instead of adding it would be more useful?
Vector2 _b_warp_2d(Vector2 pos) {
warp_2d(pos.x, pos.y);
return pos;
}
Vector3 _b_warp_3d(Vector3 pos) {
warp_3d(pos.x, pos.y, pos.z);
return pos;
}
fast_noise_lite::FastNoiseLite _fn;
// TODO FastNoiseLite should rather have getters
NoiseType _noise_type = TYPE_VALUE;
int _seed = 0;
float _period = 64.f;
float _amplitude = 30.f;
FractalType _fractal_type = FRACTAL_NONE;
int _fractal_octaves = 3;
float _fractal_lacunarity = 2.f;
float _fractal_gain = 0.5f;
RotationType3D _rotation_type_3d = ROTATION_3D_NONE;
};
VARIANT_ENUM_CAST(FastNoiseLiteGradient::NoiseType);
VARIANT_ENUM_CAST(FastNoiseLiteGradient::FractalType);
VARIANT_ENUM_CAST(FastNoiseLiteGradient::RotationType3D);
#endif // FAST_NOISE_LITE_GRADIENT_H