mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-11 20:35:08 +01:00
VoxelBuffer storage is now flat to reduce memory usage and simplify code
This commit is contained in:
parent
3d3d996ed9
commit
68cf221d1a
16
vector3i.h
16
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;
|
||||
}
|
||||
|
42
voxel.cpp
42
voxel.cpp
@ -103,36 +103,18 @@ Ref<Voxel> 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();
|
||||
|
@ -1,4 +1,8 @@
|
||||
#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() {
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user