Spaces to tabs

This commit is contained in:
Marc Gilleron 2017-01-01 04:40:16 +01:00
parent 8acf40d338
commit 8d1c8cc339
13 changed files with 928 additions and 928 deletions

View File

@ -7,12 +7,12 @@
void register_voxel_types() { void register_voxel_types() {
ObjectTypeDB::register_type<Voxel>(); ObjectTypeDB::register_type<Voxel>();
ObjectTypeDB::register_type<VoxelBuffer>(); ObjectTypeDB::register_type<VoxelBuffer>();
ObjectTypeDB::register_type<VoxelMesher>(); ObjectTypeDB::register_type<VoxelMesher>();
ObjectTypeDB::register_type<VoxelLibrary>(); ObjectTypeDB::register_type<VoxelLibrary>();
ObjectTypeDB::register_type<VoxelMap>(); ObjectTypeDB::register_type<VoxelMap>();
ObjectTypeDB::register_type<VoxelTerrain>(); ObjectTypeDB::register_type<VoxelTerrain>();
} }

View File

@ -5,134 +5,134 @@
struct Vector3i { struct Vector3i {
union { union {
struct { struct {
int x; int x;
int y; int y;
int z; int z;
}; };
int coords[3]; 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; *this = other;
} }
_FORCE_INLINE_ Vector3i(const Vector3 & f) { _FORCE_INLINE_ Vector3i(const Vector3 & f) {
x = Math::floor(f.x); x = Math::floor(f.x);
y = Math::floor(f.y); y = Math::floor(f.y);
z = Math::floor(f.z); z = Math::floor(f.z);
} }
_FORCE_INLINE_ Vector3 to_vec3() const { _FORCE_INLINE_ Vector3 to_vec3() const {
return Vector3(x, y, z); return Vector3(x, y, z);
} }
_FORCE_INLINE_ int volume() const { _FORCE_INLINE_ int volume() const {
return x*y*z; return x*y*z;
} }
_FORCE_INLINE_ int length_sq() const { _FORCE_INLINE_ int length_sq() const {
return x*x + y*y + z*z; return x*x + y*y + z*z;
} }
_FORCE_INLINE_ float length() const { _FORCE_INLINE_ float length() const {
return Math::sqrt(length_sq()); return Math::sqrt(length_sq());
} }
_FORCE_INLINE_ Vector3i & operator=(const Vector3i & other) { _FORCE_INLINE_ Vector3i & operator=(const Vector3i & other) {
x = other.x; x = other.x;
y = other.y; y = other.y;
z = other.z; z = other.z;
return *this; return *this;
} }
_FORCE_INLINE_ void operator+=(const Vector3i & other) { _FORCE_INLINE_ void operator+=(const Vector3i & other) {
x += other.x; x += other.x;
y += other.y; y += other.y;
z += other.z; z += other.z;
} }
_FORCE_INLINE_ void operator-=(const Vector3i & other) { _FORCE_INLINE_ void operator-=(const Vector3i & other) {
x -= other.x; x -= other.x;
y -= other.y; y -= other.y;
z -= other.z; z -= other.z;
} }
_FORCE_INLINE_ int & operator[](unsigned int i) { _FORCE_INLINE_ int & operator[](unsigned int i) {
return coords[i]; return coords[i];
} }
void clamp_to(const Vector3i min, const Vector3i max) { void clamp_to(const Vector3i min, const Vector3i max) {
if (x < min.x) x = min.x; if (x < min.x) x = min.x;
if (y < min.y) y = min.y; if (y < min.y) y = min.y;
if (z < min.z) z = min.z; if (z < min.z) z = min.z;
if (x >= max.x) x = max.x - 1; if (x >= max.x) x = max.x - 1;
if (y >= max.y) y = max.y - 1; if (y >= max.y) y = max.y - 1;
if (z >= max.z) z = max.z - 1; if (z >= max.z) z = max.z - 1;
} }
_FORCE_INLINE_ bool is_contained_in(const Vector3i & min, const Vector3i & max) { _FORCE_INLINE_ bool is_contained_in(const Vector3i & min, const Vector3i & max) {
return x >= min.x && y >= min.y && z >= min.z return x >= min.x && y >= min.y && z >= min.z
&& x < max.x && y < max.y && z < max.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( return Vector3i(
x % size.x, x % size.x,
y % size.y, y % size.y,
z % size.z 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.x, b.x);
sort_min_max(a.y, b.y); sort_min_max(a.y, b.y);
sort_min_max(a.z, b.z); sort_min_max(a.z, b.z);
} }
private: 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) { if (a > b) {
int temp = a; int temp = a;
a = b; a = b;
b = temp; 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); 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); 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); 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); 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); 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; 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; return a.x != b.x && a.y != b.y && a.z != b.z;
} }
struct Vector3iHasher { struct Vector3iHasher {
@ -140,7 +140,7 @@ struct Vector3iHasher {
uint32_t hash = hash_djb2_one_32(v.x); uint32_t hash = hash_djb2_one_32(v.x);
hash = hash_djb2_one_32(v.y, hash); hash = hash_djb2_one_32(v.y, hash);
return hash_djb2_one_32(v.z, hash); return hash_djb2_one_32(v.z, hash);
} }
}; };
#endif // VOXEL_VECTOR3I_H #endif // VOXEL_VECTOR3I_H

280
voxel.cpp
View File

