#ifndef PROC_NODES_BLENDER_VORONOI_H
#define PROC_NODES_BLENDER_VORONOI_H
// BLENDER'S VORONOI — NOW AN ADAPTER, NOT AN IMPLEMENTATION.
//
// The arithmetic is in src/shared/blender_voronoi.inc, compiled as GLSL and as
// C++ from one text, exactly as the hash, perlin and erosion filter are. This
// header is the godot-typed face: it converts Vector2/3/4 and the parameter
// block at the call site and calls the one implementation. Every name the node
// used is still here, so noise_nodes.cpp did not change.
//
// ⛔ VORONOI USES THE PCG INTEGER HASHES, NOT THE JENKINS FLOAT HASH -- except
// in 1D, which uses hash_float_to_float. Read off Blender's source rather than
// assumed: one hash per file would be the right shape with unrelated numbers.
//
// ⚠ THE PARAMETER BLOCK IS COPIED FIELD BY FIELD, ALL ELEVEN. GLSL structs
// cannot carry default member initialisers, so BvParams has none and whatever
// this function fails to set is garbage rather than a sensible default. The
// defaults live HERE, on the godot-side struct the node fills in, which is
// where they were before.
#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 bvoronoi {
using namespace bnoise;
enum {
VORONOI_EUCLIDEAN = 0,
VORONOI_MANHATTAN = 1,
VORONOI_CHEBYCHEV = 2,
VORONOI_MINKOWSKI = 3,
};
// Blender's SHD_VORONOI_* order, which is NOT the order the UI lists them in.
enum {
VORONOI_F1 = 0,
VORONOI_F2 = 1,
VORONOI_SMOOTH_F1 = 2,
VORONOI_DISTANCE_TO_EDGE = 3,
VORONOI_N_SPHERE_RADIUS = 4,
};
struct VoronoiParams {
float scale = 1.0f;
float detail = 0.0f;
float roughness = 0.5f;
float lacunarity = 2.0f;
float smoothness = 0.0f;
float exponent = 0.5f;
float randomness = 1.0f;
float max_distance = 1.0f;
bool normalize = false;
int feature = VORONOI_F1;
int metric = VORONOI_EUCLIDEAN;
};
struct VoronoiOutput {
float distance = 0.0f;
Vector3 color;
Vector4 position;
};
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 gd3(const bnoisegl::vec3 &v) { return Vector3(v.x, v.y, v.z); }
inline Vector4 gd4(const bnoisegl::vec4 &v) { return Vector4(v.x, v.y, v.z, v.w); }
// All eleven. A field left unset is not a default here, it is garbage.
inline bnoisegl::BvParams gl(const VoronoiParams &p) {
bnoisegl::BvParams o;
o.scale = p.scale;
o.detail = p.detail;
o.roughness = p.roughness;
o.lacunarity = p.lacunarity;
o.smoothness = p.smoothness;
o.exponent = p.exponent;
o.randomness = p.randomness;
o.max_distance = p.max_distance;
o.normalize = p.normalize;
o.feature = p.feature;
o.metric = p.metric;
return o;
}
inline VoronoiOutput gd(const bnoisegl::BvOutput &o) {
VoronoiOutput r;
r.distance = o.distance;
r.color = gd3(o.color);
r.position = gd4(o.position);
return r;
}
} // namespace detail
inline float voronoi_distance(float a, float b, const VoronoiParams &p) {
return bnoisegl::bv_voronoi_distance(a, b);
}
inline float voronoi_distance(const Vector2 &a, const Vector2 &b, const VoronoiParams &p) {
return bnoisegl::bv_voronoi_distance(detail::gl(a), detail::gl(b), detail::gl(p));
}
inline float voronoi_distance(const Vector3 &a, const Vector3 &b, const VoronoiParams &p) {
return bnoisegl::bv_voronoi_distance(detail::gl(a), detail::gl(b), detail::gl(p));
}
inline float voronoi_distance(const Vector4 &a, const Vector4 &b, const VoronoiParams &p) {
return bnoisegl::bv_voronoi_distance(detail::gl(a), detail::gl(b), detail::gl(p));
}
inline float voronoi_n_sphere_radius(const VoronoiParams &p, float c) {
return bnoisegl::bv_voronoi_n_sphere_radius(detail::gl(p), c);
}
inline float voronoi_n_sphere_radius(const VoronoiParams &p, const Vector2 &c) {
return bnoisegl::bv_voronoi_n_sphere_radius(detail::gl(p), detail::gl(c));
}
inline float voronoi_n_sphere_radius(const VoronoiParams &p, const Vector3 &c) {
return bnoisegl::bv_voronoi_n_sphere_radius(detail::gl(p), detail::gl(c));
}
inline float voronoi_n_sphere_radius(const VoronoiParams &p, const Vector4 &c) {
return bnoisegl::bv_voronoi_n_sphere_radius(detail::gl(p), detail::gl(c));
}
inline float fractal_voronoi_distance_to_edge(const VoronoiParams &p, float c) {
return bnoisegl::bv_fractal_voronoi_distance_to_edge_1(detail::gl(p), c);
}
inline float fractal_voronoi_distance_to_edge(const VoronoiParams &p, const Vector2 &c) {
return bnoisegl::bv_fractal_voronoi_distance_to_edge_2(detail::gl(p), detail::gl(c));
}
inline float fractal_voronoi_distance_to_edge(const VoronoiParams &p, const Vector3 &c) {
return bnoisegl::bv_fractal_voronoi_distance_to_edge_3(detail::gl(p), detail::gl(c));
}
inline float fractal_voronoi_distance_to_edge(const VoronoiParams &p, const Vector4 &c) {
return bnoisegl::bv_fractal_voronoi_distance_to_edge_4(detail::gl(p), detail::gl(c));
}
inline VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &p, float c, bool calc_color) {
return detail::gd(bnoisegl::bv_fractal_voronoi_x_fx_1(detail::gl(p), c, calc_color));
}
inline VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &p, const Vector2 &c,
bool calc_color) {
return detail::gd(
bnoisegl::bv_fractal_voronoi_x_fx_2(detail::gl(p), detail::gl(c), calc_color));
}
inline VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &p, const Vector3 &c,
bool calc_color) {
return detail::gd(
bnoisegl::bv_fractal_voronoi_x_fx_3(detail::gl(p), detail::gl(c), calc_color));
}
inline VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &p, const Vector4 &c,
bool calc_color) {
return detail::gd(
bnoisegl::bv_fractal_voronoi_x_fx_4(detail::gl(p), detail::gl(c), calc_color));
}
} // namespace bvoronoi
} // namespace godot
#endif // PROC_NODES_BLENDER_VORONOI_H