#include "fast_noise_2.h" #include "../math/funcs.h" #include FastNoise2::FastNoise2() { // Setup default update_generator(); } void FastNoise2::set_encoded_node_tree(String data) { if (data != _last_set_encoded_node_tree) { _last_set_encoded_node_tree = data; emit_changed(); } } bool FastNoise2::is_valid() const { return _generator.get() != nullptr; } String FastNoise2::get_encoded_node_tree() const { // There is no way to get back an encoded node tree from `FastNoise::SmartNode<>` return _last_set_encoded_node_tree; } FastNoise2::SIMDLevel FastNoise2::get_simd_level() const { ERR_FAIL_COND_V(!is_valid(), SIMD_NULL); return SIMDLevel(_generator->GetSIMDLevel()); } String FastNoise2::get_simd_level_name(SIMDLevel level) { switch (level) { case SIMD_NULL: return "Null"; case SIMD_SCALAR: return "Scalar"; case SIMD_SSE: return "SSE"; case SIMD_SSE2: return "SSE2"; case SIMD_SSE3: return "SSE3"; case SIMD_SSE41: return "SSE41"; case SIMD_SSE42: return "SSE42"; case SIMD_AVX: return "AVX"; case SIMD_AVX2: return "AVX2"; case SIMD_AVX512: return "AVX512"; case SIMD_NEON: return "NEON"; default: ERR_PRINT(String("Unknown SIMD level {0}").format(varray(level))); return "Error"; } } void FastNoise2::set_seed(int seed) { if (_seed == seed) { return; } _seed = seed; emit_changed(); } int FastNoise2::get_seed() const { return _seed; } void FastNoise2::set_noise_type(NoiseType type) { if (_noise_type == type) { return; } _noise_type = type; emit_changed(); } FastNoise2::NoiseType FastNoise2::get_noise_type() const { return _noise_type; } void FastNoise2::set_period(float p) { if (p < 0.0001f) { p = 0.0001f; } if (_period == p) { return; } _period = p; emit_changed(); } float FastNoise2::get_period() const { return _period; } void FastNoise2::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; emit_changed(); } void FastNoise2::set_fractal_type(FractalType type) { if (_fractal_type == type) { return; } _fractal_type = type; emit_changed(); } FastNoise2::FractalType FastNoise2::get_fractal_type() const { return _fractal_type; } int FastNoise2::get_fractal_octaves() const { return _fractal_octaves; } void FastNoise2::set_fractal_lacunarity(float lacunarity) { if (_fractal_lacunarity == lacunarity) { return; } _fractal_lacunarity = lacunarity; emit_changed(); } float FastNoise2::get_fractal_lacunarity() const { return _fractal_lacunarity; } void FastNoise2::set_fractal_gain(float gain) { if (_fractal_gain == gain) { return; } _fractal_gain = gain; emit_changed(); } float FastNoise2::get_fractal_gain() const { return _fractal_gain; } void FastNoise2::set_fractal_ping_pong_strength(float s) { if (_fractal_ping_pong_strength == s) { return; } _fractal_ping_pong_strength = s; emit_changed(); } float FastNoise2::get_fractal_ping_pong_strength() const { return _fractal_ping_pong_strength; } void FastNoise2::set_terrace_enabled(bool enable) { if (enable == _terrace_enabled) { return; } _terrace_enabled = enable; emit_changed(); } bool FastNoise2::is_terrace_enabled() const { return _terrace_enabled; } void FastNoise2::set_terrace_multiplier(float m) { const float clamped_multiplier = max(m, 0.f); if (clamped_multiplier == _terrace_multiplier) { return; } _terrace_multiplier = clamped_multiplier; emit_changed(); } float FastNoise2::get_terrace_multiplier() const { return _terrace_multiplier; } void FastNoise2::set_terrace_smoothness(float s) { const float clamped_smoothness = max(s, 0.f); if (_terrace_smoothness == clamped_smoothness) { return; } _terrace_smoothness = clamped_smoothness; emit_changed(); } float FastNoise2::get_terrace_smoothness() const { return _terrace_smoothness; } void FastNoise2::set_remap_enabled(bool enabled) { if (enabled != _remap_enabled) { _remap_enabled = enabled; emit_changed(); } } bool FastNoise2::is_remap_enabled() const { return _remap_enabled; } void FastNoise2::set_remap_min(float min_value) { if (min_value != _remap_min) { _remap_min = min_value; emit_changed(); } } float FastNoise2::get_remap_min() const { return _remap_min; } void FastNoise2::set_remap_max(float max_value) { if (max_value != _remap_max) { _remap_max = max_value; emit_changed(); } } float FastNoise2::get_remap_max() const { return _remap_max; } void FastNoise2::set_cellular_distance_function(CellularDistanceFunction cdf) { if (cdf == _cellular_distance_function) { return; } _cellular_distance_function = cdf; emit_changed(); } FastNoise2::CellularDistanceFunction FastNoise2::get_cellular_distance_function() const { return _cellular_distance_function; } void FastNoise2::set_cellular_return_type(CellularReturnType rt) { if (_cellular_return_type == rt) { return; } _cellular_return_type = rt; emit_changed(); } FastNoise2::CellularReturnType FastNoise2::get_cellular_return_type() const { return _cellular_return_type; } void FastNoise2::set_cellular_jitter(float jitter) { jitter = clamp(jitter, 0.f, 1.f); if (_cellular_jitter == jitter) { return; } _cellular_jitter = jitter; emit_changed(); } float FastNoise2::get_cellular_jitter() const { return _cellular_jitter; } float FastNoise2::get_noise_2d_single(Vector2 pos) const { ERR_FAIL_COND_V(!is_valid(), 0.0); return _generator->GenSingle2D(pos.x, pos.y, _seed); } float FastNoise2::get_noise_3d_single(Vector3 pos) const { ERR_FAIL_COND_V(!is_valid(), 0.0); return _generator->GenSingle3D(pos.x, pos.y, pos.z, _seed); } void FastNoise2::get_noise_2d_series(Span src_x, Span src_y, Span dst) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(src_x.size() != src_y.size() || src_x.size() != dst.size()); _generator->GenPositionArray2D(dst.data(), dst.size(), src_x.data(), src_y.data(), 0, 0, _seed); } void FastNoise2::get_noise_3d_series( Span src_x, Span src_y, Span src_z, Span dst) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(src_x.size() != src_y.size() || src_x.size() != src_z.size() || src_x.size() != dst.size()); _generator->GenPositionArray3D(dst.data(), dst.size(), src_x.data(), src_y.data(), src_z.data(), 0, 0, 0, _seed); } void FastNoise2::get_noise_2d_grid(Vector2 origin, Vector2i size, Span dst) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(size.x < 0 || size.y < 0); ERR_FAIL_COND(dst.size() != size.x * size.y); _generator->GenUniformGrid2D(dst.data(), origin.x, origin.y, size.x, size.y, 1.f, _seed); } void FastNoise2::get_noise_3d_grid(Vector3 origin, Vector3i size, Span dst) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(!is_valid_size(size)); ERR_FAIL_COND(dst.size() != size.x * size.y * size.z); _generator->GenUniformGrid3D(dst.data(), origin.x, origin.y, origin.z, size.x, size.y, size.z, 1.f, _seed); } void FastNoise2::get_noise_2d_grid_tileable(Vector2i size, Span dst) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(size.x < 0 || size.y < 0); ERR_FAIL_COND(dst.size() != size.x * size.y); _generator->GenTileable2D(dst.data(), size.x, size.y, 1.f, _seed); } void FastNoise2::generate_image(Ref image, bool tileable) const { ERR_FAIL_COND(!is_valid()); ERR_FAIL_COND(image.is_null()); std::vector buffer; buffer.resize(image->get_width() * image->get_height()); if (tileable) { get_noise_2d_grid_tileable(Vector2i(image->get_width(), image->get_height()), to_span(buffer)); } else { get_noise_2d_grid(Vector2(), Vector2i(image->get_width(), image->get_height()), to_span(buffer)); } unsigned int i = 0; for (int y = 0; y < image->get_height(); ++y) { for (int x = 0; x < image->get_width(); ++x) { #ifdef DEBUG_ENABLED CRASH_COND(i >= buffer.size()); #endif // Assuming -1..1 output. Some noise types can have different range though. const float n = buffer[i] * 0.5f + 0.5f; ++i; image->set_pixel(x, y, Color(n, n, n)); } } } void FastNoise2::update_generator() { if (_noise_type == TYPE_ENCODED_NODE_TREE) { CharString cs = _last_set_encoded_node_tree.utf8(); _generator = FastNoise::NewFromEncodedNodeTree(cs.get_data()); ERR_FAIL_COND(!is_valid()); // TODO Maybe apply period modifier here? // NoiseTool assumes we scale input coordinates so typical noise made in there has period 1... return; } FastNoise::SmartNode noise_node; switch (_noise_type) { case TYPE_OPEN_SIMPLEX_2: noise_node = FastNoise::New(); break; case TYPE_SIMPLEX: noise_node = FastNoise::New(); break; case TYPE_PERLIN: noise_node = FastNoise::New(); break; case TYPE_VALUE: noise_node = FastNoise::New(); break; case TYPE_CELLULAR: { FastNoise::SmartNode cd = FastNoise::New(); cd->SetDistanceFunction(FastNoise::DistanceFunction(_cellular_distance_function)); cd->SetReturnType(FastNoise::CellularDistance::ReturnType(_cellular_return_type)); cd->SetJitterModifier(_cellular_jitter); noise_node = cd; } break; default: ERR_PRINT(String("Unknown noise type {0}").format(varray(_noise_type))); return; } ERR_FAIL_COND(noise_node.get() == nullptr); FastNoise::SmartNode<> generator_node = noise_node; if (_period != 1.f) { FastNoise::SmartNode scale_node = FastNoise::New(); scale_node->SetScale(1.f / _period); scale_node->SetSource(generator_node); generator_node = scale_node; } FastNoise::SmartNode> fractal_node; switch (_fractal_type) { case FRACTAL_NONE: break; case FRACTAL_FBM: fractal_node = FastNoise::New(); break; case FRACTAL_PING_PONG: { FastNoise::SmartNode pp_node = FastNoise::New(); pp_node->SetPingPongStrength(_fractal_ping_pong_strength); fractal_node = pp_node; } break; case FRACTAL_RIDGED: fractal_node = FastNoise::New(); break; default: ERR_PRINT(String("Unknown fractal type {0}").format(varray(_fractal_type))); return; } if (fractal_node) { fractal_node->SetGain(_fractal_gain); fractal_node->SetLacunarity(_fractal_lacunarity); fractal_node->SetOctaveCount(_fractal_octaves); //fractal_node->SetWeightedStrength(_fractal_weighted_strength); fractal_node->SetSource(generator_node); generator_node = fractal_node; } if (_terrace_enabled) { FastNoise::SmartNode terrace_node = FastNoise::New(); terrace_node->SetMultiplier(_terrace_multiplier); terrace_node->SetSmoothness(_terrace_smoothness); terrace_node->SetSource(generator_node); generator_node = terrace_node; } if (_remap_enabled) { FastNoise::SmartNode remap_node = FastNoise::New(); remap_node->SetRemap(-1.0, 1.0, _remap_min, _remap_max); remap_node->SetSource(generator_node); generator_node = remap_node; } ERR_FAIL_COND(generator_node.get() == nullptr); _generator = generator_node; } String FastNoise2::_b_get_simd_level_name(SIMDLevel level) { return get_simd_level_name(level); } void FastNoise2::_bind_methods() { ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoise2::set_noise_type); ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoise2::get_noise_type); ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoise2::set_seed); ClassDB::bind_method(D_METHOD("get_seed"), &FastNoise2::get_seed); ClassDB::bind_method(D_METHOD("set_period", "period"), &FastNoise2::set_period); ClassDB::bind_method(D_METHOD("get_period"), &FastNoise2::get_period); // ClassDB::bind_method(D_METHOD("set_warp_noise", "gradient_noise"), &FastNoise2::set_warp_noise); // ClassDB::bind_method(D_METHOD("get_warp_noise"), &FastNoise2::get_warp_noise); ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoise2::set_fractal_type); ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoise2::get_fractal_type); ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octaves"), &FastNoise2::set_fractal_octaves); ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoise2::get_fractal_octaves); ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoise2::set_fractal_lacunarity); ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoise2::get_fractal_lacunarity); ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoise2::set_fractal_gain); ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoise2::get_fractal_gain); ClassDB::bind_method( D_METHOD("set_fractal_ping_pong_strength", "strength"), &FastNoise2::set_fractal_ping_pong_strength); ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoise2::get_fractal_ping_pong_strength); // ClassDB::bind_method( // D_METHOD("set_fractal_weighted_strength", "strength"), &FastNoise2::set_fractal_weighted_strength); // ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoise2::get_fractal_weighted_strength); ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "cell_distance_func"), &FastNoise2::set_cellular_distance_function); ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoise2::get_cellular_distance_function); ClassDB::bind_method(D_METHOD("set_cellular_return_type", "return_type"), &FastNoise2::set_cellular_return_type); ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoise2::get_cellular_return_type); ClassDB::bind_method(D_METHOD("set_cellular_jitter", "return_type"), &FastNoise2::set_cellular_jitter); ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoise2::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("set_terrace_enabled", "enabled"), &FastNoise2::set_terrace_enabled); ClassDB::bind_method(D_METHOD("is_terrace_enabled"), &FastNoise2::is_terrace_enabled); ClassDB::bind_method(D_METHOD("set_terrace_multiplier", "multiplier"), &FastNoise2::set_terrace_multiplier); ClassDB::bind_method(D_METHOD("get_terrace_multiplier"), &FastNoise2::get_terrace_multiplier); ClassDB::bind_method(D_METHOD("set_terrace_smoothness", "smoothness"), &FastNoise2::set_terrace_smoothness); ClassDB::bind_method(D_METHOD("get_terrace_smoothness"), &FastNoise2::get_terrace_smoothness); ClassDB::bind_method(D_METHOD("set_remap_enabled", "enabled"), &FastNoise2::set_remap_enabled); ClassDB::bind_method(D_METHOD("is_remap_enabled"), &FastNoise2::is_remap_enabled); ClassDB::bind_method(D_METHOD("set_remap_min", "min_value"), &FastNoise2::set_remap_min); ClassDB::bind_method(D_METHOD("get_remap_min"), &FastNoise2::get_remap_min); ClassDB::bind_method(D_METHOD("set_remap_max", "max_value"), &FastNoise2::set_remap_max); ClassDB::bind_method(D_METHOD("get_remap_max"), &FastNoise2::get_remap_max); ClassDB::bind_method(D_METHOD("set_encoded_node_tree", "code"), &FastNoise2::set_encoded_node_tree); ClassDB::bind_method(D_METHOD("get_encoded_node_tree"), &FastNoise2::get_encoded_node_tree); ClassDB::bind_method(D_METHOD("get_noise_2d_single", "pos"), &FastNoise2::get_noise_2d_single); ClassDB::bind_method(D_METHOD("get_noise_3d_single", "pos"), &FastNoise2::get_noise_3d_single); ClassDB::bind_method(D_METHOD("generate_image", "image", "tileable"), &FastNoise2::generate_image); ClassDB::bind_method(D_METHOD("get_simd_level_name", "level"), &FastNoise2::_b_get_simd_level_name); // ClassDB::bind_method(D_METHOD("_on_warp_noise_changed"), &FastNoiseLite::_on_warp_noise_changed); ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, NOISE_TYPE_HINT_STRING), "set_noise_type", "get_noise_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "period", PROPERTY_HINT_RANGE, "0.0001,10000.0,0.1,exp"), "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, FRACTAL_TYPE_HINT_STRING), "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::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_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength"); // ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "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, CELLULAR_DISTANCE_FUNCTION_HINT_STRING), "set_cellular_distance_function", "get_cellular_distance_function"); ADD_PROPERTY( PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, CELLULAR_RETURN_TYPE_HINT_STRING), "set_cellular_return_type", "get_cellular_return_type"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_cellular_jitter", "get_cellular_jitter"); ADD_GROUP("Terrace", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "terrace_enabled"), "set_terrace_enabled", "is_terrace_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "terrace_multiplier", PROPERTY_HINT_RANGE, "0.0,100.0,0.1"), "set_terrace_multiplier", "get_terrace_multiplier"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "terrace_smoothness", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_terrace_smoothness", "get_terrace_smoothness"); ADD_GROUP("Remap", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "remap_enabled"), "set_remap_enabled", "is_remap_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "remap_min"), "set_remap_min", "get_remap_min"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "remap_max"), "set_remap_max", "get_remap_max"); ADD_GROUP("Advanced", ""); ADD_PROPERTY(PropertyInfo(Variant::STRING, "encoded_node_tree"), "set_encoded_node_tree", "get_encoded_node_tree"); // 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_SIMPLEX); BIND_ENUM_CONSTANT(TYPE_PERLIN); BIND_ENUM_CONSTANT(TYPE_VALUE); BIND_ENUM_CONSTANT(TYPE_CELLULAR); BIND_ENUM_CONSTANT(TYPE_ENCODED_NODE_TREE); 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_DISTANCE_MAX_AXIS); BIND_ENUM_CONSTANT(CELLULAR_RETURN_INDEX_0); BIND_ENUM_CONSTANT(CELLULAR_RETURN_INDEX_0_ADD_1); BIND_ENUM_CONSTANT(CELLULAR_RETURN_INDEX_0_SUB_1); BIND_ENUM_CONSTANT(CELLULAR_RETURN_INDEX_0_MUL_1); BIND_ENUM_CONSTANT(CELLULAR_RETURN_INDEX_0_DIV_1); BIND_ENUM_CONSTANT(SIMD_NULL); BIND_ENUM_CONSTANT(SIMD_SCALAR); BIND_ENUM_CONSTANT(SIMD_SSE); BIND_ENUM_CONSTANT(SIMD_SSE2); BIND_ENUM_CONSTANT(SIMD_SSE3); BIND_ENUM_CONSTANT(SIMD_SSSE3); BIND_ENUM_CONSTANT(SIMD_SSE41); BIND_ENUM_CONSTANT(SIMD_SSE42); BIND_ENUM_CONSTANT(SIMD_AVX); BIND_ENUM_CONSTANT(SIMD_AVX2); BIND_ENUM_CONSTANT(SIMD_AVX512); BIND_ENUM_CONSTANT(SIMD_NEON); }