@ -2,160 +2,160 @@
#include "voxel_library.h" #include "voxel_library.h"
#include "voxel_mesher.h" #include "voxel_mesher.h"
Voxel::Voxel() : Reference(), Voxel::Voxel() : Reference(),
_id(-1), _id(-1),
_material_id(0), _material_id(0),
_is_transparent(false), _is_transparent(false),
_library(NULL), _library(NULL),
_color(1.f, 1.f, 1.f) _color(1.f, 1.f, 1.f)
{} {}
Ref<Voxel> Voxel::set_id(int id) { Ref<Voxel> Voxel::set_id(int id) {
ERR_FAIL_COND_V(id < 0 || id >= 256, Ref<Voxel>(this)); ERR_FAIL_COND_V(id < 0 || id >= 256, Ref<Voxel>(this));
// Cannot modify ID after creation // Cannot modify ID after creation
ERR_FAIL_COND_V(_id != -1, Ref<Voxel>(this)); ERR_FAIL_COND_V(_id != -1, Ref<Voxel>(this));
_id = id; _id = id;
return Ref<Voxel>(this); return Ref<Voxel>(this);
} }
Ref<Voxel> Voxel::set_material_id(unsigned int id) { Ref<Voxel> Voxel::set_material_id(unsigned int id) {
ERR_FAIL_COND_V(id >= VoxelMesher::MAX_MATERIALS, Ref<Voxel>(this)); ERR_FAIL_COND_V(id >= VoxelMesher::MAX_MATERIALS, Ref<Voxel>(this));
_material_id = id; _material_id = id;
return Ref<Voxel>(this); return Ref<Voxel>(this);
} }
Ref<Voxel> Voxel::set_cube_geometry(float sy) { Ref<Voxel> Voxel::set_cube_geometry(float sy) {
const Vector3 vertices[SIDE_COUNT][6] = { const Vector3 vertices[SIDE_COUNT][6] = {
{ {
// LEFT // LEFT
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(0, sy, 0), Vector3(0, sy, 0),
Vector3(0, sy, 1), Vector3(0, sy, 1),
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(0, sy, 1), Vector3(0, sy, 1),
Vector3(0, 0, 1), Vector3(0, 0, 1),
}, },
{ {
// RIGHT // RIGHT
Vector3(1, 0, 0), Vector3(1, 0, 0),
Vector3(1, sy, 1), Vector3(1, sy, 1),
Vector3(1, sy, 0), Vector3(1, sy, 0),
Vector3(1, 0, 0), Vector3(1, 0, 0),
Vector3(1, 0, 1), Vector3(1, 0, 1),
Vector3(1, sy, 1) Vector3(1, sy, 1)
}, },
{ {
// BOTTOM // BOTTOM
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(1, 0, 1), Vector3(1, 0, 1),
Vector3(1, 0, 0), Vector3(1, 0, 0),
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(0, 0, 1), Vector3(0, 0, 1),
Vector3(1, 0, 1) Vector3(1, 0, 1)
}, },
{ {
// TOP // TOP
Vector3(0, sy, 0), Vector3(0, sy, 0),
Vector3(1, sy, 0), Vector3(1, sy, 0),
Vector3(1, sy, 1), Vector3(1, sy, 1),
Vector3(0, sy, 0), Vector3(0, sy, 0),
Vector3(1, sy, 1), Vector3(1, sy, 1),
Vector3(0, sy, 1) Vector3(0, sy, 1)
}, },
{ {
// BACK // BACK
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(1, 0, 0), Vector3(1, 0, 0),
Vector3(1, sy, 0), Vector3(1, sy, 0),
Vector3(0, 0, 0), Vector3(0, 0, 0),
Vector3(1, sy, 0), Vector3(1, sy, 0),
Vector3(0, sy, 0), Vector3(0, sy, 0),
}, },
{ {
// FRONT // FRONT
Vector3(1, 0, 1), Vector3(1, 0, 1),
Vector3(0, 0, 1), Vector3(0, 0, 1),
Vector3(1, sy, 1), Vector3(1, sy, 1),
Vector3(0, 0, 1), Vector3(0, 0, 1),
Vector3(0, sy, 1), Vector3(0, sy, 1),
Vector3(1, sy, 1) Vector3(1, sy, 1)
} }
}; };
for (unsigned int side = 0; side < SIDE_COUNT; ++side) { for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_vertices[side].resize(6); _model_side_vertices[side].resize(6);
DVector<Vector3>::Write w = _model_side_vertices[side].write(); DVector<Vector3>::Write w = _model_side_vertices[side].write();
for (unsigned int i = 0; i < 6; ++i) { for (unsigned int i = 0; i < 6; ++i) {
w[i] = vertices[side][i]; w[i] = vertices[side][i];
} }
} }
return Ref<Voxel>(this); return Ref<Voxel>(this);
} }
Ref<Voxel> Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) { Ref<Voxel> Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) {
ERR_FAIL_COND_V(_library == NULL, Ref<Voxel>()); ERR_FAIL_COND_V(_library == NULL, Ref<Voxel>());
float e = 0.001; float e = 0.001;
const Vector2 uv[4] = { const Vector2 uv[4] = {
Vector2(e, e), Vector2(e, e),
Vector2(1.f - e, e), Vector2(1.f - e, e),
Vector2(e, 1.f - e), Vector2(e, 1.f - e),
Vector2(1.f - e, 1.f - e), Vector2(1.f - e, 1.f - e),
}; };
const int uv6[SIDE_COUNT][6] = { const int uv6[SIDE_COUNT][6] = {
// LEFT // LEFT
{ 2,0,1,2,1,3 }, { 2,0,1,2,1,3 },
// RIGHT // RIGHT
{ 2,1,0,2,3,1 }, { 2,1,0,2,3,1 },
// BOTTOM // BOTTOM
{ 0,3,1,0,2,3 }, { 0,3,1,0,2,3 },
// TOP // TOP
{ 0,1,3,0,3,2 }, { 0,1,3,0,3,2 },
// BACK // BACK
{ 2,3,1,2,1,0 }, { 2,3,1,2,1,0 },
// FRONT // FRONT
{ 3,2,1,2,0,1 } { 3,2,1,2,0,1 }
}; };
float s = 1.0 / (float)_library->get_atlas_size(); float s = 1.0 / (float)_library->get_atlas_size();
for (unsigned int side = 0; side < SIDE_COUNT; ++side) { for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_uv[side].resize(6); _model_side_uv[side].resize(6);
DVector<Vector2>::Write w = _model_side_uv[side].write(); DVector<Vector2>::Write w = _model_side_uv[side].write();
for (unsigned int i = 0; i < 6; ++i) { for (unsigned int i = 0; i < 6; ++i) {
w[i] = (atlas_pos[side] + uv[uv6[side][i]]) * s; w[i] = (atlas_pos[side] + uv[uv6[side][i]]) * s;
} }
} }
return Ref<Voxel>(this); return Ref<Voxel>(this);
} }
Ref<Voxel> Voxel::set_cube_uv_all_sides(Vector2 atlas_pos) { Ref<Voxel> Voxel::set_cube_uv_all_sides(Vector2 atlas_pos) {
const Vector2 positions[6] = { const Vector2 positions[6] = {
atlas_pos, atlas_pos,
atlas_pos, atlas_pos,
atlas_pos, atlas_pos,
atlas_pos, atlas_pos,
atlas_pos, atlas_pos,
atlas_pos atlas_pos
}; };
return _set_cube_uv_sides(positions); return _set_cube_uv_sides(positions);
} }
Ref<Voxel> Voxel::set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos) { Ref<Voxel> Voxel::set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos) {
const Vector2 positions[6] = { const Vector2 positions[6] = {
side_atlas_pos, side_atlas_pos,
side_atlas_pos, side_atlas_pos,
bottom_atlas_pos, bottom_atlas_pos,
top_atlas_pos, top_atlas_pos,
side_atlas_pos, side_atlas_pos,
side_atlas_pos, side_atlas_pos,
}; };
return _set_cube_uv_sides(positions); return _set_cube_uv_sides(positions);
} }
//Ref<Voxel> Voxel::set_xquad_geometry(Vector2 atlas_pos) { //Ref<Voxel> Voxel::set_xquad_geometry(Vector2 atlas_pos) {
@ -165,24 +165,24 @@ Ref<Voxel> Voxel::set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atla
void Voxel::_bind_methods() { void Voxel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_name:Voxel", "name"), &Voxel::set_name); ObjectTypeDB::bind_method(_MD("set_name:Voxel", "name"), &Voxel::set_name);
ObjectTypeDB::bind_method(_MD("get_name"), &Voxel::get_name); ObjectTypeDB::bind_method(_MD("get_name"), &Voxel::get_name);
ObjectTypeDB::bind_method(_MD("set_id:Voxel", "id"), &Voxel::set_id); ObjectTypeDB::bind_method(_MD("set_id:Voxel", "id"), &Voxel::set_id);
ObjectTypeDB::bind_method(_MD("get_id"), &Voxel::get_id); ObjectTypeDB::bind_method(_MD("get_id"), &Voxel::get_id);
ObjectTypeDB::bind_method(_MD("set_color:Voxel", "color"), &Voxel::set_color); ObjectTypeDB::bind_method(_MD("set_color:Voxel", "color"), &Voxel::set_color);
ObjectTypeDB::bind_method(_MD("get_color"), &Voxel::get_color); ObjectTypeDB::bind_method(_MD("get_color"), &Voxel::get_color);
ObjectTypeDB::bind_method(_MD("set_transparent:Voxel", "color"), &Voxel::set_transparent, DEFVAL(true)); ObjectTypeDB::bind_method(_MD("set_transparent:Voxel", "color"), &Voxel::set_transparent, DEFVAL(true));
ObjectTypeDB::bind_method(_MD("is_transparent"), &Voxel::is_transparent); ObjectTypeDB::bind_method(_MD("is_transparent"), &Voxel::is_transparent);
ObjectTypeDB::bind_method(_MD("set_material_id", "id"), &Voxel::set_material_id); ObjectTypeDB::bind_method(_MD("set_material_id", "id"), &Voxel::set_material_id);
ObjectTypeDB::bind_method(_MD("get_material_id"), &Voxel::get_material_id); ObjectTypeDB::bind_method(_MD("get_material_id"), &Voxel::get_material_id);
ObjectTypeDB::bind_method(_MD("set_cube_geometry:Voxel", "height"), &Voxel::set_cube_geometry, DEFVAL(1.f)); ObjectTypeDB::bind_method(_MD("set_cube_geometry:Voxel", "height"), &Voxel::set_cube_geometry, DEFVAL(1.f));
ObjectTypeDB::bind_method(_MD("set_cube_uv_all_sides:Voxel", "atlas_pos"), &Voxel::set_cube_uv_all_sides); ObjectTypeDB::bind_method(_MD("set_cube_uv_all_sides:Voxel", "atlas_pos"), &Voxel::set_cube_uv_all_sides);
ObjectTypeDB::bind_method(_MD("set_cube_uv_tbs_sides:Voxel", "top_atlas_pos", "side_atlas_pos", "bottom_atlas_pos"), &Voxel::set_cube_uv_tbs_sides); ObjectTypeDB::bind_method(_MD("set_cube_uv_tbs_sides:Voxel", "top_atlas_pos", "side_atlas_pos", "bottom_atlas_pos"), &Voxel::set_cube_uv_tbs_sides);
} }

102
voxel.h
View File

@ -9,82 +9,82 @@ class VoxelLibrary;
// A voxel can be a simple coloured cube, or a more complex model. // A voxel can be a simple coloured cube, or a more complex model.
// Important: it is recommended that you create voxels from a library rather than using new(). // Important: it is recommended that you create voxels from a library rather than using new().
class Voxel : public Reference { class Voxel : public Reference {
OBJ_TYPE(Voxel, Reference) OBJ_TYPE(Voxel, Reference)
public: public:
enum Side { enum Side {
SIDE_LEFT = 0, SIDE_LEFT = 0,
SIDE_RIGHT, SIDE_RIGHT,
SIDE_BOTTOM, SIDE_BOTTOM,
SIDE_TOP, SIDE_TOP,
SIDE_BACK, SIDE_BACK,
SIDE_FRONT, SIDE_FRONT,
SIDE_COUNT SIDE_COUNT
}; };
private: private:
VoxelLibrary * _library; VoxelLibrary * _library;
// Identifiers // Identifiers
int _id; int _id;
String _name; String _name;
// Properties // Properties
int _material_id; int _material_id;
bool _is_transparent; bool _is_transparent;
// Model // Model
Color _color; Color _color;
DVector<Vector3> _model_vertices; DVector<Vector3> _model_vertices;
DVector<Vector3> _model_normals; DVector<Vector3> _model_normals;
DVector<Vector2> _model_uv; DVector<Vector2> _model_uv;
DVector<Vector3> _model_side_vertices[SIDE_COUNT]; DVector<Vector3> _model_side_vertices[SIDE_COUNT];
DVector<Vector2> _model_side_uv[SIDE_COUNT]; DVector<Vector2> _model_side_uv[SIDE_COUNT];
// TODO Child voxel types // TODO Child voxel types
public: public:
Voxel(); Voxel();
// Properties // Properties
_FORCE_INLINE_ Ref<Voxel> set_name(String name) { _name = name; return Ref<Voxel>(this); } _FORCE_INLINE_ Ref<Voxel> set_name(String name) { _name = name; return Ref<Voxel>(this); }
_FORCE_INLINE_ String get_name() const { return _name; } _FORCE_INLINE_ String get_name() const { return _name; }
Ref<Voxel> set_id(int id); Ref<Voxel> set_id(int id);
_FORCE_INLINE_ int get_id() const { return _id; } _FORCE_INLINE_ int get_id() const { return _id; }
_FORCE_INLINE_ Ref<Voxel> set_color(Color color) { _color = color; return Ref<Voxel>(this); } _FORCE_INLINE_ Ref<Voxel> set_color(Color color) { _color = color; return Ref<Voxel>(this); }
_FORCE_INLINE_ Color get_color() const { return _color; } _FORCE_INLINE_ Color get_color() const { return _color; }
Ref<Voxel> set_material_id(unsigned int id); Ref<Voxel> set_material_id(unsigned int id);
_FORCE_INLINE_ unsigned int get_material_id() const { return _material_id; } _FORCE_INLINE_ unsigned int get_material_id() const { return _material_id; }
_FORCE_INLINE_ Ref<Voxel> set_transparent(bool t = true) { _is_transparent = t; return Ref<Voxel>(this); } _FORCE_INLINE_ Ref<Voxel> set_transparent(bool t = true) { _is_transparent = t; return Ref<Voxel>(this); }
_FORCE_INLINE_ bool is_transparent() const { return _is_transparent; } _FORCE_INLINE_ bool is_transparent() const { return _is_transparent; }
// Built-in geometry generators // Built-in geometry generators
Ref<Voxel> set_cube_geometry(float sy = 1); Ref<Voxel> set_cube_geometry(float sy = 1);
Ref<Voxel> set_cube_uv_all_sides(Vector2 atlas_pos); Ref<Voxel> set_cube_uv_all_sides(Vector2 atlas_pos);
Ref<Voxel> set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos); Ref<Voxel> set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos);
//Ref<Voxel> set_xquad_geometry(Vector2 atlas_pos); //Ref<Voxel> set_xquad_geometry(Vector2 atlas_pos);
// Getters for native usage only // Getters for native usage only
const DVector<Vector3> & get_model_vertices() const { return _model_vertices; } const DVector<Vector3> & get_model_vertices() const { return _model_vertices; }
const DVector<Vector3> & get_model_normals() const { return _model_normals; } const DVector<Vector3> & get_model_normals() const { return _model_normals; }
const DVector<Vector2> & get_model_uv() const { return _model_uv; } const DVector<Vector2> & get_model_uv() const { return _model_uv; }
const DVector<Vector3> & get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; } const DVector<Vector3> & get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; }
const DVector<Vector2> & get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; } const DVector<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: protected:
Ref<Voxel> _set_cube_uv_sides(const Vector2 atlas_pos[6]); Ref<Voxel> _set_cube_uv_sides(const Vector2 atlas_pos[6]);
static void _bind_methods(); static void _bind_methods();
}; };

