Updated and integrated FastNoise2

master
Marc Gilleron 2021-12-31 05:06:00 +00:00
parent 03f2f8c4b3
commit 56b4920902
60 changed files with 5217 additions and 1279 deletions

38
SCsub
View File

@ -1,11 +1,8 @@
Import('env')
Import('env_modules')
# TODO Support is turned off for now because Godot 3 doesn't compile with C++17.
# FastNoise2 use C++17 features and STL both in its headers and runtime as well.
# SIMD noise support would have to wait for Godot 4 (or GDNative port, which will only be worth in Godot 4 too)
FAST_NOISE_2_SRC = False
FAST_NOISE_2_STATIC = False
# Note, support for FastNoise2 requires C++17
FAST_NOISE_2_SRC = True
RUN_TESTS = False
if env['target'] == 'debug':
@ -94,34 +91,17 @@ if env["platform"] == "windows":
if FAST_NOISE_2_SRC:
# Build from source. Should be the simplest, but requires C++17
SConscript('thirdparty/fast_noise_2/SConscript', exports = ["env", "env_voxel"])
if FAST_NOISE_2_STATIC:
# Build from a pre-built static lib. This requires to check every build combination (and have them as well),
# AND it also requires C++17 due to differences of runtimes.
fn2_path = "C:/Projects/FastNoise2/0.7-alpha"
if env["platform"] == "windows":
if env.msvc:
if env['bits'] == '64':
env_voxel.Append(LIBPATH = [fn2_path + "/lib/win64-msvc"])
else:
raise RuntimeError("FastNoise2 32-bit builds are not supported yet")
else:
raise RuntimeError("FastNoise2 can only be built with MSVC at the moment")
env_voxel.Append(CPPPATH = [fn2_path + '/include'])
if env['target'] == 'debug':
env_voxel.Append(LIBS = ['FastNoise'])
else:
env_voxel.Append(LIBS = ['FastNoiseD'])
else:
raise RuntimeError("FastNoise2 can only be built on Windows at the moment")
env_voxel.Append(CPPPATH=["thirdparty/fast_noise_2/include"])
voxel_files += [
"util/noise/fast_noise_2.cpp"
]
env_voxel.Append(CPPDEFINES = ["VOXEL_FAST_NOISE_2_SUPPORT"])
if env["tools"]:
voxel_files += [
"editor/fast_noise_2/*.cpp"
]
# ----------------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,117 @@
#include "fast_noise_2_editor_plugin.h"
#include "../../util/noise/fast_noise_2.h"
#include <core/core_string_names.h>
#include <editor/editor_scale.h>
class FastNoise2Viewer : public Control {
GDCLASS(FastNoise2Viewer, Control)
public:
static const int PREVIEW_WIDTH = 300;
static const int PREVIEW_HEIGHT = 150;
FastNoise2Viewer() {
set_custom_minimum_size(Vector2(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);
}
void set_noise(Ref<FastNoise2> noise) {
if (_noise == noise) {
return;
}
if (_noise.is_valid()) {
_noise->disconnect(
CoreStringNames::get_singleton()->changed, callable_mp(this, &FastNoise2Viewer::_on_noise_changed));
}
_noise = noise;
if (_noise.is_valid()) {
_noise->connect(
CoreStringNames::get_singleton()->changed, callable_mp(this, &FastNoise2Viewer::_on_noise_changed));
set_process(true);
update_preview();
} else {
set_process(false);
_time_before_update = -1.f;
}
}
private:
void _on_noise_changed() {
_time_before_update = 0.5f;
}
void _notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PROCESS: {
if (_time_before_update > 0.f) {
_time_before_update -= get_process_delta_time();
if (_time_before_update <= 0.f) {
update_preview();
}
}
} break;
}
}
// TODO Use thread?
void update_preview() {
_noise->update_generator();
const Vector2i preview_size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
Ref<Image> im;
im.instantiate();
im->create(preview_size.x, preview_size.y, false, Image::FORMAT_RGB8);
if (_noise.is_valid()) {
_noise->generate_image(im);
}
Ref<ImageTexture> tex;
tex.instantiate();
tex->create_from_image(im);
_texture_rect->set_texture(tex);
}
Ref<FastNoise2> _noise;
float _time_before_update = -1.f;
TextureRect *_texture_rect = nullptr;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FastNoise2EditorInspectorPlugin : public EditorInspectorPlugin {
GDCLASS(FastNoise2EditorInspectorPlugin, EditorInspectorPlugin)
public:
bool can_handle(Object *p_object) override {
return Object::cast_to<FastNoise2>(p_object) != nullptr;
}
void parse_begin(Object *p_object) override {
FastNoise2 *noise_ptr = Object::cast_to<FastNoise2>(p_object);
if (noise_ptr) {
Ref<FastNoise2> noise(noise_ptr);
FastNoise2Viewer *viewer = memnew(FastNoise2Viewer);
viewer->set_noise(noise);
add_custom_control(viewer);
return;
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FastNoise2EditorPlugin::FastNoise2EditorPlugin(EditorNode *p_node) {
Ref<FastNoise2EditorInspectorPlugin> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
}

View File

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

View File

@ -150,7 +150,7 @@ class FastNoiseLiteEditorInspectorPlugin : public EditorInspectorPlugin {
GDCLASS(FastNoiseLiteEditorInspectorPlugin, EditorInspectorPlugin)
public:
bool can_handle(Object *p_object) override {
return Object::cast_to<FastNoiseLite>(p_object) != NULL || Object::cast_to<FastNoiseLiteGradient>(p_object);
return Object::cast_to<FastNoiseLite>(p_object) != nullptr || Object::cast_to<FastNoiseLiteGradient>(p_object);
}
void parse_begin(Object *p_object) override {

View File

@ -1,4 +1,5 @@
#include "register_types.h"
#include "constants/voxel_string_names.h"
#include "edition/voxel_tool.h"
#include "edition/voxel_tool_buffer.h"
#include "edition/voxel_tool_lod_terrain.h"
@ -24,6 +25,8 @@
#include "streams/vox_loader.h"
#include "streams/voxel_stream_block_files.h"
#include "streams/voxel_stream_script.h"
#include "terrain/instancing/voxel_instance_component.h"
#include "terrain/instancing/voxel_instance_library_scene_item.h"
#include "terrain/instancing/voxel_instancer.h"
#include "terrain/voxel_box_mover.h"
#include "terrain/voxel_lod_terrain.h"
@ -31,15 +34,13 @@
#include "terrain/voxel_terrain.h"
#include "terrain/voxel_viewer.h"
#include "util/macros.h"
#ifdef VOXEL_FAST_NOISE_2_SUPPORT
#include "util/noise/fast_noise_2.h"
#endif
#include "constants/voxel_string_names.h"
#include "terrain/instancing/voxel_instance_component.h"
#include "terrain/instancing/voxel_instance_library_scene_item.h"
#include "util/noise/fast_noise_lite.h"
#include "util/noise/fast_noise_lite_gradient.h"
#ifdef VOXEL_ENABLE_FAST_NOISE_2
#include "util/noise/fast_noise_2.h"
#endif
#include <core/config/engine.h>
#ifdef TOOLS_ENABLED
@ -51,7 +52,10 @@
#include "editor/terrain/voxel_terrain_editor_plugin.h"
#include "editor/vox/vox_editor_plugin.h"
#include "editor/voxel_debug.h"
#ifdef VOXEL_ENABLE_FAST_NOISE_2
#include "editor/fast_noise_2/fast_noise_2_editor_plugin.h"
#endif
#endif // TOOLS_ENABLED
#ifdef VOXEL_RUN_TESTS
#include "tests/tests.h"
@ -121,7 +125,7 @@ void register_voxel_types() {
ClassDB::register_class<FastNoiseLite>();
ClassDB::register_class<FastNoiseLiteGradient>();
// See SCsub
#ifdef VOXEL_FAST_NOISE_2_SUPPORT
#ifdef VOXEL_ENABLE_FAST_NOISE_2
ClassDB::register_class<FastNoise2>();
#endif
@ -153,7 +157,10 @@ void register_voxel_types() {
EditorPlugins::add_by_type<FastNoiseLiteEditorPlugin>();
EditorPlugins::add_by_type<VoxEditorPlugin>();
EditorPlugins::add_by_type<VoxelInstancerEditorPlugin>();
#ifdef VOXEL_ENABLE_FAST_NOISE_2
EditorPlugins::add_by_type<FastNoise2EditorPlugin>();
#endif
#endif // TOOLS_ENABLED
#ifdef VOXEL_RUN_TESTS
zylann::voxel::tests::run_voxel_tests();

View File

@ -9,6 +9,10 @@
#include "test_octree.h"
#include "testing.h"
#ifdef VOXEL_ENABLE_FAST_NOISE_2
#include "../util/noise/fast_noise_2.h"
#endif
#include <core/io/dir_access.h>
#include <core/string/print_string.h>
#include <core/templates/hash_map.h>
@ -1104,6 +1108,24 @@ void test_region_file() {
}
}
#ifdef VOXEL_ENABLE_FAST_NOISE_2
void test_fast_noise_2() {
// Very basic test
Ref<FastNoise2> noise;
noise.instantiate();
float nv = noise->get_noise_2d_single(Vector2(42, 666));
print_line(String("SIMD level: {0}").format(varray(noise->get_simd_level())));
print_line(String("Noise: {0}").format(varray(nv)));
Ref<Image> im;
im.instantiate();
im->create(256, 256, false, Image::FORMAT_RGB8);
noise->generate_image(im);
//im->save_png("zylann_test_fastnoise2.png");
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define VOXEL_TEST(fname) \
@ -1132,6 +1154,9 @@ void run_voxel_tests() {
VOXEL_TEST(test_voxel_buffer_create);
VOXEL_TEST(test_block_serializer);
VOXEL_TEST(test_region_file);
#ifdef VOXEL_ENABLE_FAST_NOISE_2
VOXEL_TEST(test_fast_noise_2);
#endif
print_line("------------ Voxel tests end -------------");
}

47
thirdparty/fast_noise_2/.clang-format vendored Normal file
View File

@ -0,0 +1,47 @@
---
Language: Cpp
BasedOnStyle: Microsoft
AccessModifierOffset: -4
AlignOperands: false
AlignTrailingComments: false
AlwaysBreakTemplateDeclarations: Yes
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakConstructorInitializers: AfterColon
ColumnLimit: 0
Cpp11BracedListStyle: false
IncludeCategories:
- Regex: '^<.*'
Priority: 1
- Regex: '^".*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
PointerAlignment: Left
SpaceAfterTemplateKeyword: 'false'
SpaceBeforeCpp11BracedList: 'true'
SpaceBeforeParens: Never
SpaceBeforeRangeBasedForLoopColon: 'false'
SpaceInEmptyParentheses: 'false'
SpacesInCStyleCastParentheses: 'false'
SpacesInContainerLiterals: 'false'
SpacesInParentheses: 'true'
SpacesInSquareBrackets: 'false'
UseTab: Never
...

View File

@ -1,11 +1,14 @@
# CMakeList.txt : CMake project for FastNoise
# CMakeList.txt : CMake project for FastNoise2
cmake_minimum_required(VERSION 3.7.1)
project(FastNoise2 VERSION 0.5.0)
project(FastNoise2 VERSION 0.9.4)
set(CMAKE_CXX_STANDARD 17)
option(FASTNOISE2_NOISETOOL "Build Noise Tool" ON)
option(FASTNOISE2_TESTS "Build Test" OFF)
# Build DLL
#set(BUILD_SHARED_LIBS ON)
option(FASTNOISE2_NOISETOOL "Build NoiseTool application" ON)
option(FASTNOISE2_TESTS "Build tests" OFF)
if(MSVC)
#setup pdb target location
@ -14,29 +17,30 @@ if(MSVC)
set(CMAKE_PDB_OUTPUT_DIRECTORY "${pdb_output_dir}")
set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${pdb_output_dir}")
#need to sync pdp files
#need to sync pdb files
add_compile_options("/FS")
endif()
set(install_targets "")
add_subdirectory(src)
if(FASTNOISE2_NOISETOOL)
add_subdirectory(NoiseTool)
endif()
if(FASTNOISE2_TESTS)
add_subdirectory(tests)
endif()
#Install -----------------------------------------------------------
# Introduce variables:
# * CMAKE_INSTALL_LIBDIR
# * CMAKE_INSTALL_BINDIR
include(GNUInstallDirs)
set(install_targets "")
add_subdirectory(src)
if(FASTNOISE2_NOISETOOL)
include(cmake/CPM.cmake)
add_subdirectory(NoiseTool)
endif()
if(FASTNOISE2_TESTS)
include(cmake/CPM.cmake)
add_subdirectory(tests)
endif()
#Install -----------------------------------------------------------
# Layout. This works for all platforms:
# * <prefix>/lib*/cmake/<PROJECT-NAME>
@ -84,23 +88,6 @@ install(
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
if(FASTNOISE2_NOISETOOL)
if(WIN32)
#need sdl2 dll on windows, linux its expected to be installed
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") #32bit
install(
FILES NoiseTool/ThirdParty/SDL2-2.0.12/lib/x86/SDL2.dll
DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
else()
install(
FILES NoiseTool/ThirdParty/SDL2-2.0.12/lib/x64/SDL2.dll
DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
endif()
endif()
endif()
# Headers:
install(
FILES ${install_fastsimd_headers}
@ -110,6 +97,10 @@ install(
FILES ${install_fastnoise_headers}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/FastNoise"
)
install(
FILES ${install_fastnoise_generators_headers}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/FastNoise/Generators"
)
# Config
# * <prefix>/lib/cmake/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake

View File

@ -11,6 +11,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\out\\build\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -27,8 +32,14 @@
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"addressSanitizerEnabled": true,
"inheritEnvironments": [ "msvc_x64" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -47,6 +58,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -65,6 +81,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -83,6 +104,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -101,6 +127,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -119,6 +150,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x86" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -137,6 +173,11 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x86" ],
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -144,7 +185,7 @@
}
]
},
{
{
"name": "x64-WSL-GCC-Debug",
"generator": "Ninja",
"configurationType": "Debug",
@ -158,6 +199,11 @@
"wslPath": "${defaultWSLPath}",
"addressSanitizerRuntimeFlags": "detect_leaks=0",
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -179,6 +225,11 @@
"wslPath": "${defaultWSLPath}",
"addressSanitizerRuntimeFlags": "detect_leaks=0",
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "FASTNOISE2_TESTS",
"value": "True",
@ -200,9 +251,15 @@
"wslPath": "${defaultWSLPath}",
"addressSanitizerRuntimeFlags": "detect_leaks=0",
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "CMAKE_CXX_FLAGS",
"value": "-m32"
"value": "-m32",
"type": "STRING"
},
{
"name": "FASTNOISE2_TESTS",
@ -225,9 +282,15 @@
"wslPath": "${defaultWSLPath}",
"addressSanitizerRuntimeFlags": "detect_leaks=0",
"variables": [
{
"name": "CPM_SOURCE_CACHE",
"value": "${projectDir}\\cpm-cache",
"type": "PATH"
},
{
"name": "CMAKE_CXX_FLAGS",
"value": "-m32"
"value": "-m32",
"type": "STRING"
},
{
"name": "FASTNOISE2_TESTS",

View File

@ -1,15 +1,20 @@
[![GitHub Actions CI](https://img.shields.io/github/workflow/status/Auburn/FastNoise2/CI?style=flat-square&logo=GitHub "GitHub Actions CI")](https://github.com/Auburn/FastNoise2/actions)
[![GitHub Actions CI](https://img.shields.io/github/workflow/status/Auburn/FastNoise2/CI?style=flat-square&logo=GitHub "GitHub Actions CI")](https://github.com/Auburn/FastNoise2/actions?query=workflow%3ACI)
[![Discord](https://img.shields.io/discord/703636892901441577?style=flat-square&logo=discord "Discord")](https://discord.gg/SHVaVfV)
# FastNoise2
[Documentation WIP](https://github.com/Auburn/FastNoise2/wiki)
WIP successor to [FastNoiseSIMD](https://github.com/Auburn/FastNoiseSIMD)
Modular node based noise generation library using SIMD, modern C++17 and templates
FastNoise2 is a fully featured noise generation library which aims to meet all your coherent noise needs while being extremely fast
Uses FastSIMD to compile classes with multiple SIMD types
Uses FastSIMD to compile classes with multiple SIMD types and selects the fastest supported SIMD level at runtime
- Scalar (non-SIMD)
- SSE2
- SSE4.1
- AVX2
- AVX512
Supports:
- 32/64 bit
@ -20,31 +25,50 @@ Supports:
- Clang
- GCC
Check the [releases](https://github.com/Auburns/FastNoise2/releases) for early versions of the Noise Tool
Bindings:
- [C#](https://github.com/Auburn/FastNoise2Bindings)
Roadmap:
- [Vague collection of ideas](https://github.com/users/Auburn/projects/1)
## Noise Tool
The FastNoise2 noise tool provides a node graph editor to create trees of FastNoise2 nodes. Node trees can be exported as serialised strings and loaded into the FastNoise2 library in your own code. The noise tool has 2D and 3D previews for the node graph output, see screenshots below for examples.
Check the [Releases](https://github.com/Auburn/FastNoise2/releases/latest) for compiled NoiseTool binaries
![NoiseTool](https://user-images.githubusercontent.com/1349548/90967950-4e8da600-e4de-11ea-902a-94e72cb86481.png)
## Performance
FastNoise2 has continuous benchmarking to track of performance for each node type across commits
Results can be found here: https://auburn.github.io/fastnoise2benchmarking/
### Library Comparisons
Benchmarked using [NoiseBenchmarking](https://github.com/Auburn/NoiseBenchmarking)
- CPU: Intel 7820X @ 4.9Ghz
- OS: Win10 x64
- Compiler: clang-cl 10.0.0 -m64 /O2
Million points of noise generated per second (higher = better)
| 3D | Value | Perlin | (*Open)Simplex | Cellular |
|--------------------|--------|--------|----------------|----------|
| FastNoise Lite | 64.13 | 47.93 | 36.83* | 12.49 |
| FastNoise (Legacy) | 49.34 | 37.75 | 44.74 | 13.27 |
| FastNoise2 (AVX2) | 494.49 | 261.10 | 268.44 | 52.43 |
| libnoise | | 27.35 | | 0.65 |
| stb perlin | | 34.32 | | |
| 2D | Value | Perlin | Simplex | Cellular |
|--------------------|--------|--------|---------|----------|
| FastNoise Lite | 114.01 | 92.83 | 71.30 | 39.15 |
| FastNoise (Legacy) | 102.12 | 87.99 | 65.29 | 36.84 |
| FastNoise2 (AVX2) | 776.33 | 624.27 | 466.03 | 194.30 |
# Getting Started
There are 2 ways to use FastNoise 2, creating a node tree structure in code or importing a serialised node tree created using the NoiseTool.
This is creating a Simplex Fractal FBm with 5 octaves from code:
```
auto fnSimplex = FastNoise::New<FastNoise::Simplex>();
auto fnFractal = FastNoise::New<FastNoise::FractalFBm>();
fnFractal->SetSource( fnSimplex );
fnFractal->SetOctaveCount( 5 );
fnFractal->GenUniformGrid2D( ... );
```
Here is the same Simplex Fractal FBm with 5 octaves but using serialised data from the NoiseTool:
```
FastNoise::SmartNode<> fnGenerator = FastNoise::NewFromEncodedNodeTree( "DQAFAAAAAAAAQAgAAAAAAD8=" );
fnGenerator->GenUniformGrid2D( ... );
```
This is the node graph for the above from the NoiseTool
![SimplexFractalNodes](https://user-images.githubusercontent.com/1349548/90897006-72f16180-e3bc-11ea-8cc3-a68daed7b6c1.png)
See [documentation](https://github.com/Auburn/FastNoise2/wiki)

View File

@ -9,11 +9,16 @@ if env["use_lto"]:
# Need to either produce an error, fallback on Scalar, or turn off support entirely?
pass
env_voxel.Append(CPPPATH=["thirdparty/fast_noise_2/include"])
#env_voxel.Append(CPPDEFINES=["VOXEL_SUPPORT_FAST_NOISE_2"])
#env_voxel.Append(CPPPATH=["thirdparty/fast_noise_2/include"])
env_voxel.Append(CPPPATH=["include"])
env_voxel.Append(CPPDEFINES=["VOXEL_ENABLE_FAST_NOISE_2"])
env_voxel.Append(CPPDEFINES=["FASTNOISE_STATIC_LIB"])
fn2_sources_common = [
"src/FastNoise/FastNoiseMetadata.cpp",
"src/FastNoise/Metadata.cpp",
"src/FastNoise/FastNoise_C.cpp",
"src/FastNoise/SmartNode.cpp",
"src/FastSIMD/FastSIMD.cpp"
]
fn2_sources_scalar = [
@ -56,6 +61,7 @@ env_fn2_sse42 = env_fn2.Clone()
env_fn2_avx2 = env_fn2.Clone()
env_fn2_avx512 = env_fn2.Clone()
env_fn2_arm = env_fn2.Clone()
# TODO NEON?
if env.msvc:
if env["bits"] == "32":
@ -108,4 +114,5 @@ if env["platform"] == "android":
elif env["platform"] in ["windows", "x11", "osx"]:
# AVX is supported on desktop only
env_fn2_avx2.add_source_files(env.modules_sources, fn2_sources_avx2)
env_fn2_avx512.add_source_files(env.modules_sources, fn2_sources_avx512)
env_fn2_avx512.add_source_files(env.modules_sources, fn2_sources_avx512)

903
thirdparty/fast_noise_2/cmake/CPM.cmake vendored Normal file
View File

@ -0,0 +1,903 @@
# CPM.cmake - CMake's missing package manager
# ===========================================
# See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions.
#
# MIT License
# -----------
#[[
Copyright (c) 2021 Lars Melchior and additional contributors
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.
]]
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
set(CURRENT_CPM_VERSION 0.32.2)
if(CPM_DIRECTORY)
if(NOT CPM_DIRECTORY STREQUAL CMAKE_CURRENT_LIST_DIR)
if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION)
message(
AUTHOR_WARNING
"${CPM_INDENT} \
A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \
It is recommended to upgrade CPM to the most recent version. \
See https://github.com/cpm-cmake/CPM.cmake for more information."
)
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
include(FetchContent)
endif()
return()
endif()
get_property(
CPM_INITIALIZED GLOBAL ""
PROPERTY CPM_INITIALIZED
SET
)
if(CPM_INITIALIZED)
return()
endif()
endif()
set_property(GLOBAL PROPERTY CPM_INITIALIZED true)
option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies"
$ENV{CPM_USE_LOCAL_PACKAGES}
)
option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies"
$ENV{CPM_LOCAL_PACKAGES_ONLY}
)
option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL})
option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package"
$ENV{CPM_DONT_UPDATE_MODULE_PATH}
)
option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path"
$ENV{CPM_DONT_CREATE_PACKAGE_LOCK}
)
option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK
"Add all packages added through CPM.cmake to the package lock"
$ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK}
)
set(CPM_VERSION
${CURRENT_CPM_VERSION}
CACHE INTERNAL ""
)
set(CPM_DIRECTORY
${CMAKE_CURRENT_LIST_DIR}
CACHE INTERNAL ""
)
set(CPM_FILE
${CMAKE_CURRENT_LIST_FILE}
CACHE INTERNAL ""
)
set(CPM_PACKAGES
""
CACHE INTERNAL ""
)
set(CPM_DRY_RUN
OFF
CACHE INTERNAL "Don't download or configure dependencies (for testing)"
)
if(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
else()
set(CPM_SOURCE_CACHE_DEFAULT OFF)
endif()
set(CPM_SOURCE_CACHE
${CPM_SOURCE_CACHE_DEFAULT}
CACHE PATH "Directory to download CPM dependencies"
)
if(NOT CPM_DONT_UPDATE_MODULE_PATH)
set(CPM_MODULE_PATH
"${CMAKE_BINARY_DIR}/CPM_modules"
CACHE INTERNAL ""
)
# remove old modules
file(REMOVE_RECURSE ${CPM_MODULE_PATH})
file(MAKE_DIRECTORY ${CPM_MODULE_PATH})
# locally added CPM modules should override global packages
set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}")
endif()
if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
set(CPM_PACKAGE_LOCK_FILE
"${CMAKE_BINARY_DIR}/cpm-package-lock.cmake"
CACHE INTERNAL ""
)
file(WRITE ${CPM_PACKAGE_LOCK_FILE}
"# CPM Package Lock\n# This file should be committed to version control\n\n"
)
endif()
include(FetchContent)
# Try to infer package name from git repository uri (path or url)
function(cpm_package_name_from_git_uri URI RESULT)
if("${URI}" MATCHES "([^/:]+)/?.git/?$")
set(${RESULT}
${CMAKE_MATCH_1}
PARENT_SCOPE
)
else()
unset(${RESULT} PARENT_SCOPE)
endif()
endfunction()
# Try to infer package name and version from a url
function(cpm_package_name_and_ver_from_url url outName outVer)
if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)")
# We matched an archive
set(filename "${CMAKE_MATCH_1}")
if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)")
# We matched <name>-<version> (ie foo-1.2.3)
set(${outName}
"${CMAKE_MATCH_1}"
PARENT_SCOPE
)
set(${outVer}
"${CMAKE_MATCH_2}"
PARENT_SCOPE
)
elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)")
# We couldn't find a name, but we found a version
#
# In many cases (which we don't handle here) the url would look something like
# `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly
# distinguish the package name from the irrelevant bits. Moreover if we try to match the
# package name from the filename, we'd get bogus at best.
unset(${outName} PARENT_SCOPE)
set(${outVer}
"${CMAKE_MATCH_1}"
PARENT_SCOPE
)
else()
# Boldly assume that the file name is the package name.
#
# Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but
# such cases should be quite rare. No popular service does this... we think.
set(${outName}
"${filename}"
PARENT_SCOPE
)
unset(${outVer} PARENT_SCOPE)
endif()
else()
# No ideas yet what to do with non-archives
unset(${outName} PARENT_SCOPE)
unset(${outVer} PARENT_SCOPE)
endif()
endfunction()
# Initialize logging prefix
if(NOT CPM_INDENT)
set(CPM_INDENT
"CPM:"
CACHE INTERNAL ""
)
endif()
function(cpm_find_package NAME VERSION)
string(REPLACE " " ";" EXTRA_ARGS "${ARGN}")
find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET)
if(${CPM_ARGS_NAME}_FOUND)
message(STATUS "${CPM_INDENT} using local package ${CPM_ARGS_NAME}@${VERSION}")
CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}")
set(CPM_PACKAGE_FOUND
YES
PARENT_SCOPE
)
else()
set(CPM_PACKAGE_FOUND
NO
PARENT_SCOPE
)
endif()
endfunction()
# Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from
# finding the system library
function(cpm_create_module_file Name)
if(NOT CPM_DONT_UPDATE_MODULE_PATH)
# erase any previous modules
file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake
"include(${CPM_FILE})\n${ARGN}\nset(${Name}_FOUND TRUE)"
)
endif()
endfunction()
# Find a package locally or fallback to CPMAddPackage
function(CPMFindPackage)
set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN})
if(NOT DEFINED CPM_ARGS_VERSION)
if(DEFINED CPM_ARGS_GIT_TAG)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
endif()
endif()
if(CPM_DOWNLOAD_ALL)
CPMAddPackage(${ARGN})
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
if(CPM_PACKAGE_ALREADY_ADDED)
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(NOT CPM_PACKAGE_FOUND)
CPMAddPackage(${ARGN})
cpm_export_variables(${CPM_ARGS_NAME})
endif()
endfunction()
# checks if a package has been added before
function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION)
if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES)
CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION)
if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}")
message(
WARNING
"${CPM_INDENT} requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})."
)
endif()
cpm_get_fetch_properties(${CPM_ARGS_NAME})
set(${CPM_ARGS_NAME}_ADDED NO)
set(CPM_PACKAGE_ALREADY_ADDED
YES
PARENT_SCOPE
)
cpm_export_variables(${CPM_ARGS_NAME})
else()
set(CPM_PACKAGE_ALREADY_ADDED
NO
PARENT_SCOPE
)
endif()
endfunction()
# Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of
# arguments which can then be parsed idiomatically. For example gh:foo/bar@1.2.3 will be converted
# to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3
function(cpm_parse_add_package_single_arg arg outArgs)
# Look for a scheme
if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$")
string(TOLOWER "${CMAKE_MATCH_1}" scheme)
set(uri "${CMAKE_MATCH_2}")
# Check for CPM-specific schemes
if(scheme STREQUAL "gh")
set(out "GITHUB_REPOSITORY;${uri}")
set(packageType "git")
elseif(scheme STREQUAL "gl")
set(out "GITLAB_REPOSITORY;${uri}")
set(packageType "git")
elseif(scheme STREQUAL "bb")
set(out "BITBUCKET_REPOSITORY;${uri}")
set(packageType "git")
# A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine
# type
elseif(arg MATCHES ".git/?(@|#|$)")
set(out "GIT_REPOSITORY;${arg}")
set(packageType "git")
else()
# Fall back to a URL
set(out "URL;${arg}")
set(packageType "archive")
# We could also check for SVN since FetchContent supports it, but SVN is so rare these days.
# We just won't bother with the additional complexity it will induce in this function. SVN is
# done by multi-arg
endif()
else()
if(arg MATCHES ".git/?(@|#|$)")
set(out "GIT_REPOSITORY;${arg}")
set(packageType "git")
else()
# Give up
message(FATAL_ERROR "CPM: Can't determine package type of '${arg}'")
endif()
endif()
# For all packages we interpret @... as version. Only replace the last occurence. Thus URIs
# containing '@' can be used
string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}")
# Parse the rest according to package type
if(packageType STREQUAL "git")
# For git repos we interpret #... as a tag or branch or commit hash
string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}")
elseif(packageType STREQUAL "archive")
# For archives we interpret #... as a URL hash.
string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}")
# We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url
# should do this at a later point
else()
# We should never get here. This is an assertion and hitting it means there's a bug in the code
# above. A packageType was set, but not handled by this if-else.
message(FATAL_ERROR "CPM: Unsupported package type '${packageType}' of '${arg}'")
endif()
set(${outArgs}
${out}
PARENT_SCOPE
)
endfunction()
# Download and add a package from source
function(CPMAddPackage)
list(LENGTH ARGN argnLength)
if(argnLength EQUAL 1)
cpm_parse_add_package_single_arg("${ARGN}" ARGN)
# The shorthand syntax implies EXCLUDE_FROM_ALL
set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES")
endif()
set(oneValueArgs
NAME
FORCE
VERSION
GIT_TAG
DOWNLOAD_ONLY
GITHUB_REPOSITORY
GITLAB_REPOSITORY
BITBUCKET_REPOSITORY
GIT_REPOSITORY
SOURCE_DIR
DOWNLOAD_COMMAND
FIND_PACKAGE_ARGUMENTS
NO_CACHE
GIT_SHALLOW
EXCLUDE_FROM_ALL
SOURCE_SUBDIR
)
set(multiValueArgs URL OPTIONS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
# Set default values for arguments
if(NOT DEFINED CPM_ARGS_VERSION)
if(DEFINED CPM_ARGS_GIT_TAG)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
endif()
endif()
if(CPM_ARGS_DOWNLOAD_ONLY)
set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY})
else()
set(DOWNLOAD_ONLY NO)
endif()
if(DEFINED CPM_ARGS_GITHUB_REPOSITORY)
set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git")
elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY)
set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git")
elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY)
set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git")
endif()
if(DEFINED CPM_ARGS_GIT_REPOSITORY)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY})
if(NOT DEFINED CPM_ARGS_GIT_TAG)
set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION})
endif()
# If a name wasn't provided, try to infer it from the git repo
if(NOT DEFINED CPM_ARGS_NAME)
cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME)
endif()
endif()
set(CPM_SKIP_FETCH FALSE)
if(DEFINED CPM_ARGS_GIT_TAG)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG})
# If GIT_SHALLOW is explicitly specified, honor the value.
if(DEFINED CPM_ARGS_GIT_SHALLOW)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW})
endif()
endif()
if(DEFINED CPM_ARGS_URL)
# If a name or version aren't provided, try to infer them from the URL
list(GET CPM_ARGS_URL 0 firstUrl)
cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl)
# If we fail to obtain name and version from the first URL, we could try other URLs if any.
# However multiple URLs are expected to be quite rare, so for now we won't bother.
# If the caller provided their own name and version, they trump the inferred ones.
if(NOT DEFINED CPM_ARGS_NAME)
set(CPM_ARGS_NAME ${nameFromUrl})
endif()
if(NOT DEFINED CPM_ARGS_VERSION)
set(CPM_ARGS_VERSION ${verFromUrl})
endif()
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
endif()
# Check for required arguments
if(NOT DEFINED CPM_ARGS_NAME)
message(
FATAL_ERROR
"CPM: 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'"
)
endif()
# Check if package has been added before
cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
if(CPM_PACKAGE_ALREADY_ADDED)
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
# Check for manual overrides
if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "")
set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE})
set(CPM_${CPM_ARGS_NAME}_SOURCE "")
CPMAddPackage(
NAME "${CPM_ARGS_NAME}"
SOURCE_DIR "${PACKAGE_SOURCE}"
EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}"
OPTIONS "${CPM_ARGS_OPTIONS}"
SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}"
FORCE True
)
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
# Check for available declaration
if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "")
set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}})
set(CPM_DECLARATION_${CPM_ARGS_NAME} "")
CPMAddPackage(${declaration})
cpm_export_variables(${CPM_ARGS_NAME})
# checking again to ensure version and option compatibility
cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
return()
endif()
if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(CPM_PACKAGE_FOUND)
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
if(CPM_LOCAL_PACKAGES_ONLY)
message(
SEND_ERROR
"CPM: ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})"
)
endif()
endif()
CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}")
if(DEFINED CPM_ARGS_GIT_TAG)
set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}")
elseif(DEFINED CPM_ARGS_SOURCE_DIR)
set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}")
else()
set(PACKAGE_INFO "${CPM_ARGS_VERSION}")
endif()
if(DEFINED FETCHCONTENT_BASE_DIR)
# respect user's FETCHCONTENT_BASE_DIR if set
set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR})
else()
set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps)
endif()
if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
elseif(DEFINED CPM_ARGS_SOURCE_DIR)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR})
elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE)
string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
list(SORT origin_parameters)
string(SHA1 origin_hash "${origin_parameters}")
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash})
# Expand `download_directory` relative path. This is important because EXISTS doesn't work for
# relative paths.
get_filename_component(download_directory ${download_directory} ABSOLUTE)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory})
if(EXISTS ${download_directory})
# avoid FetchContent modules to improve performance
set(${CPM_ARGS_NAME}_BINARY_DIR ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build)
set(${CPM_ARGS_NAME}_ADDED YES)
set(${CPM_ARGS_NAME}_SOURCE_DIR ${download_directory})
cpm_add_subdirectory(
"${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}"
"${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}"
"${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}"
)
set(CPM_SKIP_FETCH TRUE)
set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}")
else()
# Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but
# it should guarantee no commit hash get mis-detected.
if(NOT DEFINED CPM_ARGS_GIT_SHALLOW)
cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH)
if(NOT ${IS_HASH})
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE)
endif()
endif()
# remove timestamps so CMake will re-download the dependency
file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild)
set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}")
endif()
endif()
cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(${ARGN})")
if(CPM_PACKAGE_LOCK_ENABLED)
if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK)
cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
elseif(CPM_ARGS_SOURCE_DIR)
cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory")
else()
cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
endif()
endif()
message(
STATUS "${CPM_INDENT} adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})"
)
if(NOT CPM_SKIP_FETCH)
cpm_declare_fetch(
"${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}"
)
cpm_fetch_package("${CPM_ARGS_NAME}")
cpm_add_subdirectory(
"${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}"
"${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}"
"${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}"
)
cpm_get_fetch_properties("${CPM_ARGS_NAME}")
endif()
set(${CPM_ARGS_NAME}_ADDED YES)
cpm_export_variables("${CPM_ARGS_NAME}")
endfunction()
# Fetch a previously declared package
macro(CPMGetPackage Name)
if(DEFINED "CPM_DECLARATION_${Name}")
CPMAddPackage(NAME ${Name})
else()
message(SEND_ERROR "Cannot retrieve package ${Name}: no declaration available")
endif()
endmacro()
# export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set
macro(cpm_export_variables name)
set(${name}_SOURCE_DIR
"${${name}_SOURCE_DIR}"
PARENT_SCOPE
)
set(${name}_BINARY_DIR
"${${name}_BINARY_DIR}"
PARENT_SCOPE
)
set(${name}_ADDED
"${${name}_ADDED}"
PARENT_SCOPE
)
endmacro()
# declares a package, so that any call to CPMAddPackage for the package name will use these
# arguments instead. Previous declarations will not be overriden.
macro(CPMDeclarePackage Name)
if(NOT DEFINED "CPM_DECLARATION_${Name}")
set("CPM_DECLARATION_${Name}" "${ARGN}")
endif()
endmacro()
function(cpm_add_to_package_lock Name)
if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN})
file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n")
endif()
endfunction()
function(cpm_add_comment_to_package_lock Name)
if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN})
file(APPEND ${CPM_PACKAGE_LOCK_FILE}
"# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n"
)
endif()
endfunction()
# includes the package lock file if it exists and creates a target `cpm-write-package-lock` to
# update it
macro(CPMUsePackageLock file)
if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE)
if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
endif()
if(NOT TARGET cpm-update-package-lock)
add_custom_target(
cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE}
${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}
)
endif()
set(CPM_PACKAGE_LOCK_ENABLED true)
endif()
endmacro()
# registers a package that has been added to CPM
function(CPMRegisterPackage PACKAGE VERSION)
list(APPEND CPM_PACKAGES ${PACKAGE})
set(CPM_PACKAGES
${CPM_PACKAGES}
CACHE INTERNAL ""
)
set("CPM_PACKAGE_${PACKAGE}_VERSION"
${VERSION}
CACHE INTERNAL ""
)
endfunction()
# retrieve the current version of the package to ${OUTPUT}
function(CPMGetPackageVersion PACKAGE OUTPUT)
set(${OUTPUT}
"${CPM_PACKAGE_${PACKAGE}_VERSION}"
PARENT_SCOPE
)
endfunction()
# declares a package in FetchContent_Declare
function(cpm_declare_fetch PACKAGE VERSION INFO)
if(${CPM_DRY_RUN})
message(STATUS "${CPM_INDENT} package not declared (dry run)")
return()
endif()
FetchContent_Declare(${PACKAGE} ${ARGN})
endfunction()
# returns properties for a package previously defined by cpm_declare_fetch
function(cpm_get_fetch_properties PACKAGE)
if(${CPM_DRY_RUN})
return()
endif()
FetchContent_GetProperties(${PACKAGE})
string(TOLOWER ${PACKAGE} lpackage)
set(${PACKAGE}_SOURCE_DIR
"${${lpackage}_SOURCE_DIR}"
PARENT_SCOPE
)
set(${PACKAGE}_BINARY_DIR
"${${lpackage}_BINARY_DIR}"
PARENT_SCOPE
)
endfunction()
# adds a package as a subdirectory if viable, according to provided options
function(
cpm_add_subdirectory
PACKAGE
DOWNLOAD_ONLY
SOURCE_DIR
BINARY_DIR
EXCLUDE
OPTIONS
)
if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt)
if(EXCLUDE)
set(addSubdirectoryExtraArgs EXCLUDE_FROM_ALL)
else()
set(addSubdirectoryExtraArgs "")
endif()
if(OPTIONS)
# the policy allows us to change options without caching
cmake_policy(SET CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
foreach(OPTION ${OPTIONS})
cpm_parse_option(${OPTION})
set(${OPTION_KEY} ${OPTION_VALUE})
endforeach()
endif()
set(CPM_OLD_INDENT "${CPM_INDENT}")
set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:")
add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs})
set(CPM_INDENT "${CPM_OLD_INDENT}")
endif()
endfunction()
# downloads a previously declared package via FetchContent and exports the variables
# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope
function(cpm_fetch_package PACKAGE)
if(${CPM_DRY_RUN})
message(STATUS "${CPM_INDENT} package ${PACKAGE} not fetched (dry run)")
return()
endif()
FetchContent_GetProperties(${PACKAGE})
if(NOT ${lower_case_name}_POPULATED)
FetchContent_Populate(${PACKAGE})
endif()
string(TOLOWER "${PACKAGE}" lower_case_name)
set(${PACKAGE}_SOURCE_DIR
${${lower_case_name}_SOURCE_DIR}
PARENT_SCOPE
)
set(${PACKAGE}_BINARY_DIR
${${lower_case_name}_BINARY_DIR}
PARENT_SCOPE
)
endfunction()
# splits a package option
function(cpm_parse_option OPTION)
string(REGEX MATCH "^[^ ]+" OPTION_KEY ${OPTION})
string(LENGTH ${OPTION} OPTION_LENGTH)
string(LENGTH ${OPTION_KEY} OPTION_KEY_LENGTH)
if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH)
# no value for key provided, assume user wants to set option to "ON"
set(OPTION_VALUE "ON")
else()
math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1")
string(SUBSTRING ${OPTION} "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE)
endif()
set(OPTION_KEY
"${OPTION_KEY}"
PARENT_SCOPE
)
set(OPTION_VALUE
"${OPTION_VALUE}"
PARENT_SCOPE
)
endfunction()
# guesses the package version from a git tag
function(cpm_get_version_from_git_tag GIT_TAG RESULT)
string(LENGTH ${GIT_TAG} length)
if(length EQUAL 40)
# GIT_TAG is probably a git hash
set(${RESULT}
0
PARENT_SCOPE
)
else()
string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG})
set(${RESULT}
${CMAKE_MATCH_1}
PARENT_SCOPE
)
endif()
endfunction()
# guesses if the git tag is a commit hash or an actual tag or a branch nane.
function(cpm_is_git_tag_commit_hash GIT_TAG RESULT)
string(LENGTH "${GIT_TAG}" length)
# full hash has 40 characters, and short hash has at least 7 characters.
if(length LESS 7 OR length GREATER 40)
set(${RESULT}
0
PARENT_SCOPE
)
else()
if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$")
set(${RESULT}
1
PARENT_SCOPE
)
else()
set(${RESULT}
0
PARENT_SCOPE
)
endif()
endif()
endfunction()
function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
set(oneValueArgs
NAME
FORCE
VERSION
GIT_TAG
DOWNLOAD_ONLY
GITHUB_REPOSITORY
GITLAB_REPOSITORY
GIT_REPOSITORY
SOURCE_DIR
DOWNLOAD_COMMAND
FIND_PACKAGE_ARGUMENTS
NO_CACHE
GIT_SHALLOW
)
set(multiValueArgs OPTIONS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
foreach(oneArgName ${oneValueArgs})
if(DEFINED CPM_ARGS_${oneArgName})
if(${IS_IN_COMMENT})
string(APPEND PRETTY_OUT_VAR "#")
endif()
if(${oneArgName} STREQUAL "SOURCE_DIR")
string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName}
${CPM_ARGS_${oneArgName}}
)
endif()
string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n")
endif()
endforeach()
foreach(multiArgName ${multiValueArgs})
if(DEFINED CPM_ARGS_${multiArgName})
if(${IS_IN_COMMENT})
string(APPEND PRETTY_OUT_VAR "#")
endif()
string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n")
foreach(singleOption ${CPM_ARGS_${multiArgName}})
if(${IS_IN_COMMENT})
string(APPEND PRETTY_OUT_VAR "#")
endif()
string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n")
endforeach()
endif()
endforeach()
if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "")
if(${IS_IN_COMMENT})
string(APPEND PRETTY_OUT_VAR "#")
endif()
string(APPEND PRETTY_OUT_VAR " ")
foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS})
string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}")
endforeach()
string(APPEND PRETTY_OUT_VAR "\n")
endif()
set(${OUT_VAR}
${PRETTY_OUT_VAR}
PARENT_SCOPE
)
endfunction()

