210 lines
7.1 KiB
C++
210 lines
7.1 KiB
C++
#include <core/engine.h>
|
|
#include "world_map_data.h"
|
|
#include "world_generator.h"
|
|
|
|
WorldGenerator::WorldGenerator() {
|
|
#ifdef TOOLS_ENABLED
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
// Have one by default in editor
|
|
_noise.instance();
|
|
_mount_noise.instance();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void WorldGenerator::set_noise(Ref<OpenSimplexNoise> noise) {
|
|
_noise = noise;
|
|
}
|
|
|
|
Ref<OpenSimplexNoise> WorldGenerator::get_noise() const {
|
|
return _noise;
|
|
}
|
|
|
|
void WorldGenerator::set_mount_noise(Ref<OpenSimplexNoise> noise) {
|
|
_mount_noise = noise;
|
|
}
|
|
|
|
Ref<OpenSimplexNoise> WorldGenerator::get_mount_noise() const {
|
|
return _mount_noise;
|
|
}
|
|
|
|
float WorldGenerator::height_func(int x, int y, int z)
|
|
{
|
|
float mh = _noise->get_noise_2d((float)x * main_multiplier, (float)z * main_multiplier);
|
|
float mth = _mount_noise->get_noise_2d((float)x * mount_multiplier, (float)z * mount_multiplier);
|
|
float dmt = 15.0f;
|
|
float d1 = initial_spawn_radius + 33.5f * mth;
|
|
float h1 = initial_spawn_height + 0.03f * mth;
|
|
float d2 = d1 + 20.0f + 0.05 * mth;
|
|
float h2 = _range.start + 0.15f * mth;
|
|
Vector3 pos((float)x, (float)y, (float)z);
|
|
float d = pos.distance_squared_to(initial_spawn);
|
|
float factor = (d1 * d1 + 1.0f) / (d + 1.0f);
|
|
float th = (d < d1 * d1) ? h1 : h1 * factor + h2 * (1.0f - factor);
|
|
float fh = th;
|
|
float iheight = CLAMP(fh, _range.start, initial_spawn_height) / _range.height;
|
|
float oheight = (mh + mth * 0.01 + 0.1 * mth * CLAMP(y - mount_offset, 0.0f, dmt) / dmt);
|
|
float rt = CLAMP(d2 * d2 / (d + 1.0f), 0.0f, 1.0f);
|
|
return 0.5f + 0.5f * (iheight * rt + oheight * (1.0f - rt));
|
|
}
|
|
|
|
void WorldGenerator::set_mount_offset(float offt)
|
|
{
|
|
mount_offset = offt;
|
|
}
|
|
|
|
float WorldGenerator::get_mount_offset() const
|
|
{
|
|
return mount_offset;
|
|
}
|
|
|
|
void WorldGenerator::set_main_multiplier(float mult)
|
|
{
|
|
main_multiplier = mult;
|
|
}
|
|
|
|
float WorldGenerator::get_main_multiplier() const
|
|
{
|
|
return main_multiplier;
|
|
}
|
|
|
|
void WorldGenerator::set_initial_spawn_height(float height)
|
|
{
|
|
initial_spawn_height = height;
|
|
}
|
|
|
|
float WorldGenerator::get_initial_spawn_height() const
|
|
{
|
|
return initial_spawn_height;
|
|
}
|
|
|
|
void WorldGenerator::set_density_map(Ref<DensityMap> map)
|
|
{
|
|
density_map = map;
|
|
}
|
|
|
|
Ref<DensityMap> WorldGenerator::get_density_map() const
|
|
{
|
|
return density_map;
|
|
}
|
|
|
|
VoxelGenerator::Result WorldGenerator::generate_block(VoxelBlockRequest &input) {
|
|
|
|
ERR_FAIL_COND_V(_noise.is_null(), Result());
|
|
#ifdef WORLD_MAP_TESTS
|
|
WorldMapData *wmd = WorldMapData::get_singleton();
|
|
if (!wmd->tests_run) {
|
|
wmd->unit_test();
|
|
wmd->tests_run = true;
|
|
}
|
|
#endif
|
|
Result result;
|
|
|
|
VoxelBufferInternal &out_buffer = input.voxel_buffer;
|
|
result = WorldGenerator::generate(
|
|
out_buffer,
|
|
[this](int x, int y, int z) { return height_func(x, y, z); },
|
|
input.origin_in_voxels, input.lod);
|
|
|
|
out_buffer.compress_uniform_channels();
|
|
return result;
|
|
}
|
|
|
|
void WorldGenerator::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_noise", "noise"), &WorldGenerator::set_noise);
|
|
ClassDB::bind_method(D_METHOD("get_noise"), &WorldGenerator::get_noise);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_mount_noise", "noise"), &WorldGenerator::set_mount_noise);
|
|
ClassDB::bind_method(D_METHOD("get_mount_noise"), &WorldGenerator::get_mount_noise);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_channel", "channel"), &WorldGenerator::set_channel);
|
|
ClassDB::bind_method(D_METHOD("get_channel"), &WorldGenerator::get_channel);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_height_start", "start"), &WorldGenerator::set_height_start);
|
|
ClassDB::bind_method(D_METHOD("get_height_start"), &WorldGenerator::get_height_start);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_mount_offset", "offt"), &WorldGenerator::set_mount_offset);
|
|
ClassDB::bind_method(D_METHOD("get_mount_offset"), &WorldGenerator::get_mount_offset);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_main_multiplier", "mult"), &WorldGenerator::set_main_multiplier);
|
|
ClassDB::bind_method(D_METHOD("get_main_multiplier"), &WorldGenerator::get_main_multiplier);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_initial_spawn_height", "height"), &WorldGenerator::set_initial_spawn_height);
|
|
ClassDB::bind_method(D_METHOD("get_initial_spawn_height"), &WorldGenerator::get_initial_spawn_height);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_initial_spawn_radius", "radius"), &WorldGenerator::set_initial_spawn_radius);
|
|
ClassDB::bind_method(D_METHOD("get_initial_spawn_radius"), &WorldGenerator::get_initial_spawn_radius);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_height_range", "range"), &WorldGenerator::set_height_range);
|
|
ClassDB::bind_method(D_METHOD("get_height_range"), &WorldGenerator::get_height_range);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_iso_scale", "scale"), &WorldGenerator::set_iso_scale);
|
|
ClassDB::bind_method(D_METHOD("get_iso_scale"), &WorldGenerator::get_iso_scale);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_density_map", "density_map"), &WorldGenerator::set_density_map);
|
|
ClassDB::bind_method(D_METHOD("get_density_map"), &WorldGenerator::get_density_map);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise");
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mount_noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_mount_noise", "get_mount_noise");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mount_offset"), "set_mount_offset", "get_mount_offset");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "main_multiplier"), "set_main_multiplier", "get_main_multiplier");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "initial_spawn_height"), "set_initial_spawn_height", "get_initial_spawn_height");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "initial_spawn_radius"), "set_initial_spawn_radius", "get_initial_spawn_radius");
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "channel", PROPERTY_HINT_ENUM, VoxelBuffer::CHANNEL_ID_HINT_STRING), "set_channel", "get_channel");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_start"), "set_height_start", "get_height_start");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_range"), "set_height_range", "get_height_range");
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "density_map", PROPERTY_HINT_RESOURCE_TYPE, "DensityMap"), "set_density_map", "get_density_map");
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "iso_scale"), "set_iso_scale", "get_iso_scale");
|
|
}
|
|
void WorldGenerator::set_channel(VoxelBuffer::ChannelId channel) {
|
|
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
|
|
if (_channel != channel) {
|
|
_channel = channel;
|
|
emit_changed();
|
|
}
|
|
}
|
|
|
|
VoxelBuffer::ChannelId WorldGenerator::get_channel() const {
|
|
return _channel;
|
|
}
|
|
|
|
int WorldGenerator::get_used_channels_mask() const {
|
|
return (1 << _channel);
|
|
}
|
|
|
|
void WorldGenerator::set_height_start(float start) {
|
|
_range.start = start;
|
|
}
|
|
|
|
float WorldGenerator::get_height_start() const {
|
|
return _range.start;
|
|
}
|
|
|
|
void WorldGenerator::set_height_range(float range) {
|
|
_range.height = range;
|
|
}
|
|
|
|
float WorldGenerator::get_height_range() const {
|
|
return _range.height;
|
|
}
|
|
|
|
void WorldGenerator::set_initial_spawn_radius(float radius)
|
|
{
|
|
initial_spawn_radius = radius;
|
|
}
|
|
|
|
float WorldGenerator::get_initial_spawn_radius() const
|
|
{
|
|
return initial_spawn_radius;
|
|
}
|
|
|
|
void WorldGenerator::set_iso_scale(float iso_scale) {
|
|
_iso_scale = iso_scale;
|
|
}
|
|
|
|
float WorldGenerator::get_iso_scale() const {
|
|
return _iso_scale;
|
|
}
|
|
|