View File

@ -10,254 +10,254 @@ VoxelBuffer::VoxelBuffer() {
} }
VoxelBuffer::~VoxelBuffer() { VoxelBuffer::~VoxelBuffer() {
clear(); clear();
} }
void VoxelBuffer::create(int sx, int sy, int sz) { void VoxelBuffer::create(int sx, int sy, int sz) {
if (sx <= 0 || sy <= 0 || sz <= 0) { if (sx <= 0 || sy <= 0 || sz <= 0) {
return; return;
} }
Vector3i new_size(sx, sy, sz); Vector3i new_size(sx, sy, sz);
if (new_size != _size) { if (new_size != _size) {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i]; Channel & channel = _channels[i];
if (channel.data) { if (channel.data) {
// TODO Optimize with realloc // TODO Optimize with realloc
delete_channel(i, _size); delete_channel(i, _size);
create_channel(i, new_size); create_channel(i, new_size);
} }
} }
_size = new_size; _size = new_size;
} }
} }
void VoxelBuffer::clear() { void VoxelBuffer::clear() {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) { for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i]; Channel & channel = _channels[i];
if (channel.data) { if (channel.data) {
delete_channel(i, _size); delete_channel(i, _size);
} }
} }
} }
void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) { void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
delete_channel(channel_index, _size); delete_channel(channel_index, _size);
_channels[channel_index].defval = clear_value; _channels[channel_index].defval = clear_value;
} }
int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) const { int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) const {
ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, 0); ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, 0);
const Channel & channel = _channels[channel_index];
if (validate_pos(x, y, z) && channel.data) { const Channel & channel = _channels[channel_index];
return VOXEL_AT(channel.data, x,y,z);
} if (validate_pos(x, y, z) && channel.data) {
else { return VOXEL_AT(channel.data, x,y,z);
return channel.defval; }
} else {
return channel.defval;
}
} }
void VoxelBuffer::set_voxel(int value, int x, int y, int z, unsigned int channel_index) { 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)); ERR_FAIL_COND(!validate_pos(x, y, z));
Channel & channel = _channels[channel_index]; Channel & channel = _channels[channel_index];
if (channel.defval != value) { if (channel.defval != value) {
if (channel.data == NULL) { if (channel.data == NULL) {
create_channel(channel_index, _size); create_channel(channel_index, _size);
} }
VOXEL_AT(channel.data, x, y, z) = value; VOXEL_AT(channel.data, x, y, z) = value;
} }
} }
void VoxelBuffer::set_voxel_v(int value, Vector3 pos, unsigned int channel_index) { void VoxelBuffer::set_voxel_v(int value, Vector3 pos, unsigned int channel_index) {
set_voxel(value, pos.x, pos.y, pos.z, channel_index); set_voxel(value, pos.x, pos.y, pos.z, 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];
if (channel.data == NULL && channel.defval == defval) if (channel.data == NULL && channel.defval == defval)
return; return;
else else
create_channel_noinit(channel_index, _size); create_channel_noinit(channel_index, _size);
unsigned int volume = get_volume(); unsigned int volume = get_volume();
memset(channel.data, defval, volume); memset(channel.data, defval, volume);
} }
void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index) { void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS); ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
Vector3i::sort_min_max(min, max); Vector3i::sort_min_max(min, max);
min.clamp_to(Vector3i(0, 0, 0), _size); 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; Vector3i area_size = max - min;
Channel & channel = _channels[channel_index]; Channel & channel = _channels[channel_index];
if (channel.data == NULL) { if (channel.data == NULL) {
if (channel.defval == defval) if (channel.defval == defval)
return; return;
else else
create_channel(channel_index, _size); create_channel(channel_index, _size);
} }
Vector3i pos; Vector3i pos;
for (pos.z = min.z; pos.z < max.z; ++pos.z) { for (pos.z = min.z; pos.z < max.z; ++pos.z) {
for (pos.x = min.x; pos.x < max.x; ++pos.x) { for (pos.x = min.x; pos.x < max.x; ++pos.x) {
unsigned int dst_ri = index(pos.x, pos.y + min.y, pos.z); unsigned int dst_ri = index(pos.x, pos.y + min.y, pos.z);
memset(&channel.data[dst_ri], defval, area_size.y * sizeof(uint8_t)); memset(&channel.data[dst_ri], defval, area_size.y * sizeof(uint8_t));
} }
} }
} }
bool VoxelBuffer::is_uniform(unsigned int channel_index) { bool VoxelBuffer::is_uniform(unsigned int channel_index) {
ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, true); ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, true);
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];
unsigned int volume = get_volume();
for (unsigned int i = 0; i < volume; ++i) {
if (channel.data[i] != voxel) {
return false;
}
}
return true; uint8_t voxel = channel.data[0];
unsigned int volume = get_volume();
for (unsigned int i = 0; i < volume; ++i) {
if (channel.data[i] != voxel) {
return false;
}
}
return true;
} }
void VoxelBuffer::optimize() { 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]); clear_channel(i, _channels[i].data[0]);
} }
} }
} }
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_INDEX(channel_index, MAX_CHANNELS);
ERR_FAIL_COND(other._size == _size); ERR_FAIL_COND(other._size == _size);
Channel & channel = _channels[channel_index]; Channel & channel = _channels[channel_index];
const Channel & other_channel = other._channels[channel_index]; const Channel & other_channel = other._channels[channel_index];
if (other_channel.data) { if (other_channel.data) {
if (channel.data == NULL) { if (channel.data == NULL) {
create_channel_noinit(channel_index, _size); create_channel_noinit(channel_index, _size);
} }
memcpy(channel.data, other_channel.data, get_volume() * sizeof(uint8_t)); memcpy(channel.data, other_channel.data, get_volume() * sizeof(uint8_t));
} }
else if(channel.data) { else if(channel.data) {
delete_channel(channel_index, _size); delete_channel(channel_index, _size);
} }
channel.defval = other_channel.defval; 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); ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
Channel & channel = _channels[channel_index]; Channel & channel = _channels[channel_index];
const Channel & other_channel = other._channels[channel_index]; const Channel & other_channel = other._channels[channel_index];
Vector3i::sort_min_max(src_min, src_max); Vector3i::sort_min_max(src_min, src_max);
src_min.clamp_to(Vector3i(0, 0, 0), other._size); 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); dst_min.clamp_to(Vector3i(0, 0, 0), _size);
Vector3i area_size = src_max - src_min; Vector3i area_size = src_max - src_min;
//Vector3i dst_max = dst_min + area_size; //Vector3i dst_max = dst_min + area_size;
if (area_size == _size) { if (area_size == _size) {
copy_from(other, channel_index); copy_from(other, channel_index);
} }
else { else {
if (other_channel.data) { if (other_channel.data) {
if (channel.data == NULL) { if (channel.data == NULL) {
create_channel(channel_index, _size); create_channel(channel_index, _size);
} }
// Copy row by row // Copy row by row
Vector3i pos; Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) { for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
for (pos.x = 0; pos.x < area_size.x; ++pos.x) { for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
// Row direction is Y // Row direction is Y
unsigned int src_ri = other.index(pos.x + src_min.x, pos.y + src_min.y, pos.z + src_min.z); unsigned int src_ri = other.index(pos.x + src_min.x, pos.y + src_min.y, pos.z + src_min.z);
unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z); unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
memcpy(&channel.data[dst_ri], &other_channel.data[src_ri], area_size.y * sizeof(uint8_t)); 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) { if (channel.data == NULL) {
create_channel(channel_index, _size); create_channel(channel_index, _size);
} }
// Set row by row // Set row by row
Vector3i pos; Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) { for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
for (pos.x = 0; pos.x < area_size.x; ++pos.x) { for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z); unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
memset(&channel.data[dst_ri], other_channel.defval, area_size.y * sizeof(uint8_t)); memset(&channel.data[dst_ri], other_channel.defval, area_size.y * sizeof(uint8_t));
} }
} }
} }
} }
} }
void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) { void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) {
create_channel_noinit(i, size); create_channel_noinit(i, size);
memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t)); memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t));
} }
void VoxelBuffer::create_channel_noinit(int i, Vector3i size) { 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; 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, Vector3i size) { void VoxelBuffer::delete_channel(int i, Vector3i size) {
Channel & channel = _channels[i]; Channel & channel = _channels[i];
memfree(channel.data); memfree(channel.data);
channel.data = NULL; channel.data = NULL;
} }
void VoxelBuffer::_bind_methods() { void VoxelBuffer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create); ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create);
ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear); ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear);
ObjectTypeDB::bind_method(_MD("get_size_x"), &VoxelBuffer::get_size_x); ObjectTypeDB::bind_method(_MD("get_size_x"), &VoxelBuffer::get_size_x);
ObjectTypeDB::bind_method(_MD("get_size_y"), &VoxelBuffer::get_size_y); ObjectTypeDB::bind_method(_MD("get_size_y"), &VoxelBuffer::get_size_y);
ObjectTypeDB::bind_method(_MD("get_size_z"), &VoxelBuffer::get_size_z); ObjectTypeDB::bind_method(_MD("get_size_z"), &VoxelBuffer::get_size_z);
ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "channel"), &VoxelBuffer::_set_voxel_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "channel"), &VoxelBuffer::_set_voxel_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("set_voxel_v", "value", "pos", "channel"), &VoxelBuffer::set_voxel_v, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("set_voxel_v", "value", "pos", "channel"), &VoxelBuffer::set_voxel_v, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "channel"), &VoxelBuffer::_get_voxel_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "channel"), &VoxelBuffer::_get_voxel_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("fill", "value", "channel"), &VoxelBuffer::fill, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("fill", "value", "channel"), &VoxelBuffer::fill, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("fill_area", "value", "min", "max", "channel"), &VoxelBuffer::_fill_area_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("fill_area", "value", "min", "max", "channel"), &VoxelBuffer::_fill_area_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("copy_from", "other:VoxelBuffer", "channel"), &VoxelBuffer::_copy_from_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("copy_from", "other:VoxelBuffer", "channel"), &VoxelBuffer::_copy_from_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("copy_from_area", "other:VoxelBuffer", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_copy_from_area_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("copy_from_area", "other:VoxelBuffer", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_copy_from_area_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize); ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize);
} }
void VoxelBuffer::_copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel) { void VoxelBuffer::_copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel) {
ERR_FAIL_COND(other.is_null()); ERR_FAIL_COND(other.is_null());
copy_from(**other, channel); copy_from(**other, channel);
} }
void VoxelBuffer::_copy_from_area_binding(Ref<VoxelBuffer> other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, unsigned int channel) { void VoxelBuffer::_copy_from_area_binding(Ref<VoxelBuffer> other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, unsigned int channel) {
ERR_FAIL_COND(other.is_null()); ERR_FAIL_COND(other.is_null());
copy_from(**other, Vector3i(src_min), Vector3i(src_max), Vector3i(dst_min), channel); copy_from(**other, Vector3i(src_min), Vector3i(src_max), Vector3i(dst_min), channel);
} }

