From 68cf221d1aee75670e9d80597a6ec9229f170e79 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Tue, 3 May 2016 00:09:07 +0200 Subject: [PATCH] VoxelBuffer storage is now flat to reduce memory usage and simplify code --- vector3i.h | 16 +++++++++++ voxel.cpp | 42 ++++++++-------------------- voxel_buffer.cpp | 72 ++++++++++++++++-------------------------------- voxel_buffer.h | 16 ++++++++--- 4 files changed, 63 insertions(+), 83 deletions(-) diff --git a/vector3i.h b/vector3i.h index d8f7b72..0acfd59 100644 --- a/vector3i.h +++ b/vector3i.h @@ -22,6 +22,22 @@ struct Vector3i { return *this; } + Vector3i operator+(const Vector3i & other) { + return Vector3i(x + other.x, y + other.y, z + other.z); + } + + Vector3i operator-(const Vector3i & other) { + return Vector3i(x - other.x, y - other.y, z - other.z); + } + + Vector3i operator*(int n) { + return Vector3i(x * n, y * n, z * n); + } + + Vector3i operator/(int n) { + return Vector3i(x / n, y / n, z / n); + } + bool operator==(const Vector3i & other) { return x == other.x && y == other.y && z == other.z; } diff --git a/voxel.cpp b/voxel.cpp index d7d2e03..12fc891 100644 --- a/voxel.cpp +++ b/voxel.cpp @@ -103,36 +103,18 @@ Ref Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) { }; const int uv6[SIDE_COUNT][6] = { - { - // LEFT - //0,1,3,0,1,2 - 2,0,1,2,1,3 - }, - { - // RIGHT - //0,3,1,0,2,3 - 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 - //0,1,3,0,3,2 - 2,3,1,2,1,0 - }, - { - // FRONT - //1,0,3,0,2,3 - 3,2,1,2,0,1 - } + // LEFT + { 2,0,1,2,1,3 }, + // RIGHT + { 2,1,0,2,3,1 }, + // BOTTOM + { 0,3,1,0,2,3 }, + // TOP + { 0,1,3,0,3,2 }, + // BACK + { 2,3,1,2,1,0 }, + // FRONT + { 3,2,1,2,0,1 } }; float s = 1.0 / (float)_library->get_atlas_size(); diff --git a/voxel_buffer.cpp b/voxel_buffer.cpp index f65259d..e9f7e5d 100644 --- a/voxel_buffer.cpp +++ b/voxel_buffer.cpp @@ -1,4 +1,8 @@ #include "voxel_buffer.h" +#include + +//#define VOXEL_AT(_data, x, y, z) data[z][x][y] +#define VOXEL_AT(_data, _x, _y, _z) _data[index(_x,_y,_z)] VoxelBuffer::VoxelBuffer() { @@ -52,7 +56,7 @@ int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) cons const Channel & channel = _channels[channel_index]; if (validate_local_pos(x, y, z) && channel.data) { - return channel.data[z][x][y]; + return VOXEL_AT(channel.data, x,y,z); } else { return channel.defval; @@ -65,7 +69,7 @@ int VoxelBuffer::get_voxel_local(int x, int y, int z, unsigned int channel_index const Channel & channel = _channels[channel_index]; if (validate_local_pos(x, y, z) && channel.data) { - return channel.data[z][x][y]; + return VOXEL_AT(channel.data, x, y, z); } else { return channel.defval; @@ -87,7 +91,7 @@ void VoxelBuffer::set_voxel(int value, int x, int y, int z, unsigned int channel if (channel.data == NULL) { create_channel(channel_index, _size); } - channel.data[z][x][y] = value; + VOXEL_AT(channel.data, x, y, z) = value; } } @@ -97,17 +101,9 @@ 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]; - - for (unsigned int z = 0; z < _size.z; ++z) { - for (unsigned int x = 0; x < _size.x; ++x) { - uint8_t * column = channel.data[z][x]; - for (unsigned int y = 0; y < _size.y; ++y) { - column[y] = defval; - } - } - } + Channel & channel = _channels[channel_index]; + unsigned int volume = get_volume(); + memset(channel.data, defval, volume); } bool VoxelBuffer::is_uniform(unsigned int channel_index) { @@ -116,24 +112,22 @@ bool VoxelBuffer::is_uniform(unsigned int channel_index) { Channel & channel = _channels[channel_index]; if (channel.data == NULL) return true; - uint8_t voxel = channel.data[0][0][0]; - for (unsigned int z = 0; z < _size.z; ++z) { - for (unsigned int x = 0; x < _size.x; ++x) { - uint8_t * column = channel.data[z][x]; - for (unsigned int y = 0; y < _size.y; ++y) { - if (column[y] != voxel) { - return false; - } - } + + uint8_t voxel = channel.data[0]; + unsigned int volume = get_volume(); + for (unsigned int i = 0; i < volume; ++i) { + if (channel.data[i] != voxel) { + return false; } } + return true; } void VoxelBuffer::optimize() { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { if (_channels[i].data && is_uniform(i)) { - clear_channel(i, _channels[i].data[0][0][0]); + clear_channel(i, _channels[i].data[0]); } } } @@ -141,35 +135,15 @@ void VoxelBuffer::optimize() { void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) { Channel & channel = _channels[i]; - channel.data = (uint8_t***)memalloc(size.z * sizeof(uint8_t**)); - - for (unsigned int z = 0; z < size.z; ++z) { - - uint8_t ** plane = (uint8_t**)memalloc(size.x * sizeof(uint8_t*)); - channel.data[z] = plane; - - for (unsigned int x = 0; x < size.x; ++x) { - - uint8_t * column = (uint8_t*)memalloc(size.y * sizeof(uint8_t)); - plane[x] = column; - - for (unsigned int y = 0; y < size.y; ++y) { - column[y] = defval; - } - } - } + unsigned int volume = size.x * size.y * size.z; + channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t)); + + memset(channel.data, defval, volume); } void VoxelBuffer::delete_channel(int i, Vector3i size) { - Channel & channel = _channels[i]; - - for (unsigned int z = 0; z < size.z; ++z) { - for (unsigned int x = 0; x < size.x; ++x) { - memfree(channel.data[z][x]); - } - memfree(channel.data[z]); - } + Channel & channel = _channels[i]; memfree(channel.data); channel.data = NULL; } diff --git a/voxel_buffer.h b/voxel_buffer.h index 5100ca0..2940271 100644 --- a/voxel_buffer.h +++ b/voxel_buffer.h @@ -17,11 +17,11 @@ class VoxelBuffer : public Reference { struct Channel { // Allocated when the channel is populated. - // Array of array of arrays, in order [z][x][y] because it makes vertical-wise access faster (the engine is Y-up). - // SUGG: move to flat storage? - uint8_t *** data; + // Flat array, in order [z][x][y] because it allows faster vertical-wise access (the engine is Y-up). + uint8_t * data; - uint8_t defval; // Default value when data is null + // Default value when data is null + uint8_t defval; Channel() : data(NULL), defval(0) {} }; @@ -75,6 +75,14 @@ public: && z < _size.x; } + _FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const { + return (z * _size.z + x) * _size.x + y; + } + + _FORCE_INLINE_ unsigned int get_volume() { + return _size.x * _size.y * _size.z; + } + private: void create_channel(int i, Vector3i size, uint8_t defval=0); void delete_channel(int i, Vector3i size);