Browse Source

Restructure and refine the noise module

Hendrik Brucker 3 years ago
parent
commit
bde6fc9c82

+ 1 - 0
modules/noise/SCsub

@@ -27,6 +27,7 @@ env.modules_sources += thirdparty_obj
 module_obj = []
 
 env_noise.add_source_files(module_obj, "*.cpp")
+env_noise.add_source_files(module_obj, "editor/*.cpp")
 env.modules_sources += module_obj
 
 # Needed to force rebuilding the module files when the thirdparty library is updated.

+ 1 - 7
modules/noise/doc_classes/FastNoiseLite.xml

@@ -16,12 +16,9 @@
 		<member name="cellular_jitter" type="float" setter="set_cellular_jitter" getter="get_cellular_jitter" default="0.45">
 			Maximum distance a point can move off of its grid position. Set to [code]0[/code] for an even grid.
 		</member>
-		<member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="0">
+		<member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="1">
 			Return type from cellular noise calculations. See [enum CellularReturnType].
 		</member>
-		<member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
-			A [Gradient] which is used to map the luminance of each pixel to a color value.
-		</member>
 		<member name="domain_warp_amplitude" type="float" setter="set_domain_warp_amplitude" getter="get_domain_warp_amplitude" default="30.0">
 			Sets the maximum warp distance from the origin.
 		</member>
@@ -69,9 +66,6 @@
 		<member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.01">
 			The frequency for all noise types. Low frequency results in smooth noise while high frequency results in rougher, more granular noise.
 		</member>
-		<member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false">
-			Determines whether the noise image returned by [method Noise.get_image] is calculated in 3d space. May result in reduced contrast.
-		</member>
 		<member name="noise_type" type="int" setter="set_noise_type" getter="get_noise_type" enum="FastNoiseLite.NoiseType" default="1">
 			The noise algorithm used. See [enum NoiseType].
 		</member>

+ 10 - 8
modules/noise/doc_classes/Noise.xml

@@ -11,23 +11,24 @@
 	<tutorials>
 	</tutorials>
 	<methods>
-		<method name="get_image">
+		<method name="get_image" qualifiers="const">
 			<return type="Image" />
 			<argument index="0" name="width" type="int" />
 			<argument index="1" name="height" type="int" />
 			<argument index="2" name="invert" type="bool" default="false" />
+			<argument index="3" name="in_3d_space" type="bool" default="false" />
 			<description>
 				Returns a 2D [Image] noise image.
 			</description>
 		</method>
-		<method name="get_noise_1d">
+		<method name="get_noise_1d" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="x" type="float" />
 			<description>
 				Returns the 1D noise value at the given (x) coordinate.
 			</description>
 		</method>
-		<method name="get_noise_2d">
+		<method name="get_noise_2d" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="x" type="float" />
 			<argument index="1" name="y" type="float" />
@@ -35,14 +36,14 @@
 				Returns the 2D noise value at the given position.
 			</description>
 		</method>
-		<method name="get_noise_2dv">
+		<method name="get_noise_2dv" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="v" type="Vector2" />
 			<description>
 				Returns the 2D noise value at the given position.
 			</description>
 		</method>
-		<method name="get_noise_3d">
+		<method name="get_noise_3d" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="x" type="float" />
 			<argument index="1" name="y" type="float" />
@@ -51,19 +52,20 @@
 				Returns the 3D noise value at the given position.
 			</description>
 		</method>
-		<method name="get_noise_3dv">
+		<method name="get_noise_3dv" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="v" type="Vector3" />
 			<description>
 				Returns the 3D noise value at the given position.
 			</description>
 		</method>
-		<method name="get_seamless_image">
+		<method name="get_seamless_image" qualifiers="const">
 			<return type="Image" />
 			<argument index="0" name="width" type="int" />
 			<argument index="1" name="height" type="int" />
 			<argument index="2" name="invert" type="bool" default="false" />
-			<argument index="3" name="skirt" type="float" default="0.1" />
+			<argument index="3" name="in_3d_space" type="bool" default="false" />
+			<argument index="4" name="skirt" type="float" default="0.1" />
 			<description>
 				Returns a seamless 2D [Image] noise image.
 			</description>

+ 11 - 0
modules/noise/doc_classes/NoiseTexture.xml

@@ -24,9 +24,20 @@
 		<member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0">
 			Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer.
 		</member>
+		<member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
+			A [Gradient] which is used to map the luminance of each pixel to a color value.
+		</member>
+		<member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="is_generating_mipmaps" default="true">
+			Determines whether mipmaps are generated for this texture.
+			Enabling this results in less texture aliasing, but the noise texture generation may take longer.
+			Requires (anisotropic) mipmap filtering to be enabled for a material to have an effect.
+		</member>
 		<member name="height" type="int" setter="set_height" getter="get_height" default="512">
 			Height of the generated texture.
 		</member>
+		<member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false">
+			Determines whether the noise image is calculated in 3D space. May result in reduced contrast.
+		</member>
 		<member name="invert" type="bool" setter="set_invert" getter="get_invert" default="false">
 			If [code]true[/code], inverts the noise texture. White becomes black, black becomes white.
 		</member>

+ 149 - 0
modules/noise/editor/noise_editor_plugin.cpp