View File

@ -10,93 +10,93 @@
// Note: for float storage (marching cubes for example), you can map [0..256] to [0..1] and save 3 bytes per cell // Note: for float storage (marching cubes for example), you can map [0..256] to [0..1] and save 3 bytes per cell
class VoxelBuffer : public Reference { class VoxelBuffer : public Reference {
OBJ_TYPE(VoxelBuffer, Reference) OBJ_TYPE(VoxelBuffer, Reference)
public: public:
// Arbitrary value, 8 should be enough. Tweak for your needs. // Arbitrary value, 8 should be enough. Tweak for your needs.
static const int MAX_CHANNELS = 8; static const int MAX_CHANNELS = 8;
private: private:
struct Channel { struct Channel {
// Allocated when the channel is populated. // 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). // 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 // Default value when data is null
uint8_t defval; uint8_t defval;
Channel() : data(NULL), defval(0) {}
};
// Each channel can store arbitary data. Channel() : data(NULL), defval(0) {}
// For example, you can decide to store colors (R, G, B, A), gameplay types (type, state, light) or both. };
Channel _channels[MAX_CHANNELS];
// How many voxels are there in the three directions. All populated channels have the same size. // Each channel can store arbitary data.
Vector3i _size; // For example, you can decide to store colors (R, G, B, A), gameplay types (type, state, light) or both.
Channel _channels[MAX_CHANNELS];
// How many voxels are there in the three directions. All populated channels have the same size.
Vector3i _size;
public: public:
VoxelBuffer(); VoxelBuffer();
~VoxelBuffer(); ~VoxelBuffer();
void create(int sx, int sy, int sz); void create(int sx, int sy, int sz);
void clear(); 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; } _FORCE_INLINE_ Vector3i get_size() const { return _size; }
int get_voxel(int x, int y, int z, unsigned int channel_index=0) const; 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(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); void set_voxel_v(int value, Vector3 pos, unsigned int channel_index = 0);
_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_ 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); } _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); }
void fill(int defval, unsigned int channel_index = 0); void fill(int defval, unsigned int channel_index = 0);
void fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index = 0); void fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index = 0);
bool is_uniform(unsigned int channel_index = 0); bool is_uniform(unsigned int channel_index = 0);
void optimize(); void optimize();
void copy_from(const VoxelBuffer & other, 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); 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 { _FORCE_INLINE_ bool validate_pos(unsigned int x, unsigned int y, unsigned int z) const {
return x < _size.x return x < _size.x
&& y < _size.y && y < _size.y
&& z < _size.x; && z < _size.x;
} }
_FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const { _FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x + y; return (z * _size.z + x) * _size.x + y;
} }
_FORCE_INLINE_ unsigned int row_index(unsigned int x, unsigned int y, unsigned int z) const { _FORCE_INLINE_ unsigned int row_index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x; return (z * _size.z + x) * _size.x;
} }
_FORCE_INLINE_ unsigned int get_volume() { _FORCE_INLINE_ unsigned int get_volume() {
return _size.x * _size.y * _size.z; return _size.x * _size.y * _size.z;
} }
private: private:
void create_channel_noinit(int i, Vector3i size); 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, Vector3i size); void delete_channel(int i, Vector3i size);
protected: protected:
static void _bind_methods(); static void _bind_methods();
_FORCE_INLINE_ int get_size_x() const { return _size.x; }
_FORCE_INLINE_ int get_size_y() const { return _size.y; }
_FORCE_INLINE_ int get_size_z() const { return _size.z; }
_FORCE_INLINE_ int _get_voxel_binding(int x, int y, int z, unsigned int channel) const { return get_voxel(x, y, z, channel); } _FORCE_INLINE_ int get_size_x() const { return _size.x; }
_FORCE_INLINE_ void _set_voxel_binding(int value, int x, int y, int z, unsigned int channel) { set_voxel(value, x, y, z, channel); } _FORCE_INLINE_ int get_size_y() const { return _size.y; }
void _copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel); _FORCE_INLINE_ int get_size_z() const { return _size.z; }
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_ int _get_voxel_binding(int x, int y, int z, unsigned int channel) const { return get_voxel(x, y, z, channel); }
_FORCE_INLINE_ void _set_voxel_binding(int value, int x, int y, int z, unsigned int channel) { set_voxel(value, x, y, z, channel); }
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); }
}; };

View File

@ -1,36 +1,36 @@
#include "voxel_library.h" #include "voxel_library.h"
VoxelLibrary::VoxelLibrary() : Reference(), _atlas_size(1) { VoxelLibrary::VoxelLibrary() : Reference(), _atlas_size(1) {
create_voxel(0, "air")->set_transparent(true); create_voxel(0, "air")->set_transparent(true);
} }
VoxelLibrary::~VoxelLibrary() { VoxelLibrary::~VoxelLibrary() {
for (unsigned int i = 0; i < MAX_VOXEL_TYPES; ++i) { for (unsigned int i = 0; i < MAX_VOXEL_TYPES; ++i) {
if (_voxel_types[i].is_valid()) { if (_voxel_types[i].is_valid()) {
_voxel_types[i]->set_library_ptr(NULL); _voxel_types[i]->set_library_ptr(NULL);
} }
} }
} }
void VoxelLibrary::set_atlas_size(int s) { void VoxelLibrary::set_atlas_size(int s) {
ERR_FAIL_COND(s <= 0); ERR_FAIL_COND(s <= 0);
_atlas_size = s; _atlas_size = s;
} }
Ref<Voxel> VoxelLibrary::create_voxel(int id, String name) { Ref<Voxel> VoxelLibrary::create_voxel(int id, String name) {
ERR_FAIL_COND_V(id < 0 || id >= MAX_VOXEL_TYPES, Ref<Voxel>()); ERR_FAIL_COND_V(id < 0 || id >= MAX_VOXEL_TYPES, Ref<Voxel>());
Ref<Voxel> voxel(memnew(Voxel)); Ref<Voxel> voxel(memnew(Voxel));
voxel->set_library_ptr(this); voxel->set_library_ptr(this);
voxel->set_id(id); voxel->set_id(id);
voxel->set_name(name); voxel->set_name(name);
_voxel_types[id] = voxel; _voxel_types[id] = voxel;
return voxel; return voxel;
} }
void VoxelLibrary::_bind_methods() { void VoxelLibrary::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create_voxel:Voxel", "id", "name"), &VoxelLibrary::create_voxel); ObjectTypeDB::bind_method(_MD("create_voxel:Voxel", "id", "name"), &VoxelLibrary::create_voxel);
ObjectTypeDB::bind_method(_MD("set_atlas_size", "square_size"), &VoxelLibrary::set_atlas_size); ObjectTypeDB::bind_method(_MD("set_atlas_size", "square_size"), &VoxelLibrary::set_atlas_size);
} }

