VoxelBuffer storage is now flat to reduce memory usage and simplify code

This commit is contained in:
Marc Gilleron 2016-05-03 00:09:07 +02:00
parent 3d3d996ed9
commit 68cf221d1a
4 changed files with 63 additions and 83 deletions

View File

@ -22,6 +22,22 @@ struct Vector3i {
return *this; 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) { bool operator==(const Vector3i & other) {
return x == other.x && y == other.y && z == other.z; return x == other.x && y == other.y && z == other.z;
} }

View File

@ -103,36 +103,18 @@ Ref<Voxel> Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) {
}; };
const int uv6[SIDE_COUNT][6] = { const int uv6[SIDE_COUNT][6] = {
{ // LEFT
// LEFT { 2,0,1,2,1,3 },
//0,1,3,0,1,2 // RIGHT
2,0,1,2,1,3 { 2,1,0,2,3,1 },
}, // BOTTOM
{ { 0,3,1,0,2,3 },
// RIGHT // TOP
//0,3,1,0,2,3 { 0,1,3,0,3,2 },
2,1,0,2,3,1 // BACK
}, { 2,3,1,2,1,0 },
{ // FRONT
// BOTTOM { 3,2,1,2,0,1 }
//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
}
}; };
float s = 1.0 / (float)_library->get_atlas_size(); float s = 1.0 / (float)_library->get_atlas_size();

View File

@ -1,4 +1,8 @@
#include "voxel_buffer.h" #include "voxel_buffer.h"
#include <string.h>
//#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() { 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]; const Channel & channel = _channels[channel_index];
if (validate_local_pos(x, y, z) && channel.data) { if (validate_local_pos(x, y, z) && channel.data) {
return channel.data[z][x][y]; return VOXEL_AT(channel.data, x,y,z);
} }
else { else {
return channel.defval; 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]; const Channel & channel = _channels[channel_index];
if (validate_local_pos(x, y, z) && channel.data) { if (validate_local_pos(x, y, z) && channel.data) {
return channel.data[z][x][y]; return VOXEL_AT(channel.data, x, y, z);
} }
else { else {
return channel.defval; 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) { if (channel.data == NULL) {
create_channel(channel_index, _size); 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) { void VoxelBuffer::fill(int defval, unsigned int channel_index) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
Channel & channel = _channels[channel_index];
Channel & channel = _channels[channel_index]; unsigned int volume = get_volume();
memset(channel.data, defval, volume);
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;
}
}
}
} }
bool VoxelBuffer::is_uniform(unsigned int channel_index) { 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]; Channel & channel = _channels[channel_index];
if (channel.data == NULL) if (channel.data == NULL)
return true; return true;
uint8_t voxel = channel.data[0][0][0];
for (unsigned int z = 0; z < _size.z; ++z) { uint8_t voxel = channel.data[0];
for (unsigned int x = 0; x < _size.x; ++x) { unsigned int volume = get_volume();
uint8_t * column = channel.data[z][x]; for (unsigned int i = 0; i < volume; ++i) {
for (unsigned int y = 0; y < _size.y; ++y) { if (channel.data[i] != voxel) {
if (column[y] != voxel) { return false;
return false;
}
}
} }
} }
return true; return true;
} }
void VoxelBuffer::optimize() { void VoxelBuffer::optimize() {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
if (_channels[i].data && is_uniform(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) { void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) {
Channel & channel = _channels[i]; Channel & channel = _channels[i];
channel.data = (uint8_t***)memalloc(size.z * sizeof(uint8_t**)); unsigned int volume = size.x * size.y * size.z;
channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t));
for (unsigned int z = 0; z < size.z; ++z) {
memset(channel.data, defval, volume);
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;
}
}
}
} }
void VoxelBuffer::delete_channel(int i, Vector3i size) { void VoxelBuffer::delete_channel(int i, Vector3i size) {
Channel & channel = _channels[i]; 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]);
}
memfree(channel.data); memfree(channel.data);
channel.data = NULL; channel.data = NULL;
} }

View File

@ -17,11 +17,11 @@ class VoxelBuffer : public Reference {
struct Channel { struct Channel {
// Allocated when the channel is populated. // 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). // Flat array, in order [z][x][y] because it allows faster vertical-wise access (the engine is Y-up).
// SUGG: move to flat storage? uint8_t * data;
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) {} Channel() : data(NULL), defval(0) {}
}; };
@ -75,6 +75,14 @@ public:
&& z < _size.x; && 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: private:
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, Vector3i size); void delete_channel(int i, Vector3i size);