@@ -0,0 +1,149 @@
+/*************************************************************************/
+/*  noise_editor_plugin.cpp                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "noise_editor_plugin.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_scale.h"
+
+#include "modules/noise/noise.h"
+#include "modules/noise/noise_texture.h"
+
+class NoisePreview : public Control {
+	GDCLASS(NoisePreview, Control)
+
+	static const int PREVIEW_HEIGHT = 150;
+	static const int PADDING_3D_SPACE_SWITCH = 2;
+
+	Ref<Noise> _noise;
+	Size2i _preview_texture_size;
+
+	TextureRect *_texture_rect = nullptr;
+	Button *_3d_space_switch = nullptr;
+
+public:
+	NoisePreview() {
+		set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT));
+
+		_texture_rect = memnew(TextureRect);
+		_texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+		_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED);
+		add_child(_texture_rect);
+
+		_3d_space_switch = memnew(Button);
+		_3d_space_switch->set_text(TTR("3D"));
+		_3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space."));
+		_3d_space_switch->set_toggle_mode(true);
+		_3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH);
+		_3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH);
+		_3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed));
+		add_child(_3d_space_switch);
+	}
+
+	void set_noise(Ref<Noise> noise) {
+		if (_noise == noise) {
+			return;
+		}
+		_noise = noise;
+		if (_noise.is_valid()) {
+			if (_noise->has_meta("_preview_in_3d_space_")) {
+				_3d_space_switch->set_pressed(true);
+			}
+
+			update_preview();
+		}
+	}
+
+private:
+	void _on_3d_button_pressed() {
+		if (_3d_space_switch->is_pressed()) {
+			_noise->set_meta("_preview_in_3d_space_", true);
+		} else {
+			_noise->remove_meta("_preview_in_3d_space_");
+		}
+	}
+
+	void _notification(int p_what) {
+		switch (p_what) {
+			case NOTIFICATION_RESIZED: {
+				_preview_texture_size = get_size();
+				update_preview();
+			} break;
+		}
+	}
+
+	void update_preview() {
+		if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) {
+			Ref<NoiseTexture> tex;
+			tex.instantiate();
+			tex->set_width(_preview_texture_size.width);
+			tex->set_height(_preview_texture_size.height);
+			tex->set_in_3d_space(_3d_space_switch->is_pressed());
+			tex->set_noise(_noise);
+			_texture_rect->set_texture(tex);
+		}
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class NoiseEditorInspectorPlugin : public EditorInspectorPlugin {
+	GDCLASS(NoiseEditorInspectorPlugin, EditorInspectorPlugin)
+public:
+	bool can_handle(Object *p_object) override {
+		return Object::cast_to<Noise>(p_object) != nullptr;
+	}
+
+	void parse_begin(Object *p_object) override {
+		Noise *noise_ptr = Object::cast_to<Noise>(p_object);
+		if (noise_ptr) {
+			Ref<Noise> noise(noise_ptr);
+
+			NoisePreview *viewer = memnew(NoisePreview);
+			viewer->set_noise(noise);
+			add_custom_control(viewer);
+		}
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+String NoiseEditorPlugin::get_name() const {
+	return Noise::get_class_static();
+}
+
+NoiseEditorPlugin::NoiseEditorPlugin() {
+	Ref<NoiseEditorInspectorPlugin> plugin;
+	plugin.instantiate();
+	add_inspector_plugin(plugin);
+}
+
+#endif // TOOLS_ENABLED

+ 49 - 0
modules/noise/editor/noise_editor_plugin.h

@@ -0,0 +1,49 @@
+/*************************************************************************/
+/*  noise_editor_plugin.h                                                */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef NOISE_EDITOR_PLUGIN_H
+#define NOISE_EDITOR_PLUGIN_H
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_plugin.h"
+
+class NoiseEditorPlugin : public EditorPlugin {
+	GDCLASS(NoiseEditorPlugin, EditorPlugin)
+
+public:
+	String get_name() const override;
+
+	NoiseEditorPlugin();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // NOISE_EDITOR_PLUGIN_H

+ 73 - 164
modules/noise/fastnoise_lite.cpp

@@ -31,31 +31,29 @@
 #include "fastnoise_lite.h"
 
 FastNoiseLite::FastNoiseLite() {
-	// Most defaults copied from the library.
-	set_noise_type(TYPE_SIMPLEX_SMOOTH);
-	set_seed(0);
-	set_frequency(0.01);
-	set_in_3d_space(false);
-
-	set_fractal_type(FRACTAL_FBM);
-	set_fractal_octaves(5);
-	set_fractal_lacunarity(2.0);
-	set_fractal_gain(0.5);
-	set_fractal_weighted_strength(0.0);
-	set_fractal_ping_pong_strength(2.0);
-
-	set_cellular_distance_function(DISTANCE_EUCLIDEAN);
-	set_cellular_return_type(RETURN_CELL_VALUE);
-	set_cellular_jitter(0.45);
-
-	set_domain_warp_enabled(false);
-	set_domain_warp_type(DOMAIN_WARP_SIMPLEX);
-	set_domain_warp_amplitude(30.0);
-	set_domain_warp_frequency(0.05);
-	set_domain_warp_fractal_type(DOMAIN_WARP_FRACTAL_PROGRESSIVE);
-	set_domain_warp_fractal_octaves(5);
-	set_domain_warp_fractal_lacunarity(6);
-	set_domain_warp_fractal_gain(0.5);
+	_noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type);
+	_noise.SetSeed(seed);
+	_noise.SetFrequency(frequency);
+
+	_noise.SetFractalType((_FastNoiseLite::FractalType)fractal_type);
+	_noise.SetFractalOctaves(fractal_octaves);
+	_noise.SetFractalLacunarity(fractal_lacunarity);
+	_noise.SetFractalGain(fractal_gain);
+	_noise.SetFractalWeightedStrength(fractal_weighted_strength);
+	_noise.SetFractalPingPongStrength(fractal_ping_pong_strength);
+
+	_noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)cellular_distance_function);
+	_noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)cellular_return_type);
+	_noise.SetCellularJitter(cellular_jitter);
+
+	_domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)domain_warp_type);
+	_domain_warp_noise.SetSeed(seed);
+	_domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude);
+	_domain_warp_noise.SetFrequency(domain_warp_frequency);
+	_domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None);
+	_domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves);
+	_domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity);
+	_domain_warp_noise.SetFractalGain(domain_warp_fractal_gain);
 }
 
 FastNoiseLite::~FastNoiseLite() {
@@ -77,6 +75,7 @@ FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const {
 void FastNoiseLite::set_seed(int p_seed) {
 	seed = p_seed;
 	_noise.SetSeed(p_seed);
+	_domain_warp_noise.SetSeed(p_seed);
 	emit_changed();
 }
 
@@ -94,14 +93,6 @@ real_t FastNoiseLite::get_frequency() const {
 	return frequency;
 }
 
-void FastNoiseLite::set_in_3d_space(bool p_enable) {
-	in_3d_space = p_enable;
-	emit_changed();
-}
-bool FastNoiseLite::is_in_3d_space() const {
-	return in_3d_space;
-}
-
 void FastNoiseLite::set_offset(Vector3 p_offset) {
 	offset = p_offset;
 	emit_changed();
@@ -111,46 +102,6 @@ Vector3 FastNoiseLite::get_offset() const {
 	return offset;
 }
 
-void FastNoiseLite::set_color_ramp(const Ref<Gradient> &p_gradient) {
-	color_ramp = p_gradient;
-	if (color_ramp.is_valid()) {
-		color_ramp->connect(SNAME("changed"), callable_mp(this, &FastNoiseLite::_changed));
-		emit_changed();
-	}
-}
-
-Ref<Gradient> FastNoiseLite::get_color_ramp() const {
-	return color_ramp;
-}
-
-// Noise functions.
-
-real_t FastNoiseLite::get_noise_1d(real_t p_x) {
-	return get_noise_2d(p_x, 0.0);
-}
-
-real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) {
-	return get_noise_2d(p_v.x, p_v.y);
-}
-
-real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) {
-	if (domain_warp_enabled) {
-		_domain_warp_noise.DomainWarp(p_x, p_y);
-	}
-	return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
-}
-
-real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) {
-	return get_noise_3d(p_v.x, p_v.y, p_v.z);
-}
-
-real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) {
-	if (domain_warp_enabled) {
-		_domain_warp_noise.DomainWarp(p_x, p_y, p_z);
-	}
-	return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
-}
-
 // Fractal.
 
 void FastNoiseLite::set_fractal_type(FractalType p_type) {
@@ -204,12 +155,12 @@ real_t FastNoiseLite::get_fractal_weighted_strength() const {
 }
 
 void FastNoiseLite::set_fractal_ping_pong_strength(real_t p_ping_pong_strength) {
-	fractal_pinp_pong_strength = p_ping_pong_strength;
+	fractal_ping_pong_strength = p_ping_pong_strength;
 	_noise.SetFractalPingPongStrength(p_ping_pong_strength);
 	emit_changed();
 }
 real_t FastNoiseLite::get_fractal_ping_pong_strength() const {
-	return fractal_pinp_pong_strength;
+	return fractal_ping_pong_strength;
 }
 
 // Cellular.
@@ -237,7 +188,6 @@ real_t FastNoiseLite::get_cellular_jitter() const {
 void FastNoiseLite::set_cellular_return_type(CellularReturnType p_ret) {
 	cellular_return_type = p_ret;
 	_noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)p_ret);
-
 	emit_changed();
 }
 
@@ -345,68 +295,32 @@ real_t FastNoiseLite::get_domain_warp_fractal_gain() const {
 	return domain_warp_fractal_gain;
 }
 
-// Textures.
+// Noise interface functions.
 