View File

@ -5,31 +5,31 @@
#include "voxel.h" #include "voxel.h"
class VoxelLibrary : public Reference { class VoxelLibrary : public Reference {
OBJ_TYPE(VoxelLibrary, Reference) OBJ_TYPE(VoxelLibrary, Reference)
public: public:
static const unsigned int MAX_VOXEL_TYPES = 256; // Required limit because voxel types are stored in 8 bits static const unsigned int MAX_VOXEL_TYPES = 256; // Required limit because voxel types are stored in 8 bits
VoxelLibrary(); VoxelLibrary();
~VoxelLibrary(); ~VoxelLibrary();
int get_atlas_size() const { return _atlas_size; } int get_atlas_size() const { return _atlas_size; }
void set_atlas_size(int s); void set_atlas_size(int s);
// Use this factory rather than creating voxels from scratch // Use this factory rather than creating voxels from scratch
Ref<Voxel> create_voxel(int id, String name); Ref<Voxel> create_voxel(int id, String name);
// Internal getters // Internal getters
_FORCE_INLINE_ bool has_voxel(int id) const { return _voxel_types[id].is_valid(); } _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]; }
private: private:
Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES]; Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES];
int _atlas_size; int _atlas_size;
protected: protected:
static void _bind_methods(); static void _bind_methods();
}; };

View File

@ -1,9 +1,9 @@
#include "voxel_map.h" #include "voxel_map.h"
VoxelMap::VoxelMap() : _last_accessed_block(NULL) { VoxelMap::VoxelMap() : _last_accessed_block(NULL) {
for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) { for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) {
_default_voxel[i] = 0; _default_voxel[i] = 0;
} }
} }
VoxelMap::~VoxelMap() { VoxelMap::~VoxelMap() {
@ -11,21 +11,21 @@ VoxelMap::~VoxelMap() {
} }
int VoxelMap::get_voxel(Vector3i pos, unsigned int c) { int VoxelMap::get_voxel(Vector3i pos, unsigned int c) {
Vector3i bpos = voxel_to_block(pos); Vector3i bpos = voxel_to_block(pos);
VoxelBlock * block = get_block(bpos); VoxelBlock * block = get_block(bpos);
if (block == NULL) { if (block == NULL) {
return _default_voxel[c]; return _default_voxel[c];
} }
return block->voxels->get_voxel(pos - block_to_voxel(bpos), c); return block->voxels->get_voxel(pos - block_to_voxel(bpos), c);
} }
MeshInstance * VoxelBlock::get_mesh_instance(const Node & root) { MeshInstance * VoxelBlock::get_mesh_instance(const Node & root) {
if (mesh_instance_path.is_empty()) if (mesh_instance_path.is_empty())
return NULL; return NULL;
Node * n = root.get_node(mesh_instance_path); Node * n = root.get_node(mesh_instance_path);
if (n == NULL) if (n == NULL)
return NULL; return NULL;
return n->cast_to<MeshInstance>(); return n->cast_to<MeshInstance>();
} }
VoxelBlock::~VoxelBlock() { VoxelBlock::~VoxelBlock() {
@ -34,204 +34,204 @@ VoxelBlock::~VoxelBlock() {
// Helper // Helper
VoxelBlock * VoxelBlock::create(Vector3i bpos, VoxelBuffer * buffer) { VoxelBlock * VoxelBlock::create(Vector3i bpos, VoxelBuffer * buffer) {
VoxelBlock * block = memnew(VoxelBlock); VoxelBlock * block = memnew(VoxelBlock);
block->pos = bpos; block->pos = bpos;
if (buffer) { if (buffer) {
const int bs = VoxelBlock::SIZE; const int bs = VoxelBlock::SIZE;
ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL); ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL);
} }
else { else {
buffer = memnew(VoxelBuffer); buffer = memnew(VoxelBuffer);
} }
ERR_FAIL_COND_V(buffer == NULL, NULL); ERR_FAIL_COND_V(buffer == NULL, NULL);
block->voxels = Ref<VoxelBuffer>(buffer); block->voxels = Ref<VoxelBuffer>(buffer);
//block->map = &map; //block->map = &map;
return block; return block;
} }
void VoxelMap::set_voxel(int value, Vector3i pos, unsigned int c) { void VoxelMap::set_voxel(int value, Vector3i pos, unsigned int c) {
Vector3i bpos = voxel_to_block(pos); Vector3i bpos = voxel_to_block(pos);
VoxelBlock * block = get_block(bpos); VoxelBlock * block = get_block(bpos);
if (block == NULL) { if (block == NULL) {
block = VoxelBlock::create(bpos); block = VoxelBlock::create(bpos);
set_block(bpos, block); set_block(bpos, block);
} }
block->voxels->set_voxel(value, pos - block_to_voxel(bpos), c); block->voxels->set_voxel(value, pos - block_to_voxel(bpos), c);
} }
void VoxelMap::set_default_voxel(int value, unsigned int channel) { void VoxelMap::set_default_voxel(int value, unsigned int channel) {
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS); ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
_default_voxel[channel] = value; _default_voxel[channel] = value;
} }
int VoxelMap::get_default_voxel(unsigned int channel) { int VoxelMap::get_default_voxel(unsigned int channel) {
ERR_FAIL_INDEX_V(channel, VoxelBuffer::MAX_CHANNELS, 0); ERR_FAIL_INDEX_V(channel, VoxelBuffer::MAX_CHANNELS, 0);
return _default_voxel[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) { if (_last_accessed_block && _last_accessed_block->pos == bpos) {
return _last_accessed_block; return _last_accessed_block;
} }
Ref<VoxelBlock> * p = _blocks.getptr(bpos); Ref<VoxelBlock> * p = _blocks.getptr(bpos);
if (p) { if (p) {
_last_accessed_block = p->ptr(); _last_accessed_block = p->ptr();
return _last_accessed_block; return _last_accessed_block;
} }
return NULL; return NULL;
} }
void VoxelMap::set_block(Vector3i bpos, VoxelBlock * block) { void VoxelMap::set_block(Vector3i bpos, VoxelBlock * block) {
if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) { if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) {
_last_accessed_block = block; _last_accessed_block = block;
} }
_blocks.set(bpos, block); _blocks.set(bpos, block);
} }
void VoxelMap::set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer) { void VoxelMap::set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer) {
ERR_FAIL_COND(buffer.is_null()); ERR_FAIL_COND(buffer.is_null());
VoxelBlock * block = get_block(bpos); VoxelBlock * block = get_block(bpos);
if (block == NULL) { if (block == NULL) {
block = VoxelBlock::create(bpos, *buffer); block = VoxelBlock::create(bpos, *buffer);
set_block(bpos, block); set_block(bpos, block);
} }
else { else {
block->voxels = buffer; block->voxels = buffer;
} }
} }
bool VoxelMap::has_block(Vector3i pos) const { bool VoxelMap::has_block(Vector3i pos) const {
return /*(_last_accessed_block != NULL && _last_accessed_block->pos == pos) ||*/ _blocks.has(pos); return /*(_last_accessed_block != NULL && _last_accessed_block->pos == pos) ||*/ _blocks.has(pos);
} }
Vector3i g_moore_neighboring_3d[26] = { Vector3i g_moore_neighboring_3d[26] = {
Vector3i(-1,-1,-1), Vector3i(-1,-1,-1),
Vector3i(0,-1,-1), Vector3i(0,-1,-1),
Vector3i(1,-1,-1), Vector3i(1,-1,-1),
Vector3i(-1,-1,0), Vector3i(-1,-1,0),
Vector3i(0,-1,0), Vector3i(0,-1,0),
Vector3i(1,-1,0), Vector3i(1,-1,0),
Vector3i(-1,-1,1), Vector3i(-1,-1,1),
Vector3i(0,-1,1), Vector3i(0,-1,1),
Vector3i(1,-1,1), Vector3i(1,-1,1),
Vector3i(-1,0,-1), Vector3i(-1,0,-1),
Vector3i(0,0,-1), Vector3i(0,0,-1),
Vector3i(1,0,-1), Vector3i(1,0,-1),
Vector3i(-1,0,0), Vector3i(-1,0,0),
//Vector3i(0,0,0), //Vector3i(0,0,0),
Vector3i(1,0,0), Vector3i(1,0,0),
Vector3i(-1,0,1), Vector3i(-1,0,1),
Vector3i(0,0,1), Vector3i(0,0,1),
Vector3i(1,0,1), Vector3i(1,0,1),
Vector3i(-1,1,-1), Vector3i(-1,1,-1),
Vector3i(0,1,-1), Vector3i(0,1,-1),
Vector3i(1,1,-1), Vector3i(1,1,-1),
Vector3i(-1,1,0), Vector3i(-1,1,0),
Vector3i(0,1,0), Vector3i(0,1,0),
Vector3i(1,1,0), Vector3i(1,1,0),
Vector3i(-1,1,1), Vector3i(-1,1,1),
Vector3i(0,1,1), Vector3i(0,1,1),
Vector3i(1,1,1), Vector3i(1,1,1),
}; };
bool VoxelMap::is_block_surrounded(Vector3i pos) const { bool VoxelMap::is_block_surrounded(Vector3i pos) const {
for (unsigned int i = 0; i < 26; ++i) { for (unsigned int i = 0; i < 26; ++i) {
Vector3i bpos = pos + g_moore_neighboring_3d[i]; Vector3i bpos = pos + g_moore_neighboring_3d[i];
if (!has_block(bpos)) { if (!has_block(bpos)) {
return false; return false;
} }
} }
return true; return true;
} }
void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsigned int channel) { void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsigned int channel) {
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS); ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
Vector3i max_pos = min_pos + dst_buffer.get_size(); Vector3i max_pos = min_pos + dst_buffer.get_size();
Vector3i min_block_pos = voxel_to_block(min_pos); 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)); ERR_FAIL_COND((max_block_pos - min_block_pos) != Vector3(3, 3, 3));
Vector3i bpos; Vector3i bpos;
for (bpos.z = min_block_pos.z; bpos.z < max_block_pos.z; ++bpos.z) { for (bpos.z = min_block_pos.z; bpos.z < max_block_pos.z; ++bpos.z) {
for (bpos.x = min_block_pos.x; bpos.x < max_block_pos.x; ++bpos.x) { 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) { 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) { if (block) {
VoxelBuffer & src_buffer = **block->voxels; VoxelBuffer & src_buffer = **block->voxels;
Vector3i offset = block_to_voxel(bpos); Vector3i offset = block_to_voxel(bpos);
// Note: copy_from takes care of clamping the area if it's on an edge // 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); dst_buffer.copy_from(src_buffer, min_pos - offset, max_pos - offset, offset - min_pos, channel);
} }
else { else {
Vector3i offset = block_to_voxel(bpos); Vector3i offset = block_to_voxel(bpos);
dst_buffer.fill_area( dst_buffer.fill_area(
_default_voxel[channel], _default_voxel[channel],
offset - min_pos, offset - min_pos,
offset - min_pos + Vector3i(VoxelBlock::SIZE,VoxelBlock::SIZE, VoxelBlock::SIZE) offset - min_pos + Vector3i(VoxelBlock::SIZE,VoxelBlock::SIZE, VoxelBlock::SIZE)
); );
} }
} }
} }
} }
} }
void VoxelMap::remove_blocks_not_in_area(Vector3i min, Vector3i max) { void VoxelMap::remove_blocks_not_in_area(Vector3i min, Vector3i max) {
Vector3i::sort_min_max(min, max); Vector3i::sort_min_max(min, max);
Vector<Vector3i> to_remove; Vector<Vector3i> to_remove;
Vector3i * key = NULL; Vector3i * key = NULL;
while (_blocks.next(key)) { while (_blocks.next(key)) {
Ref<VoxelBlock> & block_ref = _blocks.get(*key); Ref<VoxelBlock> & block_ref = _blocks.get(*key);
ERR_FAIL_COND(block_ref.is_null()); // Should never trigger ERR_FAIL_COND(block_ref.is_null()); // Should never trigger
VoxelBlock & block = **block_ref; VoxelBlock & block = **block_ref;
if (!block.pos.is_contained_in(min, max)) { if (!block.pos.is_contained_in(min, max)) {
//if (_observer) //if (_observer)
// _observer->block_removed(block); // _observer->block_removed(block);
to_remove.push_back(*key); to_remove.push_back(*key);
if (&block == _last_accessed_block) if (&block == _last_accessed_block)
_last_accessed_block = NULL; _last_accessed_block = NULL;
} }
} }
for (unsigned int i = 0; i < to_remove.size(); ++i) { for (unsigned int i = 0; i < to_remove.size(); ++i) {
_blocks.erase(to_remove[i]); _blocks.erase(to_remove[i]);
} }
} }
void VoxelMap::_bind_methods() { void VoxelMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "c"), &VoxelMap::_get_voxel_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "c"), &VoxelMap::_get_voxel_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "c"), &VoxelMap::_set_voxel_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "c"), &VoxelMap::_set_voxel_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_default_voxel", "channel"), &VoxelMap::get_default_voxel, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_default_voxel", "channel"), &VoxelMap::get_default_voxel, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("set_default_voxel", "value", "channel"), &VoxelMap::set_default_voxel, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("set_default_voxel", "value", "channel"), &VoxelMap::set_default_voxel, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("has_block", "x", "y", "z"), &VoxelMap::_has_block_binding); ObjectTypeDB::bind_method(_MD("has_block", "x", "y", "z"), &VoxelMap::_has_block_binding);
ObjectTypeDB::bind_method(_MD("get_buffer_copy", "min_pos", "out_buffer:VoxelBuffer", "channel"), &VoxelMap::_get_buffer_copy_binding, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_buffer_copy", "min_pos", "out_buffer:VoxelBuffer", "channel"), &VoxelMap::_get_buffer_copy_binding, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("set_block_buffer", "block_pos", "buffer:VoxelBuffer"), &VoxelMap::_set_block_buffer_binding); ObjectTypeDB::bind_method(_MD("set_block_buffer", "block_pos", "buffer:VoxelBuffer"), &VoxelMap::_set_block_buffer_binding);
ObjectTypeDB::bind_method(_MD("voxel_to_block", "voxel_pos"), &VoxelMap::_voxel_to_block_binding); ObjectTypeDB::bind_method(_MD("voxel_to_block", "voxel_pos"), &VoxelMap::_voxel_to_block_binding);
ObjectTypeDB::bind_method(_MD("block_to_voxel", "block_pos"), &VoxelMap::_block_to_voxel_binding); ObjectTypeDB::bind_method(_MD("block_to_voxel", "block_pos"), &VoxelMap::_block_to_voxel_binding);
ObjectTypeDB::bind_method(_MD("get_block_size"), &VoxelMap::get_block_size); ObjectTypeDB::bind_method(_MD("get_block_size"), &VoxelMap::get_block_size);
//ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations"), _SCS("set_iterations"), _SCS("get_iterations")); //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) { void VoxelMap::_get_buffer_copy_binding(Vector3 pos, Ref<VoxelBuffer> dst_buffer_ref, unsigned int channel) {
ERR_FAIL_COND(dst_buffer_ref.is_null()); ERR_FAIL_COND(dst_buffer_ref.is_null());
get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel); get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel);
} }