View File

@ -2,5 +2,5 @@ include(CMakeFindDependencyMacro)
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
check_required_components("@PROJECT_NAME@")

View File

@ -1,10 +1,7 @@
#pragma once
#include <memory>
#include "FastSIMD/FastSIMD.h"
#include "FastNoise_Config.h"
// Node class definitions
#include "Generators/BasicGenerators.h"
#include "Generators/Value.h"
#include "Generators/Perlin.h"
@ -18,16 +15,36 @@
namespace FastNoise
{
/// <summary>
/// Create new instance of a FastNoise node
/// </summary>
/// <example>
/// auto node = FastNoise::New<FastNoise::Simplex>();
/// </example>
/// <typeparam name="T">Node class to create</typeparam>
/// <param name="maxSimdLevel">Max SIMD level, Null = Auto</param>
/// <returns>SmartNode<T> is guaranteed not nullptr</returns>
template<typename T>
inline SmartNode<T> New( FastSIMD::eLevel maxLevel = FastSIMD::Level_Null )
SmartNode<T> New( FastSIMD::eLevel maxSimdLevel /*= FastSIMD::Level_Null*/ )
{
static_assert( std::is_base_of_v<Generator, T>, "Use FastSIMD::New() to create non FastNoise classes" );
static_assert( std::is_base_of<Generator, T>::value, "This function should only be used for FastNoise node classes, for example FastNoise::Simplex" );
static_assert( std::is_member_function_pointer<decltype(&T::GetMetadata)>::value, "Cannot create abstract node class, use a derived class, for example: Fractal -> FractalFBm" );
return SmartNode<T>( FastSIMD::New<T>( maxLevel ) );
#if FASTNOISE_USE_SHARED_PTR
return SmartNode<T>( FastSIMD::New<T>( maxSimdLevel ) );
#else
return SmartNode<T>( FastSIMD::New<T>( maxSimdLevel, &SmartNodeManager::Allocate ) );
#endif
}
inline SmartNode<> NewFromEncodedNodeTree( const char* encodedNodeTreeString, FastSIMD::eLevel maxLevel = FastSIMD::Level_Null )
{
return Metadata::DeserialiseSmartNode( encodedNodeTreeString, maxLevel );
}
}
/// <summary>
/// Create a tree of FastNoise nodes from an encoded string
/// </summary>
/// <example>
/// FastNoise::SmartNode<> rootNode = FastNoise::NewFromEncodedNodeTree( "DQAFAAAAAAAAQAgAAAAAAD8AAAAAAA==" );
/// </example>
/// <param name="encodedNodeTreeString">Can be generated using the NoiseTool</param>
/// <param name="maxSimdLevel">Max SIMD level, Null = Auto</param>
/// <returns>Root node of the tree, nullptr for invalid strings</returns>
FASTNOISE_API SmartNode<> NewFromEncodedNodeTree( const char* encodedNodeTreeString, FastSIMD::eLevel maxSimdLevel = FastSIMD::Level_Null );
}

View File

