2016-05-10 01:59:54 +02:00
|
|
|
#include "voxel_map.h"
|
2017-01-03 02:50:19 +01:00
|
|
|
#include "core/os/os.h"
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// VoxelBlock
|
|
|
|
//----------------------------------------------------------------------------
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
MeshInstance *VoxelBlock::get_mesh_instance(const Node &root) {
|
2017-01-01 04:40:16 +01:00
|
|
|
if (mesh_instance_path.is_empty())
|
|
|
|
return NULL;
|
2017-08-13 01:19:39 +02:00
|
|
|
Node *n = root.get_node(mesh_instance_path);
|
2017-01-01 04:40:16 +01:00
|
|
|
if (n == NULL)
|
|
|
|
return NULL;
|
|
|
|
return n->cast_to<MeshInstance>();
|
2017-03-26 18:09:37 +02:00
|
|
|
}
|
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
// Helper
|
2017-08-20 15:17:54 +02:00
|
|
|
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size) {
|
|
|
|
const int bs = size;
|
2017-01-05 02:39:40 +01:00
|
|
|
ERR_FAIL_COND_V(buffer.is_null(), NULL);
|
|
|
|
ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL);
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block = memnew(VoxelBlock);
|
2017-01-01 04:40:16 +01:00
|
|
|
block->pos = bpos;
|
2017-01-05 02:39:40 +01:00
|
|
|
|
|
|
|
block->voxels = buffer;
|
2017-01-01 04:40:16 +01:00
|
|
|
//block->map = ↦
|
|
|
|
return block;
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock::VoxelBlock()
|
|
|
|
: voxels(NULL) {
|
2017-01-03 02:50:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// VoxelMap
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelMap::VoxelMap()
|
|
|
|
: _last_accessed_block(NULL) {
|
2017-08-20 15:17:54 +02:00
|
|
|
|
|
|
|
// TODO Make it configurable in editor (with all necessary notifications and updatings!)
|
|
|
|
set_block_size_pow2(4);
|
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) {
|
|
|
|
_default_voxel[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VoxelMap::~VoxelMap() {
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
2017-08-20 15:17:54 +02:00
|
|
|
void VoxelMap::set_block_size_pow2(unsigned int p) {
|
|
|
|
|
|
|
|
// Limit to 8, 16, 32
|
|
|
|
ERR_FAIL_COND(p < 3 || p > 5);
|
|
|
|
|
|
|
|
_block_size_pow2 = p;
|
|
|
|
_block_size = 1 << _block_size_pow2;
|
|
|
|
_block_size_mask = _block_size_pow2 - 1;
|
|
|
|
}
|
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
int VoxelMap::get_voxel(Vector3i pos, unsigned int c) {
|
|
|
|
Vector3i bpos = voxel_to_block(pos);
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block = get_block(bpos);
|
2017-01-03 02:50:19 +01:00
|
|
|
if (block == NULL) {
|
|
|
|
return _default_voxel[c];
|
|
|
|
}
|
2017-03-29 22:36:42 +02:00
|
|
|
return block->voxels->get_voxel(VoxelMap::to_local(pos), c);
|
2017-01-03 02:50:19 +01:00
|
|
|
}
|
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
void VoxelMap::set_voxel(int value, Vector3i pos, unsigned int c) {
|
2017-01-05 02:39:40 +01:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
Vector3i bpos = voxel_to_block(pos);
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block = get_block(bpos);
|
2017-01-05 02:39:40 +01:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
if (block == NULL) {
|
2017-01-05 02:39:40 +01:00
|
|
|
|
|
|
|
Ref<VoxelBuffer> buffer(memnew(VoxelBuffer));
|
2017-08-20 15:17:54 +02:00
|
|
|
buffer->create(_block_size, _block_size, _block_size);
|
2017-01-05 02:39:40 +01:00
|
|
|
buffer->set_default_values(_default_voxel);
|
|
|
|
|
2017-08-20 15:17:54 +02:00
|
|
|
block = VoxelBlock::create(bpos, buffer, _block_size);
|
2017-01-05 02:39:40 +01:00
|
|
|
|
2017-01-01 04:03:56 +01:00
|
|
|
set_block(bpos, block);
|
2017-01-01 04:40:16 +01:00
|
|
|
}
|
2017-01-05 02:39:40 +01:00
|
|
|
|
2017-03-29 22:36:42 +02:00
|
|
|
block->voxels->set_voxel(value, VoxelMap::to_local(pos), c);
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelMap::set_default_voxel(int value, unsigned int channel) {
|
2017-01-01 04:40:16 +01:00
|
|
|
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
|
|
|
|
_default_voxel[channel] = value;
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int VoxelMap::get_default_voxel(unsigned int channel) {
|
2017-01-01 04:40:16 +01:00
|
|
|
ERR_FAIL_INDEX_V(channel, VoxelBuffer::MAX_CHANNELS, 0);
|
|
|
|
return _default_voxel[channel];
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *VoxelMap::get_block(Vector3i bpos) {
|
2017-01-01 04:40:16 +01:00
|
|
|
if (_last_accessed_block && _last_accessed_block->pos == bpos) {
|
|
|
|
return _last_accessed_block;
|
|
|
|
}
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock **p = _blocks.getptr(bpos);
|
2017-01-01 04:40:16 +01:00
|
|
|
if (p) {
|
2017-01-03 02:50:19 +01:00
|
|
|
_last_accessed_block = *p;
|
2017-01-01 04:40:16 +01:00
|
|
|
return _last_accessed_block;
|
|
|
|
}
|
|
|
|
return NULL;
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
void VoxelMap::set_block(Vector3i bpos, VoxelBlock *block) {
|
2017-01-05 02:39:40 +01:00
|
|
|
ERR_FAIL_COND(block == NULL);
|
2017-01-01 04:40:16 +01:00
|
|
|
if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) {
|
|
|
|
_last_accessed_block = block;
|
|
|
|
}
|
|
|
|
_blocks.set(bpos, block);
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelMap::set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer) {
|
2017-01-01 04:40:16 +01:00
|
|
|
ERR_FAIL_COND(buffer.is_null());
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block = get_block(bpos);
|
2017-01-01 04:40:16 +01:00
|
|
|
if (block == NULL) {
|
2017-08-20 15:17:54 +02:00
|
|
|
block = VoxelBlock::create(bpos, *buffer, _block_size);
|
2017-01-01 04:40:16 +01:00
|
|
|
set_block(bpos, block);
|
2017-08-13 01:19:39 +02:00
|
|
|
} else {
|
2017-01-01 04:40:16 +01:00
|
|
|
block->voxels = buffer;
|
|
|
|
}
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool VoxelMap::has_block(Vector3i pos) const {
|
2017-01-01 04:40:16 +01:00
|
|
|
return /*(_last_accessed_block != NULL && _last_accessed_block->pos == pos) ||*/ _blocks.has(pos);
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector3i g_moore_neighboring_3d[26] = {
|
2017-08-13 01:19:39 +02:00
|
|
|
Vector3i(-1, -1, -1),
|
|
|
|
Vector3i(0, -1, -1),
|
|
|
|
Vector3i(1, -1, -1),
|
|
|
|
Vector3i(-1, -1, 0),
|
|
|
|
Vector3i(0, -1, 0),
|
|
|
|
Vector3i(1, -1, 0),
|
|
|
|
Vector3i(-1, -1, 1),
|
|
|
|
Vector3i(0, -1, 1),
|
|
|
|
Vector3i(1, -1, 1),
|
|
|
|
|
|
|
|
Vector3i(-1, 0, -1),
|
|
|
|
Vector3i(0, 0, -1),
|
|
|
|
Vector3i(1, 0, -1),
|
|
|
|
Vector3i(-1, 0, 0),
|
2017-01-01 04:40:16 +01:00
|
|
|
//Vector3i(0,0,0),
|
2017-08-13 01:19:39 +02:00
|
|
|
Vector3i(1, 0, 0),
|
|
|
|
Vector3i(-1, 0, 1),
|
|
|
|
Vector3i(0, 0, 1),
|
|
|
|
Vector3i(1, 0, 1),
|
|
|
|
|
|
|
|
Vector3i(-1, 1, -1),
|
|
|
|
Vector3i(0, 1, -1),
|
|
|
|
Vector3i(1, 1, -1),
|
|
|
|
Vector3i(-1, 1, 0),
|
|
|
|
Vector3i(0, 1, 0),
|
|
|
|
Vector3i(1, 1, 0),
|
|
|
|
Vector3i(-1, 1, 1),
|
|
|
|
Vector3i(0, 1, 1),
|
|
|
|
Vector3i(1, 1, 1),
|
2016-05-10 01:59:54 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
bool VoxelMap::is_block_surrounded(Vector3i pos) const {
|
2017-01-01 04:40:16 +01:00
|
|
|
for (unsigned int i = 0; i < 26; ++i) {
|
|
|
|
Vector3i bpos = pos + g_moore_neighboring_3d[i];
|
|
|
|
if (!has_block(bpos)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsigned int channels_mask) {
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
Vector3i max_pos = min_pos + dst_buffer.get_size();
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
Vector3i min_block_pos = voxel_to_block(min_pos);
|
2017-08-13 01:19:39 +02:00
|
|
|
Vector3i max_block_pos = voxel_to_block(max_pos - Vector3i(1, 1, 1)) + Vector3i(1, 1, 1);
|
2017-01-01 04:40:16 +01:00
|
|
|
ERR_FAIL_COND((max_block_pos - min_block_pos) != Vector3(3, 3, 3));
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-08-20 15:17:54 +02:00
|
|
|
const Vector3i block_size_v(_block_size, _block_size, _block_size);
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
for (unsigned int channel = 0; channel < VoxelBuffer::MAX_CHANNELS; ++channel) {
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
if (((1 << channel) & channels_mask) == 0) {
|
2017-04-06 23:44:11 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-04-06 23:44:11 +02:00
|
|
|
Vector3i bpos;
|
|
|
|
for (bpos.z = min_block_pos.z; bpos.z < max_block_pos.z; ++bpos.z) {
|
|
|
|
for (bpos.x = min_block_pos.x; bpos.x < max_block_pos.x; ++bpos.x) {
|
|
|
|
for (bpos.y = min_block_pos.y; bpos.y < max_block_pos.y; ++bpos.y) {
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block = get_block(bpos);
|
2017-04-06 23:44:11 +02:00
|
|
|
if (block) {
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBuffer &src_buffer = **block->voxels;
|
2017-04-06 23:44:11 +02:00
|
|
|
Vector3i offset = block_to_voxel(bpos);
|
|
|
|
// Note: copy_from takes care of clamping the area if it's on an edge
|
|
|
|
dst_buffer.copy_from(src_buffer, min_pos - offset, max_pos - offset, offset - min_pos, channel);
|
2017-08-20 15:17:54 +02:00
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
} else {
|
2017-04-06 23:44:11 +02:00
|
|
|
Vector3i offset = block_to_voxel(bpos);
|
|
|
|
dst_buffer.fill_area(
|
2017-08-13 01:19:39 +02:00
|
|
|
_default_voxel[channel],
|
|
|
|
offset - min_pos,
|
2017-08-20 15:17:54 +02:00
|
|
|
offset - min_pos + block_size_v);
|
2017-04-06 23:44:11 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-01 04:40:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelMap::remove_blocks_not_in_area(Vector3i min, Vector3i max) {
|
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
Vector3i::sort_min_max(min, max);
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
Vector<Vector3i> to_remove;
|
2017-08-13 01:19:39 +02:00
|
|
|
const Vector3i *key = NULL;
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
while (key = _blocks.next(key)) {
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block_ref = _blocks.get(*key);
|
2017-01-03 02:50:19 +01:00
|
|
|
ERR_FAIL_COND(block_ref == NULL); // Should never trigger
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
if (block_ref->pos.is_contained_in(min, max)) {
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
//if (_observer)
|
|
|
|
// _observer->block_removed(block);
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
to_remove.push_back(*key);
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
if (block_ref == _last_accessed_block)
|
2017-01-01 04:40:16 +01:00
|
|
|
_last_accessed_block = NULL;
|
|
|
|
}
|
|
|
|
}
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
for (unsigned int i = 0; i < to_remove.size(); ++i) {
|
|
|
|
_blocks.erase(to_remove[i]);
|
|
|
|
}
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
2017-01-03 02:50:19 +01:00
|
|
|
void VoxelMap::clear() {
|
2017-08-13 01:19:39 +02:00
|
|
|
const Vector3i *key = NULL;
|
2017-01-03 02:50:19 +01:00
|
|
|
while (key = _blocks.next(key)) {
|
2017-08-13 01:19:39 +02:00
|
|
|
VoxelBlock *block_ref = _blocks.get(*key);
|
|
|
|
if (block_ref == NULL) {
|
2017-01-03 02:50:19 +01:00
|
|
|
OS::get_singleton()->printerr("Unexpected NULL in VoxelMap::clear()");
|
|
|
|
}
|
|
|
|
memdelete(block_ref);
|
|
|
|
}
|
|
|
|
_blocks.clear();
|
|
|
|
_last_accessed_block = NULL;
|
|
|
|
}
|
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
void VoxelMap::_bind_methods() {
|
|
|
|
|
2017-03-25 01:23:36 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get_voxel", "x", "y", "z", "c"), &VoxelMap::_get_voxel_binding, DEFVAL(0));
|
|
|
|
ClassDB::bind_method(D_METHOD("set_voxel", "value", "x", "y", "z", "c"), &VoxelMap::_set_voxel_binding, DEFVAL(0));
|
2017-03-29 22:36:42 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("get_voxel_v", "pos", "c"), &VoxelMap::_get_voxel_v_binding, DEFVAL(0));
|
|
|
|
ClassDB::bind_method(D_METHOD("set_voxel_v", "value", "pos", "c"), &VoxelMap::_set_voxel_v_binding, DEFVAL(0));
|
2017-03-25 01:23:36 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get_default_voxel", "channel"), &VoxelMap::get_default_voxel, DEFVAL(0));
|
|
|
|
ClassDB::bind_method(D_METHOD("set_default_voxel", "value", "channel"), &VoxelMap::set_default_voxel, DEFVAL(0));
|
|
|
|
ClassDB::bind_method(D_METHOD("has_block", "x", "y", "z"), &VoxelMap::_has_block_binding);
|
2017-08-13 00:08:53 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("get_buffer_copy", "min_pos", "out_buffer", "channel"), &VoxelMap::_get_buffer_copy_binding, DEFVAL(0));
|
|
|
|
ClassDB::bind_method(D_METHOD("set_block_buffer", "block_pos", "buffer"), &VoxelMap::_set_block_buffer_binding);
|
2017-03-25 01:23:36 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("voxel_to_block", "voxel_pos"), &VoxelMap::_voxel_to_block_binding);
|
|
|
|
ClassDB::bind_method(D_METHOD("block_to_voxel", "block_pos"), &VoxelMap::_block_to_voxel_binding);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_block_size"), &VoxelMap::get_block_size);
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
//ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations"), _SCS("set_iterations"), _SCS("get_iterations"));
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelMap::_get_buffer_copy_binding(Vector3 pos, Ref<VoxelBuffer> dst_buffer_ref, unsigned int channel) {
|
2017-01-01 04:40:16 +01:00
|
|
|
ERR_FAIL_COND(dst_buffer_ref.is_null());
|
|
|
|
get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel);
|
2016-05-10 01:59:54 +02:00
|
|
|
}
|