#ifndef VOXEL_GENERATOR_NOISE_2D_H
#define VOXEL_GENERATOR_NOISE_2D_H

#include <modules/voxel/generators/voxel_generator.h>

class WorldGenerator : public VoxelGenerator {
	GDCLASS(WorldGenerator, VoxelGenerator)
	
public:
	WorldGenerator();

	int get_used_channels_mask() const override;

	void set_iso_scale(float iso_scale);
	float get_iso_scale() const;

	Result generate_block(VoxelBlockRequest &input) override;
	float height_func(int x, int y, int z);

private:
	static void _bind_methods();
protected:
	template <typename Height_F>
	Result generate(VoxelBufferInternal &out_buffer, Height_F height_func, Vector3i origin, int lod) {

		const int channel = VoxelBuffer::CHANNEL_SDF;
		const Vector3i bs = out_buffer.get_size();

		/* TODO: get via RoadsData */
		if (origin.y > 300.0f) {
			// The bottom of the block is above the highest ground can go (default is air)
			Result result;
			result.max_lod_hint = true;
			return result;
		}
		if (origin.y + (bs.y << lod) < -1000.0f) {
			// The top of the block is below the lowest ground can go
			out_buffer.clear_channel(channel, 0);
			Result result;
			result.max_lod_hint = true;
			return result;
		}

		const int stride = 1 << lod;
		int gz = origin.z;
		for (int z = 0; z < bs.z; ++z, gz += stride) {

			int gx = origin.x;
			for (int x = 0; x < bs.x; ++x, gx += stride) {

				int gy = origin.y;
				for (int y = 0; y < bs.y; ++y, gy += stride) {
					float sdf = height_func(gx, gy, gz);
					out_buffer.set_voxel_f(sdf * _iso_scale, x, y, z, channel);
				}

			} // for x
		} // for z


		return Result();
	}

private:
	int _matter_type = 1;
	float _iso_scale = 0.1;
};

#endif // VOXEL_GENERATOR_NOISE_2D_H