@ -1,331 +0,0 @@
#pragma once
#include <functional>
#include <memory>
#include <type_traits>
#include <vector>
#include <cstdint>
#include "FastNoise_Config.h"
#include "FastSIMD/FastSIMD.h"
namespace FastNoise
{
class Generator;
template<typename T>
struct PerDimensionVariable;
struct NodeData;
struct Metadata
{
Metadata( const char* className )
{
name = className;
id = AddMetadataClass( this );
}
static const std::vector<const Metadata*>& GetMetadataClasses()
{
return sMetadataClasses;
}
static const Metadata* GetMetadataClass( std::uint16_t nodeId )
{
if( nodeId < sMetadataClasses.size() )
{
return sMetadataClasses[nodeId];
}
return nullptr;
}
static std::string SerialiseNodeData( NodeData* nodeData, bool fixUp = false );
static SmartNode<> DeserialiseSmartNode( const char* serialisedBase64NodeData, FastSIMD::eLevel level = FastSIMD::Level_Null );
static NodeData* DeserialiseNodeData( const char* serialisedBase64NodeData, std::vector<std::unique_ptr<NodeData>>& nodeDataOut );
struct MemberVariable
{
enum eType
{
EFloat,
EInt,
EEnum
};
union ValueUnion
{
float f;
std::int32_t i;
ValueUnion( float v = 0 )
{
f = v;
}
ValueUnion( std::int32_t v )
{
i = v;
}
operator float()
{
return f;
}
operator std::int32_t()
{
return i;
}
bool operator ==( const ValueUnion& rhs ) const
{
return i == rhs.i;
}
};
const char* name;
eType type;
int dimensionIdx = -1;
ValueUnion valueDefault, valueMin, valueMax;
std::vector<const char*> enumNames;
std::function<void( Generator*, ValueUnion )> setFunc;
};
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddVariable( const char* name, T defaultV, U&& func, T minV = 0, T maxV = 0 )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v ) { func( dynamic_cast<GetArg<U, 0>>(g), v ); };
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddVariable( const char* name, T defaultV, void(U::* func)(T), T minV = 0, T maxV = 0 )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v ) { (dynamic_cast<U*>(g)->*func)(v); };
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<std::is_enum_v<T>>, typename... NAMES>
void AddVariableEnum( const char* name, T defaultV, void(U::* func)(T), NAMES... names )
{
MemberVariable member;
member.name = name;
member.type = MemberVariable::EEnum;
member.valueDefault = (int32_t)defaultV;
member.enumNames = { names... };
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v ) { (dynamic_cast<U*>(g)->*func)((T)v.i); };
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddPerDimensionVariable( const char* name, T defaultV, U&& func, T minV = 0, T maxV = 0 )
{
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<T>::varArray ) / sizeof( *PerDimensionVariable<T>::varArray ); idx++ )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.dimensionIdx = idx;
member.setFunc = [func, idx]( Generator* g, MemberVariable::ValueUnion v ) { func( dynamic_cast<GetArg<U, 0>>(g) ).get()[idx] = v; };
memberVariables.push_back( member );
}
}
struct MemberNode
{
const char* name;
int dimensionIdx = -1;
std::function<bool( Generator*, SmartNodeArg<> )> setFunc;
};
template<typename T, typename U>
void AddGeneratorSource( const char* name, void(U::* func)(SmartNodeArg<T>) )
{
MemberNode member;
member.name = name;
member.setFunc = [func]( Generator* g, SmartNodeArg<> s )
{
SmartNode<T> downCast = std::dynamic_pointer_cast<T>(s);
if( downCast )
{
(dynamic_cast<U*>(g)->*func)( downCast );
}
return (bool)downCast;
};
memberNodes.push_back( member );
}
template<typename U>
void AddPerDimensionGeneratorSource( const char* name, U&& func )
{
using GeneratorSourceT = typename std::invoke_result_t<U, GetArg<U, 0>>::type::Type;
using T = typename GeneratorSourceT::Type;
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<GeneratorSourceT>::varArray ) / sizeof( *PerDimensionVariable<GeneratorSourceT>::varArray ); idx++ )
{
MemberNode member;
member.name = name;
member.dimensionIdx = idx;
member.setFunc = [func, idx]( auto* g, SmartNodeArg<> s )
{
SmartNode<T> downCast = std::dynamic_pointer_cast<T>(s);
if( downCast )
{
g->SetSourceMemberVariable( func( dynamic_cast<GetArg<U, 0>>(g) ).get()[idx], downCast );
}
return (bool)downCast;
};
memberNodes.push_back( member );
}
}
struct MemberHybrid
{
const char* name;
float valueDefault = 0.0f;
int dimensionIdx = -1;
std::function<void( Generator*, float )> setValueFunc;
std::function<bool( Generator*, SmartNodeArg<> )> setNodeFunc;
};
template<typename T, typename U>
void AddHybridSource( const char* name, float defaultValue, void(U::* funcNode)(SmartNodeArg<T>), void(U::* funcValue)(float) )
{
MemberHybrid member;
member.name = name;
member.valueDefault = defaultValue;
member.setNodeFunc = [funcNode]( auto* g, SmartNodeArg<> s )
{
SmartNode<T> downCast = std::dynamic_pointer_cast<T>(s);
if( downCast )
{
(dynamic_cast<U*>(g)->*funcNode)( downCast );
}
return (bool)downCast;
};
member.setValueFunc = [funcValue]( Generator* g, float v )
{
(dynamic_cast<U*>(g)->*funcValue)(v);
};
memberHybrids.push_back( member );
}
template<typename U>
void AddPerDimensionHybridSource( const char* name, float defaultV, U&& func )
{
using HybridSourceT = typename std::invoke_result_t<U, GetArg<U, 0>>::type::Type;
using T = typename HybridSourceT::Type;
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<HybridSourceT>::varArray ) / sizeof( *PerDimensionVariable<HybridSourceT>::varArray ); idx++ )
{
MemberHybrid member;
member.name = name;
member.valueDefault = defaultV;
member.dimensionIdx = idx;
member.setNodeFunc = [func, idx]( auto* g, SmartNodeArg<> s )
{
SmartNode<T> downCast = std::dynamic_pointer_cast<T>(s);
if( downCast )
{
g->SetSourceMemberVariable( func( dynamic_cast<GetArg<U, 0>>(g) ).get()[idx], downCast );
}
return (bool)downCast;
};
member.setValueFunc = [func, idx]( Generator* g, float v ) { func( dynamic_cast<GetArg<U, 0>>(g) ).get()[idx] = v; };
memberHybrids.push_back( member );
}
}
std::uint16_t id;
const char* name;
std::vector<const char*> groups;
std::vector<MemberVariable> memberVariables;
std::vector<MemberNode> memberNodes;
std::vector<MemberHybrid> memberHybrids;
virtual Generator* NodeFactory( FastSIMD::eLevel level = FastSIMD::Level_Null ) const = 0;
private:
template<typename F, typename Ret, typename... Args>
static std::tuple<Args...> GetArg_Helper( Ret( F::* )(Args...) const );
template<typename F, std::size_t I>
using GetArg = std::tuple_element_t<I, decltype(GetArg_Helper( &F::operator() ))>;
static std::uint16_t AddMetadataClass( const Metadata* newMetadata )
{
sMetadataClasses.emplace_back( newMetadata );
return (std::uint16_t)sMetadataClasses.size() - 1;
}
static std::vector<const Metadata*> sMetadataClasses;
};
struct NodeData
{
NodeData( const Metadata* metadata );
const Metadata* metadata;
std::vector<Metadata::MemberVariable::ValueUnion> variables;
std::vector<NodeData*> nodes;
std::vector<std::pair<NodeData*, float>> hybrids;
bool operator ==( const NodeData& rhs ) const
{
return metadata == rhs.metadata &&
variables == rhs.variables &&
nodes == rhs.nodes &&
hybrids == rhs.hybrids;
}
};
}
#define FASTNOISE_METADATA( ... ) public:\
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );\
const FastNoise::Metadata* GetMetadata() const override;\
struct Metadata : __VA_ARGS__::Metadata{\
Generator* NodeFactory( FastSIMD::eLevel ) const override;
#define FASTNOISE_METADATA_ABSTRACT( ... ) public:\
struct Metadata : __VA_ARGS__::Metadata{

View File

@ -84,7 +84,7 @@ FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( White ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( Checkerboard ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( SineWave ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( PositionOutput ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( DistanceToOrigin ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( DistanceToPoint ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( Value ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( Perlin ) )
@ -96,9 +96,8 @@ FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( CellularDistance ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( CellularLookup ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( FractalFBm ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( FractalBillow ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( FractalPingPong ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( FractalRidged ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( FractalRidgedMulti ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( DomainWarpGradient ) )
FASTSIMD_BUILD_CLASS( FASTNOISE_CLASS( DomainWarpFractalProgressive ) )

View File

@ -0,0 +1,83 @@
#ifndef FASTNOISE_C_H
#define FASTNOISE_C_H
#include "FastNoise_Export.h"
#ifdef __cplusplus
extern "C" {
#endif
FASTNOISE_API void* fnNewFromEncodedNodeTree( const char* encodedString, unsigned /*FastSIMD::eLevel*/ simdLevel /*0 = Auto*/ );
FASTNOISE_API void fnDeleteNodeRef( void* node );
FASTNOISE_API unsigned fnGetSIMDLevel( const void* node );
FASTNOISE_API int fnGetMetadataID( const void* node );
FASTNOISE_API void fnGenUniformGrid2D( const void* node, float* noiseOut,
int xStart, int yStart,
int xSize, int ySize,
float frequency, int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenUniformGrid3D( const void* node, float* noiseOut,
int xStart, int yStart, int zStart,
int xSize, int ySize, int zSize,
float frequency, int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenUniformGrid4D( const void* node, float* noiseOut,
int xStart, int yStart, int zStart, int wStart,
int xSize, int ySize, int zSize, int wSize,
float frequency, int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenPositionArray2D( const void* node, float* noiseOut, int count,
const float* xPosArray, const float* yPosArray,
float xOffset, float yOffset,
int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenPositionArray3D( const void* node, float* noiseOut, int count,
const float* xPosArray, const float* yPosArray, const float* zPosArray,
float xOffset, float yOffset, float zOffset,
int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenPositionArray4D( const void* node, float* noiseOut, int count,
const float* xPosArray, const float* yPosArray, const float* zPosArray, const float* wPosArray,
float xOffset, float yOffset, float zOffset, float wOffset,
int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API void fnGenTileable2D( const void* node, float* noiseOut,
int xSize, int ySize,
float frequency, int seed, float* outputMinMax /*nullptr or float[2]*/ );
FASTNOISE_API float fnGenSingle2D( const void* node, float x, float y, int seed );
FASTNOISE_API float fnGenSingle3D( const void* node, float x, float y, float z, int seed );
FASTNOISE_API float fnGenSingle4D( const void* node, float x, float y, float z, float w, int seed );
FASTNOISE_API int fnGetMetadataCount();
FASTNOISE_API const char* fnGetMetadataName( int id ); // valid IDs up to `fnGetMetadataCount() - 1`
FASTNOISE_API void* fnNewFromMetadata( int id, unsigned /*FastSIMD::eLevel*/ simdLevel /*0 = Auto*/ );
FASTNOISE_API int fnGetMetadataVariableCount( int id );
FASTNOISE_API const char* fnGetMetadataVariableName( int id, int variableIndex );
FASTNOISE_API int fnGetMetadataVariableType( int id, int variableIndex );
FASTNOISE_API int fnGetMetadataVariableDimensionIdx( int id, int variableIndex );
FASTNOISE_API int fnGetMetadataEnumCount( int id, int variableIndex );
FASTNOISE_API const char* fnGetMetadataEnumName( int id, int variableIndex, int enumIndex );
FASTNOISE_API bool fnSetVariableFloat( void* node, int variableIndex, float value );
FASTNOISE_API bool fnSetVariableIntEnum( void* node, int variableIndex, int value );
FASTNOISE_API int fnGetMetadataNodeLookupCount( int id );
FASTNOISE_API const char* fnGetMetadataNodeLookupName( int id, int nodeLookupIndex );
FASTNOISE_API int fnGetMetadataNodeLookupDimensionIdx( int id, int nodeLookupIndex );
FASTNOISE_API bool fnSetNodeLookup( void* node, int nodeLookupIndex, const void* nodeLookup );
FASTNOISE_API int fnGetMetadataHybridCount( int id );
FASTNOISE_API const char* fnGetMetadataHybridName( int id, int hybridIndex );
FASTNOISE_API int fnGetMetadataHybridDimensionIdx( int id, int hybridIndex );
FASTNOISE_API bool fnSetHybridNodeLookup( void* node, int hybridIndex, const void* nodeLookup );
FASTNOISE_API bool fnSetHybridFloat( void* node, int hybridIndex, float value );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,7 +1,13 @@
#pragma once
#include "FastSIMD/FastSIMD.h"
#include <FastSIMD/FastSIMD.h>
#include "FastNoise_Export.h"
#define FASTNOISE_CALC_MIN_MAX 1
#define FASTNOISE_CALC_MIN_MAX true
#define FASTNOISE_USE_SHARED_PTR false
#if FASTNOISE_USE_SHARED_PTR
#include <memory>
#endif
namespace FastNoise
{
@ -11,10 +17,28 @@ namespace FastNoise
FastSIMD::Level_SSE41 |
FastSIMD::Level_AVX2 |
FastSIMD::Level_AVX512 ;
class Generator;
struct Metadata;
template<typename T = class Generator>
template<typename T>
struct MetadataT;
#if FASTNOISE_USE_SHARED_PTR
template<typename T = Generator>
using SmartNode = std::shared_ptr<T>;
#else
template<typename T = Generator>
class SmartNode;
#endif
template<typename T = class Generator>
using SmartNodeArg = const SmartNode<T>&;
}
template<typename T = Generator>
using SmartNodeArg = const SmartNode<const T>&;
template<typename T>
SmartNode<T> New( FastSIMD::eLevel maxSimdLevel = FastSIMD::Level_Null );
} // namespace FastNoise
#if !FASTNOISE_USE_SHARED_PTR
#include "SmartNode.h"
#endif

View File

@ -0,0 +1,14 @@
#ifndef FASTNOISE_EXPORT_H
#define FASTNOISE_EXPORT_H
#if !defined( FASTNOISE_STATIC_LIB ) && ( defined( _WIN32 ) || defined( __CYGWIN__ ) )
#ifdef FASTNOISE_EXPORT
#define FASTNOISE_API __declspec( dllexport )
#else
#define FASTNOISE_API __declspec( dllimport )
#endif
#else
#define FASTNOISE_API
#endif
#endif

View File

@ -6,104 +6,166 @@ namespace FastNoise
class Constant : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetValue( float value ) { mValue = value; }
protected:
float mValue = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Value", 1.0f, &Constant::SetValue );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Constant> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Value", 1.0f, &Constant::SetValue );
}
};
#endif
class White : public virtual Generator
{
FASTNOISE_METADATA( Generator )
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<White> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
}
};
#endif
class Checkerboard : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSize( float value ) { mSize = value; }
protected:
float mSize = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Size", 1.0f, &Checkerboard::SetSize );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Checkerboard> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Size", 1.0f, &Checkerboard::SetSize );
}
};
#endif
class SineWave : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetScale( float value ) { mScale = value; }
protected:
float mScale = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Scale", 1.0f, &SineWave::SetScale );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<SineWave> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
this->AddVariable( "Scale", 1.0f, &SineWave::SetScale );
}
};
#endif
class PositionOutput : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
template<Dim D>
void Set( float multiplier, float offset = 0.0f ) { mMultiplier[(int)D] = multiplier; mOffset[(int)D] = offset; }
protected:
PerDimensionVariable<float> mMultiplier;
PerDimensionVariable<float> mOffset;
PerDimensionVariable<float> mMultiplier = 0.0f;
PerDimensionVariable<float> mOffset = 0.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
this->AddPerDimensionVariable( "Multiplier", 0.0f, []( PositionOutput* p ) { return std::ref( p->mMultiplier ); } );
this->AddPerDimensionVariable( "Offset", 0.0f, []( PositionOutput* p ) { return std::ref( p->mOffset ); } );
}
};
template<typename T>
friend struct MetadataT;
};
class DistanceToOrigin : public virtual Generator
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<PositionOutput> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
this->AddPerDimensionVariable( "Multiplier", 0.0f, []( PositionOutput* p ) { return std::ref( p->mMultiplier ); } );
this->AddPerDimensionVariable( "Offset", 0.0f, []( PositionOutput* p ) { return std::ref( p->mOffset ); } );
}
};
#endif
class DistanceToPoint : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetDistanceFunction( DistanceFunction value ) { mDistanceFunction = value; }
template<Dim D>
void SetScale( float value ) { mPoint[(int)D] = value; }
protected:
GeneratorSource mSource;
DistanceFunction mDistanceFunction = DistanceFunction::EuclideanSquared;
PerDimensionVariable<float> mPoint = 0.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Basic Generators" );
this->AddVariableEnum( "Distance Function", DistanceFunction::Euclidean, &DistanceToOrigin::SetDistanceFunction, "Euclidean", "Euclidean Squared", "Manhattan", "Hybrid" );
}
};
template<typename T>
friend struct MetadataT;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DistanceToPoint> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Basic Generators" );
this->AddVariableEnum( "Distance Function", DistanceFunction::Euclidean, &DistanceToPoint::SetDistanceFunction, kDistanceFunction_Strings );
this->AddPerDimensionVariable( "Point", 0.0f, []( DistanceToPoint* p ) { return std::ref( p->mPoint ); } );
}
};
#endif
}

View File

@ -1,4 +1,3 @@
#include <cassert>
#include "FastSIMD/InlInclude.h"
#include "BasicGenerators.h"
@ -83,7 +82,7 @@ class FS_T<FastNoise::PositionOutput, FS> : public virtual FastNoise::PositionOu
};
template<typename FS>
class FS_T<FastNoise::DistanceToOrigin, FS> : public virtual FastNoise::DistanceToOrigin, public FS_T<FastNoise::Generator, FS>
class FS_T<FastNoise::DistanceToPoint, FS> : public virtual FastNoise::DistanceToPoint, public FS_T<FastNoise::Generator, FS>
{
FASTSIMD_DECLARE_FS_TYPES;
FASTNOISE_IMPL_GEN_T;
@ -91,6 +90,9 @@ class FS_T<FastNoise::DistanceToOrigin, FS> : public virtual FastNoise::Distance
template<typename... P>
FS_INLINE float32v GenT( int32v seed, P... pos ) const
{
size_t pointIdx = 0;
((pos -= float32v( mPoint[pointIdx++] )), ...);
return FnUtils::CalcDistance( mDistanceFunction, pos... );
}
};

View File

@ -14,19 +14,22 @@ namespace FastNoise
protected:
GeneratorSource mLHS;
HybridSource mRHS;
FASTNOISE_METADATA_ABSTRACT( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "LHS", &OperatorSourceLHS::SetLHS );
this->AddHybridSource( "RHS", 0.0f, &OperatorSourceLHS::SetRHS, &OperatorSourceLHS::SetRHS );
}
};
HybridSource mRHS = 0.0f;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<OperatorSourceLHS> : MetadataT<Generator>
{
MetadataT()
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "LHS", &OperatorSourceLHS::SetLHS );
this->AddHybridSource( "RHS", 0.0f, &OperatorSourceLHS::SetRHS, &OperatorSourceLHS::SetRHS );
}
};
#endif
class OperatorHybridLHS : public virtual Generator
{
public:
@ -36,143 +39,230 @@ namespace FastNoise
void SetRHS( float value ) { mRHS = value; }
protected:
HybridSource mLHS;
HybridSource mRHS;
FASTNOISE_METADATA_ABSTRACT( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Blends" );
this->AddHybridSource( "LHS", 0.0f, &OperatorHybridLHS::SetLHS, &OperatorHybridLHS::SetLHS );
this->AddHybridSource( "RHS", 0.0f, &OperatorHybridLHS::SetRHS, &OperatorHybridLHS::SetRHS );
}
};
HybridSource mLHS = 0.0f;
HybridSource mRHS = 0.0f;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<OperatorHybridLHS> : MetadataT<Generator>
{
MetadataT()
{
groups.push_back( "Blends" );
this->AddHybridSource( "LHS", 0.0f, &OperatorHybridLHS::SetLHS, &OperatorHybridLHS::SetLHS );
this->AddHybridSource( "RHS", 0.0f, &OperatorHybridLHS::SetRHS, &OperatorHybridLHS::SetRHS );
}
};
#endif
class Add : public virtual OperatorSourceLHS
{
FASTNOISE_METADATA( OperatorSourceLHS )
using OperatorSourceLHS::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Add> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class Subtract : public virtual OperatorHybridLHS
{
FASTNOISE_METADATA( OperatorHybridLHS )
using OperatorHybridLHS::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Subtract> : MetadataT<OperatorHybridLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class Multiply : public virtual OperatorSourceLHS
{
FASTNOISE_METADATA( OperatorSourceLHS )
using OperatorSourceLHS::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Multiply> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class Divide : public virtual OperatorHybridLHS
{
FASTNOISE_METADATA( OperatorHybridLHS )
using OperatorHybridLHS::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Divide> : MetadataT<OperatorHybridLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class Min : public virtual OperatorSourceLHS
{
FASTNOISE_METADATA( OperatorSourceLHS )
using OperatorSourceLHS::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Min> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class Max : public virtual OperatorSourceLHS
{
FASTNOISE_METADATA( OperatorSourceLHS )
using OperatorSourceLHS::Metadata::Metadata;
};
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Max> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class PowFloat : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetValue( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mValue, gen ); }
void SetValue( float value ) { mValue = value; }
void SetPow( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mPow, gen ); }
void SetPow( float value ) { mPow = value; }
protected:
HybridSource mValue;
HybridSource mPow;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Blends" );
this->AddHybridSource( "Value", 2.0f, &PowFloat::SetValue, &PowFloat::SetValue );
this->AddHybridSource( "Pow", 2.0f, &PowFloat::SetPow, &PowFloat::SetPow );
}
};
HybridSource mValue = 2.0f;
HybridSource mPow = 2.0f;
};
class PowInt : public virtual OperatorHybridLHS
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<PowFloat> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Blends" );
this->AddHybridSource( "Value", 2.0f, &PowFloat::SetValue, &PowFloat::SetValue );
this->AddHybridSource( "Pow", 2.0f, &PowFloat::SetPow, &PowFloat::SetPow );
}
};
#endif
class PowInt : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetValue( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mValue, gen ); }
void SetPow( int32_t value ) { mPow = value; }
void SetPow( int value ) { mPow = value; }
protected:
GeneratorSource mValue;
int32_t mPow;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "Value", &PowInt::SetValue );
this->AddVariable( "Pow", 2, &PowInt::SetPow, 2, INT_MAX );
}
};
int mPow = 2;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<PowInt> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "Value", &PowInt::SetValue );
this->AddVariable( "Pow", 2, &PowInt::SetPow, 2, INT_MAX );
}
};
#endif
class MinSmooth : public virtual OperatorSourceLHS
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSmoothness( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSmoothness, gen ); }
void SetSmoothness( float value ) { mSmoothness = value; }
protected:
HybridSource mSmoothness = 0.1f;
FASTNOISE_METADATA( OperatorSourceLHS )
Metadata( const char* className ) : OperatorSourceLHS::Metadata( className )
{
this->AddHybridSource( "Smoothness", 0.1f, &MinSmooth::SetSmoothness, &MinSmooth::SetSmoothness );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<MinSmooth> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddHybridSource( "Smoothness", 0.1f, &MinSmooth::SetSmoothness, &MinSmooth::SetSmoothness );
}
};
#endif
class MaxSmooth : public virtual OperatorSourceLHS
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSmoothness( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSmoothness, gen ); }
void SetSmoothness( float value ) { mSmoothness = value; }
protected:
HybridSource mSmoothness = 0.1f;
FASTNOISE_METADATA( OperatorSourceLHS )
Metadata( const char* className ) : OperatorSourceLHS::Metadata( className )
{
this->AddHybridSource( "Smoothness", 0.1f, &MaxSmooth::SetSmoothness, &MaxSmooth::SetSmoothness );
}
};
HybridSource mSmoothness = 0.1f;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<MaxSmooth> : MetadataT<OperatorSourceLHS>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddHybridSource( "Smoothness", 0.1f, &MaxSmooth::SetSmoothness, &MaxSmooth::SetSmoothness );
}
};
#endif
class Fade : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetA( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mA, gen ); }
void SetB( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mB, gen ); }
@ -183,16 +273,21 @@ namespace FastNoise
GeneratorSource mA;
GeneratorSource mB;
HybridSource mFade = 0.5f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "A", &Fade::SetA );
this->AddGeneratorSource( "B", &Fade::SetB );
this->AddHybridSource( "Fade", 0.5f, &Fade::SetFade, &Fade::SetFade );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Fade> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Blends" );
this->AddGeneratorSource( "A", &Fade::SetA );
this->AddGeneratorSource( "B", &Fade::SetB );
this->AddHybridSource( "Fade", 0.5f, &Fade::SetFade, &Fade::SetFade );
}
};
#endif
}

View File

@ -2,7 +2,6 @@
#include "Blends.h"
template<typename FS>
class FS_T<FastNoise::Add, FS> : public virtual FastNoise::Add, public FS_T<FastNoise::Generator, FS>
{
@ -80,7 +79,7 @@ class FS_T<FastNoise::PowInt, FS> : public virtual FastNoise::PowInt, public FS_
float32v value = this->GetSourceValue( mValue, seed, pos... );
float32v pow = value * value;
for( int32_t i = 2; i < mPow; i++ )
for( int i = 2; i < mPow; i++ )
{
pow *= value;
}

View File

@ -1,7 +1,8 @@
#pragma once
#include "Generator.h"
#include <algorithm>
namespace FastNoise
{
class Cellular : public virtual Generator
@ -14,43 +15,54 @@ namespace FastNoise
protected:
HybridSource mJitterModifier = 1.0f;
DistanceFunction mDistanceFunction = DistanceFunction::EuclideanSquared;
const float kJitter2D = 0.437015f;
const float kJitter3D = 0.396143f;
const float kJitter4D = 0.366025f;
FASTNOISE_METADATA_ABSTRACT( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Coherent Noise" );
this->AddHybridSource( "Jitter Modifier", 1.0f, &Cellular::SetJitterModifier, &Cellular::SetJitterModifier );
this->AddVariableEnum( "Distance Function", DistanceFunction::EuclideanSquared, &Cellular::SetDistanceFunction, "Euclidean", "Euclidean Squared", "Manhattan", "Hybrid" );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Cellular> : MetadataT<Generator>
{
MetadataT()
{
groups.push_back( "Coherent Noise" );
this->AddHybridSource( "Jitter Modifier", 1.0f, &Cellular::SetJitterModifier, &Cellular::SetJitterModifier );
this->AddVariableEnum( "Distance Function", DistanceFunction::EuclideanSquared, &Cellular::SetDistanceFunction, kDistanceFunction_Strings );
}
};
#endif
class CellularValue : public virtual Cellular
{
public:
void SetValueIndex( int value ) { mValueIndex = value; }
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
protected:
static const int kMaxDistanceCount = 4;
int mValueIndex = 0;
void SetValueIndex( int value ) { mValueIndex = std::min( std::max( value, 0 ), kMaxDistanceCount - 1 ); }
FASTNOISE_METADATA( Cellular )
Metadata( const char* className ) : Cellular::Metadata( className )
{
this->AddVariable( "Value Index", 0, &CellularValue::SetValueIndex, 0, kMaxDistanceCount - 1 );
}
};
protected:
int mValueIndex = 0;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<CellularValue> : MetadataT<Cellular>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddVariable( "Value Index", 0, &CellularValue::SetValueIndex, 0, CellularValue::kMaxDistanceCount - 1 );
}
};
#endif
class CellularDistance : public virtual Cellular
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
enum class ReturnType
{
Index0,
@ -60,45 +72,58 @@ namespace FastNoise
Index0Div1
};
void SetDistanceIndex0( int value ) { mDistanceIndex0 = value; }
void SetDistanceIndex1( int value ) { mDistanceIndex1 = value; }
static const int kMaxDistanceCount = 4;
void SetDistanceIndex0( int value ) { mDistanceIndex0 = std::min( std::max( value, 0 ), kMaxDistanceCount - 1 ); }
void SetDistanceIndex1( int value ) { mDistanceIndex1 = std::min( std::max( value, 0 ), kMaxDistanceCount - 1 ); }
void SetReturnType( ReturnType value ) { mReturnType = value; }
protected:
static const int kMaxDistanceCount = 4;
ReturnType mReturnType = ReturnType::Index0;
int mDistanceIndex0 = 0;
int mDistanceIndex1 = 1;
FASTNOISE_METADATA( Cellular )
Metadata( const char* className ) : Cellular::Metadata( className )
{
this->AddVariable( "Distance Index 0", 0, &CellularDistance::SetDistanceIndex0, 0, kMaxDistanceCount - 1 );
this->AddVariable( "Distance Index 1", 1, &CellularDistance::SetDistanceIndex1, 0, kMaxDistanceCount - 1 );
this->AddVariableEnum( "Return Type", ReturnType::Index0, &CellularDistance::SetReturnType, "Index0", "Index0Add1", "Index0Sub1", "Index0Mul1", "Index0Div1" );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<CellularDistance> : MetadataT<Cellular>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddVariable( "Distance Index 0", 0, &CellularDistance::SetDistanceIndex0, 0, CellularDistance::kMaxDistanceCount - 1 );
this->AddVariable( "Distance Index 1", 1, &CellularDistance::SetDistanceIndex1, 0, CellularDistance::kMaxDistanceCount - 1 );
this->AddVariableEnum( "Return Type", CellularDistance::ReturnType::Index0, &CellularDistance::SetReturnType, "Index0", "Index0Add1", "Index0Sub1", "Index0Mul1", "Index0Div1" );
}
};
#endif
class CellularLookup : public virtual Cellular
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetLookup( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mLookup, gen ); }
void SetLookupFrequency( float freq ) { mLookupFreq = freq; }
protected:
GeneratorSource mLookup;
float mLookupFreq = 0.1f;
FASTNOISE_METADATA( Cellular )
Metadata( const char* className ) : Cellular::Metadata( className )
{
this->AddGeneratorSource( "Lookup", &CellularLookup::SetLookup );
this->AddVariable( "Lookup Frequency", 0.1f, &CellularLookup::SetLookupFrequency );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<CellularLookup> : MetadataT<Cellular>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddGeneratorSource( "Lookup", &CellularLookup::SetLookup );
this->AddVariable( "Lookup Frequency", 0.1f, &CellularLookup::SetLookupFrequency );
}
};
#endif
}

View File

