Update everything
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <core/io/resource_loader.h>
|
||||
#include <core/os/file_access.h>
|
||||
#include <core/io/compression.h>
|
||||
#include "voxel_generator_imgmapper.h"
|
||||
#include <modules/voxel/util/fixed_array.h>
|
||||
#include "modules/voxel/util/span.h"
|
||||
@@ -45,6 +50,7 @@ namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
#if 0
|
||||
std::map<int, struct EditBrush *> EditBrushList::brushes;
|
||||
std::map<int, String> EditBrushList::brush_names;
|
||||
struct Brush0 : EditBrush
|
||||
@@ -267,18 +273,21 @@ T *RegBrush(Args &&...args)
|
||||
EditBrushList::register_brush(&data);
|
||||
return &data;
|
||||
}
|
||||
#endif
|
||||
|
||||
VoxelGeneratorImgMapper::VoxelGeneratorImgMapper()
|
||||
: VoxelGeneratorHeightmap(),
|
||||
world_size(10240),
|
||||
grid_size(0)
|
||||
{
|
||||
#if 0
|
||||
RegBrush<Brush0>(_image_draw);
|
||||
RegBrush<Brush1>(_image_draw);
|
||||
RegBrush<Brush2>(_image_draw, curve1);
|
||||
RegBrush<Brush3>(_image_draw, curve1, this);
|
||||
RegBrush<Brush4>(_image_draw, curve2, this);
|
||||
RegBrush<Brush5>(_image_draw, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
VoxelGeneratorImgMapper::~VoxelGeneratorImgMapper()
|
||||
@@ -384,7 +393,7 @@ VoxelGenerator::Result VoxelGeneratorImgMapper::generate_block(VoxelBlockRequest
|
||||
result = VoxelGeneratorHeightmap::generate(
|
||||
out_buffer,
|
||||
[this](int x, int z)
|
||||
{ return get_height_linear(Vector3(x, 0, z)); },
|
||||
{ return get_height_linear2(Vector3(x, 0, z)); },
|
||||
input.origin_in_voxels, input.lod);
|
||||
}
|
||||
|
||||
@@ -412,11 +421,12 @@ float VoxelGeneratorImgMapper::get_height(const Vector3 &v)
|
||||
else
|
||||
return get_height_repeat(**_parameters.image, v.x, v.z);
|
||||
#endif
|
||||
return get_height_linear(v);
|
||||
return get_height_linear2(v);
|
||||
}
|
||||
|
||||
float VoxelGeneratorImgMapper::get_height_linear(const Vector3 &v)
|
||||
{
|
||||
update_heightmaps(v);
|
||||
int px = (int)(v.x / grid_size);
|
||||
int pz = (int)(v.z / grid_size);
|
||||
float mx = (float)px * grid_size;
|
||||
@@ -439,11 +449,37 @@ float VoxelGeneratorImgMapper::get_height_linear(const Vector3 &v)
|
||||
return result;
|
||||
}
|
||||
|
||||
float VoxelGeneratorImgMapper::get_height_linear2(const Vector3 &v)
|
||||
{
|
||||
update_heightmaps(v);
|
||||
int px = (int)v.x + world_size / 2;
|
||||
int pz = (int)v.z + world_size / 2;
|
||||
float mx = (float)px;
|
||||
float mz = (float)pz;
|
||||
// float Mx = mx + (float)grid_size;
|
||||
// float Mz = mz + (float)grid_size;
|
||||
float x_weight = 0.0f;
|
||||
float z_weight = 0.0f;
|
||||
// float d0x = (v.x - mx) / (float)grid_size;
|
||||
// float d0z = (v.z - mz) / (float)grid_size;
|
||||
// float d1x = (mx + (float)grid_size - v.x) / (float)grid_size;
|
||||
// float d1z = (mz + (float)grid_size - v.z) / (float)grid_size;
|
||||
float p0 = get_world_pixel(px, pz);
|
||||
float p1 = get_world_pixel(px + 1, pz);
|
||||
float p2 = get_world_pixel(px, pz + 1);
|
||||
float p3 = get_world_pixel(px + 1, pz + 1);
|
||||
float a = (1.0f - x_weight);
|
||||
float b = (1.0f - z_weight);
|
||||
float result = p0 * a * b + p1 * x_weight * b + p2 * z_weight * a + p3 * x_weight * z_weight;
|
||||
return result;
|
||||
}
|
||||
|
||||
float VoxelGeneratorImgMapper::get_height_full(const Vector3 &v)
|
||||
{
|
||||
return get_height(v) * 200.0f - 100.0f;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, float r, float s, int id)
|
||||
{
|
||||
print_line("draw_brush " + (v.operator String()) + " " +
|
||||
@@ -492,191 +528,335 @@ void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, float r, float s, int
|
||||
float base_h = get_height_full(v);
|
||||
float scale = s / 100.0f;
|
||||
EditBrushList::draw_brush(v, r, s, id);
|
||||
#if 0
|
||||
switch (id)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline Vector2 world2img(Ref<Image> img, const Vector3 &v)
|
||||
{
|
||||
|
||||
Vector3 pos(v.x, v.y, v.z);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + img->get_width() / 2,
|
||||
pos.z * 0.1f + img->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, img->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, img->get_height() - 1);
|
||||
return pt;
|
||||
}
|
||||
|
||||
uint64_t VoxelGeneratorImgMapper::heightmap_index(const Vector3 &v)
|
||||
{
|
||||
int heightmap_size = 1024;
|
||||
int world_offset = world_size / 2;
|
||||
int wx = (int)v.x + world_offset;
|
||||
int wz = (int)v.z + world_offset;
|
||||
uint64_t heightmap_index = ((wz / heightmap_size) << 16) + wx / heightmap_size;
|
||||
return heightmap_index;
|
||||
}
|
||||
|
||||
static Set<uint64_t> loaded_tiles;
|
||||
static Set<uint64_t> dirty_tiles;
|
||||
static HashMap<uint64_t, uint8_t *> tiles;
|
||||
void VoxelGeneratorImgMapper::get_or_create_tile(uint64_t tile)
|
||||
{
|
||||
int heightmap_size = 1024;
|
||||
Error err = OK;
|
||||
String path = "res://terrain/" + String::hex_encode_buffer((uint8_t *)&tile, sizeof(tile)) + ".bin";
|
||||
Vector<uint8_t> buffer;
|
||||
if (loaded_tiles.has(tile))
|
||||
return;
|
||||
print_line("Loading: " + path + ": " + itos(loaded_tiles.size()));
|
||||
buffer = FileAccess::get_file_as_array(path, &err);
|
||||
if (err == OK)
|
||||
{
|
||||
case 0:
|
||||
/* flat stuff */
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
{
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* erase stuff */
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
{
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* abs draw curve */
|
||||
ERR_FAIL_COND(!curve1.is_valid());
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
{
|
||||
float h = curve1->interpolate_baked(xr / r) * scale;
|
||||
h = CLAMP(h, -100.0, 100.0f);
|
||||
c = (h + 100.0f) / 200.0;
|
||||
int i;
|
||||
uint8_t *buffer_dst = memnew_arr(uint8_t, heightmap_size * heightmap_size);
|
||||
memset(buffer_dst, 127, heightmap_size * heightmap_size);
|
||||
Compression::decompress(buffer_dst, heightmap_size * heightmap_size, buffer.ptr() + 8, buffer.size() - 8, Compression::MODE_FASTLZ);
|
||||
tiles[tile] = buffer_dst;
|
||||
loaded_tiles.insert(tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *buffer_dst = memnew_arr(uint8_t, heightmap_size * heightmap_size);
|
||||
memset(buffer_dst, 127, heightmap_size * heightmap_size);
|
||||
tiles[tile] = buffer_dst;
|
||||
loaded_tiles.insert(tile);
|
||||
dirty_tiles.insert(tile);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* rel draw curve1 */
|
||||
ERR_FAIL_COND(!curve1.is_valid());
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
{
|
||||
float h = curve1->interpolate_baked(xr / r) * scale;
|
||||
if (h < -2.0f || h > 2.0f)
|
||||
{
|
||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
||||
h = CLAMP(h, -100.0, 100.0f);
|
||||
c = (h + 100.0f) / 200.0;
|
||||
float VoxelGeneratorImgMapper::get_world_pixel(int wx, int wy)
|
||||
{
|
||||
int heightmap_size = 1024;
|
||||
uint64_t tile_x = (wx / heightmap_size) & 0xFFFF;
|
||||
uint64_t tile_z = (wy / heightmap_size) & 0xFFFF;
|
||||
uint64_t tile = tile_x | (tile_z << 16);
|
||||
assert(loaded_tiles.has(tile));
|
||||
if (loaded_tiles.has(tile))
|
||||
{
|
||||
int px = (wx % heightmap_size);
|
||||
int py = (wy % heightmap_size);
|
||||
assert(loaded_tiles.has(tile));
|
||||
assert(tiles[tile]);
|
||||
int raw_pixel = tiles[tile][px + py * heightmap_size];
|
||||
float ret = (float)(raw_pixel) / 255.0f;
|
||||
return ret;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* rel draw curve2 */
|
||||
ERR_FAIL_COND(!curve2.is_valid());
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
{
|
||||
float h = curve2->interpolate_baked(xr / r) * scale;
|
||||
if (h < -2.0f || h > 2.0f)
|
||||
{
|
||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
||||
h = CLAMP(h, -100.0, 100.0f);
|
||||
c = (h + 100.0f) / 200.0;
|
||||
void VoxelGeneratorImgMapper::set_world_pixel(int wx, int wy, float color)
|
||||
{
|
||||
int heightmap_size = 1024;
|
||||
uint64_t tile_x = (wx / heightmap_size) & 0xFFFF;
|
||||
uint64_t tile_z = (wy / heightmap_size) & 0xFFFF;
|
||||
uint64_t tile = tile_x | (tile_z << 16);
|
||||
// print_line("world pixel: " + itos(wx) + " " + itos(wy) + String::num(color));
|
||||
assert(loaded_tiles.has(tile));
|
||||
assert(tiles[tile]);
|
||||
if (loaded_tiles.has(tile))
|
||||
{
|
||||
int px = (wx % heightmap_size);
|
||||
int py = (wy % heightmap_size);
|
||||
int raw_pixels = (int)(color * 255.0f);
|
||||
tiles[tile][px + py * heightmap_size] = raw_pixels;
|
||||
dirty_tiles.insert(tile);
|
||||
// print_line("dirty tile: " + String::num_uint64(tile, 16));
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
void VoxelGeneratorImgMapper::save_dirty_tiles()
|
||||
{
|
||||
Set<uint64_t>::Element *e = dirty_tiles.front();
|
||||
int heightmap_size = 1024;
|
||||
print_line("Save Dirty Tiles");
|
||||
while (e)
|
||||
{
|
||||
uint64_t tile = e->get();
|
||||
Vector<uint8_t> buffer;
|
||||
buffer.resize(heightmap_size * heightmap_size + 8);
|
||||
buffer.write[0] = (uint8_t)(heightmap_size % 256);
|
||||
buffer.write[1] = (uint8_t)(heightmap_size >> 8);
|
||||
buffer.write[2] = (uint8_t)(heightmap_size % 256);
|
||||
buffer.write[3] = (uint8_t)(heightmap_size >> 8);
|
||||
buffer.write[4] = 0;
|
||||
buffer.write[5] = 0;
|
||||
buffer.write[6] = 0;
|
||||
buffer.write[7] = 0;
|
||||
assert(loaded_tiles.has(tile));
|
||||
assert(tiles[tile]);
|
||||
int size = Compression::compress(buffer.ptrw() + 8, tiles[tile], heightmap_size * heightmap_size, Compression::MODE_FASTLZ);
|
||||
Error err = OK;
|
||||
String path = "res://terrain/" + String::hex_encode_buffer((uint8_t *)&tile, sizeof(tile)) + ".bin";
|
||||
print_line("Saving: " + path + ": " + itos(loaded_tiles.size()));
|
||||
FileAccess *pfd = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||
if (err == OK && pfd)
|
||||
{
|
||||
Ref<Curve> curve;
|
||||
if (id == 3)
|
||||
curve = curve1;
|
||||
else if (id == 4)
|
||||
curve = curve2;
|
||||
ERR_FAIL_COND(!curve.is_valid());
|
||||
Ref<Image> img;
|
||||
img.instance();
|
||||
img->create(xs * 2, xs * 2, false, Image::FORMAT_RGBA8);
|
||||
img->fill(Color(0, 0, 0, 0));
|
||||
for (i = -xs ; i < xs + 1; i++)
|
||||
for (j = -xs ; j < xs + 1; j++) {
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r) {
|
||||
float h = curve->interpolate_baked(xr / r);
|
||||
if (h < -2.0f || h > 2.0f) {
|
||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
||||
h = CLAMP(h, -100.0, 100.0f);
|
||||
c = (h + 100.0f) / 200.0;
|
||||
pfd->store_buffer(buffer.ptr(), size + 8);
|
||||
pfd->close();
|
||||
}
|
||||
e = e->next();
|
||||
}
|
||||
dirty_tiles.clear();
|
||||
}
|
||||
|
||||
img->fill_rect(Rect2(Vector2(i + xs, j + xs), Vector2(1, 1)), Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Vector3 pos(v.x, v.y, v.z);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->blend_rect(img,
|
||||
Rect2(Vector2(), Vector2(img->get_width(), img->get_height())),
|
||||
Vector2(pt.x - xs, pt.y - xs));
|
||||
|
||||
} break;
|
||||
#endif
|
||||
case 5:
|
||||
void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, Ref<Curve> curve, float radius, float strength, int flags)
|
||||
{
|
||||
float min_x = v.x - radius;
|
||||
float min_z = v.z - radius;
|
||||
float max_x = v.x + radius;
|
||||
float max_z = v.z + radius;
|
||||
float step = grid_size;
|
||||
Vector3 min_pos(min_x, v.y, min_z), max_pos(max_x, v.y, max_z);
|
||||
int x, z;
|
||||
update_heightmaps(v);
|
||||
if (radius < 1.0f || strength <= 0.0f)
|
||||
return;
|
||||
if (!_image_draw.is_valid())
|
||||
return;
|
||||
if (!brush_canvas.is_valid())
|
||||
brush_canvas = _image_draw->duplicate();
|
||||
brush_canvas->blit_rect(_image_draw, Rect2(0, 0, _image_draw->get_width(), _image_draw->get_height()), Vector2());
|
||||
int xpos_min = min_pos.x / grid_size + _image_draw->get_width() / 2;
|
||||
int xpos_max = max_pos.x / grid_size + _image_draw->get_width() / 2;
|
||||
int zpos_min = min_pos.z / grid_size + _image_draw->get_height() / 2;
|
||||
int zpos_max = max_pos.z / grid_size + _image_draw->get_height() / 2;
|
||||
int radius_int = Math::ceil(radius / grid_size);
|
||||
int center_x = v.x / grid_size + _image_draw->get_width() / 2;
|
||||
int center_z = v.z / grid_size + _image_draw->get_height() / 2;
|
||||
int wx_min = world_size / 2 + (int)min_pos.x;
|
||||
int wx_max = world_size / 2 + (int)max_pos.x;
|
||||
int wz_min = world_size / 2 + (int)min_pos.z;
|
||||
int wz_max = world_size / 2 + (int)max_pos.z;
|
||||
int wx_center = world_size / 2 + (int)v.x;
|
||||
int wz_center = world_size / 2 + (int)v.z;
|
||||
gen.set_seed(wx_center + world_size * wz_center);
|
||||
// abs + offt (1 << 0)
|
||||
// abs (1 << 1)
|
||||
// rnd (1 << 2)
|
||||
// flatten (1 << 3)
|
||||
// smooth (1 << 4)
|
||||
// no increments (1 << 5)
|
||||
float avg = 0.0f;
|
||||
float minv = Math_INF;
|
||||
float maxv = -Math_INF;
|
||||
if (flags & 16)
|
||||
{
|
||||
float h = get_height_full(v) + 2.0f;
|
||||
h = CLAMP(h, -100.0, 100.0f);
|
||||
for (i = -8; i < 8 + 1; i++)
|
||||
for (j = -8; j < 8 + 1; j++)
|
||||
int count = 0;
|
||||
for (z = wz_min; z <= wz_max; z++)
|
||||
{
|
||||
for (x = wx_min; x <= wx_max; x++)
|
||||
{
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
h = MAX(h, get_height_full(pos) + 2.0f);
|
||||
float r = Vector2((x - wx_center), (z - wz_center)).length();
|
||||
if (r >= radius)
|
||||
continue;
|
||||
float h = get_world_pixel(x, z);
|
||||
if (minv > h)
|
||||
minv = h;
|
||||
if (maxv < h)
|
||||
maxv = h;
|
||||
avg += h;
|
||||
count++;
|
||||
}
|
||||
c = (h + 100.0f) / 200.0;
|
||||
for (i = -xs; i < xs + 1; i++)
|
||||
for (j = -xs; j < xs + 1; j++)
|
||||
}
|
||||
avg /= (float)count;
|
||||
}
|
||||
print_line("AVG: " + String::num(avg));
|
||||
for (z = wz_min; z <= wz_max; z++)
|
||||
{
|
||||
for (x = wx_min; x <= wx_max; x++)
|
||||
{
|
||||
float r = Vector2((x - wx_center), (z - wz_center)).length();
|
||||
if (r >= radius)
|
||||
continue;
|
||||
float offset = r / radius;
|
||||
float value = curve->interpolate_baked(offset) * strength;
|
||||
float nvalue = value * 0.5f; // -1:1 range
|
||||
float mvalue = nvalue * 0.5f + 0.5f; // 0:1 range
|
||||
float nh = CLAMP((v.y + 100.0f) / 200.0f, 0.0f, 1.0f);
|
||||
float h = get_world_pixel(x, z);
|
||||
float new_h = h + nvalue;
|
||||
float c;
|
||||
if (flags & 1) // absolute with offset
|
||||
new_h = nh + nvalue;
|
||||
else if (flags & 2) // absolute
|
||||
new_h = nvalue;
|
||||
if (flags & 8)
|
||||
new_h = nh;
|
||||
else if (flags & 16)
|
||||
{
|
||||
float xr = Vector2(i, j).length();
|
||||
if (xr < r)
|
||||
int ox, oz;
|
||||
float hu = maxv - avg;
|
||||
float hb = avg - minv;
|
||||
new_h = avg + (h - avg) * 0.9f;
|
||||
if (z > 0 && z < world_size - 1 && x > 0 && x < world_size - 1)
|
||||
{
|
||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
||||
float smooth_h = 0.0f;
|
||||
int smooth_count = 0;
|
||||
for (oz = 0; oz < 5; oz++)
|
||||
for (ox = 0; ox < 5; ox++)
|
||||
{
|
||||
if (ox == 0 && oz == 0)
|
||||
continue;
|
||||
smooth_h += get_world_pixel(x + ox - 2, z + oz - 2);
|
||||
smooth_count++;
|
||||
}
|
||||
new_h = new_h * 0.5f + smooth_h / (float)smooth_count * 0.5f;
|
||||
}
|
||||
}
|
||||
if (flags & 4)
|
||||
new_h = 0.95f * new_h + 0.05f * (gen.randf() - 0.5f);
|
||||
// relative
|
||||
if (flags & 32)
|
||||
c = CLAMP(new_h, 0.0f, 1.0f);
|
||||
else
|
||||
{
|
||||
if (offset > 0.9f)
|
||||
c = CLAMP(h * 0.95f + new_h * 0.05f, 0.0f, 1.0f);
|
||||
else
|
||||
c = CLAMP(h * 0.8f + new_h * 0.2f, 0.0f, 1.0f);
|
||||
}
|
||||
set_world_pixel(x, z, c);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
#if 0
|
||||
int wz = world_size / 2 + (int)v.z;
|
||||
brush_canvas->lock();
|
||||
for (z = zpos_min; z <= zpos_max; z++)
|
||||
{
|
||||
for (x = xpos_min; x <= xpos_max; x++)
|
||||
{
|
||||
float r = Vector2((x - center_x) * grid_size, (z - center_z) * grid_size).length();
|
||||
if (r >= radius)
|
||||
continue;
|
||||
float offset = r / radius;
|
||||
float value = curve->interpolate_baked(offset) * strength;
|
||||
float nvalue = value * 0.5f; // -1:1 range
|
||||
float nh = CLAMP((v.y + 100.0f) / 200.0f, 0.0f, 1.0f);
|
||||
int xx = CLAMP(x, 0, _image_draw->get_width() - 1);
|
||||
int zz = CLAMP(z, 0, _image_draw->get_height() - 1);
|
||||
// height in 0-1 range where 0.5 is zero
|
||||
float h = brush_canvas->get_pixel(xx, zz).r;
|
||||
// print_line("h: " + String::num(h));
|
||||
float new_h;
|
||||
float c;
|
||||
new_h = h + nvalue;
|
||||
if (flags & 1) // absolute
|
||||
new_h = nh + nvalue;
|
||||
// relative
|
||||
if (offset > 0.9f)
|
||||
c = CLAMP(h * 0.95f + new_h * 0.05f, 0.0f, 1.0f);
|
||||
else
|
||||
c = CLAMP(h * 0.8f + new_h * 0.2f, 0.0f, 1.0f);
|
||||
// print_line("c: " + String::num(c));
|
||||
brush_canvas->set_pixel(xx, zz, Color(c, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
brush_canvas->unlock();
|
||||
_image_draw->blit_rect(brush_canvas, Rect2(0, 0, brush_canvas->get_width(), brush_canvas->get_height()), Vector2());
|
||||
#endif
|
||||
save_dirty_tiles();
|
||||
}
|
||||
static Mutex update_heightmaps_lock;
|
||||
void VoxelGeneratorImgMapper::update_heightmaps(const Vector3 &v)
|
||||
{
|
||||
int i;
|
||||
int heightmap_size = 1024;
|
||||
uint64_t pos_x = (int)v.x + (world_size / 2);
|
||||
uint64_t pos_z = (int)v.z + (world_size / 2);
|
||||
uint64_t tile_x = (pos_x / heightmap_size) & 0xFFFF;
|
||||
uint64_t tile_z = (pos_z / heightmap_size) & 0xFFFF;
|
||||
Vector<uint64_t> tiles;
|
||||
tiles.resize(9);
|
||||
for (i = 0; i < tiles.size(); i++)
|
||||
{
|
||||
int m_x = (i % 3) - 1;
|
||||
int m_z = (i / 3) - 1;
|
||||
tiles.write[i] = (tile_z << 16) | tile_x;
|
||||
if (tile_x == 0 && m_x < 0)
|
||||
continue;
|
||||
if (tile_z == 0 && m_z < 0)
|
||||
continue;
|
||||
tiles.write[i] = ((tile_z + m_x) << 16) | (tile_x + m_z);
|
||||
}
|
||||
Vector3 pos = v;
|
||||
pos.y = 0;
|
||||
update_heightmaps_lock.lock();
|
||||
if (current_position.is_equal_approx(pos))
|
||||
goto out_unlock;
|
||||
for (i = 0; i < tiles.size(); i++)
|
||||
{
|
||||
if (!loaded_tiles.has(tiles[i]))
|
||||
get_or_create_tile(tiles[i]);
|
||||
}
|
||||
current_position = pos;
|
||||
out_unlock:
|
||||
update_heightmaps_lock.unlock();
|
||||
}
|
||||
|
||||
void VoxelGeneratorImgMapper::compose()
|
||||
{
|
||||
Ref<Image> copy;
|
||||
print_line("compose");
|
||||
// print_line("compose");
|
||||
ERR_FAIL_COND(!_image_bg.is_valid());
|
||||
ERR_FAIL_COND(!_image_overlay.is_valid());
|
||||
ERR_FAIL_COND(!_image_draw.is_valid());
|
||||
@@ -723,6 +903,7 @@ void VoxelGeneratorImgMapper::save_png()
|
||||
_image_overlay->save_png("res://terrain/terrain_edit.png");
|
||||
}
|
||||
|
||||
#if 0
|
||||
void VoxelGeneratorImgMapper::set_curve1(const Ref<Curve> &curve)
|
||||
{
|
||||
ERR_FAIL_COND(!curve.is_valid());
|
||||
@@ -770,6 +951,7 @@ Ref<Curve> VoxelGeneratorImgMapper::get_curve4() const
|
||||
{
|
||||
return curve4;
|
||||
}
|
||||
#endif
|
||||
|
||||
void VoxelGeneratorImgMapper::set_grid_size(int value)
|
||||
{
|
||||
@@ -791,10 +973,12 @@ int VoxelGeneratorImgMapper::get_world_size() const
|
||||
return world_size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::map<int, String> VoxelGeneratorImgMapper::get_brush_names() const
|
||||
{
|
||||
return EditBrushList::get_brush_names();
|
||||
}
|
||||
#endif
|
||||
|
||||
void VoxelGeneratorImgMapper::_bind_methods()
|
||||
{
|
||||
@@ -807,6 +991,7 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("set_image_draw", "image"), &VoxelGeneratorImgMapper::set_image_draw);
|
||||
ClassDB::bind_method(D_METHOD("get_image_draw"), &VoxelGeneratorImgMapper::get_image_draw);
|
||||
|
||||
#if 0
|
||||
ClassDB::bind_method(D_METHOD("set_curve1", "curve"), &VoxelGeneratorImgMapper::set_curve1);
|
||||
ClassDB::bind_method(D_METHOD("get_curve1"), &VoxelGeneratorImgMapper::get_curve1);
|
||||
ClassDB::bind_method(D_METHOD("set_curve2", "curve"), &VoxelGeneratorImgMapper::set_curve2);
|
||||
@@ -815,9 +1000,9 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("get_curve3"), &VoxelGeneratorImgMapper::get_curve3);
|
||||
ClassDB::bind_method(D_METHOD("set_curve4", "curve"), &VoxelGeneratorImgMapper::set_curve4);
|
||||
ClassDB::bind_method(D_METHOD("get_curve4"), &VoxelGeneratorImgMapper::get_curve4);
|
||||
#endif
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_height", "v", "height"), &VoxelGeneratorImgMapper::set_height);
|
||||
ClassDB::bind_method(D_METHOD("draw_brush", "v", "r", "s", "id"), &VoxelGeneratorImgMapper::draw_brush);
|
||||
ClassDB::bind_method(D_METHOD("get_height", "v"), &VoxelGeneratorImgMapper::get_height);
|
||||
ClassDB::bind_method(D_METHOD("get_height_full", "v"), &VoxelGeneratorImgMapper::get_height_full);
|
||||
ClassDB::bind_method(D_METHOD("compose"), &VoxelGeneratorImgMapper::compose);
|
||||
@@ -832,9 +1017,11 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_bg", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_bg", "get_image_bg");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_overlay", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_overlay", "get_image_overlay");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_draw", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_draw", "get_image_draw");
|
||||
#if 0
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve1", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve1", "get_curve1");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve2", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve2", "get_curve2");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve3", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve3", "get_curve3");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve4", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve4", "get_curve4");
|
||||
#endif
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blur_enabled"), "set_blur_enabled", "is_blur_enabled");
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <core/math/random_number_generator.h>
|
||||
#include <modules/voxel/generators/simple/voxel_generator_heightmap.h>
|
||||
#include <core/image.h>
|
||||
#include <scene/resources/curve.h>
|
||||
@@ -21,6 +22,7 @@ struct EditBrush
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct EditBrushList
|
||||
{
|
||||
static std::map<int, struct EditBrush *> brushes;
|
||||
@@ -46,6 +48,7 @@ public:
|
||||
return brush_names;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Provides infinite tiling heightmap based on an image
|
||||
class VoxelGeneratorImgMapper : public VoxelGeneratorHeightmap
|
||||
@@ -74,14 +77,25 @@ public:
|
||||
Result generate_block(VoxelBlockRequest &input) override;
|
||||
|
||||
void set_height(const Vector3 &v, float height);
|
||||
#if 0
|
||||
void draw_brush(const Vector3 &v, float r, float s, int id);
|
||||
#endif
|
||||
void draw_brush(const Vector3 &v, Ref<Curve> curve, float radius, float strength, int flags);
|
||||
void update_heightmaps(const Vector3 &v);
|
||||
uint64_t heightmap_index(const Vector3 &v);
|
||||
void get_or_create_tile(uint64_t tile);
|
||||
float get_world_pixel(int wx, int wy);
|
||||
void set_world_pixel(int wx, int wy, float color);
|
||||
void save_dirty_tiles();
|
||||
float get_height(const Vector3 &v);
|
||||
float get_height_linear(const Vector3 &v);
|
||||
float get_height_linear2(const Vector3 &v);
|
||||
float get_height_full(const Vector3 &v);
|
||||
float get_height_full_linear(const Vector3 &v);
|
||||
void compose();
|
||||
void save_png();
|
||||
|
||||
#if 0
|
||||
void set_curve1(const Ref<Curve> &curve);
|
||||
Ref<Curve> get_curve1() const;
|
||||
|
||||
@@ -93,10 +107,13 @@ public:
|
||||
|
||||
void set_curve4(const Ref<Curve> &curve);
|
||||
Ref<Curve> get_curve4() const;
|
||||
#endif
|
||||
|
||||
void set_world_size(int value);
|
||||
int get_world_size() const;
|
||||
#if 0
|
||||
std::map<int, String> get_brush_names() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static void _bind_methods();
|
||||
@@ -107,6 +124,9 @@ private:
|
||||
Ref<Image> _image_bg;
|
||||
Ref<Image> _image_overlay, _image_buildings;
|
||||
Ref<Image> _image_draw;
|
||||
Ref<Image> brush_canvas;
|
||||
Vector3 current_position;
|
||||
RandomNumberGenerator gen;
|
||||
|
||||
Ref<Curve> curve1, curve2, curve3, curve4;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ module_obj = []
|
||||
SConscript("buildings/SCsub")
|
||||
SConscript("rtree/SCsub")
|
||||
SConscript("ui/SCsub")
|
||||
SConscript("npc/SCsub")
|
||||
|
||||
env_stream = env_modules.Clone()
|
||||
|
||||
|
||||
@@ -113,7 +113,8 @@ void BuildingsData::build_building_aabbs()
|
||||
building_aabbs[e->get()] = aabb;
|
||||
scene->queue_delete();
|
||||
ps.unref();
|
||||
}
|
||||
} else
|
||||
print_error("Could not load: " + path);
|
||||
e = e->next();
|
||||
}
|
||||
}
|
||||
@@ -604,6 +605,12 @@ Node *BuildingsData::get_scene_item_node(const String &key,
|
||||
return bi->node;
|
||||
}
|
||||
|
||||
void BuildingsData::save_buildings()
|
||||
{
|
||||
String buildings_path = config.get_value("buildings", "buildings_path");
|
||||
save_buildings_json(buildings_path);
|
||||
}
|
||||
|
||||
Node *BuildingsData::item_nodes_get_node(const String &key) const
|
||||
{
|
||||
flecs::query_builder<const CBuildingInstance> qb =
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
Node *node);
|
||||
bool has_scene_item(const String &key, const String &bkey) const;
|
||||
Node *get_scene_item_node(const String &key, const String &bkey) const;
|
||||
void save_buildings();
|
||||
|
||||
public:
|
||||
Node *item_nodes_get_node(const String &key) const;
|
||||
|
||||
@@ -86,8 +86,8 @@ void NavPanel::_notification(int which)
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"editor_camera_moved", varray(camera_xform));
|
||||
transform_changhed = false;
|
||||
print_line("moved: " +
|
||||
(camera_xform.origin.operator String()));
|
||||
print_verbose("moved: " +
|
||||
(camera_xform.origin.operator String()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <editor/editor_node.h>
|
||||
#include "register_types.h"
|
||||
#include "stream.h"
|
||||
#include "road_debug.h"
|
||||
@@ -6,8 +7,18 @@
|
||||
#include "line_metadata_editor.h"
|
||||
#include "buildings/building_layout_editor.h"
|
||||
#include "ui/main_tabs.h"
|
||||
#include "npc/importer.h"
|
||||
#include "base_data.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _editor_init()
|
||||
{
|
||||
Ref<EditorImportNPC> import_npc;
|
||||
import_npc.instance();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_npc);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_stream_types()
|
||||
{
|
||||
ClassDB::register_class<StreamWorld>();
|
||||
@@ -17,6 +28,13 @@ void register_stream_types()
|
||||
ClassDB::register_class<LineMetadataEditor>();
|
||||
ClassDB::register_class<BuildingLayoutEditor>();
|
||||
ClassDB::register_class<MainTabs>();
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
ClassDB::register_class<EditorImportNPC>();
|
||||
ClassDB::set_current_api(prev_api);
|
||||
EditorNode::add_init_callback(_editor_init);
|
||||
#endif
|
||||
BaseData::get_singleton()->setup();
|
||||
}
|
||||
|
||||
|
||||
@@ -216,21 +216,58 @@ struct RoadLinesProcessing {
|
||||
int onext = (j + 1) % edges[i].neighbors.size();
|
||||
Vector3 n1 = normal(node - neighbors[j]);
|
||||
Vector3 n2 = normal(neighbors[onext] - node);
|
||||
float angle = n1.signed_angle_to(
|
||||
n2, Vector3(0, 1, 0));
|
||||
Vector3 a0 = (neighbors[j] - node) * 0.5 +
|
||||
node + n1 * 3.0f;
|
||||
Vector3 a1 = node + n1 * road_side_width;
|
||||
Vector3 b0 = node + n2 * road_side_width;
|
||||
Vector3 b1 = (neighbors[onext] - node) * 0.5 +
|
||||
node + n2 * 3.0f;
|
||||
Vector3 q, r;
|
||||
Geometry::get_closest_points_between_segments(
|
||||
a0, a1, b0, b1, q, r);
|
||||
Vector3 pr;
|
||||
if (Vector2(q.x, q.z).distance_squared_to(
|
||||
Vector2(r.x, r.z)) < 0.001f)
|
||||
pr = q.linear_interpolate(r, 0.5f);
|
||||
else
|
||||
pr = node + n1 * road_side_width;
|
||||
Vector3 q, r, pr;
|
||||
if (angle < 0 || angle > Math_PI) {
|
||||
Vector3 da = (a1 - a0).normalized() *
|
||||
road_side_width * 2.0f;
|
||||
Vector3 db = (b1 - b0).normalized() *
|
||||
road_side_width * 2.0f;
|
||||
Geometry::get_closest_points_between_segments(
|
||||
a0 - da, a1 + da, b0 - db,
|
||||
b1 + db, q, r);
|
||||
if (Vector2(q.x, q.z)
|
||||
.distance_squared_to(
|
||||
Vector2(r.x, r.z)) <
|
||||
0.005f)
|
||||
pr = q.linear_interpolate(r,
|
||||
0.5f);
|
||||
else {
|
||||
print_line(
|
||||
"bad luck: " +
|
||||
(q.operator String()) +
|
||||
" -> " +
|
||||
(r.operator String()));
|
||||
float e =
|
||||
Vector2(q.x, q.z).distance_squared_to(
|
||||
Vector2(r.x,
|
||||
r.z));
|
||||
print_line("dst " +
|
||||
String::num(e));
|
||||
assert(false);
|
||||
}
|
||||
/* pr = node +
|
||||
n1 * road_side_width; */
|
||||
} else {
|
||||
Geometry::get_closest_points_between_segments(
|
||||
a0, a1, b0, b1, q, r);
|
||||
if (Vector2(q.x, q.z)
|
||||
.distance_squared_to(
|
||||
Vector2(r.x, r.z)) <
|
||||
0.001f)
|
||||
pr = q.linear_interpolate(r,
|
||||
0.5f);
|
||||
else
|
||||
pr = node +
|
||||
n1 * road_side_width;
|
||||
}
|
||||
Vector3 o1 = (neighbors[j] - node) * 0.5 + node;
|
||||
Vector3 o2 = node,
|
||||
o3 = (neighbors[onext] - node) * 0.5 +
|
||||
@@ -542,6 +579,11 @@ public:
|
||||
this->center = center;
|
||||
this->mid = mid;
|
||||
this->edge = edge;
|
||||
if (!(l2 >= l1 - 0.0001f && l2 >= l3 - 0.0001f))
|
||||
print_line("bad parameters: l1 = " +
|
||||
String::num(l1) +
|
||||
" l2 = " + String::num(l2) +
|
||||
" l3 = " + String::num(l3));
|
||||
assert(l2 >= l1 - 0.0001f && l2 >= l3 - 0.0001f);
|
||||
assert(l1 - 3.0f < 0.001f);
|
||||
assert(l3 - 3.0f < 0.001f);
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#ifndef SIGNAL_HANDLER_H_
|
||||
#define SIGNAL_HANDLER_H_
|
||||
#include <core/object.h>
|
||||
#include <scene/gui/option_button.h>
|
||||
#include <scene/gui/button.h>
|
||||
#include <scene/gui/line_edit.h>
|
||||
#include <scene/gui/check_box.h>
|
||||
#include "editor_event.h"
|
||||
|
||||
#define _GODOT_HANDLER_METHOD(class_name, obj_name, sig_name, event_name, \
|
||||
@@ -86,8 +90,6 @@
|
||||
obj_name, sig_name, hdecl, hargs, hbind) \
|
||||
typedef _GODOT_HANDLER_CONCAT2(class_name, __LINE__) class_name;
|
||||
|
||||
//GODOT_HANDLER_METHOD(BrushSelectHandler, OptionButton, item_selected,
|
||||
// brush_select, (int id), (id), D_METHOD("handler", "id"))
|
||||
GODOT_HANDLER_EVENT_METHOD(OptionButtonHandler, OptionButton, item_selected,
|
||||
(int id), (id), D_METHOD("handler", "id"))
|
||||
GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
||||
@@ -95,5 +97,9 @@ GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
||||
GODOT_HANDLER_EVENT_METHOD(LineEditString, LineEdit, text_changed,
|
||||
(const String &text), (text),
|
||||
D_METHOD("handler", "text"))
|
||||
GODOT_HANDLER_EVENT_METHOD(CheckBoxPressHandler, CheckBox, pressed, (), (),
|
||||
D_METHOD("handler"))
|
||||
GODOT_HANDLER_EVENT_METHOD(PopupMenuSelectHandler, PopupMenu, id_pressed,
|
||||
(int id), (id), D_METHOD("handler", "id"))
|
||||
|
||||
#endif // SIGNAL_HANDLER_H_
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "editor_event.h"
|
||||
#include "world_editor.h"
|
||||
#include "buildings_data.h"
|
||||
#include "signal_handler.h"
|
||||
#include "terrain_editor.h"
|
||||
|
||||
@@ -73,21 +74,15 @@ TerrainEditor::~TerrainEditor()
|
||||
|
||||
void TerrainEditor::activate()
|
||||
{
|
||||
int i;
|
||||
EditorEvent::get_singleton()->event.add_listener(
|
||||
this, &TerrainEditor::event_handler);
|
||||
|
||||
assert(editor->is_inside_tree());
|
||||
imgmapper = editor->get_heightmap();
|
||||
assert(imgmapper.is_valid());
|
||||
const std::map<int, String> &brush_names = imgmapper->get_brush_names();
|
||||
assert(brush_names.size() > 0);
|
||||
Dictionary brushes;
|
||||
std::map<int, String>::const_iterator ib = brush_names.begin();
|
||||
while (ib != brush_names.end()) {
|
||||
std::pair<int, String> ibp = *ib;
|
||||
brushes[ibp.first] = ibp.second;
|
||||
ib++;
|
||||
}
|
||||
for (i = 0; i < 32; i++)
|
||||
brushes[i] = "Brush" + itos(i);
|
||||
assert(brushes.size() > 0);
|
||||
EditorEvent::get_singleton()->event.emit("terrain_load_data",
|
||||
varray(brushes));
|
||||
@@ -106,19 +101,28 @@ void TerrainEditor::deactivate()
|
||||
void TerrainEditor::event_handler(const String &event,
|
||||
const Vector<Variant> &args)
|
||||
{
|
||||
static Vector3 last_cursor_position;
|
||||
print_line("TerrainEditor::event: " + event);
|
||||
if (event == "mouse_press" || event == "mouse_drag") {
|
||||
if (!active)
|
||||
return;
|
||||
if (cursor_enabled) {
|
||||
if (event == "mouse_press")
|
||||
pressure += 0.4f;
|
||||
else if (event == "mouse_drag")
|
||||
pressure += 0.01f;
|
||||
if (event == "mouse_press") {
|
||||
if (last_cursor_position.is_equal_approx(
|
||||
get_cursor_position()))
|
||||
pressure += 0.6f;
|
||||
} else if (event == "mouse_drag")
|
||||
pressure += 0.1f;
|
||||
if (pressure > 1.0f)
|
||||
pressure = 1.0f;
|
||||
if (pressure >= 0.8f) {
|
||||
imgmapper->draw_brush(get_cursor_position(),
|
||||
1.0f, 100.0f,
|
||||
current_brush);
|
||||
assert(imgmapper.is_valid());
|
||||
imgmapper->draw_brush(
|
||||
get_cursor_position(),
|
||||
brush_curves[current_brush],
|
||||
brush_radius[current_brush],
|
||||
brush_strength[current_brush],
|
||||
brush_flags[current_brush]);
|
||||
imgmapper->compose();
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"terrain_update", varray());
|
||||
@@ -126,6 +130,7 @@ void TerrainEditor::event_handler(const String &event,
|
||||
varray());
|
||||
imgmapper->save_png();
|
||||
}
|
||||
last_cursor_position = get_cursor_position();
|
||||
flecs::log::dbg("pressure: %f", pressure);
|
||||
/* Raycasting outside physics process */
|
||||
Vector2 position = args[0];
|
||||
@@ -234,6 +239,8 @@ end:;
|
||||
strength_edit);
|
||||
ob->get_parent()->set_meta("brush_strength",
|
||||
strength_edit);
|
||||
memnew(LineEditString(strength_edit,
|
||||
"terrain_brush_strength_change"));
|
||||
} else {
|
||||
LineEdit *strength_edit = Object::cast_to<LineEdit>(
|
||||
ob->get_parent()->get_meta("brush_strength"));
|
||||
@@ -243,10 +250,12 @@ end:;
|
||||
struct flag_info {
|
||||
String caption;
|
||||
};
|
||||
struct flag_info flag_data[] = {
|
||||
{ "Absolute" },
|
||||
{ "Random" },
|
||||
};
|
||||
struct flag_info flag_data[] = { { "Absolute + Offset" },
|
||||
{ "Absolute" },
|
||||
{ "Random" },
|
||||
{ "Flatten" },
|
||||
{ "Smooth" },
|
||||
{ "No Increments" } };
|
||||
if (!ob->get_parent()->has_meta("brush_flags")) {
|
||||
VBoxContainer *flags_ui = memnew(VBoxContainer);
|
||||
int flags = brush_flags[id];
|
||||
@@ -259,6 +268,8 @@ end:;
|
||||
cb->set_text(flag_data[f_idx].caption);
|
||||
cb->set_pressed_no_signal(flags & (1 << f_idx));
|
||||
flags_ui->add_child(cb);
|
||||
memnew(CheckBoxPressHandler(
|
||||
cb, "terrain_brush_flags_change"));
|
||||
}
|
||||
ob->get_parent()->call_deferred("add_child", flags_ui);
|
||||
ob->get_parent()->set_meta("brush_flags", flags_ui);
|
||||
@@ -300,7 +311,7 @@ end:;
|
||||
if ((data.is_valid_float() || data.is_valid_integer()) &&
|
||||
current_brush >= 0) {
|
||||
brush_radius[current_brush] =
|
||||
MAX(data.to_float(), 1.0f);
|
||||
CLAMP(data.to_float(), 1.0f, 500.0f);
|
||||
print_line(data);
|
||||
MeshInstance *cursor_mesh =
|
||||
get_as_node<MeshInstance>(cursor_name + "/mi2");
|
||||
@@ -313,6 +324,161 @@ end:;
|
||||
brush_radius[current_brush] + 3.0f);
|
||||
}
|
||||
}
|
||||
} else if (event == "terrain_brush_strength_change") {
|
||||
String data = args[1];
|
||||
data = data.strip_edges();
|
||||
if ((data.is_valid_float() || data.is_valid_integer()) &&
|
||||
current_brush >= 0) {
|
||||
brush_strength[current_brush] =
|
||||
CLAMP(data.to_float(), 0.0f, 100.0f);
|
||||
print_line(data);
|
||||
}
|
||||
} else if (event == "terrain_brush_flags_change") {
|
||||
CheckBox *cb_ = Object::cast_to<CheckBox>(args[0]);
|
||||
assert(cb_);
|
||||
int i;
|
||||
int flags = 0;
|
||||
for (i = 0; i < cb_->get_parent()->get_child_count(); i++) {
|
||||
CheckBox *c = Object::cast_to<CheckBox>(
|
||||
cb_->get_parent()->get_child(i));
|
||||
assert(c);
|
||||
if (c->is_pressed())
|
||||
flags |= (1 << i);
|
||||
}
|
||||
brush_flags[current_brush] = flags;
|
||||
} else if (event == "terrain_menu") {
|
||||
PopupMenu *menu = Object::cast_to<PopupMenu>(args[0]);
|
||||
int id = args[1];
|
||||
print_line("terrain_menu: " + itos(id));
|
||||
switch (id) {
|
||||
case 2000:
|
||||
save_data();
|
||||
break;
|
||||
case 2001: {
|
||||
List<String> building_keys;
|
||||
List<String>::Element *e;
|
||||
BuildingsData::get_singleton()->get_building_keys_list(
|
||||
&building_keys);
|
||||
BuildingsData::get_singleton()->build_building_aabbs();
|
||||
e = building_keys.front();
|
||||
while (e) {
|
||||
const String &key = e->get();
|
||||
const BuildingsData::building &b =
|
||||
BuildingsData::get_singleton()
|
||||
->get_building(key);
|
||||
float i, j;
|
||||
print_line("building type: " + b.id);
|
||||
print_line("building key: " + b.key);
|
||||
print_line("building position: " +
|
||||
(b.xform.origin.operator String()));
|
||||
print_line(
|
||||
"building elevation: " +
|
||||
String::num(imgmapper->get_height_full(
|
||||
b.xform.origin)));
|
||||
AABB aabb = BuildingsData::get_singleton()
|
||||
->building_aabbs[b.id];
|
||||
print_line("building AABB: " +
|
||||
(aabb.operator String()));
|
||||
float max_elevation_c = -Math_INF,
|
||||
min_elevation_c = Math_INF;
|
||||
float extension = 0.0f;
|
||||
if (aabb.size.x >= 10.0f ||
|
||||
aabb.size.z >= 10.0f)
|
||||
extension = 5.0f;
|
||||
for (i = aabb.position.z - extension;
|
||||
i <
|
||||
aabb.position.z + aabb.size.z + extension;
|
||||
i += 1.0f)
|
||||
for (j = aabb.position.x - extension;
|
||||
j < aabb.position.x + aabb.size.x +
|
||||
extension;
|
||||
j += 1.0f) {
|
||||
Vector3 v = b.xform.xform(
|
||||
Vector3(j, 0, i));
|
||||
float h = imgmapper->get_world_pixel(
|
||||
v.x + imgmapper->get_world_size() /
|
||||
2,
|
||||
v.z + imgmapper->get_world_size() /
|
||||
2);
|
||||
if (max_elevation_c < h)
|
||||
max_elevation_c = h;
|
||||
if (min_elevation_c > h)
|
||||
min_elevation_c = h;
|
||||
}
|
||||
float max_elevation = Math::stepify(
|
||||
max_elevation_c * 200.0f - 100.0f,
|
||||
0.25f);
|
||||
print_line("building max_elevation: " +
|
||||
String::num(max_elevation));
|
||||
for (i = aabb.position.z - extension;
|
||||
i <
|
||||
aabb.position.z + aabb.size.z + extension;
|
||||
i += 0.5f) {
|
||||
float mx = 0.0f;
|
||||
for (j = aabb.position.x - extension;
|
||||
j < aabb.position.x + aabb.size.x +
|
||||
extension;
|
||||
j += 0.5f) {
|
||||
float current_c;
|
||||
Vector3 v = b.xform.xform(
|
||||
Vector3(j, 0, i));
|
||||
float h = imgmapper->get_world_pixel(
|
||||
v.x + imgmapper->get_world_size() /
|
||||
2,
|
||||
v.z + imgmapper->get_world_size() /
|
||||
2);
|
||||
float result_c =
|
||||
max_elevation_c;
|
||||
imgmapper->set_world_pixel(
|
||||
v.x + imgmapper->get_world_size() /
|
||||
2,
|
||||
v.z + imgmapper->get_world_size() /
|
||||
2,
|
||||
result_c);
|
||||
mx += 1.0f;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
float max_elevation2 =
|
||||
imgmapper->get_world_pixel(
|
||||
b.xform.origin.x +
|
||||
imgmapper->get_world_size() /
|
||||
2,
|
||||
b.xform.origin.z +
|
||||
imgmapper->get_world_size() /
|
||||
2) *
|
||||
200.0f -
|
||||
100.0f;
|
||||
print_line(
|
||||
"building max_elevation2: " +
|
||||
String::num(max_elevation2) + " -> " +
|
||||
String::num(max_elevation_c * 200.0f -
|
||||
100.0f));
|
||||
// assert(Math::abs(max_elevation2 -
|
||||
// max_elevation) < 1.0f);
|
||||
#endif
|
||||
Transform xform = BuildingsData::get_singleton()
|
||||
->get_building(key)
|
||||
.xform;
|
||||
xform.origin.y = max_elevation * 1.4998f - 0.5f;
|
||||
editor->editor_command(
|
||||
"update_building_transform",
|
||||
varray(key, xform));
|
||||
#if 0
|
||||
assert(Math::abs(BuildingsData::get_singleton()
|
||||
->get_building(key)
|
||||
.xform.origin.y -
|
||||
max_elevation * 1.4f) < 1.0f);
|
||||
#endif
|
||||
e = e->next();
|
||||
}
|
||||
imgmapper->save_dirty_tiles();
|
||||
BuildingsData::get_singleton()->save_buildings();
|
||||
editor->editor_command("nudge_generator", varray());
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,25 +202,40 @@ void MainTabs::_notification(int which)
|
||||
/* 1 */
|
||||
"Brush", 0, "terrain_select_brush",
|
||||
/* 2 */
|
||||
"Save brush data", "save_brush_data",
|
||||
"Terrain", 4,
|
||||
2000, "Save brush data", false,
|
||||
-1, "", false,
|
||||
2001, "Fixup Buildingss", false,
|
||||
2002, "Fixup Roads", false,
|
||||
"terrain_menu",
|
||||
};
|
||||
/* clang-format on */
|
||||
HashMap<String, Object *> save_data;
|
||||
ui_field::ui_field_builder(this, tab,
|
||||
"l_p{v{lo#!$b#!$}}",
|
||||
"l_p{v{lo#!$m#!$}}",
|
||||
args_data.data(),
|
||||
args_data.size(),
|
||||
&save_data);
|
||||
assert(save_data.has("terrain_select_brush"));
|
||||
assert(save_data.has("save_brush_data"));
|
||||
assert(save_data.has("terrain_menu"));
|
||||
OptionButton *ob = Object::cast_to<OptionButton>(
|
||||
save_data["terrain_select_brush"]);
|
||||
memnew(OptionButtonHandler(
|
||||
ob, "terrain_brush_select"));
|
||||
Button *b = Object::cast_to<Button>(
|
||||
save_data["save_brush_data"]);
|
||||
memnew(ButtonPressHandler(b,
|
||||
"terrain_save_data"));
|
||||
MenuButton *mb = Object::cast_to<MenuButton>(
|
||||
save_data["terrain_menu"]);
|
||||
memnew(PopupMenuSelectHandler(mb->get_popup(),
|
||||
"terrain_menu"));
|
||||
/*
|
||||
Button *b2 = Object::cast_to<Button>(
|
||||
save_data["fixup_buildings"]);
|
||||
memnew(ButtonPressHandler(
|
||||
b2, "terrain_fixup_buildings"));
|
||||
Button *b3 = Object::cast_to<Button>(
|
||||
save_data["fixup_roads"]);
|
||||
memnew(ButtonPressHandler(
|
||||
b3, "terrain_fixup_roads"));
|
||||
*/
|
||||
} break;
|
||||
case 1: {
|
||||
// VBoxContainer *v = memnew(VBoxContainer);
|
||||
|
||||
Reference in New Issue
Block a user