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;
|
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;
|
||||||
}
|
}
|
||||||
|
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] = {
|
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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user