diff --git a/vector3i.h b/vector3i.h index 8978d7b..9eaf1c4 100644 --- a/vector3i.h +++ b/vector3i.h @@ -1,8 +1,8 @@ #ifndef VOXEL_VECTOR3I_H #define VOXEL_VECTOR3I_H -#include #include +#include struct Vector3i { @@ -15,15 +15,17 @@ struct Vector3i { int coords[3]; }; - _FORCE_INLINE_ Vector3i() : x(0), y(0), z(0) {} + _FORCE_INLINE_ Vector3i() + : x(0), y(0), z(0) {} - _FORCE_INLINE_ Vector3i(int px, int py, int pz) : x(px), y(py), z(pz) {} + _FORCE_INLINE_ Vector3i(int px, int py, int pz) + : x(px), y(py), z(pz) {} - _FORCE_INLINE_ Vector3i(const Vector3i & other) { + _FORCE_INLINE_ Vector3i(const Vector3i &other) { *this = other; } - _FORCE_INLINE_ Vector3i(const Vector3 & f) { + _FORCE_INLINE_ Vector3i(const Vector3 &f) { x = Math::floor(f.x); y = Math::floor(f.y); z = Math::floor(f.z); @@ -34,39 +36,39 @@ struct Vector3i { } _FORCE_INLINE_ int volume() const { - return x*y*z; + return x * y * z; } _FORCE_INLINE_ int length_sq() const { - return x*x + y*y + z*z; + return x * x + y * y + z * z; } _FORCE_INLINE_ real_t length() const { return Math::sqrt((real_t)length_sq()); } - _FORCE_INLINE_ int distance_sq(const Vector3i & other) const; + _FORCE_INLINE_ int distance_sq(const Vector3i &other) const; - _FORCE_INLINE_ Vector3i & operator=(const Vector3i & other) { + _FORCE_INLINE_ Vector3i &operator=(const Vector3i &other) { x = other.x; y = other.y; z = other.z; return *this; } - _FORCE_INLINE_ void operator+=(const Vector3i & other) { + _FORCE_INLINE_ void operator+=(const Vector3i &other) { x += other.x; y += other.y; z += other.z; } - _FORCE_INLINE_ void operator-=(const Vector3i & other) { + _FORCE_INLINE_ void operator-=(const Vector3i &other) { x -= other.x; y -= other.y; z -= other.z; } - _FORCE_INLINE_ int & operator[](unsigned int i) { + _FORCE_INLINE_ int &operator[](unsigned int i) { return coords[i]; } @@ -80,70 +82,67 @@ struct Vector3i { if (z >= max.z) z = max.z - 1; } - _FORCE_INLINE_ bool is_contained_in(const Vector3i & min, const Vector3i & max) { - return x >= min.x && y >= min.y && z >= min.z - && x < max.x && y < max.y && z < max.z; + _FORCE_INLINE_ bool is_contained_in(const Vector3i &min, const Vector3i &max) { + return x >= min.x && y >= min.y && z >= min.z && x < max.x && y < max.y && z < max.z; } - _FORCE_INLINE_ Vector3i wrap(const Vector3i & size) { + _FORCE_INLINE_ Vector3i wrap(const Vector3i &size) { return Vector3i( - x % size.x, - y % size.y, - z % size.z - ); + x % size.x, + y % size.y, + z % size.z); } - static void sort_min_max(Vector3i & a, Vector3i & b) { + static void sort_min_max(Vector3i &a, Vector3i &b) { sort_min_max(a.x, b.x); sort_min_max(a.y, b.y); sort_min_max(a.z, b.z); } private: - static _FORCE_INLINE_ void sort_min_max(int & a, int & b) { + static _FORCE_INLINE_ void sort_min_max(int &a, int &b) { if (a > b) { int temp = a; a = b; b = temp; } } - }; -_FORCE_INLINE_ Vector3i operator+(const Vector3i a, const Vector3i & b) { +_FORCE_INLINE_ Vector3i operator+(const Vector3i a, const Vector3i &b) { return Vector3i(a.x + b.x, a.y + b.y, a.z + b.z); } -_FORCE_INLINE_ Vector3i operator-(const Vector3i & a, const Vector3i & b) { +_FORCE_INLINE_ Vector3i operator-(const Vector3i &a, const Vector3i &b) { return Vector3i(a.x - b.x, a.y - b.y, a.z - b.z); } -_FORCE_INLINE_ Vector3i operator*(const Vector3i & a, int n) { +_FORCE_INLINE_ Vector3i operator*(const Vector3i &a, int n) { return Vector3i(a.x * n, a.y * n, a.z * n); } -_FORCE_INLINE_ Vector3i operator*(int n, const Vector3i & a) { +_FORCE_INLINE_ Vector3i operator*(int n, const Vector3i &a) { return Vector3i(a.x * n, a.y * n, a.z * n); } -_FORCE_INLINE_ Vector3i operator/(const Vector3i & a, int n) { +_FORCE_INLINE_ Vector3i operator/(const Vector3i &a, int n) { return Vector3i(a.x / n, a.y / n, a.z / n); } -_FORCE_INLINE_ bool operator==(const Vector3i & a, const Vector3i & b) { +_FORCE_INLINE_ bool operator==(const Vector3i &a, const Vector3i &b) { return a.x == b.x && a.y == b.y && a.z == b.z; } -_FORCE_INLINE_ bool operator!=(const Vector3i & a, const Vector3i & b) { +_FORCE_INLINE_ bool operator!=(const Vector3i &a, const Vector3i &b) { return a.x != b.x && a.y != b.y && a.z != b.z; } -_FORCE_INLINE_ int Vector3i::distance_sq(const Vector3i & other) const { +_FORCE_INLINE_ int Vector3i::distance_sq(const Vector3i &other) const { return (other - *this).length_sq(); } struct Vector3iHasher { - static _FORCE_INLINE_ uint32_t hash(const Vector3i & v) { + static _FORCE_INLINE_ uint32_t hash(const Vector3i &v) { uint32_t hash = hash_djb2_one_32(v.x); hash = hash_djb2_one_32(v.y, hash); return hash_djb2_one_32(v.z, hash); @@ -151,4 +150,3 @@ struct Vector3iHasher { }; #endif // VOXEL_VECTOR3I_H - diff --git a/voxel.cpp b/voxel.cpp index 6b32ad6..ebbb905 100644 --- a/voxel.cpp +++ b/voxel.cpp @@ -2,13 +2,13 @@ #include "voxel_library.h" #include "voxel_mesher.h" -Voxel::Voxel() : Reference(), - _id(-1), - _material_id(0), - _is_transparent(false), - _library(NULL), - _color(1.f, 1.f, 1.f) -{} +Voxel::Voxel() + : Reference(), + _id(-1), + _material_id(0), + _is_transparent(false), + _library(NULL), + _color(1.f, 1.f, 1.f) {} Ref Voxel::set_name(String name) { _name = name; @@ -41,60 +41,48 @@ Ref Voxel::set_transparent(bool t) { Ref Voxel::set_cube_geometry(float sy) { const Vector3 vertices[SIDE_COUNT][6] = { - { - // LEFT - Vector3(0, 0, 0), - Vector3(0, sy, 0), - Vector3(0, sy, 1), - Vector3(0, 0, 0), - Vector3(0, sy, 1), - Vector3(0, 0, 1), - }, - { - // RIGHT - Vector3(1, 0, 0), - Vector3(1, sy, 1), - Vector3(1, sy, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(1, sy, 1) - }, - { - // BOTTOM - Vector3(0, 0, 0), - Vector3(1, 0, 1), - Vector3(1, 0, 0), - Vector3(0, 0, 0), - Vector3(0, 0, 1), - Vector3(1, 0, 1) - }, - { - // TOP - Vector3(0, sy, 0), - Vector3(1, sy, 0), - Vector3(1, sy, 1), - Vector3(0, sy, 0), - Vector3(1, sy, 1), - Vector3(0, sy, 1) - }, - { - // BACK - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, sy, 0), - Vector3(0, 0, 0), - Vector3(1, sy, 0), - Vector3(0, sy, 0), - }, - { - // FRONT - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(1, sy, 1), - Vector3(0, 0, 1), - Vector3(0, sy, 1), - Vector3(1, sy, 1) - } + { // LEFT + Vector3(0, 0, 0), + Vector3(0, sy, 0), + Vector3(0, sy, 1), + Vector3(0, 0, 0), + Vector3(0, sy, 1), + Vector3(0, 0, 1) }, + { // RIGHT + Vector3(1, 0, 0), + Vector3(1, sy, 1), + Vector3(1, sy, 0), + Vector3(1, 0, 0), + Vector3(1, 0, 1), + Vector3(1, sy, 1) }, + { // BOTTOM + Vector3(0, 0, 0), + Vector3(1, 0, 1), + Vector3(1, 0, 0), + Vector3(0, 0, 0), + Vector3(0, 0, 1), + Vector3(1, 0, 1) }, + { // TOP + Vector3(0, sy, 0), + Vector3(1, sy, 0), + Vector3(1, sy, 1), + Vector3(0, sy, 0), + Vector3(1, sy, 1), + Vector3(0, sy, 1) }, + { // BACK + Vector3(0, 0, 0), + Vector3(1, 0, 0), + Vector3(1, sy, 0), + Vector3(0, 0, 0), + Vector3(1, sy, 0), + Vector3(0, sy, 0) }, + { // FRONT + Vector3(1, 0, 1), + Vector3(0, 0, 1), + Vector3(1, sy, 1), + Vector3(0, 0, 1), + Vector3(0, sy, 1), + Vector3(1, sy, 1) } }; for (unsigned int side = 0; side < SIDE_COUNT; ++side) { @@ -121,17 +109,17 @@ Ref Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) { const int uv6[SIDE_COUNT][6] = { // LEFT - { 2,0,1,2,1,3 }, + { 2, 0, 1, 2, 1, 3 }, // RIGHT - { 2,1,0,2,3,1 }, + { 2, 1, 0, 2, 3, 1 }, // BOTTOM - { 0,3,1,0,2,3 }, + { 0, 3, 1, 0, 2, 3 }, // TOP - { 0,1,3,0,3,2 }, + { 0, 1, 3, 0, 3, 2 }, // BACK - { 2,3,1,2,1,0 }, + { 2, 3, 1, 2, 1, 0 }, // FRONT - { 3,2,1,2,0,1 } + { 3, 2, 1, 2, 0, 1 } }; float s = 1.0 / (float)_library->get_atlas_size(); @@ -197,9 +185,7 @@ void Voxel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cube_uv_all_sides", "atlas_pos"), &Voxel::set_cube_uv_all_sides); ClassDB::bind_method(D_METHOD("set_cube_uv_tbs_sides", "top_atlas_pos", "side_atlas_pos", "bottom_atlas_pos"), &Voxel::set_cube_uv_tbs_sides); - BIND_CONSTANT( CHANNEL_TYPE ) - BIND_CONSTANT( CHANNEL_ISOLEVEL ) - BIND_CONSTANT( CHANNEL_DATA ) - + BIND_CONSTANT(CHANNEL_TYPE) + BIND_CONSTANT(CHANNEL_ISOLEVEL) + BIND_CONSTANT(CHANNEL_DATA) } - diff --git a/voxel.h b/voxel.h index cf4d9d3..710b7bc 100644 --- a/voxel.h +++ b/voxel.h @@ -60,13 +60,13 @@ public: // Getters for native usage only - const PoolVector & get_model_vertices() const { return _model_vertices; } - const PoolVector & get_model_normals() const { return _model_normals; } - const PoolVector & get_model_uv() const { return _model_uv; } - const PoolVector & get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; } - const PoolVector & get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; } + const PoolVector &get_model_vertices() const { return _model_vertices; } + const PoolVector &get_model_normals() const { return _model_normals; } + const PoolVector &get_model_uv() const { return _model_uv; } + const PoolVector &get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; } + const PoolVector &get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; } - void set_library_ptr(VoxelLibrary * lib) { _library = lib; } + void set_library_ptr(VoxelLibrary *lib) { _library = lib; } protected: Ref _set_cube_uv_sides(const Vector2 atlas_pos[6]); @@ -74,7 +74,7 @@ protected: static void _bind_methods(); private: - VoxelLibrary * _library; + VoxelLibrary *_library; // Identifiers int _id; @@ -93,11 +93,8 @@ private: PoolVector _model_side_uv[SIDE_COUNT]; // TODO Child voxel types - }; VARIANT_ENUM_CAST(Voxel::ChannelMode) - #endif // VOXEL_TYPE_H - diff --git a/voxel_buffer.cpp b/voxel_buffer.cpp index afedc3f..7abee8c 100644 --- a/voxel_buffer.cpp +++ b/voxel_buffer.cpp @@ -1,10 +1,8 @@ #include "voxel_buffer.h" -#include #include - +#include VoxelBuffer::VoxelBuffer() { - } VoxelBuffer::~VoxelBuffer() { @@ -18,7 +16,7 @@ void VoxelBuffer::create(int sx, int sy, int sz) { Vector3i new_size(sx, sy, sz); if (new_size != _size) { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { - Channel & channel = _channels[i]; + Channel &channel = _channels[i]; if (channel.data) { // TODO Optimize with realloc delete_channel(i); @@ -31,7 +29,7 @@ void VoxelBuffer::create(int sx, int sy, int sz) { void VoxelBuffer::clear() { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { - Channel & channel = _channels[i]; + Channel &channel = _channels[i]; if (channel.data) { delete_channel(i); } @@ -40,13 +38,13 @@ void VoxelBuffer::clear() { void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) { ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); - if(_channels[channel_index].data) + if (_channels[channel_index].data) delete_channel(channel_index); _channels[channel_index].defval = clear_value; } void VoxelBuffer::set_default_values(uint8_t values[VoxelBuffer::MAX_CHANNELS]) { - for(unsigned int i = 0; i < MAX_CHANNELS; ++i) { + for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { _channels[i].defval = values[i]; } } @@ -54,29 +52,27 @@ void VoxelBuffer::set_default_values(uint8_t values[VoxelBuffer::MAX_CHANNELS]) int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) const { ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, 0); - const Channel & channel = _channels[channel_index]; + const Channel &channel = _channels[channel_index]; if (validate_pos(x, y, z) && channel.data) { - return channel.data[index(x,y,z)]; - } - else { + return channel.data[index(x, y, z)]; + } else { return channel.defval; } } void VoxelBuffer::set_voxel(int value, int x, int y, int z, unsigned int channel_index) { - ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); + ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); ERR_FAIL_COND(!validate_pos(x, y, z)); - Channel & channel = _channels[channel_index]; + Channel &channel = _channels[channel_index]; if (channel.data == NULL) { if (channel.defval != value) { create_channel(channel_index, _size); channel.data[index(x, y, z)] = value; } - } - else { + } else { channel.data[index(x, y, z)] = value; } } @@ -88,7 +84,7 @@ void VoxelBuffer::set_voxel_v(int value, Vector3 pos, unsigned int channel_index void VoxelBuffer::fill(int defval, unsigned int channel_index) { ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); - Channel & channel = _channels[channel_index]; + Channel &channel = _channels[channel_index]; if (channel.data == NULL && channel.defval == defval) return; else @@ -104,10 +100,10 @@ void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int Vector3i::sort_min_max(min, max); min.clamp_to(Vector3i(0, 0, 0), _size); - max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1,1,1)); + max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1, 1, 1)); Vector3i area_size = max - min; - Channel & channel = _channels[channel_index]; + Channel &channel = _channels[channel_index]; if (channel.data == NULL) { if (channel.defval == defval) return; @@ -127,7 +123,7 @@ void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int bool VoxelBuffer::is_uniform(unsigned int channel_index) const { ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, true); - const Channel & channel = _channels[channel_index]; + const Channel &channel = _channels[channel_index]; if (channel.data == NULL) return true; @@ -150,37 +146,36 @@ void VoxelBuffer::optimize() { } } -void VoxelBuffer::copy_from(const VoxelBuffer & other, unsigned int channel_index) { +void VoxelBuffer::copy_from(const VoxelBuffer &other, unsigned int channel_index) { ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); ERR_FAIL_COND(other._size == _size); - Channel & channel = _channels[channel_index]; - const Channel & other_channel = other._channels[channel_index]; + Channel &channel = _channels[channel_index]; + const Channel &other_channel = other._channels[channel_index]; if (other_channel.data) { if (channel.data == NULL) { create_channel_noinit(channel_index, _size); } memcpy(channel.data, other_channel.data, get_volume() * sizeof(uint8_t)); - } - else if(channel.data) { + } else if (channel.data) { delete_channel(channel_index); } channel.defval = other_channel.defval; } -void VoxelBuffer::copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index) { +void VoxelBuffer::copy_from(const VoxelBuffer &other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index) { ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); - Channel & channel = _channels[channel_index]; - const Channel & other_channel = other._channels[channel_index]; + Channel &channel = _channels[channel_index]; + const Channel &other_channel = other._channels[channel_index]; Vector3i::sort_min_max(src_min, src_max); src_min.clamp_to(Vector3i(0, 0, 0), other._size); - src_max.clamp_to(Vector3i(0, 0, 0), other._size + Vector3i(1,1,1)); + src_max.clamp_to(Vector3i(0, 0, 0), other._size + Vector3i(1, 1, 1)); dst_min.clamp_to(Vector3i(0, 0, 0), _size); Vector3i area_size = src_max - src_min; @@ -188,8 +183,7 @@ void VoxelBuffer::copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3 if (area_size == _size) { copy_from(other, channel_index); - } - else { + } else { if (other_channel.data) { if (channel.data == NULL) { create_channel(channel_index, _size); @@ -204,8 +198,7 @@ void VoxelBuffer::copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3 memcpy(&channel.data[dst_ri], &other_channel.data[src_ri], area_size.y * sizeof(uint8_t)); } } - } - else if (channel.defval != other_channel.defval) { + } else if (channel.defval != other_channel.defval) { if (channel.data == NULL) { create_channel(channel_index, _size); } @@ -227,13 +220,13 @@ void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) { } void VoxelBuffer::create_channel_noinit(int i, Vector3i size) { - Channel & channel = _channels[i]; + Channel &channel = _channels[i]; unsigned int volume = size.x * size.y * size.z; - channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t)); + channel.data = (uint8_t *)memalloc(volume * sizeof(uint8_t)); } void VoxelBuffer::delete_channel(int i) { - Channel & channel = _channels[i]; + Channel &channel = _channels[i]; ERR_FAIL_COND(channel.data == NULL); memfree(channel.data); channel.data = NULL; @@ -261,7 +254,6 @@ void VoxelBuffer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0)); ClassDB::bind_method(D_METHOD("optimize"), &VoxelBuffer::optimize); - } void VoxelBuffer::_copy_from_binding(Ref other, unsigned int channel) { diff --git a/voxel_buffer.h b/voxel_buffer.h index b5ec221..7b98e94 100644 --- a/voxel_buffer.h +++ b/voxel_buffer.h @@ -1,9 +1,9 @@ #ifndef VOXEL_BUFFER_H #define VOXEL_BUFFER_H +#include "vector3i.h" #include #include -#include "vector3i.h" // Dense voxels data storage. // Organized in 8-bit channels like images, all optional. @@ -19,9 +19,9 @@ public: // Converts -1..1 float into 0..255 integer static inline int iso_to_byte(real_t iso) { int v = static_cast(128.f * iso + 128.f); - if(v > 255) + if (v > 255) return 255; - else if(v < 0) + else if (v < 0) return 0; return v; } @@ -36,17 +36,17 @@ public: void create(int sx, int sy, int sz); void clear(); - void clear_channel(unsigned int channel_index, int clear_value=0); + void clear_channel(unsigned int channel_index, int clear_value = 0); _FORCE_INLINE_ Vector3i get_size() const { return _size; } void set_default_values(uint8_t values[MAX_CHANNELS]); - int get_voxel(int x, int y, int z, unsigned int channel_index=0) const; - void set_voxel(int value, int x, int y, int z, unsigned int channel_index=0); + int get_voxel(int x, int y, int z, unsigned int channel_index = 0) const; + void set_voxel(int value, int x, int y, int z, unsigned int channel_index = 0); void set_voxel_v(int value, Vector3 pos, unsigned int channel_index = 0); - _FORCE_INLINE_ void set_voxel_iso(real_t value, int x, int y, int z, unsigned int channel_index=0) { set_voxel(iso_to_byte(value), x,y,z, channel_index); } - _FORCE_INLINE_ real_t get_voxel_iso(int x, int y, int z, unsigned int channel_index=0) const { return byte_to_iso(get_voxel(x,y,z,channel_index)); } + _FORCE_INLINE_ void set_voxel_iso(real_t value, int x, int y, int z, unsigned int channel_index = 0) { set_voxel(iso_to_byte(value), x, y, z, channel_index); } + _FORCE_INLINE_ real_t get_voxel_iso(int x, int y, int z, unsigned int channel_index = 0) const { return byte_to_iso(get_voxel(x, y, z, channel_index)); } _FORCE_INLINE_ int get_voxel(const Vector3i pos, unsigned int channel_index = 0) const { return get_voxel(pos.x, pos.y, pos.z, channel_index); } _FORCE_INLINE_ void set_voxel(int value, const Vector3i pos, unsigned int channel_index = 0) { set_voxel(value, pos.x, pos.y, pos.z, channel_index); } @@ -57,13 +57,11 @@ public: void optimize(); - void copy_from(const VoxelBuffer & other, unsigned int channel_index=0); - void copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index = 0); + void copy_from(const VoxelBuffer &other, unsigned int channel_index = 0); + void copy_from(const VoxelBuffer &other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index = 0); _FORCE_INLINE_ bool validate_pos(unsigned int x, unsigned int y, unsigned int z) const { - return x < _size.x - && y < _size.y - && z < _size.x; + return x < _size.x && y < _size.y && z < _size.x; } _FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const { @@ -80,7 +78,7 @@ public: private: void create_channel_noinit(int i, Vector3i size); - void create_channel(int i, Vector3i size, uint8_t defval=0); + void create_channel(int i, Vector3i size, uint8_t defval = 0); void delete_channel(int i); protected: @@ -95,18 +93,19 @@ protected: void _copy_from_binding(Ref other, unsigned int channel); void _copy_from_area_binding(Ref other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, unsigned int channel); _FORCE_INLINE_ void _fill_area_binding(int defval, Vector3 min, Vector3 max, unsigned int channel_index) { fill_area(defval, Vector3i(min), Vector3i(max), channel_index); } - _FORCE_INLINE_ void _set_voxel_iso_binding(real_t value, int x, int y, int z, unsigned int channel) { set_voxel_iso(value, x,y,z, channel); } + _FORCE_INLINE_ void _set_voxel_iso_binding(real_t value, int x, int y, int z, unsigned int channel) { set_voxel_iso(value, x, y, z, channel); } private: struct Channel { // Allocated when the channel is populated. // Flat array, in order [z][x][y] because it allows faster vertical-wise access (the engine is Y-up). - uint8_t * data; + uint8_t *data; // Default value when data is null uint8_t defval; - Channel() : data(NULL), defval(0) {} + Channel() + : data(NULL), defval(0) {} }; // Each channel can store arbitary data. @@ -115,8 +114,6 @@ private: // How many voxels are there in the three directions. All populated channels have the same size. Vector3i _size; - }; #endif // VOXEL_BUFFER_H - diff --git a/voxel_library.cpp b/voxel_library.cpp index 0059a12..e0afb5b 100644 --- a/voxel_library.cpp +++ b/voxel_library.cpp @@ -1,6 +1,7 @@ #include "voxel_library.h" -VoxelLibrary::VoxelLibrary() : Reference(), _atlas_size(1) { +VoxelLibrary::VoxelLibrary() + : Reference(), _atlas_size(1) { // Defaults create_voxel(0, "air")->set_transparent(true); create_voxel(1, "solid")->set_transparent(false)->set_cube_geometry(); @@ -40,6 +41,4 @@ void VoxelLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("get_voxel", "id"), &VoxelLibrary::_get_voxel_bind); ClassDB::bind_method(D_METHOD("set_atlas_size", "square_size"), &VoxelLibrary::set_atlas_size); - } - diff --git a/voxel_library.h b/voxel_library.h index 2b200b4..6e61719 100644 --- a/voxel_library.h +++ b/voxel_library.h @@ -1,8 +1,8 @@ #ifndef VOXEL_LIBRARY_H #define VOXEL_LIBRARY_H -#include #include "voxel.h" +#include class VoxelLibrary : public Reference { GDCLASS(VoxelLibrary, Reference) @@ -22,7 +22,7 @@ public: // Internal getters _FORCE_INLINE_ bool has_voxel(int id) const { return _voxel_types[id].is_valid(); } - _FORCE_INLINE_ const Voxel & get_voxel_const(int id) const { return **_voxel_types[id]; } + _FORCE_INLINE_ const Voxel &get_voxel_const(int id) const { return **_voxel_types[id]; } protected: static void _bind_methods(); @@ -32,8 +32,6 @@ protected: private: Ref _voxel_types[MAX_VOXEL_TYPES]; int _atlas_size; - }; #endif // VOXEL_LIBRARY_H - diff --git a/voxel_map.cpp b/voxel_map.cpp index 872ab2e..f8809c2 100644 --- a/voxel_map.cpp +++ b/voxel_map.cpp @@ -5,22 +5,22 @@ // VoxelBlock //---------------------------------------------------------------------------- -MeshInstance * VoxelBlock::get_mesh_instance(const Node & root) { +MeshInstance *VoxelBlock::get_mesh_instance(const Node &root) { if (mesh_instance_path.is_empty()) return NULL; - Node * n = root.get_node(mesh_instance_path); + Node *n = root.get_node(mesh_instance_path); if (n == NULL) return NULL; return n->cast_to(); } // Helper -VoxelBlock * VoxelBlock::create(Vector3i bpos, Ref buffer) { +VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref buffer) { const int bs = VoxelBlock::SIZE; ERR_FAIL_COND_V(buffer.is_null(), NULL); ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL); - VoxelBlock * block = memnew(VoxelBlock); + VoxelBlock *block = memnew(VoxelBlock); block->pos = bpos; block->voxels = buffer; @@ -28,14 +28,16 @@ VoxelBlock * VoxelBlock::create(Vector3i bpos, Ref buffer) { return block; } -VoxelBlock::VoxelBlock(): voxels(NULL) { +VoxelBlock::VoxelBlock() + : voxels(NULL) { } //---------------------------------------------------------------------------- // VoxelMap //---------------------------------------------------------------------------- -VoxelMap::VoxelMap() : _last_accessed_block(NULL) { +VoxelMap::VoxelMap() + : _last_accessed_block(NULL) { for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) { _default_voxel[i] = 0; } @@ -47,7 +49,7 @@ VoxelMap::~VoxelMap() { int VoxelMap::get_voxel(Vector3i pos, unsigned int c) { Vector3i bpos = voxel_to_block(pos); - VoxelBlock * block = get_block(bpos); + VoxelBlock *block = get_block(bpos); if (block == NULL) { return _default_voxel[c]; } @@ -57,7 +59,7 @@ int VoxelMap::get_voxel(Vector3i pos, unsigned int c) { void VoxelMap::set_voxel(int value, Vector3i pos, unsigned int c) { Vector3i bpos = voxel_to_block(pos); - VoxelBlock * block = get_block(bpos); + VoxelBlock *block = get_block(bpos); if (block == NULL) { @@ -83,11 +85,11 @@ int VoxelMap::get_default_voxel(unsigned int channel) { return _default_voxel[channel]; } -VoxelBlock * VoxelMap::get_block(Vector3i bpos) { +VoxelBlock *VoxelMap::get_block(Vector3i bpos) { if (_last_accessed_block && _last_accessed_block->pos == bpos) { return _last_accessed_block; } - VoxelBlock ** p = _blocks.getptr(bpos); + VoxelBlock **p = _blocks.getptr(bpos); if (p) { _last_accessed_block = *p; return _last_accessed_block; @@ -95,7 +97,7 @@ VoxelBlock * VoxelMap::get_block(Vector3i bpos) { return NULL; } -void VoxelMap::set_block(Vector3i bpos, VoxelBlock * block) { +void VoxelMap::set_block(Vector3i bpos, VoxelBlock *block) { ERR_FAIL_COND(block == NULL); if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) { _last_accessed_block = block; @@ -105,12 +107,11 @@ void VoxelMap::set_block(Vector3i bpos, VoxelBlock * block) { void VoxelMap::set_block_buffer(Vector3i bpos, Ref buffer) { ERR_FAIL_COND(buffer.is_null()); - VoxelBlock * block = get_block(bpos); + VoxelBlock *block = get_block(bpos); if (block == NULL) { block = VoxelBlock::create(bpos, *buffer); set_block(bpos, block); - } - else { + } else { block->voxels = buffer; } } @@ -120,35 +121,35 @@ bool VoxelMap::has_block(Vector3i pos) const { } Vector3i g_moore_neighboring_3d[26] = { - 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, -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), + Vector3i(-1, 0, -1), + Vector3i(0, 0, -1), + Vector3i(1, 0, -1), + Vector3i(-1, 0, 0), //Vector3i(0,0,0), - Vector3i(1,0,0), - Vector3i(-1,0,1), - Vector3i(0,0,1), - Vector3i(1,0,1), + 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), + 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), }; bool VoxelMap::is_block_surrounded(Vector3i pos) const { @@ -161,17 +162,17 @@ bool VoxelMap::is_block_surrounded(Vector3i pos) const { return true; } -void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsigned int channels_mask) { +void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsigned int channels_mask) { Vector3i max_pos = min_pos + dst_buffer.get_size(); Vector3i min_block_pos = voxel_to_block(min_pos); - Vector3i max_block_pos = voxel_to_block(max_pos - Vector3i(1,1,1)) + Vector3i(1,1,1); + Vector3i max_block_pos = voxel_to_block(max_pos - Vector3i(1, 1, 1)) + Vector3i(1, 1, 1); ERR_FAIL_COND((max_block_pos - min_block_pos) != Vector3(3, 3, 3)); - for(unsigned int channel = 0; channel < VoxelBuffer::MAX_CHANNELS; ++channel) { + for (unsigned int channel = 0; channel < VoxelBuffer::MAX_CHANNELS; ++channel) { - if(((1 << channel) & channels_mask) == 0) { + if (((1 << channel) & channels_mask) == 0) { continue; } @@ -180,27 +181,23 @@ void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsig 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) { - VoxelBlock * block = get_block(bpos); + VoxelBlock *block = get_block(bpos); if (block) { - VoxelBuffer & src_buffer = **block->voxels; + VoxelBuffer &src_buffer = **block->voxels; 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); - } - else { + } else { Vector3i offset = block_to_voxel(bpos); dst_buffer.fill_area( - _default_voxel[channel], - offset - min_pos, - offset - min_pos + Vector3i(VoxelBlock::SIZE,VoxelBlock::SIZE, VoxelBlock::SIZE) - ); + _default_voxel[channel], + offset - min_pos, + offset - min_pos + Vector3i(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE)); } - } } } - } } @@ -209,11 +206,11 @@ void VoxelMap::remove_blocks_not_in_area(Vector3i min, Vector3i max) { Vector3i::sort_min_max(min, max); Vector to_remove; - const Vector3i * key = NULL; + const Vector3i *key = NULL; while (key = _blocks.next(key)) { - VoxelBlock * block_ref = _blocks.get(*key); + VoxelBlock *block_ref = _blocks.get(*key); ERR_FAIL_COND(block_ref == NULL); // Should never trigger if (block_ref->pos.is_contained_in(min, max)) { @@ -234,10 +231,10 @@ void VoxelMap::remove_blocks_not_in_area(Vector3i min, Vector3i max) { } void VoxelMap::clear() { - const Vector3i * key = NULL; + const Vector3i *key = NULL; while (key = _blocks.next(key)) { - VoxelBlock * block_ref = _blocks.get(*key); - if(block_ref == NULL) { + VoxelBlock *block_ref = _blocks.get(*key); + if (block_ref == NULL) { OS::get_singleton()->printerr("Unexpected NULL in VoxelMap::clear()"); } memdelete(block_ref); @@ -246,7 +243,6 @@ void VoxelMap::clear() { _last_accessed_block = NULL; } - void VoxelMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_voxel", "x", "y", "z", "c"), &VoxelMap::_get_voxel_binding, DEFVAL(0)); @@ -263,12 +259,9 @@ void VoxelMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_block_size"), &VoxelMap::get_block_size); //ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations"), _SCS("set_iterations"), _SCS("get_iterations")); - } - void VoxelMap::_get_buffer_copy_binding(Vector3 pos, Ref dst_buffer_ref, unsigned int channel) { ERR_FAIL_COND(dst_buffer_ref.is_null()); get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel); } - diff --git a/voxel_map.h b/voxel_map.h index 5433b93..2589df9 100644 --- a/voxel_map.h +++ b/voxel_map.h @@ -1,12 +1,11 @@ #ifndef VOXEL_MAP_H #define VOXEL_MAP_H -#include +#include "voxel_buffer.h" #include #include #include -#include "voxel_buffer.h" - +#include // Fixed-size voxel container used in VoxelMap. Used internally. class VoxelBlock { @@ -19,16 +18,14 @@ public: Vector3i pos; NodePath mesh_instance_path; - static VoxelBlock * create(Vector3i bpos, Ref buffer); + static VoxelBlock *create(Vector3i bpos, Ref buffer); - MeshInstance * get_mesh_instance(const Node & root); + MeshInstance *get_mesh_instance(const Node &root); private: VoxelBlock(); - }; - // Infinite voxel storage by means of octants like Gridmap class VoxelMap : public Reference { GDCLASS(VoxelMap, Reference) @@ -36,18 +33,16 @@ public: // Converts voxel coodinates into block coordinates static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) { return Vector3i( - pos.x >> VoxelBlock::SIZE_POW2, - pos.y >> VoxelBlock::SIZE_POW2, - pos.z >> VoxelBlock::SIZE_POW2 - ); + pos.x >> VoxelBlock::SIZE_POW2, + pos.y >> VoxelBlock::SIZE_POW2, + pos.z >> VoxelBlock::SIZE_POW2); } static _FORCE_INLINE_ Vector3i to_local(Vector3i pos) { return Vector3i( - pos.x & VoxelBlock::SIZE_MASK, - pos.y & VoxelBlock::SIZE_MASK, - pos.z & VoxelBlock::SIZE_MASK - ); + pos.x & VoxelBlock::SIZE_MASK, + pos.y & VoxelBlock::SIZE_MASK, + pos.z & VoxelBlock::SIZE_MASK); } // Converts block coodinates into voxel coordinates @@ -61,27 +56,26 @@ public: int get_voxel(Vector3i pos, unsigned int c = 0); void set_voxel(int value, Vector3i pos, unsigned int c = 0); - void set_default_voxel(int value, unsigned int channel=0); - int get_default_voxel(unsigned int channel=0); + void set_default_voxel(int value, unsigned int channel = 0); + int get_default_voxel(unsigned int channel = 0); // Gets a copy of all voxels in the area starting at min_pos having the same size as dst_buffer. - void get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsigned int channels_mask = 1); + void get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsigned int channels_mask = 1); // Moves the given buffer into a block of the map. The buffer is referenced, no copy is made. void set_block_buffer(Vector3i bpos, Ref buffer); void remove_blocks_not_in_area(Vector3i min, Vector3i max); - VoxelBlock * get_block(Vector3i bpos); + VoxelBlock *get_block(Vector3i bpos); bool has_block(Vector3i pos) const; bool is_block_surrounded(Vector3i pos) const; void clear(); - private: - void set_block(Vector3i bpos, VoxelBlock * block); + void set_block(Vector3i bpos, VoxelBlock *block); _FORCE_INLINE_ int get_block_size() const { return VoxelBlock::SIZE; } @@ -103,13 +97,11 @@ private: uint8_t _default_voxel[VoxelBuffer::MAX_CHANNELS]; // Blocks stored with a spatial hash in all 3D directions - HashMap _blocks; + HashMap _blocks; // Voxel access will most frequently be in contiguous areas, so the same blocks are accessed. // To prevent too much hashing, this reference is checked before. - VoxelBlock * _last_accessed_block; - + VoxelBlock *_last_accessed_block; }; #endif // VOXEL_MAP_H - diff --git a/voxel_mesher.cpp b/voxel_mesher.cpp index 49429e7..bf9e1c8 100644 --- a/voxel_mesher.cpp +++ b/voxel_mesher.cpp @@ -19,7 +19,7 @@ // / | / | // o----8----o | // | o---2-|---o -// 4 / 5 / +// 4 / 5 / // | 3 | 1 // |/ |/ // o----0----o @@ -31,44 +31,44 @@ static const unsigned int CORNER_COUNT = 8; static const unsigned int EDGE_COUNT = 12; static const Vector3 g_corner_position[CORNER_COUNT] = { - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 1, 0), - Vector3(1, 1, 1), - Vector3(0, 1, 1) + Vector3(0, 0, 0), + Vector3(1, 0, 0), + Vector3(1, 0, 1), + Vector3(0, 0, 1), + Vector3(0, 1, 0), + Vector3(1, 1, 0), + Vector3(1, 1, 1), + Vector3(0, 1, 1) }; static const unsigned int g_side_coord[Voxel::SIDE_COUNT] = { 0, 0, 1, 1, 2, 2 }; static const unsigned int g_side_sign[Voxel::SIDE_COUNT] = { 0, 1, 0, 1, 0, 1 }; static const Vector3i g_side_normals[Voxel::SIDE_COUNT] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, -1, 0), - Vector3i(0, 1, 0), - Vector3i(0, 0, -1), - Vector3i(0, 0, 1), + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, -1, 0), + Vector3i(0, 1, 0), + Vector3i(0, 0, -1), + Vector3i(0, 0, 1), }; static const unsigned int g_side_corners[Voxel::SIDE_COUNT][4] = { - { 0, 3, 7, 4 }, - { 1, 2, 6, 5 }, - { 0, 1, 2, 3 }, - { 4, 5, 6, 7 }, - { 0, 1, 5, 4 }, - { 3, 2, 6, 7 } + { 0, 3, 7, 4 }, + { 1, 2, 6, 5 }, + { 0, 1, 2, 3 }, + { 4, 5, 6, 7 }, + { 0, 1, 5, 4 }, + { 3, 2, 6, 7 } }; static const unsigned int g_side_edges[Voxel::SIDE_COUNT][4] = { - { 3, 7, 11, 4 }, - { 1, 6, 9, 5 }, - { 0, 1, 2, 3 }, - { 8, 9, 10, 11 }, - { 0, 5, 8, 4 }, - { 2, 6, 10, 7 } + { 3, 7, 11, 4 }, + { 1, 6, 9, 5 }, + { 0, 1, 2, 3 }, + { 8, 9, 10, 11 }, + { 0, 5, 8, 4 }, + { 2, 6, 10, 7 } }; // 3---2 @@ -84,54 +84,52 @@ static const unsigned int g_side_edges[Voxel::SIDE_COUNT][4] = { //}; static const Vector3i g_corner_inormals[CORNER_COUNT] = { - Vector3i(-1, -1, -1), - Vector3i(1, -1, -1), - Vector3i(1, -1, 1), - Vector3i(-1, -1, 1), + Vector3i(-1, -1, -1), + Vector3i(1, -1, -1), + Vector3i(1, -1, 1), + Vector3i(-1, -1, 1), - Vector3i(-1, 1, -1), - Vector3i(1, 1, -1), - Vector3i(1, 1, 1), - Vector3i(-1, 1, 1) + Vector3i(-1, 1, -1), + Vector3i(1, 1, -1), + Vector3i(1, 1, 1), + Vector3i(-1, 1, 1) }; static const Vector3i g_edge_inormals[EDGE_COUNT] = { - Vector3i(0, -1, -1), - Vector3i(1, -1, 0), - Vector3i(0, -1, 1), - Vector3i(-1, -1, 0), + Vector3i(0, -1, -1), + Vector3i(1, -1, 0), + Vector3i(0, -1, 1), + Vector3i(-1, -1, 0), - Vector3i(-1, 0, -1), - Vector3i(1, 0, -1), - Vector3i(1, 0, 1), - Vector3i(-1, 0, 1), + Vector3i(-1, 0, -1), + Vector3i(1, 0, -1), + Vector3i(1, 0, 1), + Vector3i(-1, 0, 1), - Vector3i(0, 1, -1), - Vector3i(1, 1, 0), - Vector3i(0, 1, 1), - Vector3i(-1, 1, 0) + Vector3i(0, 1, -1), + Vector3i(1, 1, 0), + Vector3i(0, 1, 1), + Vector3i(-1, 1, 0) }; static const unsigned int g_edge_corners[EDGE_COUNT][2] = { - { 0, 1 }, { 1, 2 }, { 2, 3 }, {3, 0}, - { 0, 4 }, { 1, 5 }, { 2, 6 }, {3, 7}, - { 4, 5 }, { 5, 6 }, { 6, 7 }, {7, 4} + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, + { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, + { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 } }; - -VoxelMesher::VoxelMesher(): - _baked_occlusion_darkness(0.75), - _bake_occlusion(true) -{} +VoxelMesher::VoxelMesher() + : _baked_occlusion_darkness(0.75), + _bake_occlusion(true) {} void VoxelMesher::set_library(Ref library) { - ERR_FAIL_COND(library.is_null()); - _library = library; + ERR_FAIL_COND(library.is_null()); + _library = library; } void VoxelMesher::set_material(Ref material, unsigned int id) { - ERR_FAIL_COND(id >= MAX_MATERIALS); - _materials[id] = material; + ERR_FAIL_COND(id >= MAX_MATERIALS); + _materials[id] = material; } Ref VoxelMesher::get_material(unsigned int id) const { @@ -140,224 +138,223 @@ Ref VoxelMesher::get_material(unsigned int id) const { } void VoxelMesher::set_occlusion_darkness(float darkness) { - _baked_occlusion_darkness = darkness; - if (_baked_occlusion_darkness < 0.0) - _baked_occlusion_darkness = 0.0; - else if (_baked_occlusion_darkness >= 1.0) - _baked_occlusion_darkness = 1.0; + _baked_occlusion_darkness = darkness; + if (_baked_occlusion_darkness < 0.0) + _baked_occlusion_darkness = 0.0; + else if (_baked_occlusion_darkness >= 1.0) + _baked_occlusion_darkness = 1.0; } void VoxelMesher::set_occlusion_enabled(bool enable) { - _bake_occlusion = enable; + _bake_occlusion = enable; } -inline Color Color_greyscale(float c) { return Color(c, c, c); } - -inline bool is_face_visible(const VoxelLibrary & lib, const Voxel & vt, int other_voxel_id) { - if (other_voxel_id == 0) // air - return true; - if (lib.has_voxel(other_voxel_id)) { - const Voxel & other_vt = lib.get_voxel_const(other_voxel_id); - return other_vt.is_transparent() && vt.get_id() != other_voxel_id; - } - return true; +inline Color Color_greyscale(float c) { + return Color(c, c, c); } -inline bool is_transparent(const VoxelLibrary & lib, int voxel_id) { - if (lib.has_voxel(voxel_id)) - return lib.get_voxel_const(voxel_id).is_transparent(); - return true; +inline bool is_face_visible(const VoxelLibrary &lib, const Voxel &vt, int other_voxel_id) { + if (other_voxel_id == 0) // air + return true; + if (lib.has_voxel(other_voxel_id)) { + const Voxel &other_vt = lib.get_voxel_const(other_voxel_id); + return other_vt.is_transparent() && vt.get_id() != other_voxel_id; + } + return true; +} + +inline bool is_transparent(const VoxelLibrary &lib, int voxel_id) { + if (lib.has_voxel(voxel_id)) + return lib.get_voxel_const(voxel_id).is_transparent(); + return true; } Ref VoxelMesher::build_ref(Ref buffer_ref, unsigned int channel, Ref mesh) { ERR_FAIL_COND_V(buffer_ref.is_null(), Ref()); - VoxelBuffer & buffer = **buffer_ref; + VoxelBuffer &buffer = **buffer_ref; mesh = build(buffer, channel, Vector3i(), buffer.get_size(), mesh); return mesh; } -Ref VoxelMesher::build(const VoxelBuffer & buffer, unsigned int channel, Vector3i min, Vector3i max, Ref mesh) { +Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max, Ref mesh) { ERR_FAIL_COND_V(_library.is_null(), Ref()); ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Ref()); - const VoxelLibrary & library = **_library; + const VoxelLibrary &library = **_library; - for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { - _surface_tool[i].begin(Mesh::PRIMITIVE_TRIANGLES); + for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { + _surface_tool[i].begin(Mesh::PRIMITIVE_TRIANGLES); _surface_tool[i].set_material(_materials[i]); } - float baked_occlusion_darkness; - if (_bake_occlusion) - baked_occlusion_darkness = _baked_occlusion_darkness / 3.0; + float baked_occlusion_darkness; + if (_bake_occlusion) + baked_occlusion_darkness = _baked_occlusion_darkness / 3.0; - // The technique is Culled faces. - // Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ - // However I don't feel it's worth it yet: - // - Not so much gain for organic worlds with lots of texture variations - // - Works well with cubes but not with any shape - // - Slower - // => Could be implemented in a separate class? + // The technique is Culled faces. + // Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ + // However I don't feel it's worth it yet: + // - Not so much gain for organic worlds with lots of texture variations + // - Works well with cubes but not with any shape + // - Slower + // => Could be implemented in a separate class? VOXEL_PROFILE_BEGIN("mesher_face_extraction") // Data must be padded, hence the off-by-one Vector3i::sort_min_max(min, max); - const Vector3i pad(1,1,1); + const Vector3i pad(1, 1, 1); min.clamp_to(pad, max); - max.clamp_to(min, buffer.get_size()-pad); + max.clamp_to(min, buffer.get_size() - pad); - // Iterate 3D padded data to extract voxel faces. - // This is the most intensive job in this class, so all required data should be as fit as possible. + // Iterate 3D padded data to extract voxel faces. + // This is the most intensive job in this class, so all required data should be as fit as possible. for (unsigned int z = min.z; z < max.z; ++z) { for (unsigned int x = min.x; x < max.x; ++x) { for (unsigned int y = min.y; y < max.y; ++y) { - int voxel_id = buffer.get_voxel(x, y, z, 0); + int voxel_id = buffer.get_voxel(x, y, z, 0); - if (voxel_id != 0 && library.has_voxel(voxel_id)) { + if (voxel_id != 0 && library.has_voxel(voxel_id)) { - const Voxel & voxel = library.get_voxel_const(voxel_id); + const Voxel &voxel = library.get_voxel_const(voxel_id); - SurfaceTool & st = _surface_tool[voxel.get_material_id()]; + SurfaceTool &st = _surface_tool[voxel.get_material_id()]; - // Hybrid approach: extract cube faces and decimate those that aren't visible, - // and still allow voxels to have geometry that is not a cube + // Hybrid approach: extract cube faces and decimate those that aren't visible, + // and still allow voxels to have geometry that is not a cube - // Sides - for (unsigned int side = 0; side < Voxel::SIDE_COUNT; ++side) { + // Sides + for (unsigned int side = 0; side < Voxel::SIDE_COUNT; ++side) { - const PoolVector & vertices = voxel.get_model_side_vertices(side); - if (vertices.size() != 0) { + const PoolVector &vertices = voxel.get_model_side_vertices(side); + if (vertices.size() != 0) { - Vector3i normal = g_side_normals[side]; - unsigned nx = x + normal.x; - unsigned ny = y + normal.y; - unsigned nz = z + normal.z; + Vector3i normal = g_side_normals[side]; + unsigned nx = x + normal.x; + unsigned ny = y + normal.y; + unsigned nz = z + normal.z; int neighbor_voxel_id = buffer.get_voxel(nx, ny, nz, channel); - // TODO Better face visibility test - if (is_face_visible(library, voxel, neighbor_voxel_id)) { + // TODO Better face visibility test + if (is_face_visible(library, voxel, neighbor_voxel_id)) { - // The face is visible + // The face is visible - int shaded_corner[8] = { 0 }; + int shaded_corner[8] = { 0 }; - if (_bake_occlusion) { + if (_bake_occlusion) { - // Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ + // Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ - for (unsigned int j = 0; j < 4; ++j) { - unsigned int edge = g_side_edges[side][j]; - Vector3i edge_normal = g_edge_inormals[edge]; - unsigned ex = x + edge_normal.x; - unsigned ey = y + edge_normal.y; - unsigned ez = z + edge_normal.z; - if (!is_transparent(library, buffer.get_voxel(ex, ey, ez))) { - shaded_corner[g_edge_corners[edge][0]] += 1; - shaded_corner[g_edge_corners[edge][1]] += 1; - } - } - for (unsigned int j = 0; j < 4; ++j) { - unsigned int corner = g_side_corners[side][j]; - if (shaded_corner[corner] == 2) { - shaded_corner[corner] = 3; - } - else { - Vector3i corner_normal = g_corner_inormals[corner]; - unsigned int cx = x + corner_normal.x; - unsigned int cy = y + corner_normal.y; - unsigned int cz = z + corner_normal.z; - if (!is_transparent(library, buffer.get_voxel(cx, cy, cz))) { - shaded_corner[corner] += 1; - } - } - } - } + for (unsigned int j = 0; j < 4; ++j) { + unsigned int edge = g_side_edges[side][j]; + Vector3i edge_normal = g_edge_inormals[edge]; + unsigned ex = x + edge_normal.x; + unsigned ey = y + edge_normal.y; + unsigned ez = z + edge_normal.z; + if (!is_transparent(library, buffer.get_voxel(ex, ey, ez))) { + shaded_corner[g_edge_corners[edge][0]] += 1; + shaded_corner[g_edge_corners[edge][1]] += 1; + } + } + for (unsigned int j = 0; j < 4; ++j) { + unsigned int corner = g_side_corners[side][j]; + if (shaded_corner[corner] == 2) { + shaded_corner[corner] = 3; + } else { + Vector3i corner_normal = g_corner_inormals[corner]; + unsigned int cx = x + corner_normal.x; + unsigned int cy = y + corner_normal.y; + unsigned int cz = z + corner_normal.z; + if (!is_transparent(library, buffer.get_voxel(cx, cy, cz))) { + shaded_corner[corner] += 1; + } + } + } + } PoolVector::Read rv = vertices.read(); PoolVector::Read rt = voxel.get_model_side_uv(side).read(); - Vector3 pos(x - 1, y - 1, z - 1); + Vector3 pos(x - 1, y - 1, z - 1); - for (unsigned int i = 0; i < vertices.size(); ++i) { - Vector3 v = rv[i]; + for (unsigned int i = 0; i < vertices.size(); ++i) { + Vector3 v = rv[i]; - if (_bake_occlusion) { - // General purpose occlusion colouring. - // TODO Optimize for cubes - // TODO Fix occlusion inconsistency caused by triangles orientation - float shade = 0; - for (unsigned int j = 0; j < 4; ++j) { - unsigned int corner = g_side_corners[side][j]; - if (shaded_corner[corner]) { - float s = baked_occlusion_darkness * static_cast(shaded_corner[corner]); - float k = 1.0 - g_corner_position[corner].distance_to(v); - if (k < 0.0) - k = 0.0; - s *= k; - if (s > shade) - shade = s; - } - } - float gs = 1.0 - shade; - st.add_color(Color(gs, gs, gs)); - } + if (_bake_occlusion) { + // General purpose occlusion colouring. + // TODO Optimize for cubes + // TODO Fix occlusion inconsistency caused by triangles orientation + float shade = 0; + for (unsigned int j = 0; j < 4; ++j) { + unsigned int corner = g_side_corners[side][j]; + if (shaded_corner[corner]) { + float s = baked_occlusion_darkness * static_cast(shaded_corner[corner]); + float k = 1.0 - g_corner_position[corner].distance_to(v); + if (k < 0.0) + k = 0.0; + s *= k; + if (s > shade) + shade = s; + } + } + float gs = 1.0 - shade; + st.add_color(Color(gs, gs, gs)); + } - st.add_normal(Vector3(normal.x, normal.y, normal.z)); - st.add_uv(rt[i]); - st.add_vertex(v + pos); - } - } - } - } + st.add_normal(Vector3(normal.x, normal.y, normal.z)); + st.add_uv(rt[i]); + st.add_vertex(v + pos); + } + } + } + } - // Inside - if (voxel.get_model_vertices().size() != 0) { + // Inside + if (voxel.get_model_vertices().size() != 0) { - const PoolVector & vertices = voxel.get_model_vertices(); + const PoolVector &vertices = voxel.get_model_vertices(); PoolVector::Read rv = voxel.get_model_vertices().read(); PoolVector::Read rn = voxel.get_model_normals().read(); PoolVector::Read rt = voxel.get_model_uv().read(); - Vector3 pos(x - 1, y - 1, z - 1); + Vector3 pos(x - 1, y - 1, z - 1); - for (unsigned int i = 0; i < vertices.size(); ++i) { - st.add_normal(rn[i]); - st.add_uv(rt[i]); - st.add_vertex(rv[i] + pos); - } - } - - } - - } - } - } + for (unsigned int i = 0; i < vertices.size(); ++i) { + st.add_normal(rn[i]); + st.add_uv(rt[i]); + st.add_vertex(rv[i] + pos); + } + } + } + } + } + } VOXEL_PROFILE_END("mesher_face_extraction") - // Commit mesh + // Commit mesh Ref mesh_ref = mesh; - if(mesh.is_null()) + if (mesh.is_null()) mesh_ref = Ref(memnew(ArrayMesh)); - for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { - if (_materials[i].is_valid()) { - SurfaceTool & st = _surface_tool[i]; - - // Index mesh to reduce memory usage and make upload to VRAM faster - // TODO actually, we could make it indexed from the ground up without using SurfaceTool, so we also save time! -// VOXEL_PROFILE_BEGIN("mesher_surfacetool_index") -// st.index(); -// VOXEL_PROFILE_END("mesher_surfacetool_index") + for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { + if (_materials[i].is_valid()) { + SurfaceTool &st = _surface_tool[i]; + + // Index mesh to reduce memory usage and make upload to VRAM faster + // TODO actually, we could make it indexed from the ground up without using SurfaceTool, so we also save time! + // VOXEL_PROFILE_BEGIN("mesher_surfacetool_index") + // st.index(); + // VOXEL_PROFILE_END("mesher_surfacetool_index") VOXEL_PROFILE_BEGIN("mesher_surfacetool_commit") mesh_ref = st.commit(mesh_ref); VOXEL_PROFILE_END("mesher_surfacetool_commit") st.clear(); - } - } + } + } return mesh_ref; } diff --git a/voxel_mesher.h b/voxel_mesher.h index a6e9776..c203223 100644 --- a/voxel_mesher.h +++ b/voxel_mesher.h @@ -1,14 +1,13 @@ #ifndef VOXEL_MESHER #define VOXEL_MESHER -#include -#include -#include #include "voxel.h" #include "voxel_buffer.h" #include "voxel_library.h" #include "zprofiling.h" - +#include +#include +#include // TODO Should be renamed VoxelMesherCubic or something like that class VoxelMesher : public Reference { @@ -31,8 +30,8 @@ public: void set_occlusion_enabled(bool enable); bool get_occlusion_enabled() const { return _bake_occlusion; } - Ref build(const VoxelBuffer & buffer_ref, unsigned int channel, Vector3i min, Vector3i max, Ref mesh=Ref()); - Ref build_ref(Ref buffer_ref, unsigned int channel, Ref mesh=Ref()); + Ref build(const VoxelBuffer &buffer_ref, unsigned int channel, Vector3i min, Vector3i max, Ref mesh = Ref()); + Ref build_ref(Ref buffer_ref, unsigned int channel, Ref mesh = Ref()); protected: static void _bind_methods(); @@ -50,5 +49,4 @@ private: #endif }; - #endif // VOXEL_MESHER diff --git a/voxel_mesher_smooth.cpp b/voxel_mesher_smooth.cpp index bac2837..2623f70 100644 --- a/voxel_mesher_smooth.cpp +++ b/voxel_mesher_smooth.cpp @@ -3,7 +3,6 @@ #include "transvoxel_tables.cpp" #include - inline float tof(int8_t v) { return static_cast(v) / 256.f; } @@ -42,27 +41,26 @@ const Vector3i g_corner_dirs[8] = { inline Vector3i dir_to_prev_vec(uint8_t dir) { //return g_corner_dirs[mask] - Vector3(1,1,1); return Vector3i( - -(dir & 1), - -((dir >> 1) & 1), - -((dir >> 2) & 1) - ); + -(dir & 1), + -((dir >> 1) & 1), + -((dir >> 2) & 1)); } -template -void copy_to(PoolVector & to, Vector & from) { +template +void copy_to(PoolVector &to, Vector &from) { to.resize(from.size()); PoolVector::Write w = to.write(); - for(unsigned int i = 0; i < from.size(); ++i) { + for (unsigned int i = 0; i < from.size(); ++i) { w[i] = from[i]; } } VoxelMesherSmooth::ReuseCell::ReuseCell() { case_index = 0; - for(unsigned int i = 0; i < 4; ++i) { + for (unsigned int i = 0; i < 4; ++i) { vertices[i] = -1; } } @@ -74,12 +72,12 @@ Ref VoxelMesherSmooth::build_ref(Ref voxels_ref, unsigne ERR_FAIL_COND_V(voxels_ref.is_null(), Ref()); - VoxelBuffer & voxels = **voxels_ref; + VoxelBuffer &voxels = **voxels_ref; return build(voxels, channel, mesh); } -Ref VoxelMesherSmooth::build(const VoxelBuffer & voxels, unsigned int channel, Ref mesh) { +Ref VoxelMesherSmooth::build(const VoxelBuffer &voxels, unsigned int channel, Ref mesh) { ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Ref()); @@ -93,12 +91,12 @@ Ref VoxelMesherSmooth::build(const VoxelBuffer & voxels, unsigned int m_output_indices.clear(); build_mesh(voxels, channel); -// OS::get_singleton()->print("vertices: %i, normals: %i, indices: %i\n", -// m_output_vertices.size(), -// m_output_normals.size(), -// m_output_indices.size()); + // OS::get_singleton()->print("vertices: %i, normals: %i, indices: %i\n", + // m_output_vertices.size(), + // m_output_normals.size(), + // m_output_indices.size()); - if(m_output_vertices.size() == 0) { + if (m_output_vertices.size() == 0) { // The mesh can be empty return Ref(); } @@ -114,12 +112,12 @@ Ref VoxelMesherSmooth::build(const VoxelBuffer & voxels, unsigned int Array arrays; arrays.resize(Mesh::ARRAY_MAX); arrays[Mesh::ARRAY_VERTEX] = vertices; - if(m_output_normals.size() != 0) { + if (m_output_normals.size() != 0) { arrays[Mesh::ARRAY_NORMAL] = normals; } arrays[Mesh::ARRAY_INDEX] = indices; - if(mesh.is_null()) + if (mesh.is_null()) mesh = Ref(memnew(ArrayMesh)); mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays); @@ -127,7 +125,7 @@ Ref VoxelMesherSmooth::build(const VoxelBuffer & voxels, unsigned int return mesh; } -void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int channel) { +void VoxelMesherSmooth::build_mesh(const VoxelBuffer &voxels, unsigned int channel) { // Each 2x2 voxel group is a "cell" @@ -139,8 +137,8 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan // Prepare vertex reuse cache m_block_size = block_size; unsigned int deck_area = block_size.x * block_size.y; - for(int i = 0; i < 2; ++i) { - if(m_cache[i].size() != deck_area) { + for (int i = 0; i < 2; ++i) { + if (m_cache[i].size() != deck_area) { m_cache[i].clear(); // Clear any previous data m_cache[i].resize(deck_area); } @@ -148,42 +146,41 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan // Iterate all cells with padding (expected to be neighbors) Vector3i pos; - for(pos.z = PAD.z; pos.z < block_size.z - 2; ++pos.z) { - for(pos.y = PAD.y; pos.y < block_size.y - 2; ++pos.y) { - for(pos.x = PAD.x; pos.x < block_size.x - 2; ++pos.x) { + for (pos.z = PAD.z; pos.z < block_size.z - 2; ++pos.z) { + for (pos.y = PAD.y; pos.y < block_size.y - 2; ++pos.y) { + for (pos.x = PAD.x; pos.x < block_size.x - 2; ++pos.x) { // Get the value of cells. // Negative values are "solid" and positive are "air". // Due to raw cells being unsigned 8-bit, they get converted to signed. int8_t cell_samples[8] = { - tos(voxels.get_voxel( pos.x, pos.y, pos.z, channel )), - tos(voxels.get_voxel( pos.x+1, pos.y, pos.z, channel )), - tos(voxels.get_voxel( pos.x, pos.y+1, pos.z, channel )), - tos(voxels.get_voxel( pos.x+1, pos.y+1, pos.z, channel )), - tos(voxels.get_voxel( pos.x, pos.y, pos.z+1, channel )), - tos(voxels.get_voxel( pos.x+1, pos.y, pos.z+1, channel )), - tos(voxels.get_voxel( pos.x, pos.y+1, pos.z+1, channel )), - tos(voxels.get_voxel( pos.x+1, pos.y+1, pos.z+1, channel )) + tos(voxels.get_voxel(pos.x, pos.y, pos.z, channel)), + tos(voxels.get_voxel(pos.x + 1, pos.y, pos.z, channel)), + tos(voxels.get_voxel(pos.x, pos.y + 1, pos.z, channel)), + tos(voxels.get_voxel(pos.x + 1, pos.y + 1, pos.z, channel)), + tos(voxels.get_voxel(pos.x, pos.y, pos.z + 1, channel)), + tos(voxels.get_voxel(pos.x + 1, pos.y, pos.z + 1, channel)), + tos(voxels.get_voxel(pos.x, pos.y + 1, pos.z + 1, channel)), + tos(voxels.get_voxel(pos.x + 1, pos.y + 1, pos.z + 1, channel)) }; // Concatenate the sign of cell values to obtain the case code. // Index 0 is the less significant bit, and index 7 is the most significant bit. - uint8_t case_code = - sign(cell_samples[0]) - | (sign(cell_samples[1]) << 1) - | (sign(cell_samples[2]) << 2) - | (sign(cell_samples[3]) << 3) - | (sign(cell_samples[4]) << 4) - | (sign(cell_samples[5]) << 5) - | (sign(cell_samples[6]) << 6) - | (sign(cell_samples[7]) << 7); + uint8_t case_code = sign(cell_samples[0]); + case_code |= (sign(cell_samples[1]) << 1); + case_code |= (sign(cell_samples[2]) << 2); + case_code |= (sign(cell_samples[3]) << 3); + case_code |= (sign(cell_samples[4]) << 4); + case_code |= (sign(cell_samples[5]) << 5); + case_code |= (sign(cell_samples[6]) << 6); + case_code |= (sign(cell_samples[7]) << 7); { - ReuseCell & rc = get_reuse_cell(pos); + ReuseCell &rc = get_reuse_cell(pos); rc.case_index = case_code; } - if(case_code == 0 || case_code == 255) { + if (case_code == 0 || case_code == 255) { // If the case_code is 0 or 255, there is no triangulation to do continue; } @@ -191,18 +188,13 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan // TODO We might not always need all of them // Compute normals Vector3 corner_normals[8]; - for(unsigned int i = 0; i < 8; ++i) { + for (unsigned int i = 0; i < 8; ++i) { Vector3i p = pos + g_corner_dirs[i]; - float nx = tof(tos(voxels.get_voxel(p - Vector3i(1,0,0), channel))) - - tof(tos(voxels.get_voxel(p + Vector3i(1,0,0), channel))); - - float ny = tof(tos(voxels.get_voxel(p - Vector3i(0,1,0), channel))) - - tof(tos(voxels.get_voxel(p + Vector3i(0,1,0), channel))); - - float nz = tof(tos(voxels.get_voxel(p - Vector3i(0,0,1), channel))) - - tof(tos(voxels.get_voxel(p + Vector3i(0,0,1), channel))); + float nx = tof(tos(voxels.get_voxel(p - Vector3i(1, 0, 0), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(1, 0, 0), channel))); + float ny = tof(tos(voxels.get_voxel(p - Vector3i(0, 1, 0), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(0, 1, 0), channel))); + float nz = tof(tos(voxels.get_voxel(p - Vector3i(0, 0, 1), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(0, 0, 1), channel))); corner_normals[i] = Vector3(nx, ny, nz); corner_normals[i].normalize(); @@ -214,9 +206,7 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan // While iterating through the cells in a block, a 3-bit mask is maintained whose bits indicate // whether corresponding bits in a direction code are valid uint8_t direction_validity_mask = - (pos.x > 1 ? 1 : 0) - | ((pos.y > 1 ? 1 : 0) << 1) - | ((pos.z > 1 ? 1 : 0) << 2); + (pos.x > 1 ? 1 : 0) | ((pos.y > 1 ? 1 : 0) << 1) | ((pos.z > 1 ? 1 : 0) << 2); uint8_t regular_cell_class_index = Transvoxel::regularCellClass[case_code]; Transvoxel::RegularCellData regular_cell_class = Transvoxel::regularCellData[regular_cell_class_index]; @@ -226,7 +216,7 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan int cell_mesh_indices[12]; // For each vertex in the case - for(unsigned int i = 0; i < vertex_count; ++i) { + for (unsigned int i = 0; i < vertex_count; ++i) { // The case index maps to a list of 16-bit codes providing information about the edges on which the vertices lie. // The low byte of each 16-bit code contains the corner indexes of the edge’s endpoints in one nibble each, @@ -260,7 +250,7 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan Vector3i p0 = pos + g_corner_dirs[v0]; Vector3i p1 = pos + g_corner_dirs[v1]; - if(t & 0xff) { + if (t & 0xff) { //OS::get_singleton()->print("A"); // Vertex lies in the interior of the edge. @@ -275,11 +265,11 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan bool can_reuse = (reuse_dir & direction_validity_mask) == reuse_dir; - if(can_reuse) { + if (can_reuse) { Vector3i cache_pos = pos + dir_to_prev_vec(reuse_dir); - ReuseCell & prev_cell = get_reuse_cell(cache_pos); + ReuseCell &prev_cell = get_reuse_cell(cache_pos); - if(prev_cell.case_index == 0 || prev_cell.case_index == 255) { + if (prev_cell.case_index == 0 || prev_cell.case_index == 255) { // TODO I don't think this can happen for non-corner vertices. cell_mesh_indices[i] = -1; } else { @@ -288,26 +278,26 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan } } - if(!can_reuse || cell_mesh_indices[i] == -1) { + if (!can_reuse || cell_mesh_indices[i] == -1) { // Going to create a new vertice cell_mesh_indices[i] = m_output_vertices.size(); Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1; - Vector3 primary = pi;//pos.to_vec3() + pi; + Vector3 primary = pi; //pos.to_vec3() + pi; Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1; emit_vertex(primary, normal); if (reuse_dir & 8) { // Store the generated vertex so that other cells can reuse it. - ReuseCell & rc = get_reuse_cell(pos); + ReuseCell &rc = get_reuse_cell(pos); rc.vertices[reuse_vertex_index] = cell_mesh_indices[i]; } } - } else if(t == 0 && v1 == 7) { + } else if (t == 0 && v1 == 7) { //OS::get_singleton()->print("B"); // This cell owns the vertex, so it should be created. @@ -315,12 +305,12 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan cell_mesh_indices[i] = m_output_vertices.size(); Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1; - Vector3 primary = pi;//pos.to_vec3() + pi; + Vector3 primary = pi; //pos.to_vec3() + pi; Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1; emit_vertex(primary, normal); - ReuseCell & rc = get_reuse_cell(pos); + ReuseCell &rc = get_reuse_cell(pos); rc.vertices[0] = cell_mesh_indices[i]; } else { @@ -335,7 +325,7 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan bool can_reuse = (reuse_dir & direction_validity_mask) == reuse_dir; // Note: the only difference with similar code above is that we take vertice 0 in the `else` - if(can_reuse) { + if (can_reuse) { Vector3i cache_pos = pos + dir_to_prev_vec(reuse_dir); ReuseCell prev_cell = get_reuse_cell(cache_pos); @@ -348,11 +338,11 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan } } - if(!can_reuse || cell_mesh_indices[i] < 0) { + if (!can_reuse || cell_mesh_indices[i] < 0) { cell_mesh_indices[i] = m_output_vertices.size(); Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1; - Vector3 primary = pi;//pos.to_vec3() + pi; + Vector3 primary = pi; //pos.to_vec3() + pi; Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1; emit_vertex(primary, normal); @@ -377,23 +367,18 @@ void VoxelMesherSmooth::build_mesh(const VoxelBuffer & voxels, unsigned int chan //OS::get_singleton()->print("\n"); } - -VoxelMesherSmooth::ReuseCell & VoxelMesherSmooth::get_reuse_cell(Vector3i pos) { +VoxelMesherSmooth::ReuseCell &VoxelMesherSmooth::get_reuse_cell(Vector3i pos) { int j = pos.z & 1; int i = pos.y * m_block_size.y + pos.x; return m_cache[j][i]; } - void VoxelMesherSmooth::emit_vertex(Vector3 primary, Vector3 normal) { m_output_vertices.push_back(primary - PAD.to_vec3()); m_output_normals.push_back(normal); } - void VoxelMesherSmooth::_bind_methods() { ClassDB::bind_method(D_METHOD("build", "voxels", "channel", "existing_mesh"), &VoxelMesherSmooth::build_ref, DEFVAL(Variant())); - } - diff --git a/voxel_mesher_smooth.h b/voxel_mesher_smooth.h index a0d3c02..f51d076 100644 --- a/voxel_mesher_smooth.h +++ b/voxel_mesher_smooth.h @@ -10,8 +10,8 @@ class VoxelMesherSmooth : public Reference { public: VoxelMesherSmooth(); - Ref build_ref(Ref voxels_ref, unsigned int channel, Ref mesh=Ref()); - Ref build(const VoxelBuffer & voxels, unsigned int channel, Ref mesh=Ref()); + Ref build_ref(Ref voxels_ref, unsigned int channel, Ref mesh = Ref()); + Ref build(const VoxelBuffer &voxels, unsigned int channel, Ref mesh = Ref()); protected: static void _bind_methods(); @@ -23,12 +23,12 @@ private: ReuseCell(); }; - void build_mesh(const VoxelBuffer & voxels, unsigned int channel); - ReuseCell & get_reuse_cell(Vector3i pos); + void build_mesh(const VoxelBuffer &voxels, unsigned int channel); + ReuseCell &get_reuse_cell(Vector3i pos); void emit_vertex(Vector3 primary, Vector3 normal); private: - const Vector3i PAD = Vector3i(1,1,1); + const Vector3i PAD = Vector3i(1, 1, 1); Vector m_cache[2]; Vector3i m_block_size; diff --git a/voxel_provider.cpp b/voxel_provider.cpp index 5385e88..9ede5e6 100644 --- a/voxel_provider.cpp +++ b/voxel_provider.cpp @@ -1,15 +1,14 @@ #include "voxel_provider.h" #include "voxel_map.h" - void VoxelProvider::emerge_block(Ref out_buffer, Vector3i block_pos) { ERR_FAIL_COND(out_buffer.is_null()); - ScriptInstance * script = get_script_instance(); - if(script) { + ScriptInstance *script = get_script_instance(); + if (script) { // Call script to generate buffer Variant arg1 = out_buffer; Variant arg2 = block_pos.to_vec3(); - const Variant * args[2] = { &arg1, &arg2 }; + const Variant *args[2] = { &arg1, &arg2 }; //Variant::CallError err; // wut script->call_multilevel("emerge_block", args, 2); } @@ -17,12 +16,12 @@ void VoxelProvider::emerge_block(Ref out_buffer, Vector3i block_pos void VoxelProvider::immerge_block(Ref buffer, Vector3i block_pos) { ERR_FAIL_COND(buffer.is_null()); - ScriptInstance * script = get_script_instance(); - if(script) { + ScriptInstance *script = get_script_instance(); + if (script) { // Call script to save buffer Variant arg1 = buffer; Variant arg2 = block_pos.to_vec3(); - const Variant * args[2] = { &arg1, &arg2 }; + const Variant *args[2] = { &arg1, &arg2 }; //Variant::CallError err; // wut script->call_multilevel("immerge_block", args, 2); } @@ -40,7 +39,4 @@ void VoxelProvider::_bind_methods() { ClassDB::bind_method(D_METHOD("emerge_block", "out_buffer", "block_pos"), &VoxelProvider::_emerge_block); ClassDB::bind_method(D_METHOD("immerge_block", "buffer", "block_pos"), &VoxelProvider::_immerge_block); - } - - diff --git a/voxel_provider.h b/voxel_provider.h index 40af381..9385061 100644 --- a/voxel_provider.h +++ b/voxel_provider.h @@ -4,7 +4,6 @@ #include "reference.h" #include "voxel_buffer.h" - class VoxelProvider : public Reference { GDCLASS(VoxelProvider, Reference) public: @@ -18,5 +17,4 @@ protected: void _immerge_block(Ref buffer, Vector3 block_pos); }; - #endif // VOXEL_PROVIDER_H diff --git a/voxel_provider_test.cpp b/voxel_provider_test.cpp index a19787b..121ddbf 100644 --- a/voxel_provider_test.cpp +++ b/voxel_provider_test.cpp @@ -3,7 +3,6 @@ VARIANT_ENUM_CAST(VoxelProviderTest::Mode) - VoxelProviderTest::VoxelProviderTest() { _mode = MODE_FLAT; _voxel_type = 1; @@ -34,57 +33,57 @@ void VoxelProviderTest::set_pattern_offset(Vector3i offset) { void VoxelProviderTest::emerge_block(Ref out_buffer, Vector3i block_pos) { ERR_FAIL_COND(out_buffer.is_null()); - switch(_mode) { + switch (_mode) { - case MODE_FLAT: - generate_block_flat(**out_buffer, block_pos); - break; + case MODE_FLAT: + generate_block_flat(**out_buffer, block_pos); + break; - case MODE_WAVES: - generate_block_waves(**out_buffer, block_pos); - break; + case MODE_WAVES: + generate_block_waves(**out_buffer, block_pos); + break; } } -void VoxelProviderTest::generate_block_flat(VoxelBuffer & out_buffer, Vector3i block_pos) { +void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i block_pos) { // TODO Don't expect a block pos, but a voxel pos! Vector3i size = out_buffer.get_size(); Vector3i origin = VoxelMap::block_to_voxel(block_pos); int rh = _pattern_offset.y - origin.y; - if(rh > size.y) + if (rh > size.y) rh = size.y; - for(int rz = 0; rz < size.z; ++rz) { - for(int rx = 0; rx < size.x; ++rx) { - for(int ry = 0; ry < rh; ++ry) { + for (int rz = 0; rz < size.z; ++rz) { + for (int rx = 0; rx < size.x; ++rx) { + for (int ry = 0; ry < rh; ++ry) { out_buffer.set_voxel(_voxel_type, rx, ry, rz, 0); } } } } -void VoxelProviderTest::generate_block_waves(VoxelBuffer & out_buffer, Vector3i block_pos) { +void VoxelProviderTest::generate_block_waves(VoxelBuffer &out_buffer, Vector3i block_pos) { Vector3i size = out_buffer.get_size(); Vector3i origin = VoxelMap::block_to_voxel(block_pos) + _pattern_offset; float amplitude = static_cast(_pattern_size.y); - float period_x = 1.f/static_cast(_pattern_size.x); - float period_z = 1.f/static_cast(_pattern_size.z); + float period_x = 1.f / static_cast(_pattern_size.x); + float period_z = 1.f / static_cast(_pattern_size.z); - for(int rz = 0; rz < size.z; ++rz) { - for(int rx = 0; rx < size.x; ++rx) { + for (int rz = 0; rz < size.z; ++rz) { + for (int rx = 0; rx < size.x; ++rx) { float x = origin.x + rx; float z = origin.z + rz; - int h = _pattern_offset.y + amplitude * (Math::cos(x*period_x) + Math::sin(z*period_z)); + int h = _pattern_offset.y + amplitude * (Math::cos(x * period_x) + Math::sin(z * period_z)); int rh = h - origin.y; - if(rh > size.y) + if (rh > size.y) rh = size.y; - for(int ry = 0; ry < rh; ++ry) { + for (int ry = 0; ry < rh; ++ry) { out_buffer.set_voxel(_voxel_type, rx, ry, rz, 0); } } @@ -108,4 +107,3 @@ void VoxelProviderTest::_bind_methods() { BIND_CONSTANT(MODE_FLAT); BIND_CONSTANT(MODE_WAVES); } - diff --git a/voxel_provider_test.h b/voxel_provider_test.h index 964e39f..9a2487d 100644 --- a/voxel_provider_test.h +++ b/voxel_provider_test.h @@ -3,7 +3,6 @@ #include "voxel_provider.h" - class VoxelProviderTest : public VoxelProvider { GDCLASS(VoxelProviderTest, VoxelProvider) @@ -30,8 +29,8 @@ public: void set_pattern_offset(Vector3i offset); protected: - void generate_block_flat(VoxelBuffer & out_buffer, Vector3i block_pos); - void generate_block_waves(VoxelBuffer & out_buffer, Vector3i block_pos); + void generate_block_flat(VoxelBuffer &out_buffer, Vector3i block_pos); + void generate_block_waves(VoxelBuffer &out_buffer, Vector3i block_pos); static void _bind_methods(); @@ -48,6 +47,4 @@ private: Vector3i _pattern_size; }; - #endif // VOXEL_PROVIDER_TEST_H - diff --git a/voxel_raycast.cpp b/voxel_raycast.cpp index a9734fb..c95f112 100644 --- a/voxel_raycast.cpp +++ b/voxel_raycast.cpp @@ -4,14 +4,13 @@ const float g_infinite = 9999999; bool voxel_raycast( - Vector3 ray_origin, - Vector3 ray_direction, - VoxelPredicate predicate, - void * predicate_context, - real_t max_distance, - Vector3i & out_hit_pos, - Vector3i & out_prev_pos -){ + Vector3 ray_origin, + Vector3 ray_direction, + VoxelPredicate predicate, + void *predicate_context, + real_t max_distance, + Vector3i &out_hit_pos, + Vector3i &out_prev_pos) { // Equation : p + v*t // p : ray start position (ray.pos) // v : ray orientation vector (ray.dir) @@ -29,10 +28,9 @@ bool voxel_raycast( // Voxel position Vector3i hit_pos( - Math::floor(ray_origin.x), - Math::floor(ray_origin.y), - Math::floor(ray_origin.z) - ); + Math::floor(ray_origin.x), + Math::floor(ray_origin.y), + Math::floor(ray_origin.z)); Vector3i hit_prev_pos = hit_pos; // Voxel step @@ -51,91 +49,74 @@ bool voxel_raycast( real_t tcross_z; // At which value of T we will cross a depth line? // X initialization - if(xi_step != 0) - { - if(xi_step == 1) + if (xi_step != 0) { + if (xi_step == 1) tcross_x = (Math::ceil(ray_origin.x) - ray_origin.x) * tdelta_x; else tcross_x = (ray_origin.x - Math::floor(ray_origin.x)) * tdelta_x; - } - else + } else tcross_x = g_infinite; // Will never cross on X // Y initialization - if(yi_step != 0) - { - if(yi_step == 1) + if (yi_step != 0) { + if (yi_step == 1) tcross_y = (Math::ceil(ray_origin.y) - ray_origin.y) * tdelta_y; else tcross_y = (ray_origin.y - Math::floor(ray_origin.y)) * tdelta_y; - } - else + } else tcross_y = g_infinite; // Will never cross on X // Z initialization - if(zi_step != 0) - { - if(zi_step == 1) + if (zi_step != 0) { + if (zi_step == 1) tcross_z = (Math::ceil(ray_origin.z) - ray_origin.z) * tdelta_z; else tcross_z = (ray_origin.z - Math::floor(ray_origin.z)) * tdelta_z; - } - else + } else tcross_z = g_infinite; // Will never cross on X /* Iteration */ - do - { + do { hit_prev_pos = hit_pos; - if(tcross_x < tcross_y) - { - if(tcross_x < tcross_z) - { + if (tcross_x < tcross_y) { + if (tcross_x < tcross_z) { // X collision //hit.prevPos.x = hit.pos.x; hit_pos.x += xi_step; - if(tcross_x > max_distance) + if (tcross_x > max_distance) return false; tcross_x += tdelta_x; - } - else - { + } else { // Z collision (duplicate code) //hit.prevPos.z = hit.pos.z; hit_pos.z += zi_step; - if(tcross_z > max_distance) + if (tcross_z > max_distance) return false; tcross_z += tdelta_z; } - } - else - { - if(tcross_y < tcross_z) - { + } else { + if (tcross_y < tcross_z) { // Y collision //hit.prevPos.y = hit.pos.y; hit_pos.y += yi_step; - if(tcross_y > max_distance) + if (tcross_y > max_distance) return false; tcross_y += tdelta_y; - } - else - { + } else { // Z collision (duplicate code) //hit.prevPos.z = hit.pos.z; hit_pos.z += zi_step; - if(tcross_z > max_distance) + if (tcross_z > max_distance) return false; tcross_z += tdelta_z; } } - } while(!predicate(hit_pos, predicate_context)); + } while (!predicate(hit_pos, predicate_context)); out_hit_pos = hit_pos; out_prev_pos = hit_prev_pos; return true; } - diff --git a/voxel_raycast.h b/voxel_raycast.h index 5eb7e05..1370cae 100644 --- a/voxel_raycast.h +++ b/voxel_raycast.h @@ -1,18 +1,16 @@ -#include #include "vector3i.h" +#include -// TODO Having a C++11 lambda would be nice... +// TODO that could be a template function // pos: voxel position // context: arguments to carry (as a lamdbda capture) -typedef bool(*VoxelPredicate)(Vector3i pos, void * context); +typedef bool (*VoxelPredicate)(Vector3i pos, void *context); bool voxel_raycast( - Vector3 ray_origin, - Vector3 ray_direction, - VoxelPredicate predicate, - void * predicate_context, // Handle that one with care - real_t max_distance, - Vector3i & out_hit_pos, - Vector3i & out_prev_pos -); - + Vector3 ray_origin, + Vector3 ray_direction, + VoxelPredicate predicate, + void *predicate_context, // Handle that one with care + real_t max_distance, + Vector3i &out_hit_pos, + Vector3i &out_prev_pos); diff --git a/voxel_terrain.cpp b/voxel_terrain.cpp index c927af6..d1ef2d4 100644 --- a/voxel_terrain.cpp +++ b/voxel_terrain.cpp @@ -1,9 +1,10 @@ #include "voxel_terrain.h" -#include -#include #include "voxel_raycast.h" +#include +#include -VoxelTerrain::VoxelTerrain(): Node(), _generate_collisions(true) { +VoxelTerrain::VoxelTerrain() + : Node(), _generate_collisions(true) { _map = Ref(memnew(VoxelMap)); _mesher = Ref(memnew(VoxelMesher)); @@ -14,7 +15,7 @@ Vector3i g_viewer_block_pos; // TODO UGLY! Lambdas or pointers needed... // Sorts distance to viewer struct BlockUpdateComparator { - inline bool operator()(const Vector3i & a, const Vector3i & b) const { + inline bool operator()(const Vector3i &a, const Vector3i &b) const { return a.distance_sq(g_viewer_block_pos) > b.distance_sq(g_viewer_block_pos); } }; @@ -36,7 +37,7 @@ void VoxelTerrain::set_generate_collisions(bool enabled) { } void VoxelTerrain::set_viewer_path(NodePath path) { - if(!path.is_empty()) + if (!path.is_empty()) ERR_FAIL_COND(get_viewer(path) == NULL); _viewer_path = path; } @@ -45,11 +46,11 @@ NodePath VoxelTerrain::get_viewer_path() { return _viewer_path; } -Spatial * VoxelTerrain::get_viewer(NodePath path) { - if(path.is_empty()) +Spatial *VoxelTerrain::get_viewer(NodePath path) { + if (path.is_empty()) return NULL; - Node * node = get_node(path); - if(node == NULL) + Node *node = get_node(path); + if (node == NULL) return NULL; return node->cast_to(); } @@ -61,7 +62,7 @@ Spatial * VoxelTerrain::get_viewer(NodePath path) { void VoxelTerrain::make_block_dirty(Vector3i bpos) { // TODO Immediate update viewer distance - if(is_block_dirty(bpos) == false) { + if (is_block_dirty(bpos) == false) { //OS::get_singleton()->print("Dirty (%i, %i, %i)", bpos.x, bpos.y, bpos.z); _block_update_queue.push_back(bpos); _dirty_blocks[bpos] = true; @@ -75,9 +76,9 @@ bool VoxelTerrain::is_block_dirty(Vector3i bpos) { void VoxelTerrain::make_blocks_dirty(Vector3i min, Vector3i size) { Vector3i max = min + size; Vector3i pos; - for(pos.z = min.z; pos.z < max.z; ++pos.z) { - for(pos.y = min.y; pos.y < max.y; ++pos.y) { - for(pos.x = min.x; pos.x < max.x; ++pos.x) { + for (pos.z = min.z; pos.z < max.z; ++pos.z) { + for (pos.y = min.y; pos.y < max.y; ++pos.y) { + for (pos.x = min.x; pos.x < max.x; ++pos.x) { make_block_dirty(pos); } } @@ -101,28 +102,25 @@ void VoxelTerrain::make_voxel_dirty(Vector3i pos) { bool check_corners = _mesher->get_occlusion_enabled(); - const int max = VoxelBlock::SIZE-1; + const int max = VoxelBlock::SIZE - 1; - if(rpos.x == 0) - make_block_dirty(bpos - Vector3i(1,0,0)); - else - if(rpos.x == max) - make_block_dirty(bpos + Vector3i(1,0,0)); + if (rpos.x == 0) + make_block_dirty(bpos - Vector3i(1, 0, 0)); + else if (rpos.x == max) + make_block_dirty(bpos + Vector3i(1, 0, 0)); - if(rpos.y == 0) - make_block_dirty(bpos - Vector3i(0,1,0)); - else - if(rpos.y == max) - make_block_dirty(bpos + Vector3i(0,1,0)); + if (rpos.y == 0) + make_block_dirty(bpos - Vector3i(0, 1, 0)); + else if (rpos.y == max) + make_block_dirty(bpos + Vector3i(0, 1, 0)); - if(rpos.z == 0) - make_block_dirty(bpos - Vector3i(0,0,1)); - else - if(rpos.z == max) - make_block_dirty(bpos + Vector3i(0,0,1)); + if (rpos.z == 0) + make_block_dirty(bpos - Vector3i(0, 0, 1)); + else if (rpos.z == max) + make_block_dirty(bpos + Vector3i(0, 0, 1)); // We might want to update blocks in corners in order to update ambient occlusion - if(check_corners) { + if (check_corners) { // 24------25------26 // /| /| @@ -143,17 +141,17 @@ void VoxelTerrain::make_voxel_dirty(Vector3i pos) { // I'm not good at writing piles of ifs static const int normals[27][3] = { - {-1,-1,-1}, { 0,-1,-1}, { 1,-1,-1}, - {-1,-1, 0}, { 0,-1, 0}, { 1,-1, 0}, - {-1,-1, 1}, { 0,-1, 1}, { 1,-1, 1}, + { -1, -1, -1 }, { 0, -1, -1 }, { 1, -1, -1 }, + { -1, -1, 0 }, { 0, -1, 0 }, { 1, -1, 0 }, + { -1, -1, 1 }, { 0, -1, 1 }, { 1, -1, 1 }, - {-1, 0,-1}, { 0, 0,-1}, { 1, 0,-1}, - {-1, 0, 0}, { 0, 0, 0}, { 1, 0, 0}, - {-1, 0, 1}, { 0, 0, 1}, { 1, 0, 1}, + { -1, 0, -1 }, { 0, 0, -1 }, { 1, 0, -1 }, + { -1, 0, 0 }, { 0, 0, 0 }, { 1, 0, 0 }, + { -1, 0, 1 }, { 0, 0, 1 }, { 1, 0, 1 }, - {-1, 1,-1}, { 0, 1,-1}, { 1, 1,-1}, - {-1, 1, 0}, { 0, 1, 0}, { 1, 1, 0}, - {-1, 1, 1}, { 0, 1, 1}, { 1, 1, 1} + { -1, 1, -1 }, { 0, 1, -1 }, { 1, 1, -1 }, + { -1, 1, 0 }, { 0, 1, 0 }, { 1, 1, 0 }, + { -1, 1, 1 }, { 0, 1, 1 }, { 1, 1, 1 } }; static const int ce_counts[27] = { 4, 1, 4, @@ -169,32 +167,30 @@ void VoxelTerrain::make_voxel_dirty(Vector3i pos) { 4, 1, 4 }; static const int ce_indexes_lut[27][4] = { - {0, 1, 3, 9}, {1}, {2, 1, 5, 11}, - {3}, {}, {5}, - {6, 3, 7, 15}, {7}, {8, 7, 5, 17}, + { 0, 1, 3, 9 }, { 1 }, { 2, 1, 5, 11 }, + { 3 }, {}, { 5 }, + { 6, 3, 7, 15 }, { 7 }, { 8, 7, 5, 17 }, - {9}, {}, {11}, + { 9 }, {}, { 11 }, {}, {}, {}, - {15}, {}, {17}, + { 15 }, {}, { 17 }, - {18, 9, 19, 21}, {19}, {20, 11, 19, 23}, - {21}, {}, {23}, - {24, 15, 21, 25}, {25}, {26, 17, 23, 25} + { 18, 9, 19, 21 }, { 19 }, { 20, 11, 19, 23 }, + { 21 }, {}, { 23 }, + { 24, 15, 21, 25 }, { 25 }, { 26, 17, 23, 25 } }; - int m = get_border_index(rpos.x, max) - + 3*get_border_index(rpos.z, max) - + 9*get_border_index(rpos.y, max); + int m = get_border_index(rpos.x, max) + 3 * get_border_index(rpos.z, max) + 9 * get_border_index(rpos.y, max); - const int * ce_indexes = ce_indexes_lut[m]; + const int *ce_indexes = ce_indexes_lut[m]; int ce_count = ce_counts[m]; //OS::get_singleton()->print("m=%i, rpos=(%i, %i, %i)\n", m, rpos.x, rpos.y, rpos.z); - for(int i = 0; i < ce_count; ++i) { + for (int i = 0; i < ce_count; ++i) { // TODO Because it's about ambient occlusion across 1 voxel only, // we could optimize it even more by looking at neighbor voxels, // and discard the update if we know it won't change anything - const int * normal = normals[ce_indexes[i]]; + const int *normal = normals[ce_indexes[i]]; Vector3i nbpos(bpos.x + normal[0], bpos.y + normal[1], bpos.z + normal[2]); //OS::get_singleton()->print("Corner dirty (%i, %i, %i)\n", nbpos.x, nbpos.y, nbpos.z); make_block_dirty(nbpos); @@ -210,19 +206,19 @@ void VoxelTerrain::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: - set_process(true); - break; + case NOTIFICATION_ENTER_TREE: + set_process(true); + break; - case NOTIFICATION_PROCESS: - _process(); - break; + case NOTIFICATION_PROCESS: + _process(); + break; - case NOTIFICATION_EXIT_TREE: - break; + case NOTIFICATION_EXIT_TREE: + break; - default: - break; + default: + break; } } @@ -231,11 +227,11 @@ void VoxelTerrain::_process() { } void VoxelTerrain::update_blocks() { - OS & os = *OS::get_singleton(); + OS &os = *OS::get_singleton(); // Get viewer location - Spatial * viewer = get_viewer(_viewer_path); - if(viewer) + Spatial *viewer = get_viewer(_viewer_path); + if (viewer) g_viewer_block_pos = VoxelMap::voxel_to_block(viewer->get_translation()); else g_viewer_block_pos = Vector3i(); @@ -263,7 +259,7 @@ void VoxelTerrain::update_blocks() { if (!_map->has_block(block_pos)) { // Create buffer - if(!_provider.is_null()) { + if (!_provider.is_null()) { VOXEL_PROFILE_BEGIN("voxel_buffer_creation_gen") @@ -291,7 +287,7 @@ void VoxelTerrain::update_blocks() { // Update views (mesh/collisions) - if(entire_block_changed) { + if (entire_block_changed) { // All neighbors have to be checked Vector3i ndir; for (ndir.z = -1; ndir.z < 2; ++ndir.z) { @@ -305,8 +301,7 @@ void VoxelTerrain::update_blocks() { } } } - } - else { + } else { // Only update the block, neighbors will probably follow if needed update_block_mesh(block_pos); //OS::get_singleton()->print("Update (%i, %i, %i)\n", block_pos.x, block_pos.y, block_pos.z); @@ -318,23 +313,21 @@ void VoxelTerrain::update_blocks() { } } - static inline bool is_mesh_empty(Ref mesh_ref) { - if(mesh_ref.is_null()) + if (mesh_ref.is_null()) return true; - Mesh & mesh = **mesh_ref; - if(mesh.get_surface_count() == 0) + Mesh &mesh = **mesh_ref; + if (mesh.get_surface_count() == 0) return true; // TODO Shouldn't it have an index to the surface rather than just the type? Oo - if(mesh.surface_get_array_len(Mesh::ARRAY_VERTEX) == 0) + if (mesh.surface_get_array_len(Mesh::ARRAY_VERTEX) == 0) return true; return false; } - void VoxelTerrain::update_block_mesh(Vector3i block_pos) { - VoxelBlock * block = _map->get_block(block_pos); + VoxelBlock *block = _map->get_block(block_pos); if (block == NULL) { return; } @@ -354,21 +347,20 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) { Vector3 block_node_pos = VoxelMap::block_to_voxel(block_pos).to_vec3(); - // TODO Re-use existing meshes to optimize memory cost + // TODO Re-use existing meshes to optimize memory cost // Build cubic parts of the mesh - Ref mesh = _mesher->build(nbuffer, Voxel::CHANNEL_TYPE, Vector3i(0,0,0), nbuffer.get_size()-Vector3(1,1,1)); + Ref mesh = _mesher->build(nbuffer, Voxel::CHANNEL_TYPE, Vector3i(0, 0, 0), nbuffer.get_size() - Vector3(1, 1, 1)); // Build smooth parts of the mesh _mesher_smooth->build(nbuffer, Voxel::CHANNEL_ISOLEVEL, mesh); - MeshInstance * mesh_instance = block->get_mesh_instance(*this); + MeshInstance *mesh_instance = block->get_mesh_instance(*this); - if(is_mesh_empty(mesh)) { - if(mesh_instance) { + if (is_mesh_empty(mesh)) { + if (mesh_instance) { mesh_instance->set_mesh(Ref()); } - } - else { + } else { // The mesh exist and it has vertices // TODO Don't use nodes! Use servers directly, it's faster @@ -379,15 +371,14 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) { mesh_instance->set_translation(block_node_pos); add_child(mesh_instance); block->mesh_instance_path = mesh_instance->get_path(); - } - else { + } else { // Update mesh VOXEL_PROFILE_BEGIN("mesh_instance_set_mesh") mesh_instance->set_mesh(mesh); VOXEL_PROFILE_END("mesh_instance_set_mesh") } - if(get_tree()->is_editor_hint() == false && _generate_collisions) { + if (get_tree()->is_editor_hint() == false && _generate_collisions) { // TODO Generate collisions using PhysicsServer // TODO Need to select only specific surfaces because some may not have collisions @@ -403,15 +394,15 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) { //} struct _VoxelTerrainRaycastContext { - VoxelTerrain & terrain; + VoxelTerrain &terrain; //unsigned int channel_mask; }; static bool _raycast_binding_predicate(Vector3i pos, void *context_ptr) { ERR_FAIL_COND_V(context_ptr == NULL, false); - _VoxelTerrainRaycastContext * context = (_VoxelTerrainRaycastContext*)context_ptr; - VoxelTerrain & terrain = context->terrain; + _VoxelTerrainRaycastContext *context = (_VoxelTerrainRaycastContext *)context_ptr; + VoxelTerrain &terrain = context->terrain; //unsigned int channel = context->channel; @@ -419,15 +410,15 @@ static bool _raycast_binding_predicate(Vector3i pos, void *context_ptr) { int v0 = map->get_voxel(pos, Voxel::CHANNEL_TYPE); Ref lib_ref = terrain.get_voxel_library(); - if(lib_ref.is_null()) + if (lib_ref.is_null()) return false; - const VoxelLibrary & lib = **lib_ref; + const VoxelLibrary &lib = **lib_ref; - if(lib.has_voxel(v0) == false) + if (lib.has_voxel(v0) == false) return false; - const Voxel & voxel = lib.get_voxel_const(v0); - if(voxel.is_transparent() == false) + const Voxel &voxel = lib.get_voxel_const(v0); + if (voxel.is_transparent() == false) return true; int v1 = map->get_voxel(pos, Voxel::CHANNEL_ISOLEVEL); @@ -443,14 +434,13 @@ Variant VoxelTerrain::_raycast_binding(Vector3 origin, Vector3 direction, real_t _VoxelTerrainRaycastContext context = { *this }; - if(voxel_raycast(origin, direction, _raycast_binding_predicate, &context, max_distance, hit_pos, prev_pos)) { + if (voxel_raycast(origin, direction, _raycast_binding_predicate, &context, max_distance, hit_pos, prev_pos)) { Dictionary hit = Dictionary(); hit["position"] = hit_pos.to_vec3(); hit["prev_position"] = prev_pos.to_vec3(); return hit; - } - else { + } else { return Variant(); // Null dictionary, no alloc } } @@ -484,6 +474,4 @@ void VoxelTerrain::_bind_methods() { #ifdef VOXEL_PROFILING ClassDB::bind_method(D_METHOD("get_profiling_info"), &VoxelTerrain::get_profiling_info); #endif - } - diff --git a/voxel_terrain.h b/voxel_terrain.h index 491d72f..2527f89 100644 --- a/voxel_terrain.h +++ b/voxel_terrain.h @@ -1,12 +1,12 @@ #ifndef VOXEL_TERRAIN_H #define VOXEL_TERRAIN_H -#include #include "voxel_map.h" #include "voxel_mesher.h" #include "voxel_mesher_smooth.h" #include "voxel_provider.h" #include "zprofiling.h" +#include // Infinite static terrain made of voxels. // It is loaded around VoxelTerrainStreamers. @@ -46,7 +46,7 @@ private: void update_blocks(); void update_block_mesh(Vector3i block_pos); - Spatial * get_viewer(NodePath path); + Spatial *get_viewer(NodePath path); // Observer events //void block_removed(VoxelBlock & block); @@ -90,8 +90,6 @@ private: ZProfiler _zprofiler; Dictionary get_profiling_info() { return _zprofiler.get_all_serialized_info(); } #endif - }; #endif // VOXEL_TERRAIN_H - diff --git a/zprofiling.cpp b/zprofiling.cpp index 01fe3e1..4a81cc1 100644 --- a/zprofiling.cpp +++ b/zprofiling.cpp @@ -40,7 +40,7 @@ ZProfileVar::ZProfileVar() { total_time = 0.f; hits = 0; _begin_time = 0.f; - for(unsigned int i = 0; i < BUFFERED_TIME_COUNT; ++i) + for (unsigned int i = 0; i < BUFFERED_TIME_COUNT; ++i) buffered_times[i] = 0; buffered_time_index = 0; } @@ -52,17 +52,14 @@ void ZProfileVar::begin(uint64_t time) { void ZProfileVar::end(uint64_t time) { instant_time = time - _begin_time; - if(hits == 0) - { + if (hits == 0) { min_time = instant_time; max_time = instant_time; - } - else - { - if(instant_time < min_time) + } else { + if (instant_time < min_time) min_time = instant_time; - if(instant_time > max_time) + if (instant_time > max_time) max_time = instant_time; } @@ -70,7 +67,7 @@ void ZProfileVar::end(uint64_t time) { buffered_times[buffered_time_index] = instant_time; ++buffered_time_index; - if(buffered_time_index >= BUFFERED_TIME_COUNT) + if (buffered_time_index >= BUFFERED_TIME_COUNT) buffered_time_index = 0; ++hits; @@ -86,7 +83,7 @@ Dictionary ZProfileVar::serialize() { d["hits"] = hits; Array a; - for(unsigned int i = 0; i < BUFFERED_TIME_COUNT; ++i) { + for (unsigned int i = 0; i < BUFFERED_TIME_COUNT; ++i) { a.append(buffered_times[i]); } d["buffered_times"] = a; @@ -103,47 +100,44 @@ Dictionary ZProfileVar::serialize() { //} ZProfiler::~ZProfiler() { - const String * key = NULL; + const String *key = NULL; while (key = _vars.next(key)) { - ZProfileVar * v = _vars.get(*key); + ZProfileVar *v = _vars.get(*key); memdelete(v); } } -ZProfileVar * ZProfiler::get_var(String key) { - ZProfileVar * v = NULL; - ZProfileVar ** pv = _vars.getptr(key); - if(pv == NULL) { +ZProfileVar *ZProfiler::get_var(String key) { + ZProfileVar *v = NULL; + ZProfileVar **pv = _vars.getptr(key); + if (pv == NULL) { v = memnew(ZProfileVar); _vars[key] = v; - } - else { + } else { v = *pv; } return v; } void ZProfiler::begin(String key) { - ZProfileVar * v = get_var(key); + ZProfileVar *v = get_var(key); v->begin(get_time()); } void ZProfiler::end(String key) { uint64_t time = get_time(); - ZProfileVar * v = get_var(key); + ZProfileVar *v = get_var(key); v->end(time); } Dictionary ZProfiler::get_all_serialized_info() const { Dictionary d; - const String * key = NULL; + const String *key = NULL; while (key = _vars.next(key)) { - ZProfileVar * v = _vars.get(*key); + ZProfileVar *v = _vars.get(*key); d[*key] = v->serialize(); } return d; } - #endif // VOXEL_PROFILING - diff --git a/zprofiling.h b/zprofiling.h index fb4cc1c..b8fadce 100644 --- a/zprofiling.h +++ b/zprofiling.h @@ -5,9 +5,9 @@ #ifdef VOXEL_PROFILING -#include #include #include +#include #define VOXEL_PROFILE_BEGIN(_key) _zprofiler.begin(_key); #define VOXEL_PROFILE_END(_key) _zprofiler.end(_key); @@ -26,9 +26,9 @@ public: private: //ZProfiler(); - ZProfileVar * get_var(String key); + ZProfileVar *get_var(String key); - HashMap _vars; + HashMap _vars; }; #else