Clang-format

master
Marc Gilleron 2017-08-13 01:19:39 +02:00
parent bc75ec863b
commit 51596fef95
23 changed files with 668 additions and 788 deletions

View File

@ -1,8 +1,8 @@
#ifndef VOXEL_VECTOR3I_H
#define VOXEL_VECTOR3I_H
#include <core/math/vector3.h>
#include <core/hashfuncs.h>
#include <core/math/vector3.h>
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

130
voxel.cpp
View File

@ -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> Voxel::set_name(String name) {
_name = name;
@ -41,60 +41,48 @@ Ref<Voxel> Voxel::set_transparent(bool t) {
Ref<Voxel> 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> 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)
}

17
voxel.h
View File

@ -60,13 +60,13 @@ public:
// Getters for native usage only
const PoolVector<Vector3> & get_model_vertices() const { return _model_vertices; }
const PoolVector<Vector3> & get_model_normals() const { return _model_normals; }
const PoolVector<Vector2> & get_model_uv() const { return _model_uv; }
const PoolVector<Vector3> & get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; }
const PoolVector<Vector2> & get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; }
const PoolVector<Vector3> &get_model_vertices() const { return _model_vertices; }
const PoolVector<Vector3> &get_model_normals() const { return _model_normals; }
const PoolVector<Vector2> &get_model_uv() const { return _model_uv; }
const PoolVector<Vector3> &get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; }
const PoolVector<Vector2> &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<Voxel> _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<Vector2> _model_side_uv[SIDE_COUNT];
// TODO Child voxel types
};
VARIANT_ENUM_CAST(Voxel::ChannelMode)
#endif // VOXEL_TYPE_H

View File

@ -1,10 +1,8 @@
#include "voxel_buffer.h"
#include <string.h>
#include <math_funcs.h>
#include <string.h>
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<VoxelBuffer> other, unsigned int channel) {

View File

@ -1,9 +1,9 @@
#ifndef VOXEL_BUFFER_H
#define VOXEL_BUFFER_H
#include "vector3i.h"
#include <reference.h>
#include <vector.h>
#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<int>(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<VoxelBuffer> other, unsigned int channel);
void _copy_from_area_binding(Ref<VoxelBuffer> 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

View File

@ -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);
}

View File

@ -1,8 +1,8 @@
#ifndef VOXEL_LIBRARY_H
#define VOXEL_LIBRARY_H
#include <reference.h>
#include "voxel.h"
#include <reference.h>
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> _voxel_types[MAX_VOXEL_TYPES];
int _atlas_size;
};
#endif // VOXEL_LIBRARY_H

View File

@ -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<MeshInstance>();
}
// Helper
VoxelBlock * VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer) {
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> 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<VoxelBuffer> 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<VoxelBuffer> 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<Vector3i> 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<VoxelBuffer> dst_buffer_ref, unsigned int channel) {
ERR_FAIL_COND(dst_buffer_ref.is_null());
get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel);
}

View File