View File

@ -10,24 +10,24 @@ class VoxelMap;
// Fixed-size voxel container used in VoxelMap. Used internally. // Fixed-size voxel container used in VoxelMap. Used internally.
class VoxelBlock : public Reference { class VoxelBlock : public Reference {
OBJ_TYPE(VoxelBlock, Reference) OBJ_TYPE(VoxelBlock, Reference)
public: public:
static const int SIZE_POW2 = 4; // 3=>8, 4=>16, 5=>32... static const int SIZE_POW2 = 4; // 3=>8, 4=>16, 5=>32...
static const int SIZE = 1 << SIZE_POW2; static const int SIZE = 1 << SIZE_POW2;
Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels
Vector3i pos; Vector3i pos;
NodePath mesh_instance_path; NodePath mesh_instance_path;
//VoxelMap * map; //VoxelMap * map;
MeshInstance * get_mesh_instance(const Node & root); MeshInstance * get_mesh_instance(const Node & root);
static VoxelBlock * create(Vector3i bpos, VoxelBuffer * buffer = 0); static VoxelBlock * create(Vector3i bpos, VoxelBuffer * buffer = 0);
~VoxelBlock(); ~VoxelBlock();
private: private:
VoxelBlock() : Reference(), voxels(NULL) {} VoxelBlock() : Reference(), voxels(NULL) {}
}; };
@ -38,78 +38,78 @@ private:
// Infinite voxel storage by means of octants like Gridmap // Infinite voxel storage by means of octants like Gridmap
class VoxelMap : public Reference { class VoxelMap : public Reference {
OBJ_TYPE(VoxelMap, Reference) OBJ_TYPE(VoxelMap, Reference)
// Voxel values that will be returned if access is out of map bounds // Voxel values that will be returned if access is out of map bounds
uint8_t _default_voxel[VoxelBuffer::MAX_CHANNELS]; uint8_t _default_voxel[VoxelBuffer::MAX_CHANNELS];
// Blocks stored with a spatial hash in all 3D directions // Blocks stored with a spatial hash in all 3D directions
HashMap<Vector3i, Ref<VoxelBlock>, Vector3iHasher> _blocks; HashMap<Vector3i, Ref<VoxelBlock>, Vector3iHasher> _blocks;
// Voxel access will most frequently be in contiguous areas, so the same blocks are accessed. // 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. // To prevent too much hashing, this reference is checked before.
VoxelBlock * _last_accessed_block; VoxelBlock * _last_accessed_block;
//IVoxelMapObserver * _observer; //IVoxelMapObserver * _observer;
public: public:
VoxelMap(); VoxelMap();
~VoxelMap(); ~VoxelMap();
int get_voxel(Vector3i pos, unsigned int c = 0); int get_voxel(Vector3i pos, unsigned int c = 0);
void set_voxel(int value, 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); void set_default_voxel(int value, unsigned int channel=0);
int get_default_voxel(unsigned int channel=0); int get_default_voxel(unsigned int channel=0);
// Converts voxel coodinates into block coordinates // Converts voxel coodinates into block coordinates
static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) { static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) {
return Vector3i( return Vector3i(
//pos.x < 0 ? (pos.x + 1) / VoxelBlock::SIZE - 1 : pos.x / VoxelBlock::SIZE, //pos.x < 0 ? (pos.x + 1) / VoxelBlock::SIZE - 1 : pos.x / VoxelBlock::SIZE,
//pos.y < 0 ? (pos.y + 1) / VoxelBlock::SIZE - 1 : pos.y / VoxelBlock::SIZE, //pos.y < 0 ? (pos.y + 1) / VoxelBlock::SIZE - 1 : pos.y / VoxelBlock::SIZE,
//pos.z < 0 ? (pos.z + 1) / VoxelBlock::SIZE - 1 : pos.z / VoxelBlock::SIZE //pos.z < 0 ? (pos.z + 1) / VoxelBlock::SIZE - 1 : pos.z / VoxelBlock::SIZE
pos.x >> VoxelBlock::SIZE_POW2, pos.x >> VoxelBlock::SIZE_POW2,
pos.y >> VoxelBlock::SIZE_POW2, pos.y >> VoxelBlock::SIZE_POW2,
pos.z >> VoxelBlock::SIZE_POW2 pos.z >> VoxelBlock::SIZE_POW2
); );
} }
// Converts block coodinates into voxel coordinates // Converts block coodinates into voxel coordinates
static _FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) { static _FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) {
return bpos * VoxelBlock::SIZE; return bpos * VoxelBlock::SIZE;
} }
// Gets a copy of all voxels in the area starting at min_pos having the same size as dst_buffer. // 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 channel = 0); void get_buffer_copy(Vector3i min_pos, VoxelBuffer & dst_buffer, unsigned int channel = 0);
// Moves the given buffer into a block of the map. The buffer is referenced, no copy is made. // 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 set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer);
void remove_blocks_not_in_area(Vector3i min, Vector3i max); void remove_blocks_not_in_area(Vector3i min, Vector3i max);
_FORCE_INLINE_ Ref<VoxelBlock> get_block_ref(Vector3i bpos) { return get_block(bpos); } _FORCE_INLINE_ Ref<VoxelBlock> get_block_ref(Vector3i bpos) { return get_block(bpos); }
bool has_block(Vector3i pos) const; bool has_block(Vector3i pos) const;
bool is_block_surrounded(Vector3i pos) const; bool is_block_surrounded(Vector3i pos) const;
//void set_observer(IVoxelMapObserver * observer) { _observer = observer; } //void set_observer(IVoxelMapObserver * observer) { _observer = observer; }
private: private:
VoxelBlock * get_block(Vector3i bpos); VoxelBlock * get_block(Vector3i bpos);
void set_block(Vector3i bpos, VoxelBlock * block); void set_block(Vector3i bpos, VoxelBlock * block);
_FORCE_INLINE_ int get_block_size() const { return VoxelBlock::SIZE; } _FORCE_INLINE_ int get_block_size() const { return VoxelBlock::SIZE; }
static void _bind_methods(); static void _bind_methods();
_FORCE_INLINE_ int _get_voxel_binding(int x, int y, int z, unsigned int c = 0) { return get_voxel(Vector3i(x, y, z), c); } _FORCE_INLINE_ int _get_voxel_binding(int x, int y, int z, unsigned int c = 0) { return get_voxel(Vector3i(x, y, z), c); }
_FORCE_INLINE_ void _set_voxel_binding(int value, int x, int y, int z, unsigned int c = 0) { set_voxel(value, Vector3i(x, y, z), c); } _FORCE_INLINE_ void _set_voxel_binding(int value, int x, int y, int z, unsigned int c = 0) { set_voxel(value, Vector3i(x, y, z), c); }
_FORCE_INLINE_ bool _has_block_binding(int x, int y, int z) { return has_block(Vector3i(x, y, z)); } _FORCE_INLINE_ bool _has_block_binding(int x, int y, int z) { return has_block(Vector3i(x, y, z)); }
_FORCE_INLINE_ Vector3 _voxel_to_block_binding(Vector3 pos) const { return voxel_to_block(Vector3i(pos)).to_vec3(); } _FORCE_INLINE_ Vector3 _voxel_to_block_binding(Vector3 pos) const { return voxel_to_block(Vector3i(pos)).to_vec3(); }
_FORCE_INLINE_ Vector3 _block_to_voxel_binding(Vector3 pos) const { return block_to_voxel(Vector3i(pos)).to_vec3(); } _FORCE_INLINE_ Vector3 _block_to_voxel_binding(Vector3 pos) const { return block_to_voxel(Vector3i(pos)).to_vec3(); }
bool _is_block_surrounded(Vector3 pos) const { return is_block_surrounded(Vector3i(pos)); } bool _is_block_surrounded(Vector3 pos) const { return is_block_surrounded(Vector3i(pos)); }
void _get_buffer_copy_binding(Vector3 pos, Ref<VoxelBuffer> dst_buffer_ref, unsigned int channel = 0); void _get_buffer_copy_binding(Vector3 pos, Ref<VoxelBuffer> dst_buffer_ref, unsigned int channel = 0);
void _set_block_buffer_binding(Vector3 bpos, Ref<VoxelBuffer> buffer) { set_block_buffer(Vector3i(bpos), buffer); } void _set_block_buffer_binding(Vector3 bpos, Ref<VoxelBuffer> buffer) { set_block_buffer(Vector3i(bpos), buffer); }
}; };

