#ifndef PROC_NODES_PROC_VOLUME_H
#define PROC_NODES_PROC_VOLUME_H
#include <godot_cpp/classes/material.hpp>
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/packed_float32_array.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector3i.hpp>
namespace godot {
// Volume data for SDF/density field evaluation.
// Holds either a compiled GLSL function (for GPU evaluation) or a pre-computed
// density grid (for CPU evaluation), or both.
class ProcVolume : public RefCounted {
GDCLASS(ProcVolume, RefCounted);
protected:
static void _bind_methods();
public:
// Compiled GLSL density function source.
// Expected signature: float proc_density(vec3 pos) { ... }
String glsl_source;
// Pre-computed density grid (optional, for CPU path or caching).
// Layout: density[z * res.x * res.y + y * res.x + x]
PackedFloat32Array density_grid;
// Grid parameters
Vector3 grid_origin;
Vector3 grid_size = Vector3(64, 64, 64);
Vector3i grid_resolution = Vector3i(64, 64, 64);
// Getters/setters
String get_glsl_source() const { return glsl_source; }
void set_glsl_source(const String &p_src) { glsl_source = p_src; }
PackedFloat32Array get_density_grid() const { return density_grid; }
void set_density_grid(const PackedFloat32Array &p_grid) { density_grid = p_grid; }
Vector3 get_grid_origin() const { return grid_origin; }
void set_grid_origin(const Vector3 &p_origin) { grid_origin = p_origin; }
Vector3 get_grid_size() const { return grid_size; }
void set_grid_size(const Vector3 &p_size) { grid_size = p_size; }
Vector3i get_grid_resolution() const { return grid_resolution; }
void set_grid_resolution(const Vector3i &p_res) { grid_resolution = p_res; }
bool has_glsl() const { return !glsl_source.is_empty(); }
bool has_grid() const { return density_grid.size() > 0; }
// ── THE GPU CONSUMER ─────────────────────────────────────────────────────
//
// A Godot `shader_type fog` material wrapping this volume's proc_density,
// for a FogVolume to raymarch. That is dc-terrain-nubis Layer 3 -- the
// artist-placed local effects layer -- and it is the whole reason
// glsl_source exists: an authored cloud formation, a fog body, a blob, made
// in the graph editor and rendered by the engine's own froxel pass. No
// custom compute pipeline.
//
// ⚠ THE EMITTED TEXT MUST BE GODOT SHADING LANGUAGE, NOT GLSL 450. They are
// close but not the same: no `#version`, and Godot rejects a mutable global
// at file scope. compile_to_glsl_function's output for an SDF graph is
// already portable (measured: 469 characters of vec3/float/max/length, all
// of which Godot has). A graph pulling in a noise prelude is the case to
// check, not to assume -- see demo/fog_shader_gate.gd, which compiles the
// result for real rather than eyeballing it.
String build_fog_shader_code() const;
// The same thing as a ready ShaderMaterial, so a scene is two lines:
// fog_volume.material = volume.make_fog_material()
// fog_volume.size = ...
Ref<Material> make_fog_material() const;
// Sample density from pre-computed grid (trilinear interpolation)
float sample_density(const Vector3 &p_world_pos) const;
// Deep copy
Ref<ProcVolume> duplicate_volume() const;
ProcVolume() = default;
};
} // namespace godot
#endif // PROC_NODES_PROC_VOLUME_H