OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / shared / blender_voronoi.h

163 lines · c ref:
#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