-Ref<Image> FastNoiseLite::get_image(int p_width, int p_height, bool p_invert) {
-	bool grayscale = color_ramp.is_null();
-
-	Vector<uint8_t> data;
-	data.resize(p_width * p_height * (grayscale ? 1 : 4));
-
-	uint8_t *wd8 = data.ptrw();
+real_t FastNoiseLite::get_noise_1d(real_t p_x) const {
+	return get_noise_2d(p_x, 0.0);
+}
 
-	// Get all values and identify min/max values.
-	Vector<real_t> values;
-	values.resize(p_width * p_height);
-	real_t min_val = 100;
-	real_t max_val = -100;
+real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const {
+	return get_noise_2d(p_v.x, p_v.y);
+}
 
-	for (int y = 0, i = 0; y < p_height; y++) {
-		for (int x = 0; x < p_width; x++, i++) {
-			values.set(i, is_in_3d_space() ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y));
-			if (values[i] > max_val) {
-				max_val = values[i];
-			}
-			if (values[i] < min_val) {
-				min_val = values[i];
-			}
-		}
+real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const {
+	if (domain_warp_enabled) {
+		_domain_warp_noise.DomainWarp(p_x, p_y);
 	}
+	return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
+}
 
-	// Normalize values and write to texture.
-	uint8_t value;
-	for (int i = 0, x = 0; i < p_height; i++) {
-		for (int j = 0; j < p_width; j++, x++) {
-			if (max_val == min_val) {
-				value = 0;
-			} else {
-				value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
-			}
-			if (p_invert) {
-				value = 255 - value;
-			}
-			if (grayscale) {
-				wd8[x] = value;
-			} else {
-				float luminance = value / 255.0;
-				Color ramp_color = color_ramp->get_color_at_offset(luminance);
-				wd8[x * 4 + 0] = uint8_t(CLAMP(ramp_color.r * 255, 0, 255));
-				wd8[x * 4 + 1] = uint8_t(CLAMP(ramp_color.g * 255, 0, 255));
-				wd8[x * 4 + 2] = uint8_t(CLAMP(ramp_color.b * 255, 0, 255));
-				wd8[x * 4 + 3] = uint8_t(CLAMP(ramp_color.a * 255, 0, 255));
-			}
-		}
-	}
-	if (grayscale) {
-		return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
-	} else {
-		return memnew(Image(p_width, p_height, false, Image::FORMAT_RGBA8, data));
-	}
+real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const {
+	return get_noise_3d(p_v.x, p_v.y, p_v.z);
 }
 
-Ref<Image> FastNoiseLite::get_seamless_image(int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
-	// Just return parent function. This is here only so Godot will properly document this function.
-	return Noise::get_seamless_image(p_width, p_height, p_invert, p_blend_skirt);
+real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const {
+	if (domain_warp_enabled) {
+		_domain_warp_noise.DomainWarp(p_x, p_y, p_z);
+	}
+	return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
 }
 
 void FastNoiseLite::_changed() {
@@ -418,108 +332,103 @@ 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);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
 
 	ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed);
 	ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
 
 	ClassDB::bind_method(D_METHOD("set_frequency", "freq"), &FastNoiseLite::set_frequency);
 	ClassDB::bind_method(D_METHOD("get_frequency"), &FastNoiseLite::get_frequency);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
-
-	ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &FastNoiseLite::set_in_3d_space);
-	ClassDB::bind_method(D_METHOD("is_in_3d_space"), &FastNoiseLite::is_in_3d_space);
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
 
 	ClassDB::bind_method(D_METHOD("set_offset", "offset"), &FastNoiseLite::set_offset);
 	ClassDB::bind_method(D_METHOD("get_offset"), &FastNoiseLite::get_offset);
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,1"), "set_offset", "get_offset");
-
-	ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &FastNoiseLite::set_color_ramp);
-	ClassDB::bind_method(D_METHOD("get_color_ramp"), &FastNoiseLite::get_color_ramp);
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
 
 	// Fractal.
 
-	ADD_GROUP("Fractal", "fractal_");
 	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);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type");
 
 	ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octave_count"), &FastNoiseLite::set_fractal_octaves);
 	ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "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);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "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);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
 
 	ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "weighted_strength"), &FastNoiseLite::set_fractal_weighted_strength);
 	ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength");
 
 	ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "ping_pong_strength"), &FastNoiseLite::set_fractal_ping_pong_strength);
 	ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
 
 	// Cellular.
 
-	ADD_GROUP("Cellular", "cellular_");
 	ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "func"), &FastNoiseLite::set_cellular_distance_function);
 	ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function");
 
 	ClassDB::bind_method(D_METHOD("set_cellular_jitter", "jitter"), &FastNoiseLite::set_cellular_jitter);
 	ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter");
 
 	ClassDB::bind_method(D_METHOD("set_cellular_return_type", "ret"), &FastNoiseLite::set_cellular_return_type);
 	ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type");
 
 	// Domain warp.
 
-	ADD_GROUP("Domain Warp", "domain_warp_");
-
 	ClassDB::bind_method(D_METHOD("set_domain_warp_enabled", "domain_warp_enabled"), &FastNoiseLite::set_domain_warp_enabled);
 	ClassDB::bind_method(D_METHOD("is_domain_warp_enabled"), &FastNoiseLite::is_domain_warp_enabled);
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_type", "domain_warp_type"), &FastNoiseLite::set_domain_warp_type);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_type"), &FastNoiseLite::get_domain_warp_type);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_amplitude", "domain_warp_amplitude"), &FastNoiseLite::set_domain_warp_amplitude);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_amplitude"), &FastNoiseLite::get_domain_warp_amplitude);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_frequency", "domain_warp_frequency"), &FastNoiseLite::set_domain_warp_frequency);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_frequency"), &FastNoiseLite::get_domain_warp_frequency);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_type", "domain_warp_fractal_type"), &FastNoiseLite::set_domain_warp_fractal_type);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_type"), &FastNoiseLite::get_domain_warp_fractal_type);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_octaves", "domain_warp_octave_count"), &FastNoiseLite::set_domain_warp_fractal_octaves);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_octaves"), &FastNoiseLite::get_domain_warp_fractal_octaves);
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_lacunarity", "domain_warp_lacunarity"), &FastNoiseLite::set_domain_warp_fractal_lacunarity);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_lacunarity"), &FastNoiseLite::get_domain_warp_fractal_lacunarity);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity");
 
 	ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_gain", "domain_warp_gain"), &FastNoiseLite::set_domain_warp_fractal_gain);
 	ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_gain"), &FastNoiseLite::get_domain_warp_fractal_gain);
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain");
 
 	ClassDB::bind_method(D_METHOD("_changed"), &FastNoiseLite::_changed);
 
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset");
+
+	ADD_GROUP("Fractal", "fractal_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
+
+	ADD_GROUP("Cellular", "cellular_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type");
+
+	ADD_GROUP("Domain Warp", "domain_warp_");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain");
+
 	BIND_ENUM_CONSTANT(TYPE_VALUE);
 	BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC);
 	BIND_ENUM_CONSTANT(TYPE_PERLIN);

+ 25 - 38
modules/noise/fastnoise_lite.h

@@ -99,36 +99,33 @@ private:
 	_FastNoiseLite _domain_warp_noise;
 
 	Vector3 offset;
-	NoiseType noise_type;
-	Ref<Gradient> color_ramp;
+	NoiseType noise_type = TYPE_SIMPLEX_SMOOTH;
 
-	int seed;
-	real_t frequency;
-	bool in_3d_space;
+	int seed = 0;
+	real_t frequency = 0.01;
 
 	// Fractal specific.
-	FractalType fractal_type;
-	int fractal_octaves;
-	real_t fractal_lacunarity;
-	real_t fractal_gain;
-	real_t fractal_weighted_strength;
-	real_t fractal_pinp_pong_strength;
+	FractalType fractal_type = FRACTAL_FBM;
+	int fractal_octaves = 5;
+	real_t fractal_lacunarity = 2;
+	real_t fractal_gain = 0.5;
+	real_t fractal_weighted_strength = 0;
+	real_t fractal_ping_pong_strength = 2;
 
 	// Cellular specific.
