godot_voxel/util/noise/fast_noise_lite_gradient.h

125 lines
3.5 KiB
C++

#ifndef FAST_NOISE_LITE_GRADIENT_H
#define FAST_NOISE_LITE_GRADIENT_H
#include <core/resource.h>
#include "../../thirdparty/fast_noise/FastNoiseLite.h"
// Domain warp is a transformation of coordinates before sampling the actual noise.
// It can be done with another instance of noise, however it needs a sample for each coordinate,
// so FastNoiseLite provides specialized versions of this using gradients.
// This is faster and produces higher-quality results.
//
// Note: FastNoiseLite provides this with the same class, but then its unclear which applies to what,
// so I made two classes, each with a specific purpose.
//
class FastNoiseLiteGradient : public Resource {
GDCLASS(FastNoiseLiteGradient, Resource)
typedef fast_noise_lite::FastNoiseLite _FastNoise;
public:
// TODO Had to prefix it because of https://github.com/godotengine/godot/issues/44860
static const int _MAX_OCTAVES = 32;
enum NoiseType {
TYPE_OPEN_SIMPLEX_2 = _FastNoise::DomainWarpType_OpenSimplex2,
TYPE_OPEN_SIMPLEX_2_REDUCED = _FastNoise::DomainWarpType_OpenSimplex2Reduced,
TYPE_VALUE = _FastNoise::DomainWarpType_BasicGrid
};
// This one does not map directly to FastNoise unfortunately,
// because Godot's UI wants consecutive values starting from 0...
enum FractalType {
FRACTAL_NONE,
FRACTAL_DOMAIN_WARP_PROGRESSIVE,
FRACTAL_DOMAIN_WARP_INDEPENDENT
};
enum RotationType3D {
ROTATION_3D_NONE = _FastNoise::RotationType3D_None,
ROTATION_3D_IMPROVE_XY_PLANES = _FastNoise::RotationType3D_ImproveXYPlanes,
ROTATION_3D_IMPROVE_XZ_PLANES = _FastNoise::RotationType3D_ImproveXZPlanes
};
FastNoiseLiteGradient();
void set_noise_type(NoiseType type);
NoiseType get_noise_type() const;
void set_seed(int seed);
int get_seed() const;
void set_period(float p);
float get_period() const;
void set_amplitude(float amp);
float get_amplitude() const;
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_rotation_type_3d(RotationType3D type);
RotationType3D get_rotation_type_3d() const;
// These are inline to ensure inlining actually happens. If they were bound directly to the script API,
// it means they would need to have an address, in which case I'm not sure they would be inlined?
inline void warp_2d(float &x, float &y) const {
return _fn.DomainWarp(x, y);
}
inline void warp_3d(float &x, float &y, float &z) const {
return _fn.DomainWarp(x, y, z);
}
// TODO Bounds access
// TODO Interval range analysis
private:
static void _bind_methods();
// TODO Getting the gradient instead of adding it would be more useful?
Vector2 _b_warp_2d(Vector2 pos) {
warp_2d(pos.x, pos.y);
return pos;
}
Vector3 _b_warp_3d(Vector3 pos) {
warp_3d(pos.x, pos.y, pos.z);
return pos;
}
fast_noise_lite::FastNoiseLite _fn;
// TODO FastNoiseLite should rather have getters
NoiseType _noise_type = TYPE_VALUE;
int _seed = 0;
float _period = 64.f;
float _amplitude = 30.f;
FractalType _fractal_type = FRACTAL_NONE;
int _fractal_octaves = 3;
float _fractal_lacunarity = 2.f;
float _fractal_gain = 0.5f;
RotationType3D _rotation_type_3d = ROTATION_3D_NONE;
};
VARIANT_ENUM_CAST(FastNoiseLiteGradient::NoiseType);
VARIANT_ENUM_CAST(FastNoiseLiteGradient::FractalType);
VARIANT_ENUM_CAST(FastNoiseLiteGradient::RotationType3D);
#endif // FAST_NOISE_LITE_GRADIENT_H