@ -9,6 +9,11 @@
template<typename FS>
class FS_T<FastNoise::Cellular, FS> : public virtual FastNoise::Cellular, public FS_T<FastNoise::Generator, FS>
{
protected:
const float kJitter2D = 0.437016f;
const float kJitter3D = 0.396144f;
const float kJitter4D = 0.366025f;
const float kJitterIdx23 = 0.190983f;
};
template<typename FS>
@ -18,7 +23,7 @@ class FS_T<FastNoise::CellularValue, FS> : public virtual FastNoise::CellularVal
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y ) const final
{
float32v jitter = float32v( kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
float32v jitter = float32v( this->kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
std::array<float32v, kMaxDistanceCount> value;
std::array<float32v, kMaxDistanceCount> distance;
@ -82,7 +87,7 @@ class FS_T<FastNoise::CellularValue, FS> : public virtual FastNoise::CellularVal
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z ) const final
{
float32v jitter = float32v( kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
float32v jitter = float32v( this->kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
std::array<float32v, kMaxDistanceCount> value;
std::array<float32v, kMaxDistanceCount> distance;
@ -158,7 +163,7 @@ class FS_T<FastNoise::CellularValue, FS> : public virtual FastNoise::CellularVal
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z , float32v w ) const final
{
float32v jitter = float32v( kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
float32v jitter = float32v( this->kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
std::array<float32v, kMaxDistanceCount> value;
std::array<float32v, kMaxDistanceCount> distance;
@ -252,7 +257,7 @@ class FS_T<FastNoise::CellularDistance, FS> : public virtual FastNoise::Cellular
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y ) const final
{
float32v jitter = float32v( kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
float32v jitter = float32v( this->kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
std::array<float32v, kMaxDistanceCount> distance;
distance.fill( float32v( INFINITY ) );
@ -301,7 +306,7 @@ class FS_T<FastNoise::CellularDistance, FS> : public virtual FastNoise::Cellular
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z ) const final
{
float32v jitter = float32v( kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
float32v jitter = float32v( this->kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
std::array<float32v, kMaxDistanceCount> distance;
distance.fill( float32v( INFINITY ) );
@ -362,7 +367,7 @@ class FS_T<FastNoise::CellularDistance, FS> : public virtual FastNoise::Cellular
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z, float32v w ) const final
{
float32v jitter = float32v( kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
float32v jitter = float32v( this->kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
std::array<float32v, kMaxDistanceCount> distance;
distance.fill( float32v( INFINITY ) );
@ -475,7 +480,7 @@ class FS_T<FastNoise::CellularLookup, FS> : public virtual FastNoise::CellularLo
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y ) const final
{
float32v jitter = float32v( kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
float32v jitter = float32v( this->kJitter2D ) * this->GetSourceValue( mJitterModifier, seed, x, y );
float32v distance( FLT_MAX );
float32v cellX, cellY;
@ -522,7 +527,7 @@ class FS_T<FastNoise::CellularLookup, FS> : public virtual FastNoise::CellularLo
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z ) const final
{
float32v jitter = float32v( kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
float32v jitter = float32v( this->kJitter3D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z );
float32v distance( FLT_MAX );
float32v cellX, cellY, cellZ;
@ -582,7 +587,7 @@ class FS_T<FastNoise::CellularLookup, FS> : public virtual FastNoise::CellularLo
float32v FS_VECTORCALL Gen( int32v seed, float32v x, float32v y, float32v z, float32v w ) const final
{
float32v jitter = float32v( kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
float32v jitter = float32v( this->kJitter4D ) * this->GetSourceValue( mJitterModifier, seed, x, y, z, w );
float32v distance( FLT_MAX );
float32v cellX, cellY, cellZ, cellW;

View File

@ -15,23 +15,34 @@ namespace FastNoise
GeneratorSource mSource;
HybridSource mWarpAmplitude = 1.0f;
float mWarpFrequency = 0.5f;
FASTNOISE_METADATA_ABSTRACT( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Domain Warp" );
this->AddGeneratorSource( "Source", &DomainWarp::SetSource );
this->AddHybridSource( "Warp Amplitude", 1.0f, &DomainWarp::SetWarpAmplitude, &DomainWarp::SetWarpAmplitude );
this->AddVariable( "Warp Frequency", 0.5f, &DomainWarp::SetWarpFrequency );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainWarp> : MetadataT<Generator>
{
MetadataT()
{
groups.push_back( "Domain Warp" );
this->AddGeneratorSource( "Source", &DomainWarp::SetSource );
this->AddHybridSource( "Warp Amplitude", 1.0f, &DomainWarp::SetWarpAmplitude, &DomainWarp::SetWarpAmplitude );
this->AddVariable( "Warp Frequency", 0.5f, &DomainWarp::SetWarpFrequency );
}
};
#endif
class DomainWarpGradient : public virtual DomainWarp
{
FASTNOISE_METADATA( DomainWarp )
using DomainWarp::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainWarpGradient> : MetadataT<DomainWarp>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
}

View File

@ -22,9 +22,9 @@ public:
const FastNoise::HybridSource& GetWarpAmplitude() const { return mWarpAmplitude; }
const FastNoise::GeneratorSource& GetWarpSource() const { return mSource; }
virtual void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v& xOut, float32v& yOut ) const = 0;
virtual void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v& xOut, float32v& yOut, float32v& zOut ) const = 0;
virtual void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v w, float32v& xOut, float32v& yOut, float32v& zOut, float32v& wOut ) const = 0;
virtual float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v& xOut, float32v& yOut ) const = 0;
virtual float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v& xOut, float32v& yOut, float32v& zOut ) const = 0;
virtual float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v w, float32v& xOut, float32v& yOut, float32v& zOut, float32v& wOut ) const = 0;
};
template<typename FS>
@ -33,7 +33,7 @@ class FS_T<FastNoise::DomainWarpGradient, FS> : public virtual FastNoise::Domain
FASTSIMD_DECLARE_FS_TYPES;
public:
void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v& xOut, float32v& yOut ) const final
float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v& xOut, float32v& yOut ) const final
{
float32v xs = FS_Floor_f32( x );
float32v ys = FS_Floor_f32( y );
@ -58,13 +58,20 @@ public:
#undef GRADIENT_COORD
float32v normalise = warpAmp * float32v( 1.0f / (0xffff / 2.0f) );
float32v normalise = float32v( 1.0f / (0xffff / 2.0f) );
xOut = FS_FMulAdd_f32( FnUtils::Lerp( FnUtils::Lerp( x00, x10, xs ), FnUtils::Lerp( x01, x11, xs ), ys ) - float32v( 0xffff / 2.0f ), normalise, xOut );
yOut = FS_FMulAdd_f32( FnUtils::Lerp( FnUtils::Lerp( y00, y10, xs ), FnUtils::Lerp( y01, y11, xs ), ys ) - float32v( 0xffff / 2.0f ), normalise, yOut );
float32v xWarp = (FnUtils::Lerp( FnUtils::Lerp( x00, x10, xs ), FnUtils::Lerp( x01, x11, xs ), ys ) - float32v( 0xffff / 2.0f )) * normalise;
float32v yWarp = (FnUtils::Lerp( FnUtils::Lerp( y00, y10, xs ), FnUtils::Lerp( y01, y11, xs ), ys ) - float32v( 0xffff / 2.0f )) * normalise;
xOut = FS_FMulAdd_f32( xWarp, warpAmp, xOut );
yOut = FS_FMulAdd_f32( yWarp, warpAmp, yOut );
float32v warpLengthSq = FS_FMulAdd_f32( xWarp, xWarp, yWarp * yWarp );
return warpLengthSq * FS_InvSqrt_f32( warpLengthSq );
}
void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v& xOut, float32v& yOut, float32v& zOut ) const final
float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v& xOut, float32v& yOut, float32v& zOut ) const final
{
float32v xs = FS_Floor_f32( x );
float32v ys = FS_Floor_f32( y );
@ -106,14 +113,22 @@ public:
float32v y1z = FnUtils::Lerp( FnUtils::Lerp( y001, y101, xs ), FnUtils::Lerp( y011, y111, xs ), ys );
float32v z1z = FnUtils::Lerp( FnUtils::Lerp( z001, z101, xs ), FnUtils::Lerp( z011, z111, xs ), ys );
float32v normalise = warpAmp * float32v( 1.0f / (0x3ff / 2.0f) );
float32v normalise = float32v( 1.0f / (0x3ff / 2.0f) );
xOut = FS_FMulAdd_f32( FnUtils::Lerp( x0z, x1z, zs ) - float32v( 0x3ff / 2.0f ), normalise, xOut );
yOut = FS_FMulAdd_f32( FnUtils::Lerp( y0z, y1z, zs ) - float32v( 0x3ff / 2.0f ), normalise, yOut );
zOut = FS_FMulAdd_f32( FnUtils::Lerp( z0z, z1z, zs ) - float32v( 0x3ff / 2.0f ), normalise, zOut );
float32v xWarp = (FnUtils::Lerp( x0z, x1z, zs ) - float32v( 0x3ff / 2.0f )) * normalise;
float32v yWarp = (FnUtils::Lerp( y0z, y1z, zs ) - float32v( 0x3ff / 2.0f )) * normalise;
float32v zWarp = (FnUtils::Lerp( z0z, z1z, zs ) - float32v( 0x3ff / 2.0f )) * normalise;
xOut = FS_FMulAdd_f32( xWarp, warpAmp, xOut );
yOut = FS_FMulAdd_f32( yWarp, warpAmp, yOut );
zOut = FS_FMulAdd_f32( zWarp, warpAmp, zOut );
float32v warpLengthSq = FS_FMulAdd_f32( xWarp, xWarp, FS_FMulAdd_f32( yWarp, yWarp, zWarp * zWarp ) );
return warpLengthSq * FS_InvSqrt_f32( warpLengthSq );
}
void FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v w, float32v& xOut, float32v& yOut, float32v& zOut, float32v& wOut ) const final
float32v FS_VECTORCALL Warp( int32v seed, float32v warpAmp, float32v x, float32v y, float32v z, float32v w, float32v& xOut, float32v& yOut, float32v& zOut, float32v& wOut ) const final
{
float32v xs = FS_Floor_f32( x );
float32v ys = FS_Floor_f32( y );
@ -170,12 +185,21 @@ public:
float32v z1w = FnUtils::Lerp( FnUtils::Lerp( FnUtils::Lerp( z0001, z1001, xs ), FnUtils::Lerp( z0101, z1101, xs ), ys ), FnUtils::Lerp( FnUtils::Lerp( z0011, z1011, xs ), FnUtils::Lerp( z0111, z1111, xs ), ys ), zs );
float32v w1w = FnUtils::Lerp( FnUtils::Lerp( FnUtils::Lerp( w0001, w1001, xs ), FnUtils::Lerp( w0101, w1101, xs ), ys ), FnUtils::Lerp( FnUtils::Lerp( w0011, w1011, xs ), FnUtils::Lerp( w0111, w1111, xs ), ys ), zs );
float32v normalise = warpAmp * float32v( 1.0f / (0xff / 2.0f) );
float32v normalise = float32v( 1.0f / (0xff / 2.0f) );
xOut = FS_FMulAdd_f32( FnUtils::Lerp( x0w, x1w, ws ) - float32v( 0xff / 2.0f ), normalise, xOut );
yOut = FS_FMulAdd_f32( FnUtils::Lerp( y0w, y1w, ws ) - float32v( 0xff / 2.0f ), normalise, yOut );
zOut = FS_FMulAdd_f32( FnUtils::Lerp( z0w, z1w, ws ) - float32v( 0xff / 2.0f ), normalise, zOut );
wOut = FS_FMulAdd_f32( FnUtils::Lerp( w0w, w1w, ws ) - float32v( 0xff / 2.0f ), normalise, wOut );
float32v xWarp = (FnUtils::Lerp( x0w, x1w, ws ) - float32v( 0xff / 2.0f )) * normalise;
float32v yWarp = (FnUtils::Lerp( y0w, y1w, ws ) - float32v( 0xff / 2.0f )) * normalise;
float32v zWarp = (FnUtils::Lerp( z0w, z1w, ws ) - float32v( 0xff / 2.0f )) * normalise;
float32v wWarp = (FnUtils::Lerp( w0w, w1w, ws ) - float32v( 0xff / 2.0f )) * normalise;
xOut = FS_FMulAdd_f32( xWarp, warpAmp, xOut );
yOut = FS_FMulAdd_f32( yWarp, warpAmp, yOut );
zOut = FS_FMulAdd_f32( zWarp, warpAmp, zOut );
wOut = FS_FMulAdd_f32( wWarp, warpAmp, wOut );
float32v warpLengthSq = FS_FMulAdd_f32( xWarp, xWarp, FS_FMulAdd_f32( yWarp, yWarp, FS_FMulAdd_f32( zWarp, zWarp, wWarp * wWarp ) ) );
return warpLengthSq * FS_InvSqrt_f32( warpLengthSq );
}
};

View File

@ -6,21 +6,41 @@ namespace FastNoise
{
class DomainWarpFractalProgressive : public virtual Fractal<DomainWarp>
{
FASTNOISE_METADATA( Fractal<DomainWarp> )
Metadata( const char* className ) : Fractal<DomainWarp>::Metadata( className, "Domain Warp Source" )
{
groups.push_back( "Domain Warp" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainWarpFractalProgressive> : MetadataT<Fractal<DomainWarp>>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT() : MetadataT<Fractal<DomainWarp>>( "Domain Warp Source" )
{
groups.push_back( "Domain Warp" );
}
};
#endif
class DomainWarpFractalIndependant : public virtual Fractal<DomainWarp>
{
FASTNOISE_METADATA( Fractal<DomainWarp> )
Metadata( const char* className ) : Fractal<DomainWarp>::Metadata( className, "Domain Warp Source" )
{
groups.push_back( "Domain Warp" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainWarpFractalIndependant> : MetadataT<Fractal<DomainWarp>>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT() : MetadataT<Fractal<DomainWarp>>( "Domain Warp Source" )
{
groups.push_back( "Domain Warp" );
}
};
#endif
}

View File

@ -14,20 +14,22 @@ class FS_T<FastNoise::DomainWarpFractalProgressive, FS> : public virtual FastNoi
auto* warp = this->GetSourceSIMD( mSource );
float32v amp = float32v( mFractalBounding ) * this->GetSourceValue( warp->GetWarpAmplitude(), seed, pos... );
float32v weightedStrength = this->GetSourceValue( mWeightedStrength, seed, pos... );
float32v freq = float32v( warp->GetWarpFrequency() );
int32v seedInc = seed;
float32v gain = this->GetSourceValue( mGain, seed, pos... );
float32v lacunarity( mLacunarity );
warp->Warp( seedInc, amp, (pos * freq)..., pos... );
float32v strength = warp->Warp( seedInc, amp, (pos * freq)..., pos... );
for (int i = 1; i < mOctaves; i++)
{
seedInc -= int32v( -1 );
freq *= lacunarity;
amp *= FnUtils::Lerp( float32v( 1 ), float32v( 1 ) - strength, weightedStrength );
amp *= gain;
warp->Warp( seedInc, amp, (pos * freq)..., pos... );
strength = warp->Warp( seedInc, amp, (pos * freq)..., pos... );
}
return this->GetSourceValue( warp->GetWarpSource(), seed, pos... );
@ -48,20 +50,22 @@ class FS_T<FastNoise::DomainWarpFractalIndependant, FS> : public virtual FastNoi
auto* warp = this->GetSourceSIMD( mSource );
float32v amp = float32v( mFractalBounding ) * this->GetSourceValue( warp->GetWarpAmplitude(), seed, noisePos... );
float32v weightedStrength = this->GetSourceValue( mWeightedStrength, seed, noisePos... );
float32v freq = float32v( warp->GetWarpFrequency() );
int32v seedInc = seed;
float32v gain = this->GetSourceValue( mGain, seed, noisePos... );
float32v lacunarity( mLacunarity );
warp->Warp( seedInc, amp, (noisePos * freq)..., warpPos... );
float32v strength = warp->Warp( seedInc, amp, (noisePos * freq)..., warpPos... );
for( int i = 1; i < mOctaves; i++ )
{
seedInc -= int32v( -1 );
freq *= lacunarity;
amp *= FnUtils::Lerp( float32v( 1 ), float32v( 1 ) - strength, weightedStrength );
amp *= gain;
warp->Warp( seedInc, amp, (noisePos * freq)..., warpPos... );
strength = warp->Warp( seedInc, amp, (noisePos * freq)..., warpPos... );
}
return this->GetSourceValue( warp->GetWarpSource(), seed, warpPos... );

View File

@ -10,14 +10,17 @@ namespace FastNoise
void SetSource( SmartNodeArg<T> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetGain( float value ) { mGain = value; CalculateFractalBounding(); }
void SetGain( SmartNodeArg<> gen ) { mGain = 1.0f; this->SetSourceMemberVariable( mGain, gen ); CalculateFractalBounding(); }
void SetOctaveCount( int32_t value ) { mOctaves = value; CalculateFractalBounding(); }
void SetWeightedStrength( float value ) { mWeightedStrength = value; }
void SetWeightedStrength( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mWeightedStrength, gen ); }
void SetOctaveCount( int value ) { mOctaves = value; CalculateFractalBounding(); }
void SetLacunarity( float value ) { mLacunarity = value; }
protected:
GeneratorSourceT<T> mSource;
HybridSource mGain = 0.5f;
HybridSource mWeightedStrength = 0.0f;
int32_t mOctaves = 3;
int mOctaves = 3;
float mLacunarity = 2.0f;
float mFractalBounding = 1.0f / 1.75f;
@ -26,78 +29,85 @@ namespace FastNoise
float gain = std::abs( mGain.constant );
float amp = gain;
float ampFractal = 1.0f;
for( int32_t i = 1; i < mOctaves; i++ )
for( int i = 1; i < mOctaves; i++ )
{
ampFractal += amp;
amp *= gain;
}
mFractalBounding = 1.0f / ampFractal;
}
FASTNOISE_METADATA_ABSTRACT( Generator )
Metadata( const char* className, const char* sourceName = "Source" ) : Generator::Metadata( className )
{
groups.push_back( "Fractal" );
this->AddGeneratorSource( sourceName, &Fractal::SetSource );
this->AddHybridSource( "Gain", 0.5f, &Fractal::SetGain, &Fractal::SetGain );
this->AddVariable( "Octaves", 3, &Fractal::SetOctaveCount, 2, 16 );
this->AddVariable( "Lacunarity", 2.0f, &Fractal::SetLacunarity );
}
};
}
};
#ifdef FASTNOISE_METADATA
template<typename T>
struct MetadataT<Fractal<T>> : MetadataT<Generator>
{
MetadataT( const char* sourceName = "Source" )
{
groups.push_back( "Fractal" );
this->AddGeneratorSource( sourceName, &Fractal<T>::SetSource );
this->AddHybridSource( "Gain", 0.5f, &Fractal<T>::SetGain, &Fractal<T>::SetGain );
this->AddHybridSource( "Weighted Strength", 0.0f, &Fractal<T>::SetWeightedStrength, &Fractal<T>::SetWeightedStrength );
this->AddVariable( "Octaves", 3, &Fractal<T>::SetOctaveCount, 2, 16 );
this->AddVariable( "Lacunarity", 2.0f, &Fractal<T>::SetLacunarity );
}
};
#endif
class FractalFBm : public virtual Fractal<>
{
FASTNOISE_METADATA( Fractal )
using Fractal::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
class FractalBillow : public virtual Fractal<>
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<FractalFBm> : MetadataT<Fractal<>>
{
FASTNOISE_METADATA( Fractal )
using Fractal::Metadata::Metadata;
};
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class FractalRidged : public virtual Fractal<>
{
FASTNOISE_METADATA( Fractal )
using Fractal::Metadata::Metadata;
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
class FractalRidgedMulti : public virtual Fractal<>
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<FractalRidged> : MetadataT<Fractal<>>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
};
#endif
class FractalPingPong : public virtual Fractal<>
{
public:
void SetWeightAmplitude( float value ) { mWeightAmp = value; CalculateFractalBounding(); }
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetPingPongStrength( float value ) { mPingPongStrength = value; }
void SetPingPongStrength( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mPingPongStrength, gen ); }
protected:
float mWeightAmp = 2.0f;
float mWeightBounding = 2.0f / 1.75f;
void CalculateFractalBounding() override
{
Fractal::CalculateFractalBounding();
float weight = 1.0f;
float totalWeight = weight;
for( int32_t i = 1; i < mOctaves; i++ )
{
weight *= mWeightAmp;
totalWeight += 1.0f / weight;
}
mWeightBounding = 2.0f / totalWeight;
}
FASTNOISE_METADATA( Fractal )
Metadata( const char* className ) : Fractal::Metadata( className )
{
this->AddVariable( "Weight Amplitude", 2.0f, &FractalRidgedMulti::SetWeightAmplitude );
}
};
HybridSource mPingPongStrength = 0.0f;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<FractalPingPong> : MetadataT<Fractal<>>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
this->AddHybridSource( "Ping Pong Strength", 2.0f, &FractalPingPong::SetPingPongStrength, &FractalPingPong::SetPingPongStrength );
}
};
#endif
}

View File

@ -18,45 +18,24 @@ class FS_T<FastNoise::FractalFBm, FS> : public virtual FastNoise::FractalFBm, pu
FS_INLINE float32v GenT( int32v seed, P... pos ) const
{
float32v gain = this->GetSourceValue( mGain , seed, pos... );
float32v sum = this->GetSourceValue( mSource, seed, pos... );
float32v weightedStrength = this->GetSourceValue( mWeightedStrength, seed, pos... );
float32v lacunarity( mLacunarity );
float32v amp( 1 );
float32v amp( mFractalBounding );
float32v noise = this->GetSourceValue( mSource, seed, pos... );
float32v sum = noise * amp;
for( int i = 1; i < mOctaves; i++ )
{
seed -= int32v( -1 );
amp *= FnUtils::Lerp( float32v( 1 ), (noise + float32v( 1 )) * float32v( 0.5f ), weightedStrength );
amp *= gain;
sum += this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ) * amp;
noise = this->GetSourceValue( mSource, seed, (pos *= lacunarity)... );
sum += noise * amp;
}
return sum * float32v( mFractalBounding );
}
};
template<typename FS>
class FS_T<FastNoise::FractalBillow, FS> : public virtual FastNoise::FractalBillow, public FS_T<FastNoise::Fractal<>, FS>
{
FASTSIMD_DECLARE_FS_TYPES;
FASTNOISE_IMPL_GEN_T;
template<typename... P>
FS_INLINE float32v GenT( int32v seed, P... pos ) const
{
float32v sum = FS_Abs_f32( this->GetSourceValue( mSource, seed, pos... ) ) * float32v( 2 ) - float32v( 1 );
float32v gain = this->GetSourceValue( mGain, seed, pos... );
float32v lacunarity( mLacunarity );
float32v amp( 1 );
for( int i = 1; i < mOctaves; i++ )
{
seed -= int32v( -1 );
amp *= gain;
sum += (FS_Abs_f32(this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ) ) * float32v( 2 ) - float32v( 1 )) * amp;
}
return sum * float32v( mFractalBounding );
return sum;
}
};
@ -69,17 +48,22 @@ class FS_T<FastNoise::FractalRidged, FS> : public virtual FastNoise::FractalRidg
template<typename... P>
FS_INLINE float32v GenT(int32v seed, P... pos) const
{
float32v sum = float32v( 1 ) - FS_Abs_f32( this->GetSourceValue( mSource, seed, pos... ) );
float32v gain = this->GetSourceValue( mGain, seed, pos... );
float32v weightedStrength = this->GetSourceValue( mWeightedStrength, seed, pos... );
float32v lacunarity( mLacunarity );
float32v amp( 1 );
float32v amp( mFractalBounding );
float32v noise = FS_Abs_f32( this->GetSourceValue( mSource, seed, pos... ) );
float32v sum = (noise * float32v( -2 ) + float32v( 1 )) * amp;
for( int i = 1; i < mOctaves; i++ )
{
seed -= int32v( -1 );
amp *= FnUtils::Lerp( float32v( 1 ), float32v( 1 ) - noise, weightedStrength );
amp *= gain;
sum -= (float32v( 1 ) - FS_Abs_f32( this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ) )) * amp;
noise = FS_Abs_f32( this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ) );
sum += (noise * float32v( -2 ) + float32v( 1 )) * amp;
}
return sum;
@ -87,42 +71,39 @@ class FS_T<FastNoise::FractalRidged, FS> : public virtual FastNoise::FractalRidg
};
template<typename FS>
class FS_T<FastNoise::FractalRidgedMulti, FS> : public virtual FastNoise::FractalRidgedMulti, public FS_T<FastNoise::Fractal<>, FS>
class FS_T<FastNoise::FractalPingPong, FS> : public virtual FastNoise::FractalPingPong, public FS_T<FastNoise::Fractal<>, FS>
{
FASTSIMD_DECLARE_FS_TYPES;
FASTNOISE_IMPL_GEN_T;
static float32v PingPong( float32v t )
{
t -= FS_Round_f32( t * float32v( 0.5f ) ) * float32v( 2 );
return FS_Select_f32( t < float32v( 1 ), t, float32v( 2 ) - t );
}
template<typename... P>
FS_INLINE float32v GenT( int32v seed, P... pos ) const
{
float32v offset( 1 );
float32v sum = offset - FS_Abs_f32( this->GetSourceValue( mSource, seed, pos... ) );
float32v gain = this->GetSourceValue( mGain, seed, pos... ) * float32v( 6 );
float32v gain = this->GetSourceValue( mGain , seed, pos... );
float32v weightedStrength = this->GetSourceValue( mWeightedStrength, seed, pos... );
float32v pingPongStrength = this->GetSourceValue( mPingPongStrength, seed, pos... );
float32v lacunarity( mLacunarity );
float32v amp = sum;
float32v amp( mFractalBounding );
float32v noise = PingPong( (this->GetSourceValue( mSource, seed, pos... ) + float32v( 1 )) * pingPongStrength );
float32v weightAmp( mWeightAmp );
float32v weight = weightAmp;
float32v totalWeight( 1.0f );
float32v sum = noise * amp;
for( int i = 1; i < mOctaves; i++ )
{
amp *= gain;
amp = FS_Min_f32( FS_Max_f32( amp, float32v( 0 ) ), float32v( 1 ) );
seed -= int32v( -1 );
float32v value = offset - FS_Abs_f32( this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ));
amp *= FnUtils::Lerp( float32v( 1 ), (noise + float32v( 1 )) * float32v( 0.5f ), weightedStrength );
amp *= gain;
value *= amp;
amp = value;
float32v weightRecip = FS_Reciprocal_f32( float32v( weight ) );
sum += value * weightRecip;
totalWeight += weightRecip;
weight *= weightAmp;
noise = PingPong( (this->GetSourceValue( mSource, seed, (pos *= lacunarity)... ) + float32v( 1 )) * pingPongStrength );
sum += noise * amp;
}
return sum * float32v( mWeightBounding ) - offset;
return sum;
}
};

View File