-	CellularDistanceFunction cellular_distance_function;
-	CellularReturnType cellular_return_type;
-	real_t cellular_jitter;
+	CellularDistanceFunction cellular_distance_function = DISTANCE_EUCLIDEAN;
+	CellularReturnType cellular_return_type = RETURN_DISTANCE;
+	real_t cellular_jitter = 0.45;
 
 	// Domain warp specific.
-	bool domain_warp_enabled;
-	DomainWarpType domain_warp_type;
-	real_t domain_warp_frequency;
-	real_t domain_warp_amplitude;
-
-	DomainWarpFractalType domain_warp_fractal_type;
-	int domain_warp_fractal_octaves;
-	real_t domain_warp_fractal_lacunarity;
-	real_t domain_warp_fractal_gain;
+	bool domain_warp_enabled = false;
+	DomainWarpType domain_warp_type = DOMAIN_WARP_SIMPLEX;
+	real_t domain_warp_amplitude = 30.0;
+	real_t domain_warp_frequency = 0.05;
+	DomainWarpFractalType domain_warp_fractal_type = DOMAIN_WARP_FRACTAL_PROGRESSIVE;
+	int domain_warp_fractal_octaves = 5;
+	real_t domain_warp_fractal_lacunarity = 6;
+	real_t domain_warp_fractal_gain = 0.5;
 
 public:
 	FastNoiseLite();
@@ -145,15 +142,9 @@ public:
 	void set_frequency(real_t p_freq);
 	real_t get_frequency() const;
 
-	void set_in_3d_space(bool p_enable);
-	bool is_in_3d_space() const;
-
 	void set_offset(Vector3 p_offset);
 	Vector3 get_offset() const;
 
-	void set_color_ramp(const Ref<Gradient> &p_gradient);
-	Ref<Gradient> get_color_ramp() const;
-
 	// Fractal specific.
 
 	void set_fractal_type(FractalType p_type);
@@ -212,17 +203,13 @@ public:
 	real_t get_domain_warp_fractal_gain() const;
 
 	// Interface methods.
+	real_t get_noise_1d(real_t p_x) const override;
 
-	Ref<Image> get_image(int p_width, int p_height, bool p_invert = false) override;
-	Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1) override;
-
-	real_t get_noise_1d(real_t p_x) override;
-
-	real_t get_noise_2dv(Vector2 p_v) override;
-	real_t get_noise_2d(real_t p_x, real_t p_y) override;
+	real_t get_noise_2dv(Vector2 p_v) const override;
+	real_t get_noise_2d(real_t p_x, real_t p_y) const override;
 
-	real_t get_noise_3dv(Vector3 p_v) override;
-	real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) override;
+	real_t get_noise_3dv(Vector3 p_v) const override;
+	real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const override;
 
 	void _changed();
 };

+ 48 - 4
modules/noise/noise.cpp

@@ -30,13 +30,13 @@
 
 #include "noise.h"
 
-Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
+Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt) const {
 	int skirt_width = p_width * p_blend_skirt;
 	int skirt_height = p_height * p_blend_skirt;
 	int src_width = p_width + skirt_width;
 	int src_height = p_height + skirt_height;
 
-	Ref<Image> src = get_image(src_width, src_height, p_invert);
+	Ref<Image> src = get_image(src_width, src_height, p_invert, p_in_3d_space);
 	bool grayscale = (src->get_format() == Image::FORMAT_L8);
 	if (grayscale) {
 		return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_invert, p_blend_skirt);
@@ -54,6 +54,50 @@ uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) co
 	return (uint8_t)((alpha * p_fg + inv_alpha * p_bg) >> 8);
 }
 
+Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space) const {
+	Vector<uint8_t> data;
+	data.resize(p_width * p_height);
+
+	uint8_t *wd8 = data.ptrw();
+
+	// Get all values and identify min/max values.
+	Vector<real_t> values;
+	values.resize(p_width * p_height);
+	real_t min_val = 1000;
+	real_t max_val = -1000;
+
+	for (int y = 0, i = 0; y < p_height; y++) {
+		for (int x = 0; x < p_width; x++, i++) {
+			values.set(i, p_in_3d_space ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y));
+			if (values[i] > max_val) {
+				max_val = values[i];
+			}
+			if (values[i] < min_val) {
+				min_val = values[i];
+			}
+		}
+	}
+
+	// Normalize values and write to texture.
+	uint8_t value;
+	for (int i = 0, x = 0; i < p_height; i++) {
+		for (int j = 0; j < p_width; j++, x++) {
+			if (max_val == min_val) {
+				value = 0;
+			} else {
+				value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
+			}
+			if (p_invert) {
+				value = 255 - value;
+			}
+
+			wd8[x] = value;
+		}
+	}
+
+	return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+}
+
 void Noise::_bind_methods() {
 	// Noise functions.
 	ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &Noise::get_noise_1d);
@@ -63,6 +107,6 @@ void Noise::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
 
 	// Textures.
-	ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert"), &Noise::get_image, DEFVAL(false));
-	ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(0.1));
+	ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space"), &Noise::get_image, DEFVAL(false), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1));
 }

+ 8 - 8
modules/noise/noise.h

@@ -81,7 +81,7 @@ class Noise : public Resource {
 	};
 
 	template <typename T>
