#ifndef PROC_NODES_BLENDER_PERLIN_H
#define PROC_NODES_BLENDER_PERLIN_H
// BLENDER'S PERLIN NOISE — NOW AN ADAPTER, NOT AN IMPLEMENTATION.
//
// The arithmetic that used to live here is in src/shared/blender_perlin.inc,
// compiled BOTH as GLSL and as C++, the same arrangement erosion_filter.inc
// and blender_hash.inc have. This header is the godot-typed face of it, and
// every name and signature callers used is still here -- including the
// explicit template spellings `perlin_fractal_distorted<Vector3>(...)` and
// `perlin_fbm<Vector3>(...)`, which noise_nodes.cpp writes -- so nothing
// downstream changed.
//
// WHY IT MOVED. There were two Perlins: this port, and a hand-written GLSL
// copy in GpuCompiler's hand-written noise library, carrying its own Jenkins hash,
// its own fade, its own gradients and the same unexplained 0.9820. Nothing
// compared them. The Noise Texture node could not be given GPU support without
// choosing which of the two to believe.
//
// GLSL HAS NO TEMPLATES, so the five fractal types -- which are
// `template <typename T>` in Blender's C++ -- are expanded per dimension by
// the preprocessor in the .inc, and the templates here are thin
// specialisations that pick the matching suffix. The dimension is chosen ONCE,
// by C++ overload resolution on the caller's type, instead of by a hand-copied
// suffix in twenty places.
//
// Two things in the .inc could not have been guessed and are worth repeating
// where people look:
//
// the per-dimension SCALE CONSTANTS on perlin_signed -- 0.2500, 0.6616,
// 0.9820, 0.8344 -- found experimentally by the OSL developers to remap each
// dimension's output to [-1, 1]. 0.9820 is the 3D one, and it is the same
// 0.982 that appeared as an unexplained "normalization factor matching
// iq/Blender" in ProcNodes_Noised, where it did not belong.
//
// the SEEDS of the Colour output's second and third components, which differ
// per dimension: 1D uses 1 and 2, 2D uses 2 and 3, 3D uses 3 and 4, 4D uses
// 4 and 5. "Arbitrary seeds ... for compatibility with shading functions",
// and there is no rule to derive them from.
#include "blender_noise.h"
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector4.hpp>
namespace godot {
namespace bperlin {
using namespace bnoise;
enum {
PERLIN_MULTIFRACTAL = 0,
PERLIN_FBM = 1,
PERLIN_HYBRID_MULTIFRACTAL = 2,
PERLIN_RIDGED_MULTIFRACTAL = 3,
PERLIN_HETERO_TERRAIN = 4,
};
namespace detail {
inline bnoisegl::vec2 gl(const Vector2 &v) { return bnoisegl::vec2(v.x, v.y); }
inline bnoisegl::vec3 gl(const Vector3 &v) { return bnoisegl::vec3(v.x, v.y, v.z); }
inline bnoisegl::vec4 gl(const Vector4 &v) { return bnoisegl::vec4(v.x, v.y, v.z, v.w); }
inline Vector3 gd(const bnoisegl::vec3 &v) { return Vector3(v.x, v.y, v.z); }
} // namespace detail
// --- the fractal families, dispatched by the caller's coordinate type ---
template <typename T>
float perlin_fbm(T p, float detail_v, float roughness, float lacunarity, bool normalize);
template <>
inline float perlin_fbm<float>(float p, float d, float r, float l, bool n) {
return bnoisegl::bp_perlin_fbm_1(p, d, r, l, n);
}
template <>
inline float perlin_fbm<Vector2>(Vector2 p, float d, float r, float l, bool n) {
return bnoisegl::bp_perlin_fbm_2(detail::gl(p), d, r, l, n);
}
template <>
inline float perlin_fbm<Vector3>(Vector3 p, float d, float r, float l, bool n) {
return bnoisegl::bp_perlin_fbm_3(detail::gl(p), d, r, l, n);
}
template <>
inline float perlin_fbm<Vector4>(Vector4 p, float d, float r, float l, bool n) {
return bnoisegl::bp_perlin_fbm_4(detail::gl(p), d, r, l, n);
}
template <typename T>
float perlin_select(T p, float detail_v, float roughness, float lacunarity, float offset,
float gain, int type, bool normalize);
template <>
inline float perlin_select<float>(float p, float d, float r, float l, float o, float g, int t,
bool n) {
return bnoisegl::bp_perlin_select_1(p, d, r, l, o, g, t, n);
}
template <>
inline float perlin_select<Vector2>(Vector2 p, float d, float r, float l, float o, float g, int t,
bool n) {
return bnoisegl::bp_perlin_select_2(detail::gl(p), d, r, l, o, g, t, n);
}
template <>
inline float perlin_select<Vector3>(Vector3 p, float d, float r, float l, float o, float g, int t,
bool n) {
return bnoisegl::bp_perlin_select_3(detail::gl(p), d, r, l, o, g, t, n);
}
template <>
inline float perlin_select<Vector4>(Vector4 p, float d, float r, float l, float o, float g, int t,
bool n) {
return bnoisegl::bp_perlin_select_4(detail::gl(p), d, r, l, o, g, t, n);
}
template <typename T>
float perlin_fractal_distorted(T p, float detail_v, float roughness, float lacunarity,
float offset, float gain, float distortion, int type, bool normalize);
template <>
inline float perlin_fractal_distorted<float>(float p, float d, float r, float l, float o, float g,
float dist, int t, bool n) {
return bnoisegl::bp_perlin_fractal_distorted_1(p, d, r, l, o, g, dist, t, n);
}
template <>
inline float perlin_fractal_distorted<Vector2>(Vector2 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return bnoisegl::bp_perlin_fractal_distorted_2(detail::gl(p), d, r, l, o, g, dist, t, n);
}
template <>
inline float perlin_fractal_distorted<Vector3>(Vector3 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return bnoisegl::bp_perlin_fractal_distorted_3(detail::gl(p), d, r, l, o, g, dist, t, n);
}
template <>
inline float perlin_fractal_distorted<Vector4>(Vector4 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return bnoisegl::bp_perlin_fractal_distorted_4(detail::gl(p), d, r, l, o, g, dist, t, n);
}
// The Colour output. Overloads rather than specialisations, because that is
// what the callers write and what Blender's own source does.
inline Vector3 perlin_float3_fractal_distorted(float p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return detail::gd(bnoisegl::bp_perlin_float3_fractal_distorted(p, d, r, l, o, g, dist, t, n));
}
inline Vector3 perlin_float3_fractal_distorted(Vector2 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return detail::gd(
bnoisegl::bp_perlin_float3_fractal_distorted(detail::gl(p), d, r, l, o, g, dist, t, n));
}
inline Vector3 perlin_float3_fractal_distorted(Vector3 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return detail::gd(
bnoisegl::bp_perlin_float3_fractal_distorted(detail::gl(p), d, r, l, o, g, dist, t, n));
}
inline Vector3 perlin_float3_fractal_distorted(Vector4 p, float d, float r, float l, float o,
float g, float dist, int t, bool n) {
return detail::gd(
bnoisegl::bp_perlin_float3_fractal_distorted(detail::gl(p), d, r, l, o, g, dist, t, n));
}
// --- the layers below, for probes and gates ---
inline float perlin_noise(float p) { return bnoisegl::bp_perlin_noise(p); }
inline float perlin_noise(const Vector2 &p) { return bnoisegl::bp_perlin_noise(detail::gl(p)); }
inline float perlin_noise(const Vector3 &p) { return bnoisegl::bp_perlin_noise(detail::gl(p)); }
inline float perlin_noise(const Vector4 &p) { return bnoisegl::bp_perlin_noise(detail::gl(p)); }
inline float perlin_signed(float p) { return bnoisegl::bp_perlin_signed(p); }
inline float perlin_signed(const Vector2 &p) { return bnoisegl::bp_perlin_signed(detail::gl(p)); }
inline float perlin_signed(const Vector3 &p) { return bnoisegl::bp_perlin_signed(detail::gl(p)); }
inline float perlin_signed(const Vector4 &p) { return bnoisegl::bp_perlin_signed(detail::gl(p)); }
} // namespace bperlin
} // namespace godot
#endif // PROC_NODES_BLENDER_PERLIN_H