View File

@ -9,35 +9,35 @@
#include "voxel_library.h" #include "voxel_library.h"
class VoxelMesher : public Reference { class VoxelMesher : public Reference {
OBJ_TYPE(VoxelMesher, Reference); OBJ_TYPE(VoxelMesher, Reference);
public: public:
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed. static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
private: private:
Ref<VoxelLibrary> _library; Ref<VoxelLibrary> _library;
Ref<Material> _materials[MAX_MATERIALS]; Ref<Material> _materials[MAX_MATERIALS];
SurfaceTool _surface_tool[MAX_MATERIALS]; SurfaceTool _surface_tool[MAX_MATERIALS];
float _baked_occlusion_darkness; float _baked_occlusion_darkness;
bool _bake_occlusion; bool _bake_occlusion;
public: public:
VoxelMesher(); VoxelMesher();
void set_material(Ref<Material> material, unsigned int id); void set_material(Ref<Material> material, unsigned int id);
void set_library(Ref<VoxelLibrary> library); void set_library(Ref<VoxelLibrary> library);
void set_occlusion_darkness(float darkness); void set_occlusion_darkness(float darkness);
void set_occlusion_enabled(bool enable); void set_occlusion_enabled(bool enable);
Ref<Mesh> build(const VoxelBuffer & buffer_ref);
Ref<Mesh> build_ref(Ref<VoxelBuffer> buffer_ref);
Ref<Mesh> build(const VoxelBuffer & buffer_ref);
Ref<Mesh> build_ref(Ref<VoxelBuffer> buffer_ref);
protected: protected:
static void _bind_methods(); static void _bind_methods();
}; };

View File

