#ifndef VOXEL_GENERATOR_NOISE_2D_H #define VOXEL_GENERATOR_NOISE_2D_H #include #include #include "density_map.h" class WorldGenerator : public VoxelGenerator { GDCLASS(WorldGenerator, VoxelGenerator) public: WorldGenerator(); void set_noise(Ref noise); Ref get_noise() const; void set_mount_noise(Ref noise); Ref get_mount_noise() const; void set_channel(VoxelBuffer::ChannelId channel); VoxelBuffer::ChannelId get_channel() const; int get_used_channels_mask() const override; void set_height_start(float start); float get_height_start() const; void set_height_range(float range); float get_height_range() const; void set_mount_offset(float offt); float get_mount_offset() const; void set_main_multiplier(float mult); float get_main_multiplier() const; void set_initial_spawn_height(float height); float get_initial_spawn_height() const; void set_initial_spawn_radius(float radius); float get_initial_spawn_radius() const; void set_iso_scale(float iso_scale); float get_iso_scale() const; void set_density_map(Ref map); Ref get_density_map() const; Result generate_block(VoxelBlockRequest &input) override; float height_func(int x, int y, int z); private: static void _bind_methods(); protected: template Result generate(VoxelBufferInternal &out_buffer, Height_F height_func, Vector3i origin, int lod) { const int channel = _channel; const Vector3i bs = out_buffer.get_size(); bool use_sdf = channel == VoxelBuffer::CHANNEL_SDF; if (origin.y > get_height_start() + get_height_range()) { // 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) < get_height_start()) { // The top of the block is below the lowest ground can go out_buffer.clear_channel(_channel, use_sdf ? 0 : _matter_type); Result result; result.max_lod_hint = true; return result; } const int stride = 1 << lod; if (use_sdf) { 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 h = _range.xform(height_func(gx, gy, gz)); float sdf = _iso_scale * (gy - h); out_buffer.set_voxel_f(sdf, x, y, z, channel); } } // for x } // for z } else { // Blocky 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) { // Output is blocky, so we can go for just one sample float h = _range.xform(height_func(gx, origin.y, gz)); h -= origin.y; int ih = int(h); if (ih > 0) { if (ih > bs.y) { ih = bs.y; } out_buffer.fill_area(_matter_type, Vector3i(x, 0, z), Vector3i(x + 1, ih, z + 1), channel); } } // for x } // for z } // use_sdf return Result(); } private: Ref _noise, _mount_noise; struct Range { float start = -250; float height = 500; inline float xform(float x) const { return x * height + start; } }; float mount_offset = 50.0f; float main_multiplier = 0.1f; Vector3 initial_spawn; float initial_spawn_radius = 150.0f; float initial_spawn_height = 20.0f; VoxelBuffer::ChannelId _channel = VoxelBuffer::CHANNEL_SDF; int _matter_type = 1; Range _range; float _iso_scale = 0.1; float mount_multiplier = 1.5f; Ref density_map; }; #endif // VOXEL_GENERATOR_NOISE_2D_H