@ -1,8 +1,13 @@
#pragma once
#include <cassert>
#include <cmath>
#include <algorithm>
#include "FastNoise/FastNoiseMetadata.h"
#include "FastNoise/FastNoise_Config.h"
#if !defined( FASTNOISE_METADATA ) && defined( __INTELLISENSE__ )
//#define FASTNOISE_METADATA
#endif
namespace FastNoise
{
@ -12,30 +17,45 @@ namespace FastNoise
Count
};
constexpr static const char* kDim_Strings[] =
{
"X", "Y", "Z", "W",
};
enum class DistanceFunction
{
Euclidean,
EuclideanSquared,
Manhattan,
Hybrid,
MaxAxis,
};
constexpr static const char* kDistanceFunction_Strings[] =
{
"Euclidean",
"Euclidean Squared",
"Manhattan",
"Hybrid",
"Max Axis",
};
struct OutputMinMax
{
float min = INFINITY;
float min = INFINITY;
float max = -INFINITY;
OutputMinMax& operator <<( float v )
{
min = fminf( min, v );
max = fmaxf( max, v );
min = std::min( min, v );
max = std::max( max, v );
return *this;
}
OutputMinMax& operator <<( const OutputMinMax& v )
{
min = fminf( min, v.min );
max = fmaxf( max, v.max );
min = std::min( min, v.min );
max = std::max( max, v.max );
return *this;
}
};
@ -45,8 +65,8 @@ namespace FastNoise
{
using Type = T;
SmartNode<T> base;
void* simdGeneratorPtr = nullptr;
SmartNode<const T> base;
const void* simdGeneratorPtr = nullptr;
protected:
BaseSource() = default;
@ -67,54 +87,65 @@ namespace FastNoise
}
};
class Generator
class FASTNOISE_API Generator
{
public:
using Metadata = FastNoise::Metadata;
friend Metadata;
template<typename T>
friend struct MetadataT;
virtual ~Generator() = default;
virtual FastSIMD::eLevel GetSIMDLevel() const = 0;
virtual const Metadata* GetMetadata() const = 0;
virtual const Metadata& GetMetadata() const = 0;
virtual OutputMinMax GenUniformGrid2D( float* noiseOut,
int32_t xStart, int32_t yStart,
int32_t xSize, int32_t ySize,
float frequency, int32_t seed ) const = 0;
virtual OutputMinMax GenUniformGrid2D( float* out,
int xStart, int yStart,
int xSize, int ySize,
float frequency, int seed ) const = 0;
virtual OutputMinMax GenUniformGrid3D( float* noiseOut,
int32_t xStart, int32_t yStart, int32_t zStart,
int32_t xSize, int32_t ySize, int32_t zSize,
float frequency, int32_t seed ) const = 0;
virtual OutputMinMax GenUniformGrid3D( float* out,
int xStart, int yStart, int zStart,
int xSize, int ySize, int zSize,
float frequency, int seed ) const = 0;
virtual OutputMinMax GenPositionArray2D( float* noiseOut, int32_t count,
virtual OutputMinMax GenUniformGrid4D( float* out,
int xStart, int yStart, int zStart, int wStart,
int xSize, int ySize, int zSize, int wSize,
float frequency, int seed ) const = 0;
virtual OutputMinMax GenTileable2D( float* out,
int xSize, int ySize, float frequency, int seed ) const = 0;
virtual OutputMinMax GenPositionArray2D( float* out, int count,
const float* xPosArray, const float* yPosArray,
float xOffset, float yOffset, int32_t seed ) const = 0;
float xOffset, float yOffset, int seed ) const = 0;
virtual OutputMinMax GenPositionArray3D( float* noiseOut, int32_t count,
virtual OutputMinMax GenPositionArray3D( float* out, int count,
const float* xPosArray, const float* yPosArray, const float* zPosArray,
float xOffset, float yOffset, float zOffset, int32_t seed ) const = 0;
float xOffset, float yOffset, float zOffset, int seed ) const = 0;
virtual OutputMinMax GenTileable2D( float* noiseOut,
int32_t xSize, int32_t ySize,
float frequency, int32_t seed ) const = 0;
virtual OutputMinMax GenPositionArray4D( float* out, int count,
const float* xPosArray, const float* yPosArray, const float* zPosArray, const float* wPosArray,
float xOffset, float yOffset, float zOffset, float wOffset, int seed ) const = 0;
virtual float GenSingle2D( float x, float y, int seed ) const = 0;
virtual float GenSingle3D( float x, float y, float z, int seed ) const = 0;
virtual float GenSingle4D( float x, float y, float z, float w, int seed ) const = 0;
protected:
template<typename T>
void SetSourceMemberVariable( BaseSource<T>& memberVariable, SmartNodeArg<T> gen )
{
static_assert( std::is_base_of_v<Generator, T> );
assert( gen.get() );
assert( GetSIMDLevel() == gen->GetSIMDLevel() ); // Ensure that all SIMD levels match
static_assert( std::is_base_of<Generator, T>::value, "T must be child of FastNoise::Generator class" );
assert( !gen.get() || GetSIMDLevel() == gen->GetSIMDLevel() ); // Ensure that all SIMD levels match
SetSourceSIMDPtr( dynamic_cast<const Generator*>( gen.get() ), &memberVariable.simdGeneratorPtr );
memberVariable.base = gen;
SetSourceSIMDPtr( dynamic_cast<Generator*>( gen.get() ), &memberVariable.simdGeneratorPtr );
}
private:
virtual void SetSourceSIMDPtr( Generator* base, void** simdPtr ) = 0;
virtual void SetSourceSIMDPtr( const Generator* base, const void** simdPtr ) = 0;
};
using GeneratorSource = GeneratorSourceT<Generator>;
@ -146,4 +177,267 @@ namespace FastNoise
return varArray[i];
}
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Generator> : Metadata
{
protected:
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddVariable( const char* name, T defaultV, U&& func, T minV = 0, T maxV = 0 )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v )
{
if( auto* gRealType = dynamic_cast<GetArg<U, 0>>( g ) )
{
func( gRealType, v );
return true;
}
return false;
};
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddVariable( const char* name, T defaultV, void(U::* func)(T), T minV = 0, T maxV = 0 )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
(gRealType->*func)( v );
return true;
}
return false;
};
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<std::is_enum_v<T>>, typename... ENUM_NAMES>
void AddVariableEnum( const char* name, T defaultV, void(U::* func)(T), ENUM_NAMES... enumNames )
{
MemberVariable member;
member.name = name;
member.type = MemberVariable::EEnum;
member.valueDefault = (int)defaultV;
member.enumNames = { enumNames... };
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
(gRealType->*func)( (T)v.i );
return true;
}
return false;
};
memberVariables.push_back( member );
}
template<typename T, typename U, size_t ENUM_NAMES, typename = std::enable_if_t<std::is_enum_v<T>>>
void AddVariableEnum( const char* name, T defaultV, void(U::* func)(T), const char* const (&enumNames)[ENUM_NAMES] )
{
MemberVariable member;
member.name = name;
member.type = MemberVariable::EEnum;
member.valueDefault = (int)defaultV;
member.enumNames = { enumNames, enumNames + ENUM_NAMES };
member.setFunc = [func]( Generator* g, MemberVariable::ValueUnion v )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
(gRealType->*func)( (T)v.i );
return true;
}
return false;
};
memberVariables.push_back( member );
}
template<typename T, typename U, typename = std::enable_if_t<!std::is_enum_v<T>>>
void AddPerDimensionVariable( const char* name, T defaultV, U&& func, T minV = 0, T maxV = 0 )
{
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<T>::varArray ) / sizeof( *PerDimensionVariable<T>::varArray ); idx++ )
{
MemberVariable member;
member.name = name;
member.valueDefault = defaultV;
member.valueMin = minV;
member.valueMax = maxV;
member.type = std::is_same_v<T, float> ? MemberVariable::EFloat : MemberVariable::EInt;
member.dimensionIdx = idx;
member.setFunc = [func, idx]( Generator* g, MemberVariable::ValueUnion v )
{
if( auto* gRealType = dynamic_cast<GetArg<U, 0>>( g ) )
{
func( gRealType ).get()[idx] = v;
return true;
}
return false;
};
memberVariables.push_back( member );
}
}
template<typename T, typename U>
void AddGeneratorSource( const char* name, void(U::* func)(SmartNodeArg<T>) )
{
MemberNodeLookup member;
member.name = name;
member.setFunc = [func]( Generator* g, SmartNodeArg<> s )
{
if( const T* sUpCast = dynamic_cast<const T*>( s.get() ) )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
SmartNode<const T> source( s, sUpCast );
(gRealType->*func)( source );
return true;
}
}
return false;
};
memberNodeLookups.push_back( member );
}
template<typename U>
void AddPerDimensionGeneratorSource( const char* name, U&& func )
{
using GeneratorSourceT = typename std::invoke_result_t<U, GetArg<U, 0>>::type::Type;
using T = typename GeneratorSourceT::Type;
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<GeneratorSourceT>::varArray ) / sizeof( *PerDimensionVariable<GeneratorSourceT>::varArray ); idx++ )
{
MemberNodeLookup member;
member.name = name;
member.dimensionIdx = idx;
member.setFunc = [func, idx]( Generator* g, SmartNodeArg<> s )
{
if( const T* sUpCast = dynamic_cast<const T*>( s.get() ) )
{
if( auto* gRealType = dynamic_cast<GetArg<U, 0>>( g ) )
{
SmartNode<const T> source( s, sUpCast );
g->SetSourceMemberVariable( func( gRealType ).get()[idx], source );
return true;
}
}
return false;
};
memberNodeLookups.push_back( member );
}
}
template<typename T, typename U>
void AddHybridSource( const char* name, float defaultValue, void(U::* funcNode)(SmartNodeArg<T>), void(U::* funcValue)(float) )
{
MemberHybrid member;
member.name = name;
member.valueDefault = defaultValue;
member.setNodeFunc = [funcNode]( Generator* g, SmartNodeArg<> s )
{
if( const T* sUpCast = dynamic_cast<const T*>( s.get() ) )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
SmartNode<const T> source( s, sUpCast );
(gRealType->*funcNode)( source );
return true;
}
}
return false;
};
member.setValueFunc = [funcValue]( Generator* g, float v )
{
if( U* gRealType = dynamic_cast<U*>( g ) )
{
(gRealType->*funcValue)( v );
return true;
}
return false;
};
memberHybrids.push_back( member );
}
template<typename U>
void AddPerDimensionHybridSource( const char* name, float defaultV, U&& func )
{
using HybridSourceT = typename std::invoke_result_t<U, GetArg<U, 0>>::type::Type;
using T = typename HybridSourceT::Type;
for( int idx = 0; (size_t)idx < sizeof( PerDimensionVariable<HybridSourceT>::varArray ) / sizeof( *PerDimensionVariable<HybridSourceT>::varArray ); idx++ )
{
MemberHybrid member;
member.name = name;
member.valueDefault = defaultV;
member.dimensionIdx = idx;
member.setNodeFunc = [func, idx]( Generator* g, SmartNodeArg<> s )
{
if( const T* sUpCast = dynamic_cast<const T*>( s.get() ) )
{
if( auto* gRealType = dynamic_cast<GetArg<U, 0>>( g ) )
{
SmartNode<const T> source( s, sUpCast );
g->SetSourceMemberVariable( func( gRealType ).get()[idx], source );
return true;
}
}
return false;
};
member.setValueFunc = [func, idx]( Generator* g, float v )
{
if( auto* gRealType = dynamic_cast<GetArg<U, 0>>( g ) )
{
func( gRealType ).get()[idx] = v;
return true;
}
return false;
};
memberHybrids.push_back( member );
}
}
private:
template<typename F, typename Ret, typename... Args>
static std::tuple<Args...> GetArg_Helper( Ret( F::* )(Args...) const );
template<typename F, size_t I>
using GetArg = std::tuple_element_t<I, decltype(GetArg_Helper( &F::operator() ))>;
};
#endif
}

View File

@ -28,13 +28,19 @@ public:
return FS::SIMD_Level;
}
using VoidPtrStorageType = FS_T<Generator, FS>*;
using VoidPtrStorageType = const FS_T<Generator, FS>*;
void SetSourceSIMDPtr( Generator* base, void** simdPtr ) final
void SetSourceSIMDPtr( const Generator* base, const void** simdPtr ) final
{
if( !base )
{
*simdPtr = nullptr;
return;
}
auto simd = dynamic_cast<VoidPtrStorageType>( base );
assert( simd );
*simdPtr = reinterpret_cast<void*>( simd );
*simdPtr = reinterpret_cast<const void*>( simd );
}
template<typename T, typename... POS>
@ -64,14 +70,12 @@ public:
assert( memberVariable.simdGeneratorPtr );
auto simdGen = reinterpret_cast<VoidPtrStorageType>( memberVariable.simdGeneratorPtr );
auto simdT = static_cast<FS_T<T, FS>*>( simdGen );
auto simdT = static_cast<const FS_T<T, FS>*>( simdGen );
return simdT;
}
FastNoise::OutputMinMax GenUniformGrid2D( float* noiseOut, int32_t xStart, int32_t yStart, int32_t xSize, int32_t ySize, float frequency, int32_t seed ) const final
FastNoise::OutputMinMax GenUniformGrid2D( float* noiseOut, int xStart, int yStart, int xSize, int ySize, float frequency, int seed ) const final
{
assert( xSize >= (int32_t)FS_Size_32() );
float32v min( INFINITY );
float32v max( -INFINITY );
@ -88,6 +92,8 @@ public:
xIdx += int32v::FS_Incremented();
AxisReset<true>( xIdx, yIdx, xMax, xSizeV, xSize );
while( index < totalValues - FS_Size_32() )
{
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
@ -104,9 +110,7 @@ public:
index += FS_Size_32();
xIdx += int32v( FS_Size_32() );
mask32v xReset = xIdx > xMax;
yIdx = FS_MaskedIncrement_i32( yIdx, xReset );
xIdx = FS_MaskedSub_i32( xIdx, xSizeV, xReset );
AxisReset<false>( xIdx, yIdx, xMax, xSizeV, xSize );
}
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
@ -117,10 +121,8 @@ public:
return DoRemaining( noiseOut, totalValues, index, min, max, gen );
}
FastNoise::OutputMinMax GenUniformGrid3D( float* noiseOut, int32_t xStart, int32_t yStart, int32_t zStart, int32_t xSize, int32_t ySize, int32_t zSize, float frequency, int32_t seed ) const final
FastNoise::OutputMinMax GenUniformGrid3D( float* noiseOut, int xStart, int yStart, int zStart, int xSize, int ySize, int zSize, float frequency, int seed ) const final
{
assert( xSize >= (int32_t)FS_Size_32() );
float32v min( INFINITY );
float32v max( -INFINITY );
@ -140,6 +142,9 @@ public:
xIdx += int32v::FS_Incremented();
AxisReset<true>( xIdx, yIdx, xMax, xSizeV, xSize );
AxisReset<true>( yIdx, zIdx, yMax, ySizeV, xSize * ySize );
while( index < totalValues - FS_Size_32() )
{
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
@ -156,14 +161,9 @@ public:
index += FS_Size_32();
xIdx += int32v( FS_Size_32() );
mask32v xReset = xIdx > xMax;
yIdx = FS_MaskedIncrement_i32( yIdx, xReset );
xIdx = FS_MaskedSub_i32( xIdx, xSizeV, xReset );
mask32v yReset = yIdx > yMax;
zIdx = FS_MaskedIncrement_i32( zIdx, yReset );
yIdx = FS_MaskedSub_i32( yIdx, ySizeV, yReset );
AxisReset<false>( xIdx, yIdx, xMax, xSizeV, xSize );
AxisReset<false>( yIdx, zIdx, yMax, ySizeV, xSize * ySize );
}
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
@ -175,7 +175,68 @@ public:
return DoRemaining( noiseOut, totalValues, index, min, max, gen );
}
FastNoise::OutputMinMax GenPositionArray2D( float* noiseOut, int32_t count, const float* xPosArray, const float* yPosArray, float xOffset, float yOffset, int32_t seed ) const final
FastNoise::OutputMinMax GenUniformGrid4D( float* noiseOut, int xStart, int yStart, int zStart, int wStart, int xSize, int ySize, int zSize, int wSize, float frequency, int seed ) const final
{
float32v min( INFINITY );
float32v max( -INFINITY );
int32v xIdx( xStart );
int32v yIdx( yStart );
int32v zIdx( zStart );
int32v wIdx( wStart );
float32v freqV( frequency );
int32v xSizeV( xSize );
int32v xMax = xSizeV + xIdx + int32v( -1 );
int32v ySizeV( ySize );
int32v yMax = ySizeV + yIdx + int32v( -1 );
int32v zSizeV( zSize );
int32v zMax = zSizeV + zIdx + int32v( -1 );
size_t totalValues = xSize * ySize * zSize * wSize;
size_t index = 0;
xIdx += int32v::FS_Incremented();
AxisReset<true>( xIdx, yIdx, xMax, xSizeV, xSize );
AxisReset<true>( yIdx, zIdx, yMax, ySizeV, xSize * ySize );
AxisReset<true>( zIdx, wIdx, zMax, zSizeV, xSize * ySize * zSize );
while( index < totalValues - FS_Size_32() )
{
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
float32v yPos = FS_Converti32_f32( yIdx ) * freqV;
float32v zPos = FS_Converti32_f32( zIdx ) * freqV;
float32v wPos = FS_Converti32_f32( wIdx ) * freqV;
float32v gen = Gen( int32v( seed ), xPos, yPos, zPos, wPos );
FS_Store_f32( &noiseOut[index], gen );
#if FASTNOISE_CALC_MIN_MAX
min = FS_Min_f32( min, gen );
max = FS_Max_f32( max, gen );
#endif
index += FS_Size_32();
xIdx += int32v( FS_Size_32() );
AxisReset<false>( xIdx, yIdx, xMax, xSizeV, xSize );
AxisReset<false>( yIdx, zIdx, yMax, ySizeV, xSize * ySize );
AxisReset<false>( zIdx, wIdx, zMax, zSizeV, xSize * ySize * zSize );
}
float32v xPos = FS_Converti32_f32( xIdx ) * freqV;
float32v yPos = FS_Converti32_f32( yIdx ) * freqV;
float32v zPos = FS_Converti32_f32( zIdx ) * freqV;
float32v wPos = FS_Converti32_f32( wIdx ) * freqV;
float32v gen = Gen( int32v( seed ), xPos, yPos, zPos, wPos );
return DoRemaining( noiseOut, totalValues, index, min, max, gen );
}
FastNoise::OutputMinMax GenPositionArray2D( float* noiseOut, int count, const float* xPosArray, const float* yPosArray, float xOffset, float yOffset, int seed ) const final
{
float32v min( INFINITY );
float32v max( -INFINITY );
@ -204,13 +265,13 @@ public:
return DoRemaining( noiseOut, count, index, min, max, gen );
}
FastNoise::OutputMinMax GenPositionArray3D( float* noiseOut, int32_t count, const float* xPosArray, const float* yPosArray, const float* zPosArray, float xOffset, float yOffset, float zOffset, int32_t seed ) const final
FastNoise::OutputMinMax GenPositionArray3D( float* noiseOut, int count, const float* xPosArray, const float* yPosArray, const float* zPosArray, float xOffset, float yOffset, float zOffset, int seed ) const final
{
float32v min( INFINITY );
float32v max( -INFINITY );
int32_t index = 0;
while( index < int64_t(count) - FS_Size_32() )
size_t index = 0;
while( index < count - FS_Size_32() )
{
float32v xPos = float32v( xOffset ) + FS_Load_f32( &xPosArray[index] );
float32v yPos = float32v( yOffset ) + FS_Load_f32( &yPosArray[index] );
@ -235,10 +296,56 @@ public:
return DoRemaining( noiseOut, count, index, min, max, gen );
}
FastNoise::OutputMinMax GenTileable2D( float* noiseOut, int32_t xSize, int32_t ySize, float frequency, int32_t seed ) const final
FastNoise::OutputMinMax GenPositionArray4D( float* noiseOut, int count, const float* xPosArray, const float* yPosArray, const float* zPosArray, const float* wPosArray, float xOffset, float yOffset, float zOffset, float wOffset, int seed ) const final
{
assert( xSize >= (int32_t)FS_Size_32() );
float32v min( INFINITY );
float32v max( -INFINITY );
size_t index = 0;
while( index < count - FS_Size_32() )
{
float32v xPos = float32v( xOffset ) + FS_Load_f32( &xPosArray[index] );
float32v yPos = float32v( yOffset ) + FS_Load_f32( &yPosArray[index] );
float32v zPos = float32v( zOffset ) + FS_Load_f32( &zPosArray[index] );
float32v wPos = float32v( wOffset ) + FS_Load_f32( &wPosArray[index] );
float32v gen = Gen( int32v( seed ), xPos, yPos, zPos, wPos );
FS_Store_f32( &noiseOut[index], gen );
#if FASTNOISE_CALC_MIN_MAX
min = FS_Min_f32( min, gen );
max = FS_Max_f32( max, gen );
#endif
index += FS_Size_32();
}
float32v xPos = float32v( xOffset ) + FS_Load_f32( &xPosArray[index] );
float32v yPos = float32v( yOffset ) + FS_Load_f32( &yPosArray[index] );
float32v zPos = float32v( zOffset ) + FS_Load_f32( &zPosArray[index] );
float32v wPos = float32v( wOffset ) + FS_Load_f32( &wPosArray[index] );
float32v gen = Gen( int32v( seed ), xPos, yPos, zPos, wPos );
return DoRemaining( noiseOut, count, index, min, max, gen );
}
float GenSingle2D( float x, float y, int seed ) const final
{
return FS_Extract0_f32( Gen( int32v( seed ), float32v( x ), float32v( y ) ) );
}
float GenSingle3D( float x, float y, float z, int seed ) const final
{
return FS_Extract0_f32( Gen( int32v( seed ), float32v( x ), float32v( y ), float32v( z ) ) );
}
float GenSingle4D( float x, float y, float z, float w, int seed ) const final
{
return FS_Extract0_f32( Gen( int32v( seed ), float32v( x ), float32v( y ), float32v( z ), float32v( w ) ) );
}
FastNoise::OutputMinMax GenTileable2D( float* noiseOut, int xSize, int ySize, float frequency, int seed ) const final
{
float32v min( INFINITY );
float32v max( -INFINITY );
@ -262,6 +369,8 @@ public:
xIdx += int32v::FS_Incremented();
AxisReset<true>( xIdx, yIdx, xMax, xSizeV, xSize );
while( index < totalValues - FS_Size_32() )
{
float32v xF = FS_Converti32_f32( xIdx ) * xMul;
@ -283,9 +392,7 @@ public:
index += FS_Size_32();
xIdx += int32v( FS_Size_32() );
mask32v xReset = xIdx > xMax;
yIdx = FS_MaskedIncrement_i32( yIdx, xReset );
xIdx = FS_MaskedSub_i32( xIdx, xSizeV, xReset );
AxisReset<false>( xIdx, yIdx, xMax, xSizeV, xSize );
}
float32v xF = FS_Converti32_f32( xIdx ) * xMul;
@ -302,6 +409,17 @@ public:
}
private:
template<bool INITIAL>
static FS_INLINE void AxisReset( int32v& aIdx, int32v& bIdx, int32v aMax, int32v aSize, size_t aStep )
{
for( size_t resetLoop = INITIAL ? aStep : 0; resetLoop < FS_Size_32(); resetLoop += aStep )
{
mask32v aReset = aIdx > aMax;
bIdx = FS_MaskedIncrement_i32( bIdx, aReset );
aIdx = FS_MaskedSub_i32( aIdx, aSize, aReset );
}
}
static FS_INLINE FastNoise::OutputMinMax DoRemaining( float* noiseOut, size_t totalValues, size_t index, float32v min, float32v max, float32v finalGen )
{
FastNoise::OutputMinMax minMax;
@ -318,7 +436,7 @@ private:
}
else
{
std::memcpy( &noiseOut[index], &finalGen, remaining * sizeof( int32_t ) );
std::memcpy( &noiseOut[index], &finalGen, remaining * sizeof( float ) );
#if FASTNOISE_CALC_MIN_MAX
do

View File

@ -6,27 +6,38 @@ namespace FastNoise
class DomainScale : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetScale( float value ) { mScale = value; }
protected:
GeneratorSource mSource;
float mScale = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainScale::SetSource );
this->AddVariable( "Scale", 1.0f, &DomainScale::SetScale );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainScale> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainScale::SetSource );
this->AddVariable( "Scale", 1.0f, &DomainScale::SetScale );
}
};
#endif
class DomainOffset : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
template<Dim D>
@ -37,28 +48,38 @@ namespace FastNoise
protected:
GeneratorSource mSource;
PerDimensionVariable<HybridSource> mOffset;
PerDimensionVariable<HybridSource> mOffset = 0.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainOffset::SetSource );
this->AddPerDimensionHybridSource( "Offset", 0.0f, []( DomainOffset* p ) { return std::ref( p->mOffset ); } );
}
};
template<typename T>
friend struct MetadataT;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainOffset> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainOffset::SetSource );
this->AddPerDimensionHybridSource( "Offset", 0.0f, []( DomainOffset* p ) { return std::ref( p->mOffset ); } );
}
};
#endif
class DomainRotate : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetYaw( float value ) { mYawCos = cosf( value ); mYawSin = sinf( value ); CalculateRotation(); }
void SetPitch( float value ) { mPitchCos = cosf( value ); mPitchSin = sinf( value ); CalculateRotation(); }
void SetRoll( float value ) { mRollCos = cosf( value ); mRollSin = sinf( value ); CalculateRotation(); }
void SetYaw( float value ) { mYawCos = std::cos( value ); mYawSin = std::sin( value ); CalculateRotation(); }
void SetPitch( float value ) { mPitchCos = std::cos( value ); mPitchSin = std::sin( value ); CalculateRotation(); }
void SetRoll( float value ) { mRollCos = std::cos( value ); mRollSin = std::sin( value ); CalculateRotation(); }
protected:
GeneratorSource mSource;
@ -93,44 +114,60 @@ namespace FastNoise
mZb = mPitchCos * mRollSin;
mZc = mPitchCos * mRollCos;
}
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainRotate::SetSource );
this->AddVariable( "Yaw", 0.0f, &DomainRotate::SetYaw );
this->AddVariable( "Pitch", 0.0f, &DomainRotate::SetPitch );
this->AddVariable( "Roll", 0.0f, &DomainRotate::SetRoll );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainRotate> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainRotate::SetSource );
this->AddVariable( "Yaw", 0.0f, &DomainRotate::SetYaw );
this->AddVariable( "Pitch", 0.0f, &DomainRotate::SetPitch );
this->AddVariable( "Roll", 0.0f, &DomainRotate::SetRoll );
}
};
#endif
class SeedOffset : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetOffset( int32_t value ) { mOffset = value; }
void SetOffset( int value ) { mOffset = value; }
protected:
GeneratorSource mSource;
int32_t mOffset = 1;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &SeedOffset::SetSource );
this->AddVariable( "Seed Offset", 1, &SeedOffset::SetOffset );
}
};
int mOffset = 1;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<SeedOffset> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &SeedOffset::SetSource );
this->AddVariable( "Seed Offset", 1, &SeedOffset::SetOffset );
}
};
#endif
class Remap : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetRemap( float fromMin, float fromMax, float toMin, float toMax ) { mFromMin = fromMin; mFromMax = fromMax; mToMin = toMin; mToMax = toMax; }
@ -141,43 +178,54 @@ namespace FastNoise
float mToMin = 0.0f;
float mToMax = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &Remap::SetSource );
template<typename T>
friend struct MetadataT;
};
this->AddVariable( "From Min", -1.0f,
[]( Remap* p, float f )
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Remap> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &Remap::SetSource );
this->AddVariable( "From Min", -1.0f,
[]( Remap* p, float f )
{
p->mFromMin = f;
});
this->AddVariable( "From Max", 1.0f,
[]( Remap* p, float f )
} );
this->AddVariable( "From Max", 1.0f,
[]( Remap* p, float f )
{
p->mFromMax = f;
});
this->AddVariable( "To Min", 0.0f,
[]( Remap* p, float f )
} );
this->AddVariable( "To Min", 0.0f,
[]( Remap* p, float f )
{
p->mToMin = f;
});
} );
this->AddVariable( "To Max", 1.0f,
[]( Remap* p, float f )
this->AddVariable( "To Max", 1.0f,
[]( Remap* p, float f )
{
p->mToMax = f;
});
}
};
} );
}
};
#endif
class ConvertRGBA8 : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetMinMax( float min, float max ) { mMin = min; mMax = max; }
@ -186,31 +234,42 @@ namespace FastNoise
float mMin = -1.0f;
float mMax = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &ConvertRGBA8::SetSource );
template<typename T>
friend struct MetadataT;
};
this->AddVariable( "Min", -1.0f,
[]( ConvertRGBA8* p, float f )
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<ConvertRGBA8> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &ConvertRGBA8::SetSource );
this->AddVariable( "Min", -1.0f,
[]( ConvertRGBA8* p, float f )
{
p->mMin = f;
});
} );
this->AddVariable( "Max", 1.0f,
[]( ConvertRGBA8* p, float f )
this->AddVariable( "Max", 1.0f,
[]( ConvertRGBA8* p, float f )
{
p->mMax = f;
});
}
};
} );
}
};
#endif
class Terrace : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetMultiplier( float multiplier ) { mMultiplier = multiplier; mMultiplierRecip = 1 / multiplier; }
void SetSmoothness( float smoothness ) { mSmoothness = smoothness; if( mSmoothness != 0.0f ) mSmoothnessRecip = 1 + 1 / smoothness; }
@ -221,22 +280,30 @@ namespace FastNoise
float mMultiplierRecip = 1.0f;
float mSmoothness = 0.0f;
float mSmoothnessRecip = 0.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &Terrace::SetSource );
this->AddVariable( "Multiplier", 1.0f, &Terrace::SetMultiplier );
this->AddVariable( "Smoothness", 0.0f, &Terrace::SetSmoothness );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Terrace> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &Terrace::SetSource );
this->AddVariable( "Multiplier", 1.0f, &Terrace::SetMultiplier );
this->AddVariable( "Smoothness", 0.0f, &Terrace::SetSmoothness );
}
};
#endif
class DomainAxisScale : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
template<Dim D>
@ -244,78 +311,110 @@ namespace FastNoise
protected:
GeneratorSource mSource;
PerDimensionVariable<float> mScale;
PerDimensionVariable<float> mScale = 1.0f;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainAxisScale::SetSource );
this->AddPerDimensionVariable( "Scale", 1.0f, []( DomainAxisScale* p ) { return std::ref( p->mScale ); } );
}
};
template<typename T>
friend struct MetadataT;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<DomainAxisScale> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &DomainAxisScale::SetSource );
this->AddPerDimensionVariable( "Scale", 1.0f, []( DomainAxisScale* p ) { return std::ref( p->mScale ); } );
}
};
#endif
class AddDimension : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetNewDimensionPosition( float value ) { mNewDimensionPosition = value; }
void SetNewDimensionPosition( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mNewDimensionPosition, gen ); }
protected:
GeneratorSource mSource;
HybridSource mNewDimensionPosition;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &AddDimension::SetSource );
this->AddHybridSource( "New Dimension Position", 0.0f, &AddDimension::SetNewDimensionPosition, &AddDimension::SetNewDimensionPosition );
}
};
HybridSource mNewDimensionPosition = 0.0f;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<AddDimension> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &AddDimension::SetSource );
this->AddHybridSource( "New Dimension Position", 0.0f, &AddDimension::SetNewDimensionPosition, &AddDimension::SetNewDimensionPosition );
}
};
#endif
class RemoveDimension : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
void SetRemoveDimension( Dim dimension ) { mRemoveDimension = dimension; }
protected:
GeneratorSource mSource;
Dim mRemoveDimension = Dim::Y;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &RemoveDimension::SetSource );
this->AddVariableEnum( "Remove Dimension", Dim::Y, &RemoveDimension::SetRemoveDimension, "X", "Y", "Z", "W" );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<RemoveDimension> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &RemoveDimension::SetSource );
this->AddVariableEnum( "Remove Dimension", Dim::Y, &RemoveDimension::SetRemoveDimension, kDim_Strings );
}
};
#endif
class GeneratorCache : public virtual Generator
{
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
void SetSource( SmartNodeArg<> gen ) { this->SetSourceMemberVariable( mSource, gen ); }
protected:
GeneratorSource mSource;
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &GeneratorCache::SetSource );
}
};
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<GeneratorCache> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Modifiers" );
this->AddGeneratorSource( "Source", &GeneratorCache::SetSource );
}
};
#endif
}