@ -4,175 +4,175 @@
VoxelTerrain::VoxelTerrain(): Node(), _min_y(-4), _max_y(4) { VoxelTerrain::VoxelTerrain(): Node(), _min_y(-4), _max_y(4) {
_map = Ref<VoxelMap>(memnew(VoxelMap)); _map = Ref<VoxelMap>(memnew(VoxelMap));
_mesher = Ref<VoxelMesher>(memnew(VoxelMesher)); _mesher = Ref<VoxelMesher>(memnew(VoxelMesher));
} }
struct BlockUpdateComparator0 { struct BlockUpdateComparator0 {
inline bool operator()(const Vector3i & a, const Vector3i & b) const { inline bool operator()(const Vector3i & a, const Vector3i & b) const {
return a.length_sq() > b.length_sq(); return a.length_sq() > b.length_sq();
} }
}; };
void VoxelTerrain::force_load_blocks(Vector3i center, Vector3i extents) { void VoxelTerrain::force_load_blocks(Vector3i center, Vector3i extents) {
//Vector3i min = center - extents; //Vector3i min = center - extents;
//Vector3i max = center + extents + Vector3i(1,1,1); //Vector3i max = center + extents + Vector3i(1,1,1);
//Vector3i size = max - min; //Vector3i size = max - min;
_block_update_queue.clear(); _block_update_queue.clear();
Vector3i pos; Vector3i pos;
for (pos.z = -extents.z; pos.z <= extents.z; ++pos.z) { for (pos.z = -extents.z; pos.z <= extents.z; ++pos.z) {
for (pos.x = -extents.x; pos.x <= extents.x; ++pos.x) { for (pos.x = -extents.x; pos.x <= extents.x; ++pos.x) {
for (pos.y = -extents.y; pos.y <= extents.y; ++pos.y) { for (pos.y = -extents.y; pos.y <= extents.y; ++pos.y) {
_block_update_queue.push_back(pos); _block_update_queue.push_back(pos);
} }
} }
} }
_block_update_queue.sort_custom<BlockUpdateComparator0>(); _block_update_queue.sort_custom<BlockUpdateComparator0>();
} }
int VoxelTerrain::get_block_update_count() { int VoxelTerrain::get_block_update_count() {
return _block_update_queue.size(); return _block_update_queue.size();
} }
void VoxelTerrain::_notification(int p_what) { void VoxelTerrain::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: switch (p_what) {
set_process(true);
break;
case NOTIFICATION_PROCESS: case NOTIFICATION_ENTER_TREE:
_process(); set_process(true);
break; break;
case NOTIFICATION_EXIT_TREE: case NOTIFICATION_PROCESS:
break; _process();
break;
default: case NOTIFICATION_EXIT_TREE:
break; break;
}
default:
break;
}
} }
void VoxelTerrain::_process() { void VoxelTerrain::_process() {
update_blocks(); update_blocks();
} }
void VoxelTerrain::update_blocks() { void VoxelTerrain::update_blocks() {
OS & os = *OS::get_singleton(); OS & os = *OS::get_singleton();
uint32_t time_before = os.get_ticks_msec();
uint32_t max_time = 1000 / 60;
while (!_block_update_queue.empty() && (os.get_ticks_msec() - time_before) < max_time) { uint32_t time_before = os.get_ticks_msec();
uint32_t max_time = 1000 / 60;
// TODO Move this to a thread while (!_block_update_queue.empty() && (os.get_ticks_msec() - time_before) < max_time) {
// TODO Have VoxelTerrainGenerator in C++
// TODO Keep track of MeshInstances!
// Get request // TODO Move this to a thread
Vector3i block_pos = _block_update_queue[_block_update_queue.size() - 1]; // TODO Have VoxelTerrainGenerator in C++
// TODO Keep track of MeshInstances!
if (!_map->has_block(block_pos)) { // Get request
Vector3i block_pos = _block_update_queue[_block_update_queue.size() - 1];
// Get script if (!_map->has_block(block_pos)) {
ScriptInstance * script = get_script_instance();
if (script == NULL) {
return;
}
// Create buffer // Get script
Ref<VoxelBuffer> buffer_ref = Ref<VoxelBuffer>(memnew(VoxelBuffer)); ScriptInstance * script = get_script_instance();
const Vector3i block_size(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE); if (script == NULL) {
buffer_ref->create(block_size.x, block_size.y, block_size.y); return;
}
// Call script to generate buffer // Create buffer
Variant arg1 = buffer_ref; Ref<VoxelBuffer> buffer_ref = Ref<VoxelBuffer>(memnew(VoxelBuffer));
Variant arg2 = block_pos.to_vec3(); const Vector3i block_size(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE);
const Variant * args[2] = { &arg1, &arg2 }; buffer_ref->create(block_size.x, block_size.y, block_size.y);
Variant::CallError err; // wut
script->call_multilevel("_generate_block", args, 2);
// Check script return // Call script to generate buffer
ERR_FAIL_COND(buffer_ref->get_size() != block_size); Variant arg1 = buffer_ref;
Variant arg2 = block_pos.to_vec3();
const Variant * args[2] = { &arg1, &arg2 };
Variant::CallError err; // wut
script->call_multilevel("_generate_block", args, 2);
// Store buffer // Check script return
_map->set_block_buffer(block_pos, buffer_ref); ERR_FAIL_COND(buffer_ref->get_size() != block_size);
// Update meshes // Store buffer
Vector3i ndir; _map->set_block_buffer(block_pos, buffer_ref);
for (ndir.z = -1; ndir.z < 2; ++ndir.z) {
for (ndir.x = -1; ndir.x < 2; ++ndir.x) {
for (ndir.y = -1; ndir.y < 2; ++ndir.y) {
Vector3i npos = block_pos + ndir;
if (_map->is_block_surrounded(npos)) {
update_block_mesh(npos);
}
}
}
}
//update_block_mesh(block_pos);
} // Update meshes
Vector3i ndir;
for (ndir.z = -1; ndir.z < 2; ++ndir.z) {
for (ndir.x = -1; ndir.x < 2; ++ndir.x) {
for (ndir.y = -1; ndir.y < 2; ++ndir.y) {
Vector3i npos = block_pos + ndir;
if (_map->is_block_surrounded(npos)) {
update_block_mesh(npos);
}
}
}
}
//update_block_mesh(block_pos);
// Pop request }
_block_update_queue.resize(_block_update_queue.size() - 1);
} // Pop request
_block_update_queue.resize(_block_update_queue.size() - 1);
}
} }
void VoxelTerrain::update_block_mesh(Vector3i block_pos) { void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
Ref<VoxelBlock> block_ref = _map->get_block_ref(block_pos); Ref<VoxelBlock> block_ref = _map->get_block_ref(block_pos);
if (block_ref.is_null()) { if (block_ref.is_null()) {
return; return;
} }
if (block_ref->voxels->is_uniform(0) && block_ref->voxels->get_voxel(0, 0, 0, 0) == 0) { if (block_ref->voxels->is_uniform(0) && block_ref->voxels->get_voxel(0, 0, 0, 0) == 0) {
return; return;
} }
// Create buffer padded with neighbor voxels // Create buffer padded with neighbor voxels
VoxelBuffer nbuffer; VoxelBuffer nbuffer;
nbuffer.create(VoxelBlock::SIZE + 2, VoxelBlock::SIZE + 2, VoxelBlock::SIZE + 2); nbuffer.create(VoxelBlock::SIZE + 2, VoxelBlock::SIZE + 2, VoxelBlock::SIZE + 2);
_map->get_buffer_copy(VoxelMap::block_to_voxel(block_pos) - Vector3i(1, 1, 1), nbuffer); _map->get_buffer_copy(VoxelMap::block_to_voxel(block_pos) - Vector3i(1, 1, 1), nbuffer);
// TEST // TEST
//if (block_pos == Vector3i(0, 0, 0)) { //if (block_pos == Vector3i(0, 0, 0)) {
// printf(">>>\n"); // printf(">>>\n");
// String os; // String os;
// for (unsigned int y = 0; y < nbuffer.get_size().y; ++y) { // for (unsigned int y = 0; y < nbuffer.get_size().y; ++y) {
// for (unsigned int z = 0; z < nbuffer.get_size().z; ++z) { // for (unsigned int z = 0; z < nbuffer.get_size().z; ++z) {
// for (unsigned int x = 0; x < nbuffer.get_size().x; ++x) { // for (unsigned int x = 0; x < nbuffer.get_size().x; ++x) {
// if (nbuffer.get_voxel(x, y, z) == 0) // if (nbuffer.get_voxel(x, y, z) == 0)
// os += '-'; // os += '-';
// else // else
// os += 'O'; // os += 'O';
// } // }
// os += '\n'; // os += '\n';
// } // }
// os += '\n'; // os += '\n';
// } // }
// wprintf(os.c_str()); // wprintf(os.c_str());
//} //}
// Build mesh (that part is the most CPU-intensive) // Build mesh (that part is the most CPU-intensive)
Ref<Mesh> mesh = _mesher->build(nbuffer); Ref<Mesh> mesh = _mesher->build(nbuffer);
MeshInstance * mesh_instance = block_ref->get_mesh_instance(*this); MeshInstance * mesh_instance = block_ref->get_mesh_instance(*this);
if (mesh_instance == NULL) { if (mesh_instance == NULL) {
// Create and spawn mesh // Create and spawn mesh
mesh_instance = memnew(MeshInstance); mesh_instance = memnew(MeshInstance);
mesh_instance->set_mesh(mesh); mesh_instance->set_mesh(mesh);
mesh_instance->set_translation(VoxelMap::block_to_voxel(block_pos).to_vec3()); mesh_instance->set_translation(VoxelMap::block_to_voxel(block_pos).to_vec3());
add_child(mesh_instance); add_child(mesh_instance);
block_ref->mesh_instance_path = mesh_instance->get_path(); block_ref->mesh_instance_path = mesh_instance->get_path();
} }
else { else {
// Update mesh // Update mesh
mesh_instance->set_mesh(mesh); mesh_instance->set_mesh(mesh);
} }
} }
//void VoxelTerrain::block_removed(VoxelBlock & block) { //void VoxelTerrain::block_removed(VoxelBlock & block) {
@ -184,14 +184,14 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
void VoxelTerrain::_bind_methods() { void VoxelTerrain::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_block_update_count"), &VoxelTerrain::get_block_update_count); ObjectTypeDB::bind_method(_MD("get_block_update_count"), &VoxelTerrain::get_block_update_count);
ObjectTypeDB::bind_method(_MD("get_mesher:VoxelMesher"), &VoxelTerrain::get_mesher); ObjectTypeDB::bind_method(_MD("get_mesher:VoxelMesher"), &VoxelTerrain::get_mesher);
// TODO Make those two static in VoxelMap? // TODO Make those two static in VoxelMap?
ObjectTypeDB::bind_method(_MD("voxel_to_block", "voxel_pos"), &VoxelTerrain::_voxel_to_block_binding); ObjectTypeDB::bind_method(_MD("voxel_to_block", "voxel_pos"), &VoxelTerrain::_voxel_to_block_binding);
ObjectTypeDB::bind_method(_MD("block_to_voxel", "block_pos"), &VoxelTerrain::_block_to_voxel_binding); ObjectTypeDB::bind_method(_MD("block_to_voxel", "block_pos"), &VoxelTerrain::_block_to_voxel_binding);
ObjectTypeDB::bind_method(_MD("force_load_blocks", "center", "extents"), &VoxelTerrain::_force_load_blocks_binding); ObjectTypeDB::bind_method(_MD("force_load_blocks", "center", "extents"), &VoxelTerrain::_force_load_blocks_binding);
} }

View File

@ -8,43 +8,43 @@
// Infinite static terrain made of voxels. // Infinite static terrain made of voxels.
// It is loaded around VoxelTerrainStreamers. // It is loaded around VoxelTerrainStreamers.
class VoxelTerrain : public Node /*, public IVoxelMapObserver*/ { class VoxelTerrain : public Node /*, public IVoxelMapObserver*/ {
OBJ_TYPE(VoxelTerrain, Node) OBJ_TYPE(VoxelTerrain, Node)
// Parameters // Parameters
int _min_y; // In blocks, not voxels int _min_y; // In blocks, not voxels
int _max_y; int _max_y;
// Voxel storage // Voxel storage
Ref<VoxelMap> _map; Ref<VoxelMap> _map;
Vector<Vector3i> _block_update_queue; Vector<Vector3i> _block_update_queue;
Ref<VoxelMesher> _mesher; Ref<VoxelMesher> _mesher;
public: public:
VoxelTerrain(); VoxelTerrain();
void force_load_blocks(Vector3i center, Vector3i extents); void force_load_blocks(Vector3i center, Vector3i extents);
int get_block_update_count(); int get_block_update_count();
Ref<VoxelMesher> get_mesher() { return _mesher; } Ref<VoxelMesher> get_mesher() { return _mesher; }
protected: protected:
void _notification(int p_what); void _notification(int p_what);
void _process(); void _process();
void update_blocks(); void update_blocks();
void update_block_mesh(Vector3i block_pos); void update_block_mesh(Vector3i block_pos);
// Observer events // Observer events
//void block_removed(VoxelBlock & block); //void block_removed(VoxelBlock & block);
static void _bind_methods(); static void _bind_methods();
// Convenience // Convenience
Vector3 _voxel_to_block_binding(Vector3 pos) { return Vector3i(VoxelMap::voxel_to_block(pos)).to_vec3(); } Vector3 _voxel_to_block_binding(Vector3 pos) { return Vector3i(VoxelMap::voxel_to_block(pos)).to_vec3(); }
Vector3 _block_to_voxel_binding(Vector3 pos) { return Vector3i(VoxelMap::block_to_voxel(pos)).to_vec3(); } Vector3 _block_to_voxel_binding(Vector3 pos) { return Vector3i(VoxelMap::block_to_voxel(pos)).to_vec3(); }
void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); } void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); }
}; };