@ -1,12 +1,11 @@
#ifndef VOXEL_MAP_H
#define VOXEL_MAP_H
#include <scene/main/node.h>
#include "voxel_buffer.h"
#include <core/hash_map.h>
#include <scene/3d/mesh_instance.h>
#include <scene/3d/physics_body.h>
#include "voxel_buffer.h"
#include <scene/main/node.h>
// 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<VoxelBuffer> buffer);
static VoxelBlock *create(Vector3i bpos, Ref<VoxelBuffer> 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<VoxelBuffer> 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<Vector3i, VoxelBlock*, Vector3iHasher> _blocks;
HashMap<Vector3i, VoxelBlock *, Vector3iHasher> _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

View File

@ -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<VoxelLibrary> library) {
ERR_FAIL_COND(library.is_null());
_library = library;
ERR_FAIL_COND(library.is_null());
_library = library;
}
void VoxelMesher::set_material(Ref<Material> material, unsigned int id) {
ERR_FAIL_COND(id >= MAX_MATERIALS);
_materials[id] = material;
ERR_FAIL_COND(id >= MAX_MATERIALS);
_materials[id] = material;
}
Ref<Material> VoxelMesher::get_material(unsigned int id) const {
@ -140,224 +138,223 @@ Ref<Material> 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<ArrayMesh> VoxelMesher::build_ref(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Ref<ArrayMesh> mesh) {
ERR_FAIL_COND_V(buffer_ref.is_null(), Ref<ArrayMesh>());
VoxelBuffer & buffer = **buffer_ref;
VoxelBuffer &buffer = **buffer_ref;
mesh = build(buffer, channel, Vector3i(), buffer.get_size(), mesh);
return mesh;
}
Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer & buffer, unsigned int channel, Vector3i min, Vector3i max, Ref<ArrayMesh> mesh) {
Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max, Ref<ArrayMesh> mesh) {
ERR_FAIL_COND_V(_library.is_null(), Ref<ArrayMesh>());
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Ref<ArrayMesh>());
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<Vector3> & vertices = voxel.get_model_side_vertices(side);
if (vertices.size() != 0) {
const PoolVector<Vector3> &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<Vector3>::Read rv = vertices.read();
PoolVector<Vector2>::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<float>(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<float>(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<Vector3> & vertices = voxel.get_model_vertices();
const PoolVector<Vector3> &vertices = voxel.get_model_vertices();
PoolVector<Vector3>::Read rv = voxel.get_model_vertices().read();
PoolVector<Vector3>::Read rn = voxel.get_model_normals().read();
PoolVector<Vector2>::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<ArrayMesh> mesh_ref = mesh;
if(mesh.is_null())
if (mesh.is_null())
mesh_ref = Ref<ArrayMesh>(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;
}

View File

@ -1,14 +1,13 @@
#ifndef VOXEL_MESHER
#define VOXEL_MESHER
#include <reference.h>
#include <scene/resources/mesh.h>
#include <scene/resources/surface_tool.h>
#include "voxel.h"
#include "voxel_buffer.h"
#include "voxel_library.h"
#include "zprofiling.h"
#include <reference.h>
#include <scene/resources/mesh.h>
#include <scene/resources/surface_tool.h>
// 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<ArrayMesh> build(const VoxelBuffer & buffer_ref, unsigned int channel, Vector3i min, Vector3i max, Ref<ArrayMesh> mesh=Ref<Mesh>());
Ref<ArrayMesh> build_ref(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Ref<ArrayMesh> mesh=Ref<ArrayMesh>());
Ref<ArrayMesh> build(const VoxelBuffer &buffer_ref, unsigned int channel, Vector3i min, Vector3i max, Ref<ArrayMesh> mesh = Ref<Mesh>());
Ref<ArrayMesh> build_ref(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Ref<ArrayMesh> mesh = Ref<ArrayMesh>());
protected:
static void _bind_methods();
@ -50,5 +49,4 @@ private:
#endif
};
#endif // VOXEL_MESHER

View File

@ -3,7 +3,6 @@
#include "transvoxel_tables.cpp"
#include <os/os.h>
inline float tof(int8_t v) {
return static_cast<float>(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<typename T>
void copy_to(PoolVector<T> & to, Vector<T> & from) {
template <typename T>
void copy_to(PoolVector<T> &to, Vector<T> &from) {
to.resize(from.size());
PoolVector<T>::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<ArrayMesh> VoxelMesherSmooth::build_ref(Ref<VoxelBuffer> voxels_ref, unsigne
ERR_FAIL_COND_V(voxels_ref.is_null(), Ref<ArrayMesh>());
VoxelBuffer & voxels = **voxels_ref;
VoxelBuffer &voxels = **voxels_ref;
return build(voxels, channel, mesh);
}
Ref<ArrayMesh> VoxelMesherSmooth::build(const VoxelBuffer & voxels, unsigned int channel, Ref<ArrayMesh> mesh) {
Ref<ArrayMesh> VoxelMesherSmooth::build(const VoxelBuffer &voxels, unsigned int channel, Ref<ArrayMesh> mesh) {
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Ref<ArrayMesh>());
@ -93,12 +91,12 @@ Ref<ArrayMesh> 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<ArrayMesh>();
}
@ -114,12 +112,12 @@ Ref<ArrayMesh> 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<ArrayMesh>(memnew(ArrayMesh));
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
@ -127,7 +125,7 @@ Ref<ArrayMesh> 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 edges 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()));
}

View File

@ -10,8 +10,8 @@ class VoxelMesherSmooth : public Reference {
public:
VoxelMesherSmooth();
Ref<ArrayMesh> build_ref(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh=Ref<ArrayMesh>());
Ref<ArrayMesh> build(const VoxelBuffer & voxels, unsigned int channel, Ref<ArrayMesh> mesh=Ref<ArrayMesh>());
Ref<ArrayMesh> build_ref(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh = Ref<ArrayMesh>());
Ref<ArrayMesh> build(const VoxelBuffer &voxels, unsigned int channel, Ref<ArrayMesh> mesh = Ref<ArrayMesh>());
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<ReuseCell> m_cache[2];
Vector3i m_block_size;

View File

@ -1,15 +1,14 @@
#include "voxel_provider.h"
#include "voxel_map.h"
void VoxelProvider::emerge_block(Ref<VoxelBuffer> 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<VoxelBuffer> out_buffer, Vector3i block_pos
void VoxelProvider::immerge_block(Ref<VoxelBuffer> 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);
}

View File

@ -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<VoxelBuffer> buffer, Vector3 block_pos);
};
#endif // VOXEL_PROVIDER_H

View File

@ -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<VoxelBuffer> 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<float>(_pattern_size.y);
float period_x = 1.f/static_cast<float>(_pattern_size.x);
float period_z = 1.f/static_cast<float>(_pattern_size.z);
float period_x = 1.f / static_cast<float>(_pattern_size.x);
float period_z = 1.f / static_cast<float>(_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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -1,18 +1,16 @@
#include <vector3.h>
#include "vector3i.h"
#include <vector3.h>
// 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);

View File

@ -1,9 +1,10 @@
#include "voxel_terrain.h"
#include <scene/3d/mesh_instance.h>
#include <os/os.h>
#include "voxel_raycast.h"
#include <os/os.h>
#include <scene/3d/mesh_instance.h>
VoxelTerrain::VoxelTerrain(): Node(), _generate_collisions(true) {
VoxelTerrain::VoxelTerrain()
: Node(), _generate_collisions(true) {
_map = Ref<VoxelMap>(memnew(VoxelMap));
_mesher = Ref<VoxelMesher>(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<Spatial>();
}
@ -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> 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<ArrayMesh> mesh = _mesher->build(nbuffer, Voxel::CHANNEL_TYPE, Vector3i(0,0,0), nbuffer.get_size()-Vector3(1,1,1));
Ref<ArrayMesh> 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<Mesh>());
}
}
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<VoxelLibrary> 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
}

View File

@ -1,12 +1,12 @@
#ifndef VOXEL_TERRAIN_H
#define VOXEL_TERRAIN_H
#include <scene/main/node.h>
#include "voxel_map.h"
#include "voxel_mesher.h"
#include "voxel_mesher_smooth.h"
#include "voxel_provider.h"
#include "zprofiling.h"
#include <scene/main/node.h>
// 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

View File

@ -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

View File

@ -5,9 +5,9 @@
#ifdef VOXEL_PROFILING
#include <ustring.h>
#include <dictionary.h>
#include <hash_map.h>
#include <ustring.h>
#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<String, ZProfileVar*> _vars;
HashMap<String, ZProfileVar *> _vars;
};
#else