-	Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
+	Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) const {
 		/*
 		To make a seamless image, we swap the quadrants so the edges are perfect matches.
 		We initially get a 10% larger image so we have an overlap we can use to blend over the seams.
@@ -225,16 +225,16 @@ public:
 	// Virtual destructor so we can delete any Noise derived object when referenced as a Noise*.
 	virtual ~Noise() {}
 
-	virtual real_t get_noise_1d(real_t p_x) = 0;
+	virtual real_t get_noise_1d(real_t p_x) const = 0;
 
-	virtual real_t get_noise_2dv(Vector2 p_v) = 0;
-	virtual real_t get_noise_2d(real_t p_x, real_t p_y) = 0;
+	virtual real_t get_noise_2dv(Vector2 p_v) const = 0;
+	virtual real_t get_noise_2d(real_t p_x, real_t p_y) const = 0;
 
-	virtual real_t get_noise_3dv(Vector3 p_v) = 0;
-	virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) = 0;
+	virtual real_t get_noise_3dv(Vector3 p_v) const = 0;
+	virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const = 0;
 
-	virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false) = 0;
-	virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1);
+	virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false) const;
+	virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1) const;
 };
 
 #endif // NOISE_H

+ 86 - 9
modules/noise/noise_texture.cpp

@@ -47,15 +47,22 @@ NoiseTexture::~NoiseTexture() {
 }
 
 void NoiseTexture::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
+	ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
+	ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+
 	ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width);
 	ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height);
 
-	ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
-	ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
-
 	ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture::set_invert);
 	ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert);
 
+	ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space);
+	ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space);
+
+	ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps);
+	ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps);
+
 	ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless);
 	ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless);
 
@@ -68,17 +75,22 @@ void NoiseTexture::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength);
 	ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength);
 
-	ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
-	ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
-	ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+	ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp);
+	ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp);
+
+	ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
+	ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0.05,1,0.001"), "set_seamless_blend_skirt", "get_seamless_blend_skirt");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise");
 }
 
@@ -143,18 +155,42 @@ Ref<Image> NoiseTexture::_generate_texture() {
 	Ref<Image> image;
 
 	if (seamless) {
-		image = ref_noise->get_seamless_image(size.x, size.y, invert, seamless_blend_skirt);
+		image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
 	} else {
-		image = ref_noise->get_image(size.x, size.y, invert);
+		image = ref_noise->get_image(size.x, size.y, invert, in_3d_space);
+	}
+	if (color_ramp.is_valid()) {
+		image = _modulate_with_gradient(image, color_ramp);
 	}
-
 	if (as_normal_map) {
 		image->bump_map_to_normal_map(bump_strength);
 	}
+	if (generate_mipmaps) {
+		image->generate_mipmaps();
+	}
 
 	return image;
 }
 
+Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
+	int width = p_image->get_width();
+	int height = p_image->get_height();
+
+	Ref<Image> new_image;
+	new_image.instantiate();
+	new_image->create(width, height, false, Image::FORMAT_RGBA8);
+
+	for (int row = 0; row < height; row++) {
+		for (int col = 0; col < width; col++) {
+			Color pixel_color = p_image->get_pixel(col, row);
+			Color ramp_color = color_ramp->get_color_at_offset(pixel_color.get_luminance());
+			new_image->set_pixel(col, row, ramp_color);
+		}
+	}
+
+	return new_image;
+}
+
 void NoiseTexture::_update_texture() {
 	bool use_thread = true;
 	if (first_time) {
@@ -227,6 +263,29 @@ bool NoiseTexture::get_invert() const {
 	return invert;
 }
 
+void NoiseTexture::set_in_3d_space(bool p_enable) {
+	if (p_enable == in_3d_space) {
+		return;
+	}
+	in_3d_space = p_enable;
+	_queue_update();
+}
+bool NoiseTexture::is_in_3d_space() const {
+	return in_3d_space;
+}
+
+void NoiseTexture::set_generate_mipmaps(bool p_enable) {
+	if (p_enable == generate_mipmaps) {
+		return;
+	}
+	generate_mipmaps = p_enable;
+	_queue_update();
+}
+
+bool NoiseTexture::is_generating_mipmaps() const {
+	return generate_mipmaps;
+}
+
 void NoiseTexture::set_seamless(bool p_seamless) {
 	if (p_seamless == seamless) {
 		return;
@@ -278,6 +337,24 @@ float NoiseTexture::get_bump_strength() {
 	return bump_strength;
 }
 
+void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) {
+	if (p_gradient == color_ramp) {
+		return;
+	}
+	if (color_ramp.is_valid()) {
+		color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+	}
+	color_ramp = p_gradient;
+	if (color_ramp.is_valid()) {
+		color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+	}
+	_queue_update();
+}
+
+Ref<Gradient> NoiseTexture::get_color_ramp() const {
+	return color_ramp;
+}
+
 int NoiseTexture::get_width() const {
 	return size.x;
 }

+ 17 - 3
modules/noise/noise_texture.h

@@ -51,15 +51,18 @@ private:
 	mutable RID texture;
 	uint32_t flags = 0;
 
-	Ref<Noise> noise;
+	Size2i size = Size2i(512, 512);
 	bool invert = false;
-	Vector2i size = Vector2i(512, 512);
-	Vector2 noise_offset;
+	bool in_3d_space = false;
+	bool generate_mipmaps = true;
 	bool seamless = false;
 	real_t seamless_blend_skirt = 0.1;
 	bool as_normal_map = false;
 	float bump_strength = 8.0;
 
+	Ref<Gradient> color_ramp;
+	Ref<Noise> noise;
+
 	void _thread_done(const Ref<Image> &p_image);
 	static void _thread_function(void *p_ud);
 
@@ -68,6 +71,8 @@ private:
 	void _update_texture();
 	void _set_texture_image(const Ref<Image> &p_image);
 
+	Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient);
+
 protected:
 	static void _bind_methods();
 	virtual void _validate_property(PropertyInfo &property) const override;
@@ -82,6 +87,12 @@ public:
 	void set_invert(bool p_invert);
 	bool get_invert() const;
 
+	void set_in_3d_space(bool p_enable);
+	bool is_in_3d_space() const;
+
+	void set_generate_mipmaps(bool p_enable);
+	bool is_generating_mipmaps() const;
+
 	void set_seamless(bool p_seamless);
 	bool get_seamless();
 
@@ -94,6 +105,9 @@ public:
 	void set_bump_strength(float p_bump_strength);
 	float get_bump_strength();
 
+	void set_color_ramp(const Ref<Gradient> &p_gradient);
+	Ref<Gradient> get_color_ramp() const;
+
 	int get_width() const override;
 	int get_height() const override;
 

+ 9 - 0
modules/noise/register_types.cpp

@@ -34,10 +34,19 @@
 #include "noise.h"
 #include "noise_texture.h"
 
+#ifdef TOOLS_ENABLED
+#include "editor/editor_plugin.h"
+#include "editor/noise_editor_plugin.h"
+#endif
+
 void register_noise_types() {
 	GDREGISTER_CLASS(NoiseTexture);
 	GDREGISTER_ABSTRACT_CLASS(Noise);
 	GDREGISTER_CLASS(FastNoiseLite);
+
+#ifdef TOOLS_ENABLED
+	EditorPlugins::add_by_type<NoiseEditorPlugin>();
+#endif
 }
 
 void unregister_noise_types() {

+ 46 - 46
thirdparty/noise/FastNoiseLite.h

@@ -295,7 +295,7 @@ public:
     /// Noise output bounded between -1...1
     /// </returns>
     template <typename FNfloat>
-    float GetNoise(FNfloat x, FNfloat y)
+    float GetNoise(FNfloat x, FNfloat y) const
     {
         Arguments_must_be_floating_point_values<FNfloat>();
 
@@ -321,7 +321,7 @@ public:
     /// Noise output bounded between -1...1
     /// </returns>
     template <typename FNfloat>
-    float GetNoise(FNfloat x, FNfloat y, FNfloat z)
+    float GetNoise(FNfloat x, FNfloat y, FNfloat z) const
     {
         Arguments_must_be_floating_point_values<FNfloat>();
 
@@ -350,7 +350,7 @@ public:
     /// noise = GetNoise(x, y)</code>
     /// </example>
     template <typename FNfloat>
-    void DomainWarp(FNfloat& x, FNfloat& y)
+    void DomainWarp(FNfloat& x, FNfloat& y) const
     {
         Arguments_must_be_floating_point_values<FNfloat>();
 
@@ -377,7 +377,7 @@ public:
     /// noise = GetNoise(x, y, z)</code>
     /// </example>
     template <typename FNfloat>
-    void DomainWarp(FNfloat& x, FNfloat& y, FNfloat& z)
+    void DomainWarp(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         Arguments_must_be_floating_point_values<FNfloat>();
 
@@ -528,7 +528,7 @@ private:
     }
 
 
-    float GradCoord(int seed, int xPrimed, int yPrimed, float xd, float yd)
+    float GradCoord(int seed, int xPrimed, int yPrimed, float xd, float yd) const
     {
         int hash = Hash(seed, xPrimed, yPrimed);
         hash ^= hash >> 15;
@@ -541,7 +541,7 @@ private:
     }
 
 
-    float GradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd)
+    float GradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd) const
     {
         int hash = Hash(seed, xPrimed, yPrimed, zPrimed);
         hash ^= hash >> 15;
@@ -555,7 +555,7 @@ private:
     }
 
 
-    void GradCoordOut(int seed, int xPrimed, int yPrimed, float& xo, float& yo)
+    void GradCoordOut(int seed, int xPrimed, int yPrimed, float& xo, float& yo) const
     {
         int hash = Hash(seed, xPrimed, yPrimed) & (255 << 1);
 
@@ -564,7 +564,7 @@ private:
     }
 
 
-    void GradCoordOut(int seed, int xPrimed, int yPrimed, int zPrimed, float& xo, float& yo, float& zo)
+    void GradCoordOut(int seed, int xPrimed, int yPrimed, int zPrimed, float& xo, float& yo, float& zo) const
     {
         int hash = Hash(seed, xPrimed, yPrimed, zPrimed) & (255 << 2);
 
@@ -574,7 +574,7 @@ private:
     }
 
 
-    void GradCoordDual(int seed, int xPrimed, int yPrimed, float xd, float yd, float& xo, float& yo)
+    void GradCoordDual(int seed, int xPrimed, int yPrimed, float xd, float yd, float& xo, float& yo) const
     {
         int hash = Hash(seed, xPrimed, yPrimed);
         int index1 = hash & (127 << 1);
@@ -592,7 +592,7 @@ private:
     }
 
 
-    void GradCoordDual(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd, float& xo, float& yo, float& zo)
+    void GradCoordDual(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd, float& xo, float& yo, float& zo) const
     {
         int hash = Hash(seed, xPrimed, yPrimed, zPrimed);
         int index1 = hash & (63 << 2);
@@ -616,7 +616,7 @@ private:
     // Generic noise gen
 
     template <typename FNfloat>
-    float GenNoiseSingle(int seed, FNfloat x, FNfloat y)
+    float GenNoiseSingle(int seed, FNfloat x, FNfloat y) const
     {
         switch (mNoiseType)
         {
@@ -638,7 +638,7 @@ private:
     }
 
     template <typename FNfloat>
-    float GenNoiseSingle(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float GenNoiseSingle(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         switch (mNoiseType)
         {
@@ -663,7 +663,7 @@ private:
     // Noise Coordinate Transforms (frequency, and possible skew or rotation)
 
     template <typename FNfloat>
-    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y)
+    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y) const
     {
         x *= mFrequency;
         y *= mFrequency;
@@ -686,7 +686,7 @@ private:
     }
 
     template <typename FNfloat>
-    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y, FNfloat& z)
+    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         x *= mFrequency;
         y *= mFrequency;
@@ -757,7 +757,7 @@ private:
     // Domain Warp Coordinate Transforms
 
     template <typename FNfloat>
-    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y)
+    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y) const
     {
         switch (mDomainWarpType)
         {
@@ -777,7 +777,7 @@ private:
     }
 
     template <typename FNfloat>
-    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y, FNfloat& z)
+    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         switch (mWarpTransformType3D)
         {
@@ -844,7 +844,7 @@ private:
     // Fractal FBm
 
     template <typename FNfloat>
-    float GenFractalFBm(FNfloat x, FNfloat y)
+    float GenFractalFBm(FNfloat x, FNfloat y) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -865,7 +865,7 @@ private:
     }
 
     template <typename FNfloat>
-    float GenFractalFBm(FNfloat x, FNfloat y, FNfloat z)
+    float GenFractalFBm(FNfloat x, FNfloat y, FNfloat z) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -890,7 +890,7 @@ private:
     // Fractal Ridged
 
     template <typename FNfloat>
-    float GenFractalRidged(FNfloat x, FNfloat y)
+    float GenFractalRidged(FNfloat x, FNfloat y) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -911,7 +911,7 @@ private:
     }
 
     template <typename FNfloat>
-    float GenFractalRidged(FNfloat x, FNfloat y, FNfloat z)
+    float GenFractalRidged(FNfloat x, FNfloat y, FNfloat z) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -936,7 +936,7 @@ private:
     // Fractal PingPong 
 
     template <typename FNfloat>
-    float GenFractalPingPong(FNfloat x, FNfloat y)
+    float GenFractalPingPong(FNfloat x, FNfloat y) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -957,7 +957,7 @@ private:
     }
 
     template <typename FNfloat>
-    float GenFractalPingPong(FNfloat x, FNfloat y, FNfloat z)
+    float GenFractalPingPong(FNfloat x, FNfloat y, FNfloat z) const
     {
         int seed = mSeed;
         float sum = 0;
@@ -982,7 +982,7 @@ private:
     // Simplex/OpenSimplex2 Noise
 
     template <typename FNfloat>
-    float SingleSimplex(int seed, FNfloat x, FNfloat y)
+    float SingleSimplex(int seed, FNfloat x, FNfloat y) const
     {
         // 2D OpenSimplex2 case uses the same algorithm as ordinary Simplex.
 
@@ -1053,7 +1053,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SingleOpenSimplex2(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SingleOpenSimplex2(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         // 3D OpenSimplex2 case uses two offset rotated cube grids.
 
@@ -1155,7 +1155,7 @@ private:
     // OpenSimplex2S Noise
 
     template <typename FNfloat>
-    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y)
+    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y) const
     {
         // 2D OpenSimplex2S case is a modified 2D simplex noise.
 
@@ -1286,7 +1286,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         // 3D OpenSimplex2S case uses two offset rotated cube grids.
 
@@ -1482,7 +1482,7 @@ private:
     // Cellular Noise
 
     template <typename FNfloat>
-    float SingleCellular(int seed, FNfloat x, FNfloat y)
+    float SingleCellular(int seed, FNfloat x, FNfloat y) const
     {
         int xr = FastRound(x);
         int yr = FastRound(y);
@@ -1612,7 +1612,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SingleCellular(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SingleCellular(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         int xr = FastRound(x);
         int yr = FastRound(y);
@@ -1769,7 +1769,7 @@ private:
     // Perlin Noise
 
     template <typename FNfloat>
-    float SinglePerlin(int seed, FNfloat x, FNfloat y)
+    float SinglePerlin(int seed, FNfloat x, FNfloat y) const
     {
         int x0 = FastFloor(x);
         int y0 = FastFloor(y);
@@ -1794,7 +1794,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SinglePerlin(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SinglePerlin(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         int x0 = FastFloor(x);
         int y0 = FastFloor(y);
@@ -1833,7 +1833,7 @@ private:
     // Value Cubic Noise
 
     template <typename FNfloat>
-    float SingleValueCubic(int seed, FNfloat x, FNfloat y)
+    float SingleValueCubic(int seed, FNfloat x, FNfloat y) const
     {
         int x1 = FastFloor(x);
         int y1 = FastFloor(y);
@@ -1863,7 +1863,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SingleValueCubic(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SingleValueCubic(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         int x1 = FastFloor(x);
         int y1 = FastFloor(y);
@@ -1920,7 +1920,7 @@ private:
     // Value Noise
 
     template <typename FNfloat>
-    float SingleValue(int seed, FNfloat x, FNfloat y)
+    float SingleValue(int seed, FNfloat x, FNfloat y) const
     {
         int x0 = FastFloor(x);
         int y0 = FastFloor(y);
@@ -1940,7 +1940,7 @@ private:
     }
 
     template <typename FNfloat>
-    float SingleValue(int seed, FNfloat x, FNfloat y, FNfloat z)
+    float SingleValue(int seed, FNfloat x, FNfloat y, FNfloat z) const
     {
         int x0 = FastFloor(x);
         int y0 = FastFloor(y);
@@ -1972,7 +1972,7 @@ private:
     // Domain Warp
 
     template <typename FNfloat>
-    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr)
+    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr) const
     {
         switch (mDomainWarpType)
         {
@@ -1989,7 +1989,7 @@ private:
     }
 
     template <typename FNfloat>
-    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr)
+    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr) const
     {
         switch (mDomainWarpType)
         {
@@ -2009,7 +2009,7 @@ private:
     // Domain Warp Single Wrapper
 
     template <typename FNfloat>
-    void DomainWarpSingle(FNfloat& x, FNfloat& y)
+    void DomainWarpSingle(FNfloat& x, FNfloat& y) const
     {
         int seed = mSeed;
         float amp = mDomainWarpAmp * mFractalBounding;
@@ -2023,7 +2023,7 @@ private:
     }
 
     template <typename FNfloat>
-    void DomainWarpSingle(FNfloat& x, FNfloat& y, FNfloat& z)
+    void DomainWarpSingle(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         int seed = mSeed;
         float amp = mDomainWarpAmp * mFractalBounding;
@@ -2041,7 +2041,7 @@ private:
     // Domain Warp Fractal Progressive
 
     template <typename FNfloat>
-    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y)
+    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y) const
     {
         int seed = mSeed;
         float amp = mDomainWarpAmp * mFractalBounding;
@@ -2062,7 +2062,7 @@ private:
     }
 
     template <typename FNfloat>
-    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y, FNfloat& z)
+    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         int seed = mSeed;
         float amp = mDomainWarpAmp * mFractalBounding;
@@ -2087,7 +2087,7 @@ private:
     // Domain Warp Fractal Independant
 
     template <typename FNfloat>
-    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y)
+    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y) const
     {
         FNfloat xs = x;
         FNfloat ys = y;
@@ -2108,7 +2108,7 @@ private:
     }
 
     template <typename FNfloat>
-    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y, FNfloat& z)
+    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y, FNfloat& z) const
     {
         FNfloat xs = x;
         FNfloat ys = y;
@@ -2133,7 +2133,7 @@ private:
     // Domain Warp Basic Grid
 
     template <typename FNfloat>
-    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr)
+    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr) const
     {
         FNfloat xf = x * frequency;
         FNfloat yf = y * frequency;
@@ -2166,7 +2166,7 @@ private:
     }
 
     template <typename FNfloat>
-    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr)
+    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr) const
     {
         FNfloat xf = x * frequency;
         FNfloat yf = y * frequency;
@@ -2228,7 +2228,7 @@ private:
     // Domain Warp Simplex/OpenSimplex2
 
     template <typename FNfloat>
-    void SingleDomainWarpSimplexGradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr, bool outGradOnly)
+    void SingleDomainWarpSimplexGradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr, bool outGradOnly) const
     {
         const float SQRT3 = 1.7320508075688772935274463415059f;
         const float G2 = (3 - SQRT3) / 6;
@@ -2326,7 +2326,7 @@ private:
     }
 
     template <typename FNfloat>
-    void SingleDomainWarpOpenSimplex2Gradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr, bool outGradOnly)
+    void SingleDomainWarpOpenSimplex2Gradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr, bool outGradOnly) const
     {
         x *= frequency;
         y *= frequency;

+ 414 - 0
thirdparty/noise/patches/FastNoiseLite.patch

@@ -16,3 +16,417 @@
 -#endif
 +}
 +#endif // namespace fastnoiselite
+@@ -295,7 +295,7 @@ public:
+     /// Noise output bounded between -1...1
+     /// </returns>
+     template <typename FNfloat>
+-    float GetNoise(FNfloat x, FNfloat y)
++    float GetNoise(FNfloat x, FNfloat y) const
+     {
+         Arguments_must_be_floating_point_values<FNfloat>();
+ 
+@@ -321,7 +321,7 @@ public:
+     /// Noise output bounded between -1...1
+     /// </returns>
+     template <typename FNfloat>
+-    float GetNoise(FNfloat x, FNfloat y, FNfloat z)
++    float GetNoise(FNfloat x, FNfloat y, FNfloat z) const
+     {
+         Arguments_must_be_floating_point_values<FNfloat>();
+ 
+@@ -350,7 +350,7 @@ public:
+     /// noise = GetNoise(x, y)</code>
+     /// </example>
+     template <typename FNfloat>
+-    void DomainWarp(FNfloat& x, FNfloat& y)
++    void DomainWarp(FNfloat& x, FNfloat& y) const
+     {
+         Arguments_must_be_floating_point_values<FNfloat>();
+ 
+@@ -377,7 +377,7 @@ public:
+     /// noise = GetNoise(x, y, z)</code>
+     /// </example>
+     template <typename FNfloat>
+-    void DomainWarp(FNfloat& x, FNfloat& y, FNfloat& z)
++    void DomainWarp(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         Arguments_must_be_floating_point_values<FNfloat>();
+ 
+@@ -528,7 +528,7 @@ private:
+     }
+ 
+ 
+-    float GradCoord(int seed, int xPrimed, int yPrimed, float xd, float yd)
++    float GradCoord(int seed, int xPrimed, int yPrimed, float xd, float yd) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed);
+         hash ^= hash >> 15;
+@@ -541,7 +541,7 @@ private:
+     }
+ 
+ 
+-    float GradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd)
++    float GradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed, zPrimed);
+         hash ^= hash >> 15;
+@@ -555,7 +555,7 @@ private:
+     }
+ 
+ 
+-    void GradCoordOut(int seed, int xPrimed, int yPrimed, float& xo, float& yo)
++    void GradCoordOut(int seed, int xPrimed, int yPrimed, float& xo, float& yo) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed) & (255 << 1);
+ 
+@@ -564,7 +564,7 @@ private:
+     }
+ 
+ 
+-    void GradCoordOut(int seed, int xPrimed, int yPrimed, int zPrimed, float& xo, float& yo, float& zo)
++    void GradCoordOut(int seed, int xPrimed, int yPrimed, int zPrimed, float& xo, float& yo, float& zo) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed, zPrimed) & (255 << 2);
+ 
+@@ -574,7 +574,7 @@ private:
+     }
+ 
+ 
+-    void GradCoordDual(int seed, int xPrimed, int yPrimed, float xd, float yd, float& xo, float& yo)
++    void GradCoordDual(int seed, int xPrimed, int yPrimed, float xd, float yd, float& xo, float& yo) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed);
+         int index1 = hash & (127 << 1);
+@@ -592,7 +592,7 @@ private:
+     }
+ 
+ 
+-    void GradCoordDual(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd, float& xo, float& yo, float& zo)
++    void GradCoordDual(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd, float& xo, float& yo, float& zo) const
+     {
+         int hash = Hash(seed, xPrimed, yPrimed, zPrimed);
+         int index1 = hash & (63 << 2);
+@@ -616,7 +616,7 @@ private:
+     // Generic noise gen
+ 
+     template <typename FNfloat>
+-    float GenNoiseSingle(int seed, FNfloat x, FNfloat y)
++    float GenNoiseSingle(int seed, FNfloat x, FNfloat y) const
+     {
+         switch (mNoiseType)
+         {
+@@ -638,7 +638,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float GenNoiseSingle(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float GenNoiseSingle(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         switch (mNoiseType)
+         {
+@@ -663,7 +663,7 @@ private:
+     // Noise Coordinate Transforms (frequency, and possible skew or rotation)
+ 
+     template <typename FNfloat>
+-    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y)
++    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y) const
+     {
+         x *= mFrequency;
+         y *= mFrequency;
+@@ -686,7 +686,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y, FNfloat& z)
++    void TransformNoiseCoordinate(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         x *= mFrequency;
+         y *= mFrequency;
+@@ -757,7 +757,7 @@ private:
+     // Domain Warp Coordinate Transforms
+ 
+     template <typename FNfloat>
+-    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y)
++    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y) const
+     {
+         switch (mDomainWarpType)
+         {
+@@ -777,7 +777,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y, FNfloat& z)
++    void TransformDomainWarpCoordinate(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         switch (mWarpTransformType3D)
+         {
+@@ -844,7 +844,7 @@ private:
+     // Fractal FBm
+ 
+     template <typename FNfloat>
+-    float GenFractalFBm(FNfloat x, FNfloat y)
++    float GenFractalFBm(FNfloat x, FNfloat y) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -865,7 +865,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float GenFractalFBm(FNfloat x, FNfloat y, FNfloat z)
++    float GenFractalFBm(FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -890,7 +890,7 @@ private:
+     // Fractal Ridged
+ 
+     template <typename FNfloat>
+-    float GenFractalRidged(FNfloat x, FNfloat y)
++    float GenFractalRidged(FNfloat x, FNfloat y) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -911,7 +911,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float GenFractalRidged(FNfloat x, FNfloat y, FNfloat z)
++    float GenFractalRidged(FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -936,7 +936,7 @@ private:
+     // Fractal PingPong 
+ 
+     template <typename FNfloat>
+-    float GenFractalPingPong(FNfloat x, FNfloat y)
++    float GenFractalPingPong(FNfloat x, FNfloat y) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -957,7 +957,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float GenFractalPingPong(FNfloat x, FNfloat y, FNfloat z)
++    float GenFractalPingPong(FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int seed = mSeed;
+         float sum = 0;
+@@ -982,7 +982,7 @@ private:
+     // Simplex/OpenSimplex2 Noise
+ 
+     template <typename FNfloat>
+-    float SingleSimplex(int seed, FNfloat x, FNfloat y)
++    float SingleSimplex(int seed, FNfloat x, FNfloat y) const
+     {
+         // 2D OpenSimplex2 case uses the same algorithm as ordinary Simplex.
+ 
+@@ -1053,7 +1053,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SingleOpenSimplex2(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SingleOpenSimplex2(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         // 3D OpenSimplex2 case uses two offset rotated cube grids.
+ 
+@@ -1155,7 +1155,7 @@ private:
+     // OpenSimplex2S Noise
+ 
+     template <typename FNfloat>
+-    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y)
++    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y) const
+     {
+         // 2D OpenSimplex2S case is a modified 2D simplex noise.
+ 
+@@ -1286,7 +1286,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SingleOpenSimplex2S(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         // 3D OpenSimplex2S case uses two offset rotated cube grids.
+ 
+@@ -1482,7 +1482,7 @@ private:
+     // Cellular Noise
+ 
+     template <typename FNfloat>
+-    float SingleCellular(int seed, FNfloat x, FNfloat y)
++    float SingleCellular(int seed, FNfloat x, FNfloat y) const
+     {
+         int xr = FastRound(x);
+         int yr = FastRound(y);
+@@ -1612,7 +1612,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SingleCellular(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SingleCellular(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int xr = FastRound(x);
+         int yr = FastRound(y);
+@@ -1769,7 +1769,7 @@ private:
+     // Perlin Noise
+ 
+     template <typename FNfloat>
+-    float SinglePerlin(int seed, FNfloat x, FNfloat y)
++    float SinglePerlin(int seed, FNfloat x, FNfloat y) const
+     {
+         int x0 = FastFloor(x);
+         int y0 = FastFloor(y);
+@@ -1794,7 +1794,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SinglePerlin(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SinglePerlin(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int x0 = FastFloor(x);
+         int y0 = FastFloor(y);
+@@ -1833,7 +1833,7 @@ private:
+     // Value Cubic Noise
+ 
+     template <typename FNfloat>
+-    float SingleValueCubic(int seed, FNfloat x, FNfloat y)
++    float SingleValueCubic(int seed, FNfloat x, FNfloat y) const
+     {
+         int x1 = FastFloor(x);
+         int y1 = FastFloor(y);
+@@ -1863,7 +1863,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SingleValueCubic(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SingleValueCubic(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int x1 = FastFloor(x);
+         int y1 = FastFloor(y);
+@@ -1920,7 +1920,7 @@ private:
+     // Value Noise
+ 
+     template <typename FNfloat>
+-    float SingleValue(int seed, FNfloat x, FNfloat y)
++    float SingleValue(int seed, FNfloat x, FNfloat y) const
+     {
+         int x0 = FastFloor(x);
+         int y0 = FastFloor(y);
+@@ -1940,7 +1940,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    float SingleValue(int seed, FNfloat x, FNfloat y, FNfloat z)
++    float SingleValue(int seed, FNfloat x, FNfloat y, FNfloat z) const
+     {
+         int x0 = FastFloor(x);
+         int y0 = FastFloor(y);
+@@ -1972,7 +1972,7 @@ private:
+     // Domain Warp
+ 
+     template <typename FNfloat>
+-    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr)
++    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr) const
+     {
+         switch (mDomainWarpType)
+         {
+@@ -1989,7 +1989,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr)
++    void DoSingleDomainWarp(int seed, float amp, float freq, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr) const
+     {
+         switch (mDomainWarpType)
+         {
+@@ -2009,7 +2009,7 @@ private:
+     // Domain Warp Single Wrapper
+ 
+     template <typename FNfloat>
+-    void DomainWarpSingle(FNfloat& x, FNfloat& y)
++    void DomainWarpSingle(FNfloat& x, FNfloat& y) const
+     {
+         int seed = mSeed;
+         float amp = mDomainWarpAmp * mFractalBounding;
+@@ -2023,7 +2023,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void DomainWarpSingle(FNfloat& x, FNfloat& y, FNfloat& z)
++    void DomainWarpSingle(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         int seed = mSeed;
+         float amp = mDomainWarpAmp * mFractalBounding;
+@@ -2041,7 +2041,7 @@ private:
+     // Domain Warp Fractal Progressive
+ 
+     template <typename FNfloat>
+-    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y)
++    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y) const
+     {
+         int seed = mSeed;
+         float amp = mDomainWarpAmp * mFractalBounding;
+@@ -2062,7 +2062,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y, FNfloat& z)
++    void DomainWarpFractalProgressive(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         int seed = mSeed;
+         float amp = mDomainWarpAmp * mFractalBounding;
+@@ -2087,7 +2087,7 @@ private:
+     // Domain Warp Fractal Independant
+ 
+     template <typename FNfloat>
+-    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y)
++    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y) const
+     {
+         FNfloat xs = x;
+         FNfloat ys = y;
+@@ -2108,7 +2108,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y, FNfloat& z)
++    void DomainWarpFractalIndependent(FNfloat& x, FNfloat& y, FNfloat& z) const
+     {
+         FNfloat xs = x;
+         FNfloat ys = y;
+@@ -2133,7 +2133,7 @@ private:
+     // Domain Warp Basic Grid
+ 
+     template <typename FNfloat>
+-    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr)
++    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr) const
+     {
+         FNfloat xf = x * frequency;
+         FNfloat yf = y * frequency;
+@@ -2166,7 +2166,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr)
++    void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr) const
+     {
+         FNfloat xf = x * frequency;
+         FNfloat yf = y * frequency;
+@@ -2228,7 +2228,7 @@ private:
+     // Domain Warp Simplex/OpenSimplex2
+ 
+     template <typename FNfloat>
+-    void SingleDomainWarpSimplexGradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr, bool outGradOnly)
++    void SingleDomainWarpSimplexGradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat& xr, FNfloat& yr, bool outGradOnly) const
+     {
+         const float SQRT3 = 1.7320508075688772935274463415059f;
+         const float G2 = (3 - SQRT3) / 6;
+@@ -2326,7 +2326,7 @@ private:
+     }
+ 
+     template <typename FNfloat>
+-    void SingleDomainWarpOpenSimplex2Gradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr, bool outGradOnly)
++    void SingleDomainWarpOpenSimplex2Gradient(int seed, float warpAmp, float frequency, FNfloat x, FNfloat y, FNfloat z, FNfloat& xr, FNfloat& yr, FNfloat& zr, bool outGradOnly) const
+     {
+         x *= frequency;
+         y *= frequency;