View File

@ -243,10 +243,10 @@ class FS_T<FastNoise::GeneratorCache, FS> : public virtual FastNoise::GeneratorC
template<typename... P>
FS_INLINE float32v GenT( int32v seed, P... pos ) const
{
thread_local static void* CachedGenerator = nullptr;
thread_local static float32v CachedValue;
thread_local static float32v CachedPos[sizeof...( P )];
// TLS is not always aligned, so use FS_Load/FS_Store to access SIMD types
thread_local static const void* CachedGenerator = nullptr;
thread_local static float CachedValue[FS_Size_32()];
thread_local static float CachedPos[FS_Size_32()][sizeof...( P )];
// TLS is not always aligned (compiler bug), need to avoid using SIMD types
float32v arrayPos[] = { pos... };

View File

@ -5,12 +5,21 @@ namespace FastNoise
{
class Perlin : public virtual Generator
{
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Coherent Noise" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Perlin> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Coherent Noise" );
}
};
#endif
}

View File

@ -5,23 +5,41 @@ namespace FastNoise
{
class Simplex : public virtual Generator
{
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Coherent Noise" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Simplex> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Coherent Noise" );
}
};
#endif
class OpenSimplex2 : public virtual Generator
{
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Coherent Noise" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<OpenSimplex2> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Coherent Noise" );
}
};
#endif
}

View File

@ -6,12 +6,12 @@ namespace FastNoise
{
namespace Primes
{
static constexpr int32_t X = 501125321;
static constexpr int32_t Y = 1136930381;
static constexpr int32_t Z = 1720413743;
static constexpr int32_t W = 1066037191;
static constexpr int X = 501125321;
static constexpr int Y = 1136930381;
static constexpr int Z = 1720413743;
static constexpr int W = 1066037191;
static constexpr int32_t Lookup[] = { X,Y,Z,W };
static constexpr int Lookup[] = { X,Y,Z,W };
}
template<typename FS>
@ -297,6 +297,14 @@ namespace FastNoise
return both;
}
case DistanceFunction::MaxAxis:
{
float32v max = FS_Abs_f32( dX );
((max = FS_Max_f32( FS_Abs_f32(d), max )), ...);
return max;
}
}
}
};

View File

@ -5,12 +5,21 @@ namespace FastNoise
{
class Value : public virtual Generator
{
FASTNOISE_METADATA( Generator )
Metadata( const char* className ) : Generator::Metadata( className )
{
groups.push_back( "Coherent Noise" );
}
};
public:
FASTSIMD_LEVEL_SUPPORT( FastNoise::SUPPORTED_SIMD_LEVELS );
const Metadata& GetMetadata() const override;
};
#ifdef FASTNOISE_METADATA
template<>
struct MetadataT<Value> : MetadataT<Generator>
{
SmartNode<> CreateNode( FastSIMD::eLevel ) const override;
MetadataT()
{
groups.push_back( "Coherent Noise" );
}
};
#endif
}

View File

@ -0,0 +1,229 @@
#pragma once
#include <functional>
#include <vector>
#include <string>
#include <cstdint>
#include <memory>
#include "FastNoise_Config.h"
#pragma warning( push )
#pragma warning( disable : 4251 )
namespace FastNoise
{
class Generator;
template<typename T>
struct PerDimensionVariable;
struct Metadata;
struct NodeData;
namespace Impl
{
template<typename T>
FASTNOISE_API const Metadata& GetMetadata();
}
// Stores definition of a FastNoise node class
// Node name, member name+types, functions to set members
struct FASTNOISE_API Metadata
{
virtual ~Metadata() = default;
/// <returns>Array containing metadata for every FastNoise node type</returns>
static const std::vector<const Metadata*>& GetAll()
{
return sAllMetadata;
}
/// <returns>Metadata for given Metadata::id</returns>
static const Metadata* GetFromId( uint16_t nodeId )
{
if( nodeId < sAllMetadata.size() )
{
return sAllMetadata[nodeId];
}
return nullptr;
}
/// <returns>Metadata for given node class</returns>
template<typename T>
static const Metadata& Get()
{
static_assert( std::is_base_of<Generator, T>::value, "This function should only be used for FastNoise node classes, for example FastNoise::Simplex" );
static_assert( std::is_member_function_pointer<decltype(&T::GetMetadata)>::value, "Cannot get Metadata for abstract node class, use a derived class, for example: Fractal -> FractalFBm" );
return Impl::GetMetadata<T>();
}
/// <summary>
/// Serialise node data and any source node datas (recursive)
/// </summary>
/// <param name="nodeData">Root node data</param>
/// <param name="fixUp">Remove dependency loops and invalid node types</param>
/// <returns>Empty string on error</returns>
static std::string SerialiseNodeData( NodeData* nodeData, bool fixUp = false );
/// <summary>
/// Deserialise a string created from SerialiseNodeData to a node data tree
/// </summary>
/// <param name="serialisedBase64NodeData">Encoded string to deserialise</param>
/// <param name="nodeDataOut">Storage for new node data</param>
/// <returns>Root node</returns>
static NodeData* DeserialiseNodeData( const char* serialisedBase64NodeData, std::vector<std::unique_ptr<NodeData>>& nodeDataOut );
// Base member struct
struct Member
{
const char* name;
int dimensionIdx = -1;
};
/// <summary>
/// Add spaces to node names: DomainScale -> Domain Scale
/// </summary>
/// <param name="metadata">FastNoise node metadata</param>
/// <param name="removeGroups">Removes metadata groups from name: FractalFBm -> FBm</param>
/// <returns>string with formatted name</returns>
static std::string FormatMetadataNodeName( const Metadata* metadata, bool removeGroups = false );
/// <summary>
/// Adds dimension prefix to member varibles that per-dimension:
/// DomainAxisScale::Scale -> X Scale
/// </summary>
/// <param name="member">FastNoise node metadata member</param>
/// <returns>string with formatted name</returns>
static std::string FormatMetadataMemberName( const Member& member );
// float, int or enum value
struct MemberVariable : Member
{
enum eType
{
EFloat,
EInt,
EEnum
};
union ValueUnion
{
float f;
int i;
ValueUnion( float v = 0 )
{
f = v;
}
ValueUnion( int v )
{
i = v;
}
operator float()
{
return f;
}
operator int()
{
return i;
}
bool operator ==( const ValueUnion& rhs ) const
{
return i == rhs.i;
}
};
eType type;
ValueUnion valueDefault, valueMin, valueMax;
std::vector<const char*> enumNames;
// Function to set value for given generator
// Returns true if Generator is correct node class
std::function<bool( Generator*, ValueUnion )> setFunc;
};
// Node lookup (must be valid for node to function)
struct MemberNodeLookup : Member
{
// Function to set source for given generator
// Returns true if Generator* is correct node class and SmartNodeArg<> is correct node class
std::function<bool( Generator*, SmartNodeArg<> )> setFunc;
};
// Either a constant float or node lookup
struct MemberHybrid : Member
{
float valueDefault = 0.0f;
// Function to set value for given generator
// Returns true if Generator is correct node class
std::function<bool( Generator*, float )> setValueFunc;
// Function to set source for given generator
// Source takes priority if value is also set
// Returns true if Generator is correct node class and SmartNodeArg<> is correct node class
std::function<bool( Generator*, SmartNodeArg<> )> setNodeFunc;
};
uint16_t id;
const char* name;
std::vector<const char*> groups;
std::vector<MemberVariable> memberVariables;
std::vector<MemberNodeLookup> memberNodeLookups;
std::vector<MemberHybrid> memberHybrids;
/// <summary>
/// Create new instance of a FastNoise node from metadata
/// </summary>
/// <example>
/// auto node = metadata->CreateNode();
/// metadata->memberVariables[0].setFunc( node.get(), 1.5f );
/// </example>
/// <param name="maxSimdLevel">Max SIMD level, Null = Auto</param>
/// <returns>SmartNode<T> is guaranteed not nullptr</returns>
virtual SmartNode<> CreateNode( FastSIMD::eLevel maxSimdLevel = FastSIMD::Level_Null ) const = 0;
protected:
Metadata()
{
id = AddMetadata( this );
}
private:
static uint16_t AddMetadata( const Metadata* newMetadata )
{
sAllMetadata.emplace_back( newMetadata );
return (uint16_t)sAllMetadata.size() - 1;
}
static std::vector<const Metadata*> sAllMetadata;
};
// Stores data to create an instance of a FastNoise node
// Node type, member values
struct FASTNOISE_API NodeData
{
NodeData( const Metadata* metadata );
const Metadata* metadata;
std::vector<Metadata::MemberVariable::ValueUnion> variables;
std::vector<NodeData*> nodeLookups;
std::vector<std::pair<NodeData*, float>> hybrids;
bool operator ==( const NodeData& rhs ) const
{
return metadata == rhs.metadata &&
variables == rhs.variables &&
nodeLookups == rhs.nodeLookups &&
hybrids == rhs.hybrids;
}
};
}
#pragma warning( pop )

View File

@ -0,0 +1,278 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <utility>
#include <cassert>
#include <type_traits>
#include <functional>
#include "FastNoise_Config.h"
namespace FastNoise
{
class FASTNOISE_API SmartNodeManager
{
public:
static constexpr uint64_t kInvalidReferenceId = (uint64_t)-1;
SmartNodeManager() = delete;
static void SetMemoryPoolSize( uint32_t size );
private:
template<typename>
friend struct MetadataT;
template<typename>
friend class SmartNode;
template<typename T>
friend SmartNode<T> New( FastSIMD::eLevel );
static uint64_t GetReference( const void* ptr );
static void IncReference( uint64_t id );
static void DecReference( uint64_t id, void* ptr, void ( *destructorFunc )( void* ) );
static uint32_t ReferenceCount( uint64_t id );
static void* Allocate( size_t size, size_t align );
};
template<typename T>
class SmartNode
{
public:
static_assert( std::is_base_of<Generator, T>::value, "SmartNode should only be used for FastNoise node classes" );
template<typename U>
static SmartNode DynamicCast( SmartNode<U> node )
{
if( T* dynamicCast = dynamic_cast<T*>( node.get() ) )
{
return FastNoise::SmartNode<T>( node, dynamicCast );
}
return nullptr;
}
constexpr SmartNode( std::nullptr_t = nullptr ) noexcept :
mReferenceId( SmartNodeManager::kInvalidReferenceId ),
mPtr( nullptr )
{}
SmartNode( const SmartNode& node )
{
TryInc( node.mReferenceId );
mReferenceId = node.mReferenceId;
mPtr = node.mPtr;
}
template<typename U>
SmartNode( const SmartNode<U>& node )
{
TryInc( node.mReferenceId );
mReferenceId = node.mReferenceId;
mPtr = node.mPtr;
}
template<typename U>
SmartNode( const SmartNode<U>& node, T* ptr )
{
assert( ptr );
TryInc( node.mReferenceId );
mReferenceId = node.mReferenceId;
mPtr = ptr;
}
SmartNode( SmartNode&& node ) noexcept
{
mReferenceId = node.mReferenceId;
mPtr = node.mPtr;
node.mReferenceId = SmartNodeManager::kInvalidReferenceId;
node.mPtr = nullptr;
}
template<typename U>
SmartNode( SmartNode<U>&& node ) noexcept
{
mReferenceId = node.mReferenceId;
mPtr = node.mPtr;
node.mReferenceId = SmartNodeManager::kInvalidReferenceId;
node.mPtr = nullptr;
}
~SmartNode()
{
Release();
}
SmartNode& operator=( SmartNode&& node ) noexcept
{
swap( node );
return *this;
}
template<typename U>
SmartNode& operator=( SmartNode<U>&& node ) noexcept
{
if( mReferenceId == node.mReferenceId )
{
mPtr = node.mPtr;
}
else
{
Release();
mReferenceId = node.mReferenceId;
mPtr = node.mPtr;
node.mReferenceId = SmartNodeManager::kInvalidReferenceId;
node.mPtr = nullptr;
}
return *this;
}
SmartNode& operator=( const SmartNode& node ) noexcept
{
if( mReferenceId != node.mReferenceId )
{
TryInc( node.mReferenceId );
Release();
mReferenceId = node.mReferenceId;
}
mPtr = node.mPtr;
return *this;
}
template<typename U>
SmartNode& operator=( const SmartNode<U>& node ) noexcept
{
if( mReferenceId != node.mReferenceId )
{
TryInc( node.mReferenceId );
Release();
mReferenceId = node.mReferenceId;
}
mPtr = node.mPtr;
return *this;
}
template<typename U>
friend bool operator==( const SmartNode& lhs, const SmartNode<U>& rhs ) noexcept
{
return lhs.get() == rhs.get();
}
template<typename U>
friend bool operator!=( const SmartNode& lhs, const SmartNode<U>& rhs ) noexcept
{
return lhs.get() != rhs.get();
}
T& operator*() const noexcept
{
return *mPtr;
}
T* operator->() const noexcept
{
return mPtr;
}
explicit operator bool() const noexcept
{
return mPtr;
}
T* get() const noexcept
{
return mPtr;
}
void reset( T* ptr = nullptr )
{
*this = SmartNode( ptr );
}
void swap( SmartNode& node ) noexcept
{
std::swap( mReferenceId, node.mReferenceId );
std::swap( mPtr, node.mPtr );
}
long use_count() const noexcept
{
if( mReferenceId == SmartNodeManager::kInvalidReferenceId )
{
return 0;
}
return (long)SmartNodeManager::ReferenceCount( mReferenceId );
}
bool unique() const noexcept
{
return use_count() == 1;
}
private:
template<typename U>
friend SmartNode<U> New( FastSIMD::eLevel );
template<typename U>
friend struct MetadataT;
template<typename U>
friend class SmartNode;
explicit SmartNode( T* ptr ) :
mReferenceId( SmartNodeManager::GetReference( ptr ) ),
mPtr( ptr )
{
SmartNodeManager::IncReference( mReferenceId );
}
void Release()
{
using U = typename std::remove_const<T>::type;
if( mReferenceId != SmartNodeManager::kInvalidReferenceId )
{
SmartNodeManager::DecReference( mReferenceId, const_cast<U*>( mPtr ), []( void* ptr ) { ( (U*)ptr )->~T(); } );
}
mReferenceId = SmartNodeManager::kInvalidReferenceId;
mPtr = nullptr;
}
static void TryInc( uint64_t id )
{
if( id != SmartNodeManager::kInvalidReferenceId )
{
SmartNodeManager::IncReference( id );
}
}
uint64_t mReferenceId;
T* mPtr;
};
} // namespace FastNoise
namespace std
{
template<typename T>
struct hash<FastNoise::SmartNode<T>>
{
size_t operator()( const FastNoise::SmartNode<T>& node ) const noexcept
{
return std::hash<T*>( node.get() );
}
};
}

View File

@ -1,83 +0,0 @@
#pragma once
#include <type_traits>
#include <tuple>
#include <stdexcept>
#include "FastSIMD/FunctionList.h"
template<typename T, size_t Size>
class VecN;
template<typename T>
class VecN<T, 0>
{
protected:
template<typename... A>
constexpr VecN( A... ) {}
template<typename... A>
void ForEach( A... ) const {}
template<typename... A>
void ForEachR( A... ) const {}
};
template<typename T, size_t S>
class VecN : public VecN<T, S - 1>
{
public:
static constexpr size_t Size = S;
typedef std::integral_constant<size_t, Size - 1> Index;
constexpr VecN() : Base(), value() {}
template<typename... A>
constexpr VecN( A... args ) :
Base( args... ),
value( std::get<Index::value>( std::make_tuple( args... ) ) )
{
}
template<size_t I>
FS_INLINE std::enable_if_t<(I < Size), T&> At()
{
return VecN<T, I + 1>::value;
}
template<size_t I>
FS_INLINE std::enable_if_t<(I < Size), T> At() const
{
return VecN<T, I + 1>::value;
}
template<size_t I>
FS_INLINE std::enable_if_t<(I >= Size), T&> At() const
{
throw std::out_of_range( "Index of of range" );
}
template<typename F, typename... A>
FS_INLINE void ForEach( F&& func, A&&... other )
{
Base::ForEach( func, other... );
func( Index(), value, (other.template At<Index::value>())... );
}
template<typename F, typename... A>
FS_INLINE void ForEachR( F&& func, A&&... other )
{
func( Index(), value, (other.template At<Index::value>())... );
Base::ForEachR( func, other... );
}
protected:
typedef VecN<T, Size - 1> Base;
typedef std::integral_constant<size_t, Size - 1> Index;
T value;
};

View File

@ -1,13 +1,11 @@
#pragma once
#include <cstdint>
#include "FastSIMD_Config.h"
namespace FastSIMD
{
typedef uint32_t Level_BitFlags;
enum eLevel : Level_BitFlags
enum eLevel : Level_BitFlags
{
Level_Null = 0, // Uninitilised
Level_Scalar = 1 << 0, // 80386 instruction set (Not SIMD)
@ -36,17 +34,18 @@ namespace FastSIMD
(FASTSIMD_COMPILE_AVX2 ? Level_AVX2 : 0) |
(FASTSIMD_COMPILE_AVX512 ? Level_AVX512 : 0) |
(FASTSIMD_COMPILE_NEON ? Level_NEON : 0) ;
typedef void* (*MemoryAllocator)( size_t size, size_t align );
eLevel CPUMaxSIMDLevel();
FASTSIMD_API eLevel CPUMaxSIMDLevel();
template<typename T>
T* New( eLevel maxSIMDLevel = Level_Null );
T* New( eLevel maxSIMDLevel = Level_Null, MemoryAllocator allocator = nullptr );
template<typename T, eLevel SIMD_LEVEL>
T* ClassFactory();
T* ClassFactory( MemoryAllocator allocator = nullptr );
#define FASTSIMD_LEVEL_SUPPORT( ... ) \
static const FastSIMD::Level_BitFlags Supported_SIMD_Levels = __VA_ARGS__
};
}

View File

@ -1,29 +1,33 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include "FastSIMD_Export.h"
#if defined(__arm__) || defined(__aarch64__)
#define FASTSIMD_x86 0
#define FASTSIMD_ARM 1
#define FASTSIMD_x86 false
#define FASTSIMD_ARM true
#else
#define FASTSIMD_x86 1
#define FASTSIMD_ARM 0
#define FASTSIMD_x86 true
#define FASTSIMD_ARM false
#endif
#define FASTSIMD_64BIT (INTPTR_MAX == INT64_MAX)
#define FASTSIMD_COMPILE_SCALAR (!(FASTSIMD_x86 && FASTSIMD_64BIT)) // Don't compile for x86 64bit since CPU is guaranteed SSE2 support
#define FASTSIMD_COMPILE_SSE (FASTSIMD_x86 & 000) // Not supported
#define FASTSIMD_COMPILE_SSE2 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_SSE3 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_SSSE3 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_SSE41 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_SSE42 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_AVX (FASTSIMD_x86 & 000) // Not supported
#define FASTSIMD_COMPILE_AVX2 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_AVX512 (FASTSIMD_x86 & 1 )
#define FASTSIMD_COMPILE_SSE (FASTSIMD_x86 & false) // Not supported
#define FASTSIMD_COMPILE_SSE2 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_SSE3 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_SSSE3 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_SSE41 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_SSE42 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_AVX (FASTSIMD_x86 & false) // Not supported
#define FASTSIMD_COMPILE_AVX2 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_AVX512 (FASTSIMD_x86 & true )
#define FASTSIMD_COMPILE_NEON (FASTSIMD_ARM & 1 )
#define FASTSIMD_COMPILE_NEON (FASTSIMD_ARM & true )
#define FASTSIMD_USE_FMA 1
#define FASTSIMD_CONFIG_GENERATE_CONSTANTS 0
#define FASTSIMD_USE_FMA true
#define FASTSIMD_CONFIG_GENERATE_CONSTANTS false

View File

@ -0,0 +1,11 @@
#pragma once
#if !defined( FASTNOISE_STATIC_LIB ) && ( defined( _WIN32 ) || defined( __CYGWIN__ ) )
#ifdef FASTNOISE_EXPORT // CHANGE ME
#define FASTSIMD_API __declspec( dllexport )
#else
#define FASTSIMD_API __declspec( dllimport )
#endif
#else
#define FASTSIMD_API
#endif

View File

@ -31,7 +31,7 @@
/// <code>
/// size_t FS_Size_32()
/// </code>
#define FS_Size_32() FS::template VectorSize<32>
#define FS_Size_32() FS::template VectorSize<sizeof( int32_t )>
// Vector builders
@ -90,6 +90,41 @@
#define FS_Store_i32( ... ) FS::Store_i32( __VA_ARGS__ )
// Extract
/// <summary>
/// Retreive element 0 from vector
/// </summary>
/// <code>
/// float FS_Extract0_f32( float32v f )
/// </code>
#define FS_Extract0_f32( ... ) FS::Extract0_f32( __VA_ARGS__ )
/// <summary>
/// Retreive element 0 from vector
/// </summary>
/// <code>
/// int32_t FS_Extract0_i32( int32v i )
/// </code>
#define FS_Extract0_i32( ... ) FS::Extract0_i32( __VA_ARGS__ )
/// <summary>
/// Retreive element from vector at position
/// </summary>
/// <code>
/// float FS_Extract_f32( float32v f, size_t idx )
/// </code>
#define FS_Extract_f32( ... ) FS::Extract_f32( __VA_ARGS__ )
/// <summary>
/// Retreive element from vector at position
/// </summary>
/// <code>
/// int32_t FS_Extract_i32( int32v i, size_t idx )
/// </code>
#define FS_Extract_i32( ... ) FS::Extract_i32( __VA_ARGS__ )
// Cast
/// <summary>

View File

@ -1,11 +1,15 @@
set(CMAKE_CXX_STANDARD 17)
set(install_targets ${install_targets} FastNoise PARENT_SCOPE)
file(GLOB_RECURSE FastSIMD_headers "../include/FastSIMD/*.h")
file(GLOB_RECURSE FastSIMD_include_inl "../include/FastSIMD/*.inl")
file(GLOB FastSIMD_inline "FastSIMD/*.inl")
file(GLOB_RECURSE FastSIMD_internal_headers "FastSIMD/Internal/*.h")
file(GLOB_RECURSE FastSIMD_internal_inl "FastSIMD/Internal/*.inl")
set(install_fastsimd_headers ${FastSIMD_headers} PARENT_SCOPE)
list(APPEND FastSIMD_headers ${FastSIMD_inline})
list(APPEND FastSIMD_headers ${FastSIMD_include_inl})
list(APPEND FastSIMD_internal_headers ${FastSIMD_internal_inl})
@ -28,16 +32,20 @@ file(GLOB FastNoise_inl "../include/FastNoise/*.inl")
file(GLOB_RECURSE FastNoise_generators_headers "../include/FastNoise/Generators/*.h")
file(GLOB_RECURSE FastNoise_generators_inl "../include/FastNoise/Generators/*.inl")
set(install_fastnoise_headers ${FastNoise_headers} PARENT_SCOPE)
set(install_fastnoise_generators_headers ${FastNoise_generators_headers} PARENT_SCOPE)
list(APPEND FastNoise_headers ${FastNoise_inl})
list(APPEND FastNoise_generators_headers ${FastNoise_generators_inl})
set(FastNoise_source
FastNoise/FastNoiseMetadata.cpp
)
FastNoise/Metadata.cpp
FastNoise/SmartNode.cpp
FastNoise/FastNoise_C.cpp)
source_group("SIMD" FILES ${FastSIMD_headers})
source_group("SIMD" FILES ${FastSIMD_sources})
source_group("SIMD\\internals" FILES ${FastSIMD_internal_headers})
source_group("FastSIMD" FILES ${FastSIMD_headers})
source_group("FastSIMD" FILES ${FastSIMD_sources})
source_group("FastSIMD\\internals" FILES ${FastSIMD_internal_headers})
source_group("FastNoise" FILES ${FastNoise_headers})
source_group("FastNoise" FILES ${FastNoise_source})
@ -51,17 +59,25 @@ add_library(FastNoise
${FastSIMD_internal_headers}
${FastSIMD_sources}
)
set(install_targets ${install_targets} FastNoise PARENT_SCOPE)
set(install_fastnoise_headers ${FastNoise_headers} PARENT_SCOPE)
set(install_fastsimd_headers ${FastSIMD_headers} PARENT_SCOPE)
add_library(FastNoise2 ALIAS FastNoise)
target_include_directories(FastNoise PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${FastNoise2_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(FastNoise PUBLIC FASTNOISE_STATIC_LIB)
endif()
set_target_properties(FastNoise PROPERTIES
DEFINE_SYMBOL FASTNOISE_EXPORT
DEBUG_POSTFIX D
COMPILE_PDB_NAME_DEBUG FastNoiseD)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(FastNoise PRIVATE /GL- /GS- /fp:fast)
target_compile_options(FastNoise PRIVATE /GL- /GS- /fp:fast /wd4251)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set_source_files_properties(FastSIMD/FastSIMD_Level_Scalar.cpp PROPERTIES COMPILE_FLAGS "/arch:SSE")
@ -76,9 +92,9 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
if(MSVC)
target_compile_options(FastNoise PRIVATE /GS- /fp:fast)
target_compile_options(FastNoise PRIVATE /GL- /GS- /fp:fast)
else()
target_compile_options(FastNoise PRIVATE "-ffast-math")
target_compile_options(FastNoise PRIVATE -ffast-math -fno-stack-protector)
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR "${CMAKE_CXX_FLAGS}" MATCHES "-m32")

View File

@ -0,0 +1,317 @@
#include <FastNoise/FastNoise_C.h>
#include <FastNoise/FastNoise.h>
#include <FastNoise/Metadata.h>
FastNoise::Generator* ToGen( void* p )
{
return static_cast<FastNoise::SmartNode<>*>( p )->get();
}
const FastNoise::Generator* ToGen( const void* p )
{
return static_cast<const FastNoise::SmartNode<>*>( p )->get();
}
void StoreMinMax( float* floatArray2, FastNoise::OutputMinMax minMax )
{
if( floatArray2 )
{
floatArray2[0] = minMax.min;
floatArray2[1] = minMax.max;
}
}
void* fnNewFromEncodedNodeTree( const char* encodedString, unsigned simdLevel )
{
if( FastNoise::SmartNode<> node = FastNoise::NewFromEncodedNodeTree( encodedString, (FastSIMD::eLevel)simdLevel ) )
{
return new FastNoise::SmartNode<>( std::move( node ) );
}
return nullptr;
}
void fnDeleteNodeRef( void* node )
{
delete static_cast<FastNoise::SmartNode<>*>( node );
}
unsigned fnGetSIMDLevel( const void* node )
{
return (unsigned)ToGen( node )->GetSIMDLevel();
}
int fnGetMetadataID( const void* node )
{
return ToGen( node )->GetMetadata().id;
}
void fnGenUniformGrid2D( const void* node, float* noiseOut, int xStart, int yStart, int xSize, int ySize, float frequency, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenUniformGrid2D( noiseOut, xStart, yStart, xSize, ySize, frequency, seed ) );
}
void fnGenUniformGrid3D( const void* node, float* noiseOut, int xStart, int yStart, int zStart, int xSize, int ySize, int zSize, float frequency, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenUniformGrid3D( noiseOut, xStart, yStart, zStart, xSize, ySize, zSize, frequency, seed ) );
}
void fnGenUniformGrid4D( const void* node, float* noiseOut, int xStart, int yStart, int zStart, int wStart, int xSize, int ySize, int zSize, int wSize, float frequency, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenUniformGrid4D( noiseOut, xStart, yStart, zStart, wStart, xSize, ySize, zSize, wSize, frequency, seed ) );
}
void fnGenPositionArray2D( const void* node, float* noiseOut, int count, const float* xPosArray, const float* yPosArray, float xOffset, float yOffset, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenPositionArray2D( noiseOut, count, xPosArray, yPosArray, xOffset, yOffset, seed ) );
}
void fnGenPositionArray3D( const void* node, float* noiseOut, int count, const float* xPosArray, const float* yPosArray, const float* zPosArray, float xOffset, float yOffset, float zOffset, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenPositionArray3D( noiseOut, count, xPosArray, yPosArray, zPosArray, xOffset, yOffset, zOffset, seed ) );
}
void fnGenPositionArray4D( const void* node, float* noiseOut, int count, const float* xPosArray, const float* yPosArray, const float* zPosArray, const float* wPosArray, float xOffset, float yOffset, float zOffset, float wOffset, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenPositionArray4D( noiseOut, count, xPosArray, yPosArray, zPosArray, wPosArray, xOffset, yOffset, zOffset, wOffset, seed ) );
}
float fnGenSingle2D( const void* node, float x, float y, int seed )
{
return ToGen( node )->GenSingle2D( x, y, seed );
}
float fnGenSingle3D( const void* node, float x, float y, float z, int seed )
{
return ToGen( node )->GenSingle3D( x, y, z, seed );
}
float fnGenSingle4D( const void* node, float x, float y, float z, float w, int seed )
{
return ToGen( node )->GenSingle4D( x, y, z, w, seed );
}
void fnGenTileable2D( const void* node, float* noiseOut, int xSize, int ySize, float frequency, int seed, float* outputMinMax )
{
StoreMinMax( outputMinMax, ToGen( node )->GenTileable2D( noiseOut, xSize, ySize, frequency, seed ) );
}
int fnGetMetadataCount()
{
return (int)FastNoise::Metadata::GetAll().size();
}
const char* fnGetMetadataName( int id )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
return metadata->name;
}
return "INVALID NODE ID";
}
void* fnNewFromMetadata( int id, unsigned simdLevel )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
return new FastNoise::SmartNode<>( metadata->CreateNode( (FastSIMD::eLevel)simdLevel ) );
}
return nullptr;
}
int fnGetMetadataVariableCount( int id )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
return (int)metadata->memberVariables.size();
}
return -1;
}
const char* fnGetMetadataVariableName( int id, int variableIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)variableIndex < metadata->memberVariables.size() )
{
return metadata->memberVariables[variableIndex].name;
}
return "INVALID VARIABLE INDEX";
}
return "INVALID NODE ID";
}
int fnGetMetadataVariableType( int id, int variableIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)variableIndex < metadata->memberVariables.size() )
{
return (int)metadata->memberVariables[variableIndex].type;
}
return -1;
}
return -1;
}
int fnGetMetadataVariableDimensionIdx( int id, int variableIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)variableIndex < metadata->memberVariables.size() )
{
return metadata->memberVariables[variableIndex].dimensionIdx;
}
return -1;
}
return -1;
}
int fnGetMetadataEnumCount( int id, int variableIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)variableIndex < metadata->memberVariables.size() )
{
return (int)metadata->memberVariables[variableIndex].enumNames.size();
}
return -1;
}
return -1;
}
const char* fnGetMetadataEnumName( int id, int variableIndex, int enumIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)variableIndex < metadata->memberVariables.size() )
{
if( (size_t)enumIndex < metadata->memberVariables[variableIndex].enumNames.size() )
{
return metadata->memberVariables[variableIndex].enumNames[enumIndex];
}
return "INVALID ENUM INDEX";
}
return "INVALID VARIABLE INDEX";
}
return "INVALID NODE ID";
}
bool fnSetVariableFloat( void* node, int variableIndex, float value )
{
const FastNoise::Metadata& metadata = ToGen( node )->GetMetadata();
if( (size_t)variableIndex < metadata.memberVariables.size() )
{
return metadata.memberVariables[variableIndex].setFunc( ToGen( node ), value );
}
return false;
}
bool fnSetVariableIntEnum( void* node, int variableIndex, int value )
{
const FastNoise::Metadata& metadata = ToGen( node )->GetMetadata();
if( (size_t)variableIndex < metadata.memberVariables.size() )
{
return metadata.memberVariables[variableIndex].setFunc( ToGen( node ), value );
}
return false;
}
int fnGetMetadataNodeLookupCount( int id )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
return (int)metadata->memberNodeLookups.size();
}
return -1;
}
const char* fnGetMetadataNodeLookupName( int id, int nodeLookupIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)nodeLookupIndex < metadata->memberNodeLookups.size() )
{
return metadata->memberNodeLookups[nodeLookupIndex].name;
}
return "INVALID NODE LOOKUP INDEX";
}
return "INVALID NODE ID";
}
int fnGetMetadataNodeLookupDimensionIdx( int id, int nodeLookupIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)nodeLookupIndex < metadata->memberNodeLookups.size() )
{
return metadata->memberNodeLookups[nodeLookupIndex].dimensionIdx;
}
return -1;
}
return -1;
}
bool fnSetNodeLookup( void* node, int nodeLookupIndex, const void* nodeLookup )
{
const FastNoise::Metadata& metadata = ToGen( node )->GetMetadata();
if( (size_t)nodeLookupIndex < metadata.memberNodeLookups.size() )
{
return metadata.memberNodeLookups[nodeLookupIndex].setFunc( ToGen( node ), *static_cast<const FastNoise::SmartNode<>*>( nodeLookup ) );
}
return false;
}
int fnGetMetadataHybridCount( int id )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
return (int)metadata->memberHybrids.size();
}
return -1;
}
const char* fnGetMetadataHybridName( int id, int hybridIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)hybridIndex < metadata->memberHybrids.size() )
{
return metadata->memberHybrids[hybridIndex].name;
}
return "INVALID HYBRID INDEX";
}
return "INVALID NODE ID";
}
int fnGetMetadataHybridDimensionIdx( int id, int hybridIndex )
{
if( const FastNoise::Metadata* metadata = FastNoise::Metadata::GetFromId( (uint16_t)id ) )
{
if( (size_t)hybridIndex < metadata->memberHybrids.size() )
{
return metadata->memberHybrids[hybridIndex].dimensionIdx;
}
return -1;
}
return -1;
}
bool fnSetHybridNodeLookup( void* node, int hybridIndex, const void* nodeLookup )
{
const FastNoise::Metadata& metadata = ToGen( node )->GetMetadata();
if( (size_t)hybridIndex < metadata.memberHybrids.size() )
{
return metadata.memberHybrids[hybridIndex].setNodeFunc( ToGen( node ), *static_cast<const FastNoise::SmartNode<>*>( nodeLookup ) );
}
return false;
}
bool fnSetHybridFloat( void* node, int hybridIndex, float value )
{
const FastNoise::Metadata& metadata = ToGen( node )->GetMetadata();
if( (size_t)hybridIndex < metadata.memberHybrids.size() )
{
return metadata.memberHybrids[hybridIndex].setValueFunc( ToGen( node ), value );
}
return false;
}

View File

@ -1,14 +1,19 @@
#include "FastNoise/FastNoiseMetadata.h"
#include "Base64.h"
#define FASTNOISE_METADATA // Should only be defined here
#include <unordered_set>
#include <unordered_map>
#include <type_traits>
#include <limits>
#include <cassert>
#include <cstdint>
#include "FastNoise/Metadata.h"
#include "FastNoise/FastNoise.h"
#include "Base64.h"
using namespace FastNoise;
std::vector<const Metadata*> Metadata::sMetadataClasses;
std::vector<const Metadata*> Metadata::sAllMetadata;
NodeData::NodeData( const Metadata* data )
{
@ -21,10 +26,10 @@ NodeData::NodeData( const Metadata* data )
variables.push_back( value.valueDefault );
}
for( const auto& value : metadata->memberNodes )
for( const auto& value : metadata->memberNodeLookups )
{
(void)value;
nodes.push_back( nullptr );
nodeLookups.push_back( nullptr );
}
for( const auto& value : metadata->memberHybrids )
@ -43,14 +48,16 @@ void AddToDataStream( std::vector<uint8_t>& dataStream, T value )
}
}
bool SerialiseNodeDataInternal( NodeData* nodeData, bool fixUp, std::vector<uint8_t>& dataStream, std::unordered_map<const NodeData*, uint16_t>& referenceIds, std::unordered_set<const NodeData*> dependancies = {} )
bool SerialiseNodeDataInternal( NodeData* nodeData, bool fixUp, std::vector<uint8_t>& dataStream, std::unordered_map<const NodeData*, uint16_t>& referenceIds, std::unordered_set<const NodeData*> dependencies = {} )
{
// dependencies passed by value to avoid false positives from other branches in the node tree
const Metadata* metadata = nodeData->metadata;
if( !metadata ||
nodeData->variables.size() != metadata->memberVariables.size() ||
nodeData->nodes.size() != metadata->memberNodes.size() ||
nodeData->hybrids.size() != metadata->memberHybrids.size() )
nodeData->variables.size() != metadata->memberVariables.size() ||
nodeData->nodeLookups.size() != metadata->memberNodeLookups.size() ||
nodeData->hybrids.size() != metadata->memberHybrids.size() )
{
assert( 0 ); // Member size mismatch with metadata
return false;
@ -58,62 +65,76 @@ bool SerialiseNodeDataInternal( NodeData* nodeData, bool fixUp, std::vector<uint
if( fixUp )
{
dependancies.insert( nodeData );
dependencies.insert( nodeData );
for( auto& node : nodeData->nodes )
// Null any dependency loops
for( auto& node : nodeData->nodeLookups )
{
if( dependancies.find( node ) != dependancies.end() )
if( dependencies.find( node ) != dependencies.end() )
{
node = nullptr;
}
}
for( auto& hybrid : nodeData->hybrids )
{
if( dependancies.find( hybrid.first ) != dependancies.end() )
if( dependencies.find( hybrid.first ) != dependencies.end() )
{
hybrid.first = nullptr;
}
}
}
// Reference previously encoded nodes to reduce encoded string length
// Relevant if a node has multiple links from it's output
auto reference = referenceIds.find( nodeData );
if( reference != referenceIds.end() )
{
AddToDataStream( dataStream, UINT16_MAX );
// UINT16_MAX where node ID should be
// Referenced by index in reference array, array ordering will match on decode
AddToDataStream( dataStream, std::numeric_limits<uint16_t>::max() );
AddToDataStream( dataStream, reference->second );
return true;
}
// Node ID
AddToDataStream( dataStream, metadata->id );
// Member variables
for( size_t i = 0; i < metadata->memberVariables.size(); i++ )
{
AddToDataStream( dataStream, nodeData->variables[i].i );
}
for( size_t i = 0; i < metadata->memberNodes.size(); i++ )
// Member nodes
for( size_t i = 0; i < metadata->memberNodeLookups.size(); i++ )
{
if( fixUp && nodeData->nodes[i] )
if( fixUp && nodeData->nodeLookups[i] )
{
std::unique_ptr<Generator> gen( metadata->NodeFactory() );
SmartNode<> node( nodeData->nodes[i]->metadata->NodeFactory() );
// Create test node to see if source is a valid node type
SmartNode<> test = metadata->CreateNode();
SmartNode<> node = nodeData->nodeLookups[i]->metadata->CreateNode();
if( !metadata->memberNodes[i].setFunc( gen.get(), node ) )
if( !metadata->memberNodeLookups[i].setFunc( test.get(), node ) )
{
nodeData->nodes[i] = nullptr;
nodeData->nodeLookups[i] = nullptr;
return false;
}
}
if( !nodeData->nodes[i] || !SerialiseNodeDataInternal( nodeData->nodes[i], fixUp, dataStream, referenceIds, dependancies ) )
if( !nodeData->nodeLookups[i] || !SerialiseNodeDataInternal( nodeData->nodeLookups[i], fixUp, dataStream, referenceIds, dependencies ) )
{
return false;
}
}
// Member hybrids
for( size_t i = 0; i < metadata->memberHybrids.size(); i++ )
{
// 1 byte to indicate:
// 0 = constant float value
// 1 = node lookup
if( !nodeData->hybrids[i].first )
{
AddToDataStream( dataStream, (uint8_t)0 );
@ -126,10 +147,11 @@ bool SerialiseNodeDataInternal( NodeData* nodeData, bool fixUp, std::vector<uint
{
if( fixUp )
{
std::unique_ptr<Generator> gen( metadata->NodeFactory() );
std::shared_ptr<Generator> node( nodeData->hybrids[i].first->metadata->NodeFactory() );
// Create test node to see if source is a valid node type
SmartNode<> test = metadata->CreateNode();
SmartNode<> node = nodeData->hybrids[i].first->metadata->CreateNode();
if( !metadata->memberHybrids[i].setNodeFunc( gen.get(), node ) )
if( !metadata->memberHybrids[i].setNodeFunc( test.get(), node ) )
{
nodeData->hybrids[i].first = nullptr;
return false;
@ -137,7 +159,7 @@ bool SerialiseNodeDataInternal( NodeData* nodeData, bool fixUp, std::vector<uint
}
AddToDataStream( dataStream, (uint8_t)1 );
if( !SerialiseNodeDataInternal( nodeData->hybrids[i].first, fixUp, dataStream, referenceIds, dependancies ) )
if( !SerialiseNodeDataInternal( nodeData->hybrids[i].first, fixUp, dataStream, referenceIds, dependencies ) )
{
return false;
}
@ -175,7 +197,7 @@ bool GetFromDataStream( const std::vector<uint8_t>& dataStream, size_t& idx, T&
return true;
}
SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialisedNodeData, size_t& serialIdx, std::unordered_map<uint16_t, SmartNode<>>& referenceNodes, FastSIMD::eLevel level = FastSIMD::Level_Null )
SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialisedNodeData, size_t& serialIdx, std::vector<SmartNode<>>& referenceNodes, FastSIMD::eLevel level = FastSIMD::Level_Null )
{
uint16_t nodeId;
if( !GetFromDataStream( serialisedNodeData, serialIdx, nodeId ) )
@ -183,7 +205,8 @@ SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialised
return nullptr;
}
if( nodeId == UINT16_MAX )
// UINT16_MAX indicates a reference node
if( nodeId == std::numeric_limits<uint16_t>::max() )
{
uint16_t referenceId;
if( !GetFromDataStream( serialisedNodeData, serialIdx, referenceId ) )
@ -191,30 +214,30 @@ SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialised
return nullptr;
}
auto refNode = referenceNodes.find( referenceId );
if( refNode == referenceNodes.end() )
if( referenceId >= referenceNodes.size() )
{
return nullptr;
}
return refNode->second;
return referenceNodes[referenceId];
}
const Metadata* metadata = Metadata::GetMetadataClass( nodeId );
// Create node from nodeId
const Metadata* metadata = Metadata::GetFromId( nodeId );
if( !metadata )
{
return nullptr;
}
SmartNode<> generator( metadata->NodeFactory( level ) );
SmartNode<> generator = metadata->CreateNode( level );
// Member variables
for( const auto& var : metadata->memberVariables )
{
Metadata::MemberVariable::ValueUnion v;
if( !GetFromDataStream( serialisedNodeData, serialIdx, v ) )
if( !GetFromDataStream( serialisedNodeData, serialIdx, v.i ) )
{
return nullptr;
}
@ -222,7 +245,8 @@ SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialised
var.setFunc( generator.get(), v );
}
for( const auto& node : metadata->memberNodes )
// Member nodes
for( const auto& node : metadata->memberNodeLookups )
{
SmartNode<> nodeGen = DeserialiseSmartNodeInternal( serialisedNodeData, serialIdx, referenceNodes, level );
@ -232,9 +256,14 @@ SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialised
}
}
// Member variables
for( const auto& hybrid : metadata->memberHybrids )
{
uint8_t isGenerator;
// 1 byte to indicate:
// 0 = constant float value
// 1 = node lookup
if( !GetFromDataStream( serialisedNodeData, serialIdx, isGenerator ) || isGenerator > 1 )
{
return nullptr;
@ -262,22 +291,22 @@ SmartNode<> DeserialiseSmartNodeInternal( const std::vector<uint8_t>& serialised
}
}
referenceNodes.emplace( (uint16_t)referenceNodes.size(), generator );
referenceNodes.emplace_back( generator );
return generator;
}
SmartNode<> Metadata::DeserialiseSmartNode( const char* serialisedBase64NodeData, FastSIMD::eLevel level )
SmartNode<> FastNoise::NewFromEncodedNodeTree( const char* serialisedBase64NodeData, FastSIMD::eLevel level )
{
std::vector<uint8_t> dataStream = Base64::Decode( serialisedBase64NodeData );
size_t startIdx = 0;
std::unordered_map<uint16_t, SmartNode<>> referenceNodes;
std::vector<SmartNode<>> referenceNodes;
return DeserialiseSmartNodeInternal( dataStream, startIdx, referenceNodes, level );
}
NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNodeData, std::vector<std::unique_ptr<NodeData>>& nodeDataOut, size_t& serialIdx, std::unordered_map<uint16_t, NodeData*>& referenceNodes )
NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNodeData, std::vector<std::unique_ptr<NodeData>>& nodeDataOut, size_t& serialIdx )
{
uint16_t nodeId;
if( !GetFromDataStream( serialisedNodeData, serialIdx, nodeId ) )
@ -285,7 +314,8 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
return nullptr;
}
if( nodeId == UINT16_MAX )
// UINT16_MAX indicates a reference node
if( nodeId == std::numeric_limits<uint16_t>::max() )
{
uint16_t referenceId;
if( !GetFromDataStream( serialisedNodeData, serialIdx, referenceId ) )
@ -293,17 +323,16 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
return nullptr;
}
auto refNode = referenceNodes.find( referenceId );
if( refNode == referenceNodes.end() )
if( referenceId >= nodeDataOut.size() )
{
return nullptr;
}
return refNode->second;
return nodeDataOut[referenceId].get();
}
const Metadata* metadata = Metadata::GetMetadataClass( nodeId );
// Create node from nodeId
const Metadata* metadata = Metadata::GetFromId( nodeId );
if( !metadata )
{
@ -312,6 +341,7 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
std::unique_ptr<NodeData> nodeData( new NodeData( metadata ) );
// Member variables
for( auto& var : nodeData->variables )
{
if( !GetFromDataStream( serialisedNodeData, serialIdx, var ) )
@ -320,9 +350,10 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
}
}
for( auto& node : nodeData->nodes )
// Member nodes
for( auto& node : nodeData->nodeLookups )
{
node = DeserialiseNodeDataInternal( serialisedNodeData, nodeDataOut, serialIdx, referenceNodes );
node = DeserialiseNodeDataInternal( serialisedNodeData, nodeDataOut, serialIdx );
if( !node )
{
@ -330,9 +361,14 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
}
}
// Member hybrids
for( auto& hybrid : nodeData->hybrids )
{
uint8_t isGenerator;
// 1 byte to indicate:
// 0 = constant float value
// 1 = node lookup
if( !GetFromDataStream( serialisedNodeData, serialIdx, isGenerator ) || isGenerator > 1 )
{
return nullptr;
@ -340,7 +376,7 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
if( isGenerator )
{
hybrid.first = DeserialiseNodeDataInternal( serialisedNodeData, nodeDataOut, serialIdx, referenceNodes );
hybrid.first = DeserialiseNodeDataInternal( serialisedNodeData, nodeDataOut, serialIdx );
if( !hybrid.first )
{
@ -356,8 +392,6 @@ NodeData* DeserialiseNodeDataInternal( const std::vector<uint8_t>& serialisedNod
}
}
referenceNodes.emplace( (uint16_t)referenceNodes.size(), nodeData.get() );
return nodeDataOut.emplace_back( std::move( nodeData ) ).get();
}
@ -366,20 +400,78 @@ NodeData* Metadata::DeserialiseNodeData( const char* serialisedBase64NodeData, s
std::vector<uint8_t> dataStream = Base64::Decode( serialisedBase64NodeData );
size_t startIdx = 0;
std::unordered_map<uint16_t, NodeData*> referenceNodes;
return DeserialiseNodeDataInternal( dataStream, nodeDataOut, startIdx, referenceNodes );
return DeserialiseNodeDataInternal( dataStream, nodeDataOut, startIdx );
}
std::string Metadata::FormatMetadataNodeName( const Metadata* metadata, bool removeGroups )
{
std::string string = metadata->name;
for( size_t i = 1; i < string.size(); i++ )
{
if( ( isdigit( string[i] ) || isupper( string[i] ) ) && islower( string[i - 1] ) )
{
string.insert( i++, 1, ' ' );
}
}
if( removeGroups )
{
for( auto group : metadata->groups )
{
size_t start_pos = string.find( group );
if( start_pos != std::string::npos )
{
string.erase( start_pos, std::strlen( group ) + 1 );
}
}
}
return string;
}
std::string Metadata::FormatMetadataMemberName( const Member& member )
{
std::string string = member.name;
if( member.dimensionIdx >= 0 )
{
string.insert( string.begin(), ' ' );
string.insert( 0, kDim_Strings[member.dimensionIdx] );
}
return string;
}
namespace FastNoise
{
template<typename T>
struct MetadataT;
}
template<typename T>
std::unique_ptr<const MetadataT<T>> CreateMetadataInstance( const char* className )
{
auto* newMetadata = new MetadataT<T>;
newMetadata->name = className;
return std::unique_ptr<const MetadataT<T>>( newMetadata );
}
#if FASTNOISE_USE_SHARED_PTR
#define FASTNOISE_GET_MEMORY_ALLOCATOR()
#else
#define FASTNOISE_GET_MEMORY_ALLOCATOR() , &SmartNodeManager::Allocate
#endif
#define FASTSIMD_BUILD_CLASS2( CLASS ) \
const CLASS::Metadata g ## CLASS ## Metadata( #CLASS );\
const FastNoise::Metadata* CLASS::GetMetadata() const\
const std::unique_ptr<const FastNoise::MetadataT<CLASS>> g ## CLASS ## Metadata = CreateMetadataInstance<CLASS>( #CLASS );\
template<> FASTNOISE_API const FastNoise::Metadata& FastNoise::Impl::GetMetadata<CLASS>()\
{\
return &g ## CLASS ## Metadata;\
return *g ## CLASS ## Metadata;\
}\
Generator* CLASS::Metadata::NodeFactory( FastSIMD::eLevel l ) const\
const FastNoise::Metadata& CLASS::GetMetadata() const\
{\
return FastSIMD::New<CLASS>( l );\
return FastNoise::Impl::GetMetadata<CLASS>();\
}\
SmartNode<> FastNoise::MetadataT<CLASS>::CreateNode( FastSIMD::eLevel l ) const\
{\
return SmartNode<>( FastSIMD::New<CLASS>( l FASTNOISE_GET_MEMORY_ALLOCATOR() ) );\
}
#define FASTSIMD_BUILD_CLASS( CLASS ) FASTSIMD_BUILD_CLASS2( CLASS )

View File

@ -0,0 +1,398 @@
#include <FastNoise/FastNoise_Config.h>
#if !FASTNOISE_USE_SHARED_PTR
#include <FastNoise/SmartNode.h>
#include <mutex>
#include <atomic>
#include <vector>
#include <list>
#include <cstring>
#include <memory>
#include <algorithm>
namespace FastNoise
{
union SmartNodeReference
{
uint64_t u64;
struct
{
uint32_t pool;
uint32_t id;
} u32;
};
struct SmartNodeManagerPool
{
static constexpr uint32_t kInvalidSlot = (uint32_t)-1;
struct SlotHeader
{
std::atomic<uint32_t> references;
};
struct Slot
{
uint32_t pos;
uint32_t size;
};
SmartNodeManagerPool( uint32_t size )
{
size = std::min<uint32_t>( size, INT32_MAX );
uint32_t alignOffset = size % alignof( SlotHeader );
if( alignOffset )
{
// pool size needs to be multiple of `alignof( SlotHeader )` (likely 4)
size += alignof( SlotHeader ) - alignOffset;
}
poolSize = size;
pool = (uint8_t*)new SlotHeader[size / sizeof( SlotHeader )];
freeSlots = { { 0, poolSize } };
}
SmartNodeManagerPool( const SmartNodeManagerPool& ) = delete;
SmartNodeManagerPool( SmartNodeManagerPool&& ) = delete;
~SmartNodeManagerPool()
{
assert( usedSlots.empty() );
delete[] pool;
}
auto GetUsedSlotItr( const void* ptr ) const
{
if( ptr > pool && ptr < pool + poolSize )
{
for( auto itr = usedSlots.begin(); itr != usedSlots.end(); ++itr )
{
const uint8_t* start = pool + itr->pos;
if( start < ptr && start + itr->size > ptr )
{
return itr;
}
}
}
return usedSlots.end();
}
auto GetUsedSlotItr( uint32_t pos ) const
{
return std::find_if( usedSlots.begin(), usedSlots.end(), [pos]( const Slot& slot )
{
return slot.pos == pos;
} );
}
bool ValidatePtr( uint32_t pos, const void* ptr ) const
{
if( pos >= poolSize )
{
assert( 0 );
return false;
}
auto slot = GetUsedSlotItr( ptr );
// Check pos pointing at garbage data
if( slot == usedSlots.end() )
{
assert( 0 );
return false;
}
// Check pos is correct
if( slot->pos != pos )
{
assert( 0 );
return false;
}
return true;
}
std::atomic<uint32_t>& GetReferenceCount( uint32_t pos ) const
{
SlotHeader* slot = (SlotHeader*)( pool + pos );
assert( pos < poolSize );
return slot->references;
}
uint32_t GetReferenceId( const void* ptr ) const
{
auto slot = GetUsedSlotItr( ptr );
if( slot == usedSlots.end() )
{
return UINT32_MAX;
}
return slot->pos;
}
void* TryAlloc( size_t size, size_t align )
{
align = std::max( align, alignof( SlotHeader ) );
for( uint32_t idx = 0; idx < freeSlots.size(); idx++ )
{
if( freeSlots[idx].size < size + sizeof( SlotHeader ) )
{
continue;
}
void* ptr = pool + freeSlots[idx].pos + sizeof( SlotHeader );
size_t space = freeSlots[idx].size - sizeof( SlotHeader );
if( std::align( align, size, ptr, space ) )
{
uint8_t* startSlot = pool + freeSlots[idx].pos;
uint8_t* endSlot = (uint8_t*)ptr + size;
// Align next slot correctly for SlotHeader
size_t alignmentOffset = (size_t)endSlot % alignof( SlotHeader );
if( alignmentOffset )
{
endSlot += alignof( SlotHeader ) - alignmentOffset;
}
uint32_t slotSize = (uint32_t)( endSlot - startSlot );
assert( freeSlots[idx].size >= slotSize );
usedSlots.emplace_back( Slot{ freeSlots[idx].pos, slotSize } );
freeSlots[idx].pos += slotSize;
freeSlots[idx].size -= slotSize;
// Check if remaining free slot is empty
if( freeSlots[idx].size == 0 )
{
freeSlots.erase( freeSlots.cbegin() + idx );
}
new( startSlot ) SlotHeader { 0u };
return ptr;
}
}
assert( freeSlots.empty() || freeSlots[0].size != poolSize ); // Empty pool not large enough to fit alloc, increase the pool size
return nullptr;
}
void DeAlloc( uint32_t pos )
{
SlotHeader* slotHeader = (SlotHeader*)( pool + pos );
auto slot = GetUsedSlotItr( pos );
assert( slot != usedSlots.end() );
assert( slotHeader->references == 0 );
assert( slot->size < poolSize );
// Merge free slots as necessary
Slot* expandedBefore = nullptr;
uint32_t idx = 0;
for( ; idx < freeSlots.size(); idx++ )
{
if( freeSlots[idx].pos > pos )
{
break;
}
// Found slot before, expand
if( freeSlots[idx].pos + freeSlots[idx].size == pos )
{
freeSlots[idx].size += slot->size;
expandedBefore = &freeSlots[idx];
idx++;
break;
}
}
if( idx < freeSlots.size() && freeSlots[idx].pos == pos + slot->size )
{
// Found slot before and after, expand before again, delete after
if( expandedBefore )
{
expandedBefore->size += freeSlots[idx].size;
freeSlots.erase( freeSlots.begin() + idx );
}
else // Found slot after, expand
{
freeSlots[idx].pos = pos;
freeSlots[idx].size += slot->size;
}
}
else if( !expandedBefore ) // No slots before or after, create new
{
freeSlots.emplace( freeSlots.begin() + idx, Slot { pos, slot->size } );
}
slotHeader->~SlotHeader();
assert( memset( slotHeader, 255, slot->size ) );
usedSlots.erase( slot );
}
uint32_t poolSize;
uint8_t* pool;
std::vector<Slot> freeSlots;
std::vector<Slot> usedSlots;
};
class SmartNodeMemoryAllocator
{
public:
static inline uint32_t sNewPoolSize = 256 * 1024;
bool ValidatePtr( SmartNodeReference ref, const void* ptr )
{
std::lock_guard lock( mMutex );
if( ref.u32.pool >= mPools.size() )
{
assert( 0 );
return false;
}
return std::next( mPools.begin(), ref.u32.pool )->ValidatePtr( ref.u32.id, ptr );
}
std::atomic<uint32_t>& GetReferenceCount( SmartNodeReference ref ) const
{
return std::next( mPools.begin(), ref.u32.pool )->GetReferenceCount( ref.u32.id );
}
SmartNodeReference GetReference( const void* ptr )
{
std::lock_guard lock( mMutex );
SmartNodeReference ref = { 0 };
for( auto& poolItr : mPools )
{
ref.u32.id = poolItr.GetReferenceId( ptr );
if( ref.u32.id != UINT32_MAX )
{
return ref;
}
ref.u32.pool++;
}
// Could not find ptr in pools, probably not allocated using this class
assert( 0 );
return { SmartNodeManager::kInvalidReferenceId };
}
void* Alloc( size_t size, size_t align )
{
std::lock_guard lock( mMutex );
if( void* ptr = AllocFromPools( size, align ) )
{
return ptr;
}
mPools.emplace_back( sNewPoolSize );
return AllocFromPools( size, align );
}
void Dealloc( SmartNodeReference ref )
{
std::lock_guard lock( mMutex );
std::next( mPools.begin(), ref.u32.pool )->DeAlloc( ref.u32.id );
}
private:
void* AllocFromPools( size_t size, size_t align )
{
uint32_t idx = 0;
for( auto& poolItr : mPools )
{
if( void* ptr = poolItr.TryAlloc( size, align ) )
{
return ptr;
}
idx++;
}
return nullptr;
}
// std::list is used to allow lock free reads to pools
// In most use cases there should only be 1 pool so performance is not a concern
std::list<SmartNodeManagerPool> mPools;
std::mutex mMutex;
};
static SmartNodeMemoryAllocator gMemoryAllocator;
void SmartNodeManager::SetMemoryPoolSize( uint32_t size )
{
SmartNodeMemoryAllocator::sNewPoolSize = size;
}
uint64_t SmartNodeManager::GetReference( const void* ptr )
{
assert( ptr );
return gMemoryAllocator.GetReference( ptr ).u64;
}
void SmartNodeManager::IncReference( uint64_t id )
{
assert( id != kInvalidReferenceId );
std::atomic<uint32_t>& refCount = gMemoryAllocator.GetReferenceCount( { id } );
++refCount;
}
void SmartNodeManager::DecReference( uint64_t id, void* ptr, void ( *destructorFunc )( void* ) )
{
assert( gMemoryAllocator.ValidatePtr( { id }, ptr ) );
std::atomic<uint32_t>& refCount = gMemoryAllocator.GetReferenceCount( { id } );
uint32_t previousRefCount = refCount.fetch_sub( 1 );
assert( previousRefCount );
if( previousRefCount == 1 )
{
destructorFunc( ptr );
gMemoryAllocator.Dealloc( { id } );
}
}
uint32_t SmartNodeManager::ReferenceCount( uint64_t id )
{
assert( id != kInvalidReferenceId );
return gMemoryAllocator.GetReferenceCount( { id } );
}
void* SmartNodeManager::Allocate( size_t size, size_t align )
{
return gMemoryAllocator.Alloc( size, align );
}
} // namespace FastNoise
#endif

View File

@ -9,10 +9,7 @@
#include <intrin.h>
#endif
#include "FastSIMD/TypeList.h"
static FastSIMD::eLevel simdLevel = FastSIMD::Level_Null;
#include "FastSIMD/SIMDTypeList.h"
static_assert(FastSIMD::SIMDTypeList::MinimumCompiled & FastSIMD::COMPILED_SIMD_LEVELS, "FASTSIMD_FALLBACK_SIMD_LEVEL is not a compiled SIMD level, check FastSIMD_Config.h");
@ -82,9 +79,10 @@ static int64_t xgetbv( int ctr )
}
#endif
FastSIMD::eLevel FastSIMD::CPUMaxSIMDLevel()
FASTSIMD_API FastSIMD::eLevel FastSIMD::CPUMaxSIMDLevel()
{
static eLevel simdLevel = Level_Null;
if ( simdLevel > Level_Null )
{
return simdLevel;
@ -192,15 +190,15 @@ FastSIMD::eLevel FastSIMD::CPUMaxSIMDLevel()
}
template<typename CLASS_T, FastSIMD::eLevel SIMD_LEVEL>
CLASS_T* SIMDLevelSelector( FastSIMD::eLevel maxSIMDLevel )
CLASS_T* SIMDLevelSelector( FastSIMD::eLevel maxSIMDLevel, FastSIMD::MemoryAllocator allocator )
{
if constexpr( ( CLASS_T::Supported_SIMD_Levels & SIMD_LEVEL ) != 0 )
{
CLASS_T* newClass = SIMDLevelSelector<CLASS_T, FastSIMD::SIMDTypeList::GetNextCompiledAfter<SIMD_LEVEL>>( maxSIMDLevel );
CLASS_T* newClass = SIMDLevelSelector<CLASS_T, FastSIMD::SIMDTypeList::GetNextCompiledAfter<SIMD_LEVEL>>( maxSIMDLevel, allocator );
if( !newClass && SIMD_LEVEL <= maxSIMDLevel )
{
return FastSIMD::ClassFactory<CLASS_T, SIMD_LEVEL>();
return FastSIMD::ClassFactory<CLASS_T, SIMD_LEVEL>( allocator );
}
return newClass;
@ -212,12 +210,12 @@ CLASS_T* SIMDLevelSelector( FastSIMD::eLevel maxSIMDLevel )
return nullptr;
}
return SIMDLevelSelector<CLASS_T, FastSIMD::SIMDTypeList::GetNextCompiledAfter<SIMD_LEVEL>>( maxSIMDLevel );
return SIMDLevelSelector<CLASS_T, FastSIMD::SIMDTypeList::GetNextCompiledAfter<SIMD_LEVEL>>( maxSIMDLevel, allocator );
}
}
template<typename CLASS_T>
CLASS_T* FastSIMD::New( eLevel maxSIMDLevel )
CLASS_T* FastSIMD::New( eLevel maxSIMDLevel, FastSIMD::MemoryAllocator allocator )
{
if( maxSIMDLevel == Level_Null )
{
@ -229,11 +227,11 @@ CLASS_T* FastSIMD::New( eLevel maxSIMDLevel )
}
static_assert(( CLASS_T::Supported_SIMD_Levels & FastSIMD::SIMDTypeList::MinimumCompiled ), "MinimumCompiled SIMD Level must be supported by this class" );
return SIMDLevelSelector<CLASS_T, SIMDTypeList::MinimumCompiled>( maxSIMDLevel );
return SIMDLevelSelector<CLASS_T, SIMDTypeList::MinimumCompiled>( maxSIMDLevel, allocator );
}
#define FASTSIMD_BUILD_CLASS( CLASS ) \
template CLASS* FastSIMD::New( FastSIMD::eLevel );
template FASTSIMD_API CLASS* FastSIMD::New( FastSIMD::eLevel, FastSIMD::MemoryAllocator );
#define FASTSIMD_INCLUDE_HEADER_ONLY
#include "FastSIMD_BuildList.inl"

View File

@ -233,8 +233,8 @@ namespace FastSIMD
static constexpr eLevel SIMD_Level = LEVEL_T;
template<size_t ElementSize = 8>
static constexpr size_t VectorSize = 256 / ElementSize;
template<size_t ElementSize>
static constexpr size_t VectorSize = (256 / 8) / ElementSize;
typedef AVX_f32x8 float32v;
typedef AVX2_i32x8 int32v;
@ -264,6 +264,32 @@ namespace FastSIMD
_mm256_storeu_si256( reinterpret_cast<__m256i*>(p), a );
}
// Extract
FS_INLINE static float Extract0_f32( float32v a )
{
return _mm256_cvtss_f32( a );
}
FS_INLINE static int32_t Extract0_i32( int32v a )
{
return _mm_cvtsi128_si32(_mm256_castsi256_si128( a ));
}
FS_INLINE static float Extract_f32( float32v a, size_t idx )
{
float f[8];
Store_f32( &f, a );
return f[idx & 7];
}
FS_INLINE static int32_t Extract_i32( int32v a, size_t idx )
{
int32_t i[8];
Store_i32( &i, a );
return i[idx & 7];
}
// Cast
FS_INLINE static float32v Casti32_f32( int32v a )
@ -419,7 +445,7 @@ namespace FastSIMD
FS_INLINE static bool AnyMask_bool( mask32v m )
{
return _mm256_movemask_ps( _mm256_castsi256_ps( m ) );
return !_mm256_testz_si256( m, m );
}
};

View File

@ -230,8 +230,8 @@ namespace FastSIMD
static constexpr eLevel SIMD_Level = LEVEL_T;
template<size_t ElementSize = 8>
static constexpr size_t VectorSize = 512 / ElementSize;
template<size_t ElementSize>
static constexpr size_t VectorSize = (512 / 8) / ElementSize;
typedef AVX512_f32x16 float32v;
typedef AVX512_i32x16 int32v;
@ -273,6 +273,30 @@ namespace FastSIMD
return _mm512_castps_si512( a );
}
// Extract
FS_INLINE static float Extract0_f32( float32v a )
{
return _mm512_cvtss_f32( a );
}
FS_INLINE static int32_t Extract0_i32( int32v a )
{
return _mm_cvtsi128_si32( _mm512_castsi512_si128( a ) );
}
FS_INLINE static float Extract_f32( float32v a, size_t idx )
{
float32v x = _mm512_maskz_compress_ps( mask32v( 1u << (idx & 15) ), a );
return _mm512_cvtss_f32( x );
}
FS_INLINE static int32_t Extract_i32( int32v a, size_t idx )
{
int32v x = _mm512_maskz_compress_epi32( mask32v( 1u << (idx & 15) ), a );
return _mm_cvtsi128_si32( _mm512_castsi512_si128( x ) );
}
// Convert
FS_INLINE static float32v Converti32_f32( int32v a )

View File

@ -244,8 +244,8 @@ namespace FastSIMD
static constexpr eLevel SIMD_Level = LEVEL_T;
template<size_t ElementSize = 8>
static constexpr size_t VectorSize = 128 / ElementSize;
template<size_t ElementSize>
static constexpr size_t VectorSize = (128 / 8) / ElementSize;
typedef SSE_f32x4 float32v;
typedef SSE_i32x4<LEVEL_T> int32v;
@ -275,6 +275,32 @@ namespace FastSIMD
_mm_storeu_si128( reinterpret_cast<__m128i*>(p), a );
}
// Extract
FS_INLINE static float Extract0_f32( float32v a )
{
return _mm_cvtss_f32( a );
}
FS_INLINE static int32_t Extract0_i32( int32v a )
{
return _mm_cvtsi128_si32( a );
}
FS_INLINE static float Extract_f32( float32v a, size_t idx )
{
float f[4];
Store_f32( &f, a );
return f[idx & 3];
}
FS_INLINE static int32_t Extract_i32( int32v a, size_t idx )
{
int32_t i[4];
Store_i32( &i, a );
return i[idx & 3];
}
// Cast
FS_INLINE static float32v Casti32_f32( int32v a )
@ -514,10 +540,17 @@ namespace FastSIMD
return _mm_andnot_ps( _mm_castsi128_ps( m ), a );
}
template<eLevel L = LEVEL_T, std::enable_if_t<( L < Level_SSE41 )>* = nullptr>
FS_INLINE static bool AnyMask_bool( mask32v m )
{
return _mm_movemask_ps( _mm_castsi128_ps( m ) );
}
template<eLevel L = LEVEL_T, std::enable_if_t<( L >= Level_SSE41 )>* = nullptr>
FS_INLINE static bool AnyMask_bool( mask32v m )
{
return !_mm_testz_si128( m, m );
}
};
#if FASTSIMD_COMPILE_SSE

View File

@ -238,7 +238,7 @@ namespace FastSIMD
static constexpr eLevel SIMD_Level = FastSIMD::Level_Scalar;
template<size_t ElementSize = 8>
static constexpr size_t VectorSize = 32 / ElementSize;
static constexpr size_t VectorSize = sizeof(int32_t) / ElementSize;
typedef Scalar_Float float32v;
typedef Scalar_Int int32v;
@ -268,6 +268,28 @@ namespace FastSIMD
*reinterpret_cast<int32v*>(p) = a;
}
// Extract
FS_INLINE static float Extract0_f32( float32v a )
{
return a;
}
FS_INLINE static int32_t Extract0_i32( int32v a )
{
return a;
}
FS_INLINE static float Extract_f32( float32v a, size_t idx )
{
return a;
}
FS_INLINE static int32_t Extract_i32( int32v a, size_t idx )
{
return a;
}
// Cast
FS_INLINE static float32v Casti32_f32( int32v a )

View File

@ -1,22 +1,29 @@
#pragma once
#include "FastSIMD/FastSIMD.h"
#include "FastSIMD/TypeList.h"
template<typename CLASS, typename FS>
class FS_T;
template<typename CLASS, FastSIMD::eLevel LEVEL>
CLASS* FastSIMD::ClassFactory()
CLASS* FastSIMD::ClassFactory( FastSIMD::MemoryAllocator allocator )
{
if constexpr( ( CLASS::Supported_SIMD_Levels & LEVEL & FastSIMD::COMPILED_SIMD_LEVELS ) != 0 )
{
static_assert( std::is_base_of_v<CLASS, FS_T<CLASS, FS_SIMD_CLASS>> );
return new FS_T<CLASS, FS_SIMD_CLASS>;
if( allocator )
{
void* alloc = allocator( sizeof( FS_T<CLASS, FS_SIMD_CLASS> ), alignof( FS_T<CLASS, FS_SIMD_CLASS> ) );
return new( alloc ) FS_T<CLASS, FS_SIMD_CLASS>;
}
return new FS_T<CLASS, FS_SIMD_CLASS>;
}
return nullptr;
}
#define FASTSIMD_BUILD_CLASS( CLASS ) \
template CLASS* FastSIMD::ClassFactory<CLASS, FS_SIMD_CLASS::SIMD_Level>();
template FASTSIMD_API CLASS* FastSIMD::ClassFactory<CLASS, FS_SIMD_CLASS::SIMD_Level>( FastSIMD::MemoryAllocator );
#include "../FastSIMD_BuildList.inl"

1
thirdparty/fast_noise_2/version.txt vendored Normal file
View File

@ -0,0 +1 @@
0.9.4-alpha

View File

@ -1,29 +1,611 @@
#include "fast_noise_2.h"
#include "../math/funcs.h"
#include <core/io/image.h>
FastNoise2::FastNoise2() {
// TODO Testing
set_encoded_node_tree("DQAFAAAAAAAAQAgAAAAAAD8=");
// Setup default
update_generator();
}
void FastNoise2::set_encoded_node_tree(String data) {
CharString cs = data.utf8();
_generator = FastNoise::NewFromEncodedNodeTree(cs.get_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 {
// TODO
return "";
// There is no way to get back an encoded node tree from `FastNoise::SmartNode<>`
return _last_set_encoded_node_tree;
}
void FastNoise2::get_noise_2d(unsigned int count, const float *src_x, const float *src_y, float *dst) {
_generator->GenPositionArray2D(dst, count, src_x, src_y, 0, 0, _seed);
FastNoise2::SIMDLevel FastNoise2::get_simd_level() const {
ERR_FAIL_COND_V(!is_valid(), SIMD_NULL);
return SIMDLevel(_generator->GetSIMDLevel());
}
void FastNoise2::get_noise_3d(
unsigned int count, const float *src_x, const float *src_y, const float *src_z, float *dst) {
_generator->GenPositionArray3D(dst, count, src_x, src_y, src_z, 0, 0, 0, _seed);
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<const float> src_x, Span<const float> src_y, Span<float> 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<const float> src_x, Span<const float> src_y, Span<const float> src_z, Span<float> 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<float> 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<float> 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::generate_image(Ref<Image> image) const {
ERR_FAIL_COND(!is_valid());
ERR_FAIL_COND(image.is_null());
std::vector<float> buffer;
buffer.resize(image->get_width() * image->get_height());
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) {
// Assuming -1..1 output. Some noise types can have different range though.
CRASH_COND(i >= buffer.size());
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<FastNoise::Generator> noise_node;
switch (_noise_type) {
case TYPE_OPEN_SIMPLEX_2:
noise_node = FastNoise::New<FastNoise::OpenSimplex2>();
break;
case TYPE_SIMPLEX:
noise_node = FastNoise::New<FastNoise::Simplex>();
break;
case TYPE_PERLIN:
noise_node = FastNoise::New<FastNoise::Perlin>();
break;
case TYPE_VALUE:
noise_node = FastNoise::New<FastNoise::Value>();
break;
case TYPE_CELLULAR: {
FastNoise::SmartNode<FastNoise::CellularDistance> cd = FastNoise::New<FastNoise::CellularDistance>();
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<FastNoise::DomainScale> scale_node = FastNoise::New<FastNoise::DomainScale>();
scale_node->SetScale(1.f / _period);
scale_node->SetSource(generator_node);
generator_node = scale_node;
}
FastNoise::SmartNode<FastNoise::Fractal<>> fractal_node;
switch (_fractal_type) {
case FRACTAL_NONE:
break;
case FRACTAL_FBM:
fractal_node = FastNoise::New<FastNoise::FractalFBm>();
break;
case FRACTAL_PING_PONG: {
FastNoise::SmartNode<FastNoise::FractalPingPong> pp_node = FastNoise::New<FastNoise::FractalPingPong>();
pp_node->SetPingPongStrength(_fractal_ping_pong_strength);
fractal_node = pp_node;
} break;
case FRACTAL_RIDGED:
fractal_node = FastNoise::New<FastNoise::FractalRidged>();
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<FastNoise::Terrace> terrace_node = FastNoise::New<FastNoise::Terrace>();
terrace_node->SetMultiplier(_terrace_multiplier);
terrace_node->SetSmoothness(_terrace_smoothness);
terrace_node->SetSource(generator_node);
generator_node = terrace_node;
}
if (_remap_enabled) {
FastNoise::SmartNode<FastNoise::Remap> remap_node = FastNoise::New<FastNoise::Remap>();
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;
}
void FastNoise2::_bind_methods() {
// TODO
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);
// TODO Expose series generation
// 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_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);
}

View File

@ -1,26 +1,196 @@
#ifndef VOXEL_FAST_NOISE_2_H
#define VOXEL_FAST_NOISE_2_H
#include "../span.h"
#include "FastNoise/FastNoise.h"
#include <core/resource.h>
#include <core/io/resource.h>
class Image;
// Can't call it FastNoise? because FastNoise is a namespace already
class FastNoise2 : public Resource {
GDCLASS(FastNoise2, Resource)
public:
static const int MAX_OCTAVES = 32;
enum SIMDLevel {
SIMD_NULL = FastSIMD::Level_Null, // Uninitilised
SIMD_SCALAR = FastSIMD::Level_Scalar, // 80386 instruction set (Not SIMD)
SIMD_SSE = FastSIMD::Level_SSE, // SSE (XMM) supported by CPU (not testing for O.S. support)
SIMD_SSE2 = FastSIMD::Level_SSE2, // SSE2
SIMD_SSE3 = FastSIMD::Level_SSE3, // SSE3
SIMD_SSSE3 = FastSIMD::Level_SSSE3, // Supplementary SSE3 (SSSE3)
SIMD_SSE41 = FastSIMD::Level_SSE41, // SSE4.1
SIMD_SSE42 = FastSIMD::Level_SSE42, // SSE4.2
SIMD_AVX = FastSIMD::Level_AVX, // AVX supported by CPU and operating system
SIMD_AVX2 = FastSIMD::Level_AVX2, // AVX2
SIMD_AVX512 = FastSIMD::Level_AVX512, // AVX512, AVX512DQ supported by CPU and operating system
SIMD_NEON = FastSIMD::Level_NEON, // ARM NEON
};
enum NoiseType { //
TYPE_OPEN_SIMPLEX_2 = 0,
TYPE_SIMPLEX,
TYPE_PERLIN,
TYPE_VALUE,
TYPE_CELLULAR,
TYPE_ENCODED_NODE_TREE // Special type overriding most options with a tree made in Auburn's NoiseTool
//TYPE_NODE_TREE, // TODO Implement NoiseTool inside Godot?
};
static constexpr char *NOISE_TYPE_HINT_STRING = "OpenSimplex2,Simplex,Perlin,Value,Cellular,EncodedNodeTree";
enum FractalType { //
FRACTAL_NONE = 0,
FRACTAL_FBM,
FRACTAL_RIDGED,
FRACTAL_PING_PONG
};
static constexpr char *FRACTAL_TYPE_HINT_STRING = "None,FBm,Ridged,PingPong";
enum CellularDistanceFunction { //
CELLULAR_DISTANCE_EUCLIDEAN = FastNoise::DistanceFunction::Euclidean,
CELLULAR_DISTANCE_EUCLIDEAN_SQ = FastNoise::DistanceFunction::EuclideanSquared,
CELLULAR_DISTANCE_MANHATTAN = FastNoise::DistanceFunction::Manhattan,
CELLULAR_DISTANCE_HYBRID = FastNoise::DistanceFunction::Hybrid,
CELLULAR_DISTANCE_MAX_AXIS = FastNoise::DistanceFunction::MaxAxis
};
static constexpr char *CELLULAR_DISTANCE_FUNCTION_HINT_STRING = "Euclidean,EuclideanSq,Manhattan,Hybrid,MaxAxis";
enum CellularReturnType { //
CELLULAR_RETURN_INDEX_0 = FastNoise::CellularDistance::ReturnType::Index0,
CELLULAR_RETURN_INDEX_0_ADD_1 = FastNoise::CellularDistance::ReturnType::Index0Add1,
CELLULAR_RETURN_INDEX_0_SUB_1 = FastNoise::CellularDistance::ReturnType::Index0Sub1,
CELLULAR_RETURN_INDEX_0_MUL_1 = FastNoise::CellularDistance::ReturnType::Index0Mul1,
CELLULAR_RETURN_INDEX_0_DIV_1 = FastNoise::CellularDistance::ReturnType::Index0Div1
};
static constexpr char *CELLULAR_RETURN_TYPE_HINT_STRING = "Index0,Index0Add1,Index0Sub1,Index0Mul1,Index0Div1";
FastNoise2();
SIMDLevel get_simd_level() const;
static String get_simd_level_name(SIMDLevel level);
void set_seed(int seed);
int get_seed() const;
void set_noise_type(NoiseType type);
NoiseType get_noise_type() const;
void set_period(float p);
float get_period() const;
// Fractal
void set_fractal_type(FractalType type);
FractalType get_fractal_type() const;
void set_fractal_octaves(int octaves);
int get_fractal_octaves() const;
void set_fractal_lacunarity(float lacunarity);
float get_fractal_lacunarity() const;
void set_fractal_gain(float gain);
float get_fractal_gain() const;
void set_fractal_ping_pong_strength(float s);
float get_fractal_ping_pong_strength() const;
// Terrace modifier
void set_terrace_enabled(bool enable);
bool is_terrace_enabled() const;
void set_terrace_multiplier(float m);
float get_terrace_multiplier() const;
void set_terrace_smoothness(float s);
float get_terrace_smoothness() const;
// Remap
void set_remap_enabled(bool enabled);
bool is_remap_enabled() const;
void set_remap_min(float min_value);
float get_remap_min() const;
void set_remap_max(float max_value);
float get_remap_max() const;
// Cellular
void set_cellular_distance_function(CellularDistanceFunction cdf);
CellularDistanceFunction get_cellular_distance_function() const;
void set_cellular_return_type(CellularReturnType rt);
CellularReturnType get_cellular_return_type() const;
void set_cellular_jitter(float jitter);
float get_cellular_jitter() const;
// Misc
void set_encoded_node_tree(String data);
String get_encoded_node_tree() const;
void get_noise_2d(unsigned int count, const float *src_x, const float *src_y, float *dst);
void get_noise_3d(unsigned int count, const float *src_x, const float *src_y, const float *src_z, float *dst);
void update_generator();
bool is_valid() const;
// Queries
float get_noise_2d_single(Vector2 pos) const;
float get_noise_3d_single(Vector3 pos) const;
void get_noise_2d_series(Span<const float> src_x, Span<const float> src_y, Span<float> dst) const;
void get_noise_3d_series(
Span<const float> src_x, Span<const float> src_y, Span<const float> src_z, Span<float> dst) const;
void get_noise_2d_grid(Vector2 origin, Vector2i size, Span<float> dst) const;
void get_noise_3d_grid(Vector3 origin, Vector3i size, Span<float> dst) const;
void generate_image(Ref<Image> image) const;
private:
static void _bind_methods();
FastNoise::SmartNode<> _generator;
int _seed = 1337;
NoiseType _noise_type = TYPE_OPEN_SIMPLEX_2;
String _last_set_encoded_node_tree;
float _period = 64.f;
FractalType _fractal_type = FRACTAL_NONE;
int _fractal_octaves = 3;
float _fractal_lacunarity = 2.f;
float _fractal_gain = 0.5f;
float _fractal_ping_pong_strength = 2.f;
bool _terrace_enabled = false;
float _terrace_multiplier = 1.0;
float _terrace_smoothness = 0.0;
CellularDistanceFunction _cellular_distance_function = CELLULAR_DISTANCE_EUCLIDEAN;
CellularReturnType _cellular_return_type = CELLULAR_RETURN_INDEX_0;
float _cellular_jitter = 1.0;
bool _remap_enabled = false;
float _remap_min = -1.0;
float _remap_max = 1.0;
FastNoise::SmartNode<> _generator;
};
VARIANT_ENUM_CAST(FastNoise2::SIMDLevel);
VARIANT_ENUM_CAST(FastNoise2::NoiseType);
VARIANT_ENUM_CAST(FastNoise2::FractalType);
VARIANT_ENUM_CAST(FastNoise2::CellularDistanceFunction);
VARIANT_ENUM_CAST(FastNoise2::CellularReturnType);
#endif // VOXEL_FAST_NOISE_2_H