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() {
ObjectTypeDB::register_type<Voxel>();
ObjectTypeDB::register_type<VoxelBuffer>();
ObjectTypeDB::register_type<VoxelMesher>();
ObjectTypeDB::register_type<VoxelLibrary>();
ObjectTypeDB::register_type<VoxelMap>();
ObjectTypeDB::register_type<VoxelTerrain>();
ObjectTypeDB::register_type<Voxel>();
ObjectTypeDB::register_type<VoxelBuffer>();
ObjectTypeDB::register_type<VoxelMesher>();
ObjectTypeDB::register_type<VoxelLibrary>();
ObjectTypeDB::register_type<VoxelMap>();
ObjectTypeDB::register_type<VoxelTerrain>();
}

View File

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

280
voxel.cpp
View File

@ -2,160 +2,160 @@
#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_id(int id) {
ERR_FAIL_COND_V(id < 0 || id >= 256, Ref<Voxel>(this));
// Cannot modify ID after creation
ERR_FAIL_COND_V(_id != -1, Ref<Voxel>(this));
ERR_FAIL_COND_V(id < 0 || id >= 256, Ref<Voxel>(this));
// Cannot modify ID after creation
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) {
ERR_FAIL_COND_V(id >= VoxelMesher::MAX_MATERIALS, Ref<Voxel>(this));
_material_id = id;
return Ref<Voxel>(this);
ERR_FAIL_COND_V(id >= VoxelMesher::MAX_MATERIALS, Ref<Voxel>(this));
_material_id = id;
return Ref<Voxel>(this);
}
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)
}
};
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)
}
};
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_vertices[side].resize(6);
DVector<Vector3>::Write w = _model_side_vertices[side].write();
for (unsigned int i = 0; i < 6; ++i) {
w[i] = vertices[side][i];
}
}
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_vertices[side].resize(6);
DVector<Vector3>::Write w = _model_side_vertices[side].write();
for (unsigned int i = 0; i < 6; ++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]) {
ERR_FAIL_COND_V(_library == NULL, Ref<Voxel>());
ERR_FAIL_COND_V(_library == NULL, Ref<Voxel>());
float e = 0.001;
const Vector2 uv[4] = {
Vector2(e, e),
Vector2(1.f - e, e),
Vector2(e, 1.f - e),
Vector2(1.f - e, 1.f - e),
};
float e = 0.001;
const Vector2 uv[4] = {
Vector2(e, e),
Vector2(1.f - e, e),
Vector2(e, 1.f - e),
Vector2(1.f - e, 1.f - e),
};
const int uv6[SIDE_COUNT][6] = {
// LEFT
{ 2,0,1,2,1,3 },
// RIGHT
{ 2,1,0,2,3,1 },
// BOTTOM
{ 0,3,1,0,2,3 },
// TOP
{ 0,1,3,0,3,2 },
// BACK
{ 2,3,1,2,1,0 },
// FRONT
{ 3,2,1,2,0,1 }
};
const int uv6[SIDE_COUNT][6] = {
// LEFT
{ 2,0,1,2,1,3 },
// RIGHT
{ 2,1,0,2,3,1 },
// BOTTOM
{ 0,3,1,0,2,3 },
// TOP
{ 0,1,3,0,3,2 },
// BACK
{ 2,3,1,2,1,0 },
// FRONT
{ 3,2,1,2,0,1 }
};
float s = 1.0 / (float)_library->get_atlas_size();
float s = 1.0 / (float)_library->get_atlas_size();
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_uv[side].resize(6);
DVector<Vector2>::Write w = _model_side_uv[side].write();
for (unsigned int i = 0; i < 6; ++i) {
w[i] = (atlas_pos[side] + uv[uv6[side][i]]) * s;
}
}
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_uv[side].resize(6);
DVector<Vector2>::Write w = _model_side_uv[side].write();
for (unsigned int i = 0; i < 6; ++i) {
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) {
const Vector2 positions[6] = {
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos
};
return _set_cube_uv_sides(positions);
const Vector2 positions[6] = {
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos
};
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) {
const Vector2 positions[6] = {
side_atlas_pos,
side_atlas_pos,
bottom_atlas_pos,
top_atlas_pos,
side_atlas_pos,
side_atlas_pos,
};
return _set_cube_uv_sides(positions);
const Vector2 positions[6] = {
side_atlas_pos,
side_atlas_pos,
bottom_atlas_pos,
top_atlas_pos,
side_atlas_pos,
side_atlas_pos,
};
return _set_cube_uv_sides(positions);
}
//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() {
ObjectTypeDB::bind_method(_MD("set_name:Voxel", "name"), &Voxel::set_name);
ObjectTypeDB::bind_method(_MD("get_name"), &Voxel::get_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("set_id:Voxel", "id"), &Voxel::set_id);
ObjectTypeDB::bind_method(_MD("get_id"), &Voxel::get_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("set_color:Voxel", "color"), &Voxel::set_color);
ObjectTypeDB::bind_method(_MD("get_color"), &Voxel::get_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("set_transparent:Voxel", "color"), &Voxel::set_transparent, DEFVAL(true));
ObjectTypeDB::bind_method(_MD("is_transparent"), &Voxel::is_transparent);
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("set_material_id", "id"), &Voxel::set_material_id);
ObjectTypeDB::bind_method(_MD("get_material_id"), &Voxel::get_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("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_tbs_sides:Voxel", "top_atlas_pos", "side_atlas_pos", "bottom_atlas_pos"), &Voxel::set_cube_uv_tbs_sides);
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_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.
// Important: it is recommended that you create voxels from a library rather than using new().
class Voxel : public Reference {
OBJ_TYPE(Voxel, Reference)
OBJ_TYPE(Voxel, Reference)
public:
enum Side {
SIDE_LEFT = 0,
SIDE_RIGHT,
SIDE_BOTTOM,
SIDE_TOP,
SIDE_BACK,
SIDE_FRONT,
enum Side {
SIDE_LEFT = 0,
SIDE_RIGHT,
SIDE_BOTTOM,
SIDE_TOP,
SIDE_BACK,
SIDE_FRONT,
SIDE_COUNT
};
SIDE_COUNT
};
private:
VoxelLibrary * _library;
VoxelLibrary * _library;
// Identifiers
int _id;
String _name;
// Identifiers
int _id;
String _name;
// Properties
int _material_id;
bool _is_transparent;
// Properties
int _material_id;
bool _is_transparent;
// Model
Color _color;
DVector<Vector3> _model_vertices;
DVector<Vector3> _model_normals;
DVector<Vector2> _model_uv;
DVector<Vector3> _model_side_vertices[SIDE_COUNT];
DVector<Vector2> _model_side_uv[SIDE_COUNT];
// Model
Color _color;
DVector<Vector3> _model_vertices;
DVector<Vector3> _model_normals;
DVector<Vector2> _model_uv;
DVector<Vector3> _model_side_vertices[SIDE_COUNT];
DVector<Vector2> _model_side_uv[SIDE_COUNT];
// TODO Child voxel types
// TODO Child voxel types
public:
Voxel();
Voxel();
// Properties
// Properties
_FORCE_INLINE_ Ref<Voxel> set_name(String name) { _name = name; return Ref<Voxel>(this); }
_FORCE_INLINE_ String get_name() const { return _name; }
_FORCE_INLINE_ Ref<Voxel> set_name(String name) { _name = name; return Ref<Voxel>(this); }
_FORCE_INLINE_ String get_name() const { return _name; }
Ref<Voxel> set_id(int id);
_FORCE_INLINE_ int get_id() const { return _id; }
Ref<Voxel> set_id(int 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_ Color get_color() const { return _color; }
_FORCE_INLINE_ Ref<Voxel> set_color(Color color) { _color = color; return Ref<Voxel>(this); }
_FORCE_INLINE_ Color get_color() const { return _color; }
Ref<Voxel> set_material_id(unsigned int id);
_FORCE_INLINE_ unsigned int get_material_id() const { return _material_id; }
Ref<Voxel> set_material_id(unsigned int 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_ bool is_transparent() const { return _is_transparent; }
_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; }
// Built-in geometry generators
// Built-in geometry generators
Ref<Voxel> set_cube_geometry(float sy = 1);
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_xquad_geometry(Vector2 atlas_pos);
Ref<Voxel> set_cube_geometry(float sy = 1);
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_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_normals() const { return _model_normals; }
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<Vector2> & get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; }
const DVector<Vector3> & get_model_vertices() const { return _model_vertices; }
const DVector<Vector3> & get_model_normals() const { return _model_normals; }
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<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]);
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() {
clear();
clear();
}
void VoxelBuffer::create(int sx, int sy, int sz) {
if (sx <= 0 || sy <= 0 || sz <= 0) {
return;
}
Vector3i new_size(sx, sy, sz);
if (new_size != _size) {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i];
if (channel.data) {
// TODO Optimize with realloc
delete_channel(i, _size);
create_channel(i, new_size);
}
}
_size = new_size;
}
if (sx <= 0 || sy <= 0 || sz <= 0) {
return;
}
Vector3i new_size(sx, sy, sz);
if (new_size != _size) {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i];
if (channel.data) {
// TODO Optimize with realloc
delete_channel(i, _size);
create_channel(i, new_size);
}
}
_size = new_size;
}
}
void VoxelBuffer::clear() {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i];
if (channel.data) {
delete_channel(i, _size);
}
}
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
Channel & channel = _channels[i];
if (channel.data) {
delete_channel(i, _size);
}
}
}
void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
delete_channel(channel_index, _size);
_channels[channel_index].defval = clear_value;
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
delete_channel(channel_index, _size);
_channels[channel_index].defval = clear_value;
}
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];
ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, 0);
if (validate_pos(x, y, z) && channel.data) {
return VOXEL_AT(channel.data, x,y,z);
}
else {
return channel.defval;
}
const Channel & channel = _channels[channel_index];
if (validate_pos(x, y, z) && channel.data) {
return VOXEL_AT(channel.data, 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_COND(!validate_pos(x, y, z));
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.defval != value) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
VOXEL_AT(channel.data, x, y, z) = value;
}
if (channel.defval != value) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
VOXEL_AT(channel.data, x, y, z) = value;
}
}
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) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
Channel & channel = _channels[channel_index];
if (channel.data == NULL && channel.defval == defval)
return;
else
create_channel_noinit(channel_index, _size);
Channel & channel = _channels[channel_index];
if (channel.data == NULL && channel.defval == defval)
return;
else
create_channel_noinit(channel_index, _size);
unsigned int volume = get_volume();
memset(channel.data, defval, volume);
unsigned int volume = get_volume();
memset(channel.data, defval, volume);
}
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);
max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1,1,1));
Vector3i area_size = max - min;
min.clamp_to(Vector3i(0, 0, 0), _size);
max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1,1,1));
Vector3i area_size = max - min;
Channel & channel = _channels[channel_index];
if (channel.data == NULL) {
if (channel.defval == defval)
return;
else
create_channel(channel_index, _size);
}
Channel & channel = _channels[channel_index];
if (channel.data == NULL) {
if (channel.defval == defval)
return;
else
create_channel(channel_index, _size);
}
Vector3i pos;
for (pos.z = min.z; pos.z < max.z; ++pos.z) {
for (pos.x = min.x; pos.x < max.x; ++pos.x) {
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));
}
}
Vector3i pos;
for (pos.z = min.z; pos.z < max.z; ++pos.z) {
for (pos.x = min.x; pos.x < max.x; ++pos.x) {
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));
}
}
}
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];
if (channel.data == NULL)
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;
}
}
Channel & channel = _channels[channel_index];
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;
}
void VoxelBuffer::optimize() {
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
if (_channels[i].data && is_uniform(i)) {
clear_channel(i, _channels[i].data[0]);
}
}
for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
if (_channels[i].data && is_uniform(i)) {
clear_channel(i, _channels[i].data[0]);
}
}
}
void VoxelBuffer::copy_from(const VoxelBuffer & other, unsigned int channel_index) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
ERR_FAIL_COND(other._size == _size);
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) {
delete_channel(channel_index, _size);
}
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) {
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) {
ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
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);
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_min.clamp_to(Vector3i(0, 0, 0), other._size);
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;
//Vector3i dst_max = dst_min + area_size;
dst_min.clamp_to(Vector3i(0, 0, 0), _size);
Vector3i area_size = src_max - src_min;
//Vector3i dst_max = dst_min + area_size;
if (area_size == _size) {
copy_from(other, channel_index);
}
else {
if (other_channel.data) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
// Copy row by row
Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
// 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 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));
}
}
}
else if (channel.defval != other_channel.defval) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
// Set row by row
Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
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);
memset(&channel.data[dst_ri], other_channel.defval, area_size.y * sizeof(uint8_t));
}
}
}
}
if (area_size == _size) {
copy_from(other, channel_index);
}
else {
if (other_channel.data) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
// Copy row by row
Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
// 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 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));
}
}
}
else if (channel.defval != other_channel.defval) {
if (channel.data == NULL) {
create_channel(channel_index, _size);
}
// Set row by row
Vector3i pos;
for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
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);
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) {
create_channel_noinit(i, size);
memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t));
create_channel_noinit(i, size);
memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t));
}
void VoxelBuffer::create_channel_noinit(int i, Vector3i size) {
Channel & channel = _channels[i];
unsigned int volume = size.x * size.y * size.z;
channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t));
Channel & channel = _channels[i];
unsigned int volume = size.x * size.y * size.z;
channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t));
}
void VoxelBuffer::delete_channel(int i, Vector3i size) {
Channel & channel = _channels[i];
memfree(channel.data);
channel.data = NULL;
Channel & channel = _channels[i];
memfree(channel.data);
channel.data = NULL;
}
void VoxelBuffer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create);
ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear);
ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create);
ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear);
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_z"), &VoxelBuffer::get_size_z);
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_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_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("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("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_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_area", "other:VoxelBuffer", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_copy_from_area_binding, 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("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("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize);
ObjectTypeDB::bind_method(_MD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0));
ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize);
}
void VoxelBuffer::_copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel) {
ERR_FAIL_COND(other.is_null());
copy_from(**other, channel);
ERR_FAIL_COND(other.is_null());
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) {
ERR_FAIL_COND(other.is_null());
copy_from(**other, Vector3i(src_min), Vector3i(src_max), Vector3i(dst_min), channel);
ERR_FAIL_COND(other.is_null());
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
class VoxelBuffer : public Reference {
OBJ_TYPE(VoxelBuffer, Reference)
OBJ_TYPE(VoxelBuffer, Reference)
public:
// Arbitrary value, 8 should be enough. Tweak for your needs.
static const int MAX_CHANNELS = 8;
// Arbitrary value, 8 should be enough. Tweak for your needs.
static const int MAX_CHANNELS = 8;
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;
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;
// Default value when data is null
uint8_t defval;
Channel() : data(NULL), defval(0) {}
};
// Default value when data is null
uint8_t defval;
// Each channel can store arbitary data.
// For example, you can decide to store colors (R, G, B, A), gameplay types (type, state, light) or both.
Channel _channels[MAX_CHANNELS];
Channel() : data(NULL), defval(0) {}
};
// How many voxels are there in the three directions. All populated channels have the same size.
Vector3i _size;
// Each channel can store arbitary data.
// 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:
VoxelBuffer();
~VoxelBuffer();
VoxelBuffer();
~VoxelBuffer();
void create(int sx, int sy, int sz);
void clear();
void clear_channel(unsigned int channel_index, int clear_value=0);
void create(int sx, int sy, int sz);
void clear();
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;
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_ 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); }
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_ 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); }
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(int defval, 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, 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;
}
_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;
}
_FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x + y;
}
_FORCE_INLINE_ unsigned int index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x + y;
}
_FORCE_INLINE_ unsigned int row_index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x;
}
_FORCE_INLINE_ unsigned int row_index(unsigned int x, unsigned int y, unsigned int z) const {
return (z * _size.z + x) * _size.x;
}
_FORCE_INLINE_ unsigned int get_volume() {
return _size.x * _size.y * _size.z;
}
_FORCE_INLINE_ unsigned int get_volume() {
return _size.x * _size.y * _size.z;
}
private:
void create_channel_noinit(int i, Vector3i size);
void create_channel(int i, Vector3i size, uint8_t defval=0);
void delete_channel(int i, Vector3i size);
void create_channel_noinit(int i, Vector3i size);
void create_channel(int i, Vector3i size, uint8_t defval=0);
void delete_channel(int i, Vector3i size);
protected:
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; }
static void _bind_methods();
_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); }
_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_ 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"
VoxelLibrary::VoxelLibrary() : Reference(), _atlas_size(1) {
create_voxel(0, "air")->set_transparent(true);
create_voxel(0, "air")->set_transparent(true);
}
VoxelLibrary::~VoxelLibrary() {
for (unsigned int i = 0; i < MAX_VOXEL_TYPES; ++i) {
if (_voxel_types[i].is_valid()) {
_voxel_types[i]->set_library_ptr(NULL);
}
}
for (unsigned int i = 0; i < MAX_VOXEL_TYPES; ++i) {
if (_voxel_types[i].is_valid()) {
_voxel_types[i]->set_library_ptr(NULL);
}
}
}
void VoxelLibrary::set_atlas_size(int s) {
ERR_FAIL_COND(s <= 0);
_atlas_size = s;
ERR_FAIL_COND(s <= 0);
_atlas_size = s;
}
Ref<Voxel> VoxelLibrary::create_voxel(int id, String name) {
ERR_FAIL_COND_V(id < 0 || id >= MAX_VOXEL_TYPES, Ref<Voxel>());
Ref<Voxel> voxel(memnew(Voxel));
voxel->set_library_ptr(this);
voxel->set_id(id);
voxel->set_name(name);
_voxel_types[id] = voxel;
return voxel;
ERR_FAIL_COND_V(id < 0 || id >= MAX_VOXEL_TYPES, Ref<Voxel>());
Ref<Voxel> voxel(memnew(Voxel));
voxel->set_library_ptr(this);
voxel->set_id(id);
voxel->set_name(name);
_voxel_types[id] = voxel;
return voxel;
}
void VoxelLibrary::_bind_methods() {
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("create_voxel:Voxel", "id", "name"), &VoxelLibrary::create_voxel);
ObjectTypeDB::bind_method(_MD("set_atlas_size", "square_size"), &VoxelLibrary::set_atlas_size);
}

View File

@ -5,31 +5,31 @@
#include "voxel.h"
class VoxelLibrary : public Reference {
OBJ_TYPE(VoxelLibrary, Reference)
OBJ_TYPE(VoxelLibrary, Reference)
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; }
void set_atlas_size(int s);
int get_atlas_size() const { return _atlas_size; }
void set_atlas_size(int s);
// Use this factory rather than creating voxels from scratch
Ref<Voxel> create_voxel(int id, String name);
// Use this factory rather than creating voxels from scratch
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_ const Voxel & get_voxel_const(int id) const { return **_voxel_types[id]; }
_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]; }
private:
Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES];
int _atlas_size;
Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES];
int _atlas_size;
protected:
static void _bind_methods();
static void _bind_methods();
};

View File

@ -1,9 +1,9 @@
#include "voxel_map.h"
VoxelMap::VoxelMap() : _last_accessed_block(NULL) {
for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) {
_default_voxel[i] = 0;
}
for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) {
_default_voxel[i] = 0;
}
}
VoxelMap::~VoxelMap() {
@ -11,21 +11,21 @@ VoxelMap::~VoxelMap() {
}
int VoxelMap::get_voxel(Vector3i pos, unsigned int c) {
Vector3i bpos = voxel_to_block(pos);
VoxelBlock * block = get_block(bpos);
if (block == NULL) {
return _default_voxel[c];
}
return block->voxels->get_voxel(pos - block_to_voxel(bpos), c);
Vector3i bpos = voxel_to_block(pos);
VoxelBlock * block = get_block(bpos);
if (block == NULL) {
return _default_voxel[c];
}
return block->voxels->get_voxel(pos - block_to_voxel(bpos), c);
}
MeshInstance * VoxelBlock::get_mesh_instance(const Node & root) {
if (mesh_instance_path.is_empty())
return NULL;
Node * n = root.get_node(mesh_instance_path);
if (n == NULL)
return NULL;
return n->cast_to<MeshInstance>();
if (mesh_instance_path.is_empty())
return NULL;
Node * n = root.get_node(mesh_instance_path);
if (n == NULL)
return NULL;
return n->cast_to<MeshInstance>();
}
VoxelBlock::~VoxelBlock() {
@ -34,204 +34,204 @@ VoxelBlock::~VoxelBlock() {
// Helper
VoxelBlock * VoxelBlock::create(Vector3i bpos, VoxelBuffer * buffer) {
VoxelBlock * block = memnew(VoxelBlock);
block->pos = bpos;
if (buffer) {
const int bs = VoxelBlock::SIZE;
ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL);
}
else {
buffer = memnew(VoxelBuffer);
}
ERR_FAIL_COND_V(buffer == NULL, NULL);
block->voxels = Ref<VoxelBuffer>(buffer);
//block->map = &map;
return block;
VoxelBlock * block = memnew(VoxelBlock);
block->pos = bpos;
if (buffer) {
const int bs = VoxelBlock::SIZE;
ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL);
}
else {
buffer = memnew(VoxelBuffer);
}
ERR_FAIL_COND_V(buffer == NULL, NULL);
block->voxels = Ref<VoxelBuffer>(buffer);
//block->map = &map;
return block;
}
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);
if (block == NULL) {
if (block == NULL) {
block = VoxelBlock::create(bpos);
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) {
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
_default_voxel[channel] = value;
ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS);
_default_voxel[channel] = value;
}
int VoxelMap::get_default_voxel(unsigned int channel) {
ERR_FAIL_INDEX_V(channel, VoxelBuffer::MAX_CHANNELS, 0);
return _default_voxel[channel];
ERR_FAIL_INDEX_V(channel, VoxelBuffer::MAX_CHANNELS, 0);
return _default_voxel[channel];
}
VoxelBlock * VoxelMap::get_block(Vector3i bpos) {
if (_last_accessed_block && _last_accessed_block->pos == bpos) {
return _last_accessed_block;
}
Ref<VoxelBlock> * p = _blocks.getptr(bpos);
if (p) {
_last_accessed_block = p->ptr();
return _last_accessed_block;
}
return NULL;
if (_last_accessed_block && _last_accessed_block->pos == bpos) {
return _last_accessed_block;
}
Ref<VoxelBlock> * p = _blocks.getptr(bpos);
if (p) {
_last_accessed_block = p->ptr();
return _last_accessed_block;
}
return NULL;
}
void VoxelMap::set_block(Vector3i bpos, VoxelBlock * block) {
if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) {
_last_accessed_block = block;
}
_blocks.set(bpos, block);
if (_last_accessed_block == NULL || _last_accessed_block->pos == bpos) {
_last_accessed_block = block;
}
_blocks.set(bpos, block);
}
void VoxelMap::set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer) {
ERR_FAIL_COND(buffer.is_null());
VoxelBlock * block = get_block(bpos);
if (block == NULL) {
ERR_FAIL_COND(buffer.is_null());
VoxelBlock * block = get_block(bpos);
if (block == NULL) {
block = VoxelBlock::create(bpos, *buffer);
set_block(bpos, block);
}
else {
block->voxels = buffer;
}
set_block(bpos, block);
}
else {
block->voxels = buffer;
}
}
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(-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(0,0,0),
Vector3i(1,0,0),
Vector3i(-1,0,1),
Vector3i(0,0,1),
Vector3i(1,0,1),
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,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 {
for (unsigned int i = 0; i < 26; ++i) {
Vector3i bpos = pos + g_moore_neighboring_3d[i];
if (!has_block(bpos)) {
return false;
}
}
return true;
for (unsigned int i = 0; i < 26; ++i) {
Vector3i bpos = pos + g_moore_neighboring_3d[i];
if (!has_block(bpos)) {
return false;
}
}
return true;
}
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 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));
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);
ERR_FAIL_COND((max_block_pos - min_block_pos) != Vector3(3, 3, 3));
Vector3i bpos;
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.y = min_block_pos.y; bpos.y < max_block_pos.y; ++bpos.y) {
Vector3i bpos;
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.y = min_block_pos.y; bpos.y < max_block_pos.y; ++bpos.y) {
VoxelBlock * block = get_block(bpos);
if (block) {
VoxelBlock * block = get_block(bpos);
if (block) {
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 {
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)
);
}
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 {
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)
);
}
}
}
}
}
}
}
}
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;
Vector3i * key = NULL;
Vector<Vector3i> to_remove;
Vector3i * key = NULL;
while (_blocks.next(key)) {
while (_blocks.next(key)) {
Ref<VoxelBlock> & block_ref = _blocks.get(*key);
ERR_FAIL_COND(block_ref.is_null()); // Should never trigger
VoxelBlock & block = **block_ref;
Ref<VoxelBlock> & block_ref = _blocks.get(*key);
ERR_FAIL_COND(block_ref.is_null()); // Should never trigger
VoxelBlock & block = **block_ref;
if (!block.pos.is_contained_in(min, max)) {
if (!block.pos.is_contained_in(min, max)) {
//if (_observer)
// _observer->block_removed(block);
//if (_observer)
// _observer->block_removed(block);
to_remove.push_back(*key);
to_remove.push_back(*key);
if (&block == _last_accessed_block)
_last_accessed_block = NULL;
}
}
if (&block == _last_accessed_block)
_last_accessed_block = NULL;
}
}
for (unsigned int i = 0; i < to_remove.size(); ++i) {
_blocks.erase(to_remove[i]);
}
for (unsigned int i = 0; i < to_remove.size(); ++i) {
_blocks.erase(to_remove[i]);
}
}
void VoxelMap::_bind_methods() {
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("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("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("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("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_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("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("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("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("block_to_voxel", "block_pos"), &VoxelMap::_block_to_voxel_binding);
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) {
ERR_FAIL_COND(dst_buffer_ref.is_null());
get_buffer_copy(Vector3i(pos), **dst_buffer_ref, channel);
ERR_FAIL_COND(dst_buffer_ref.is_null());
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.
class VoxelBlock : public Reference {
OBJ_TYPE(VoxelBlock, Reference)
OBJ_TYPE(VoxelBlock, Reference)
public:
static const int SIZE_POW2 = 4; // 3=>8, 4=>16, 5=>32...
static const int SIZE = 1 << SIZE_POW2;
static const int SIZE_POW2 = 4; // 3=>8, 4=>16, 5=>32...
static const int SIZE = 1 << SIZE_POW2;
Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels
Vector3i pos;
NodePath mesh_instance_path;
//VoxelMap * map;
Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels
Vector3i pos;
NodePath mesh_instance_path;
//VoxelMap * map;
MeshInstance * get_mesh_instance(const Node & root);
MeshInstance * get_mesh_instance(const Node & root);
static VoxelBlock * create(Vector3i bpos, VoxelBuffer * buffer = 0);
~VoxelBlock();
~VoxelBlock();
private:
VoxelBlock() : Reference(), voxels(NULL) {}
VoxelBlock() : Reference(), voxels(NULL) {}
};
@ -38,78 +38,78 @@ private:
// Infinite voxel storage by means of octants like Gridmap
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
uint8_t _default_voxel[VoxelBuffer::MAX_CHANNELS];
// Voxel values that will be returned if access is out of map bounds
uint8_t _default_voxel[VoxelBuffer::MAX_CHANNELS];
// Blocks stored with a spatial hash in all 3D directions
HashMap<Vector3i, Ref<VoxelBlock>, Vector3iHasher> _blocks;
// Blocks stored with a spatial hash in all 3D directions
HashMap<Vector3i, Ref<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;
// 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;
//IVoxelMapObserver * _observer;
//IVoxelMapObserver * _observer;
public:
VoxelMap();
~VoxelMap();
VoxelMap();
~VoxelMap();
int get_voxel(Vector3i pos, unsigned int c = 0);
void set_voxel(int value, 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_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);
// Converts voxel coodinates into block coordinates
static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) {
return Vector3i(
//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.z < 0 ? (pos.z + 1) / VoxelBlock::SIZE - 1 : pos.z / VoxelBlock::SIZE
pos.x >> VoxelBlock::SIZE_POW2,
pos.y >> VoxelBlock::SIZE_POW2,
pos.z >> VoxelBlock::SIZE_POW2
);
}
// Converts voxel coodinates into block coordinates
static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) {
return Vector3i(
//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.z < 0 ? (pos.z + 1) / VoxelBlock::SIZE - 1 : pos.z / VoxelBlock::SIZE
pos.x >> VoxelBlock::SIZE_POW2,
pos.y >> VoxelBlock::SIZE_POW2,
pos.z >> VoxelBlock::SIZE_POW2
);
}
// Converts block coodinates into voxel coordinates
static _FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) {
return bpos * VoxelBlock::SIZE;
}
// Converts block coodinates into voxel coordinates
static _FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) {
return bpos * VoxelBlock::SIZE;
}
// 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);
// 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);
// 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);
// 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);
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 is_block_surrounded(Vector3i pos) const;
bool has_block(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:
VoxelBlock * get_block(Vector3i bpos);
void set_block(Vector3i bpos, VoxelBlock * block);
VoxelBlock * get_block(Vector3i bpos);
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_ 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_ 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(); }
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 _set_block_buffer_binding(Vector3 bpos, Ref<VoxelBuffer> buffer) { set_block_buffer(Vector3i(bpos), buffer); }
_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_ 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 _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)); }
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); }
};

View File

@ -9,35 +9,35 @@
#include "voxel_library.h"
class VoxelMesher : public Reference {
OBJ_TYPE(VoxelMesher, Reference);
OBJ_TYPE(VoxelMesher, Reference);
public:
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
private:
Ref<VoxelLibrary> _library;
Ref<Material> _materials[MAX_MATERIALS];
SurfaceTool _surface_tool[MAX_MATERIALS];
float _baked_occlusion_darkness;
bool _bake_occlusion;
Ref<VoxelLibrary> _library;
Ref<Material> _materials[MAX_MATERIALS];
SurfaceTool _surface_tool[MAX_MATERIALS];
float _baked_occlusion_darkness;
bool _bake_occlusion;
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_enabled(bool enable);
void set_occlusion_darkness(float darkness);
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:
static void _bind_methods();
static void _bind_methods();
};

View File

@ -4,175 +4,175 @@
VoxelTerrain::VoxelTerrain(): Node(), _min_y(-4), _max_y(4) {
_map = Ref<VoxelMap>(memnew(VoxelMap));
_mesher = Ref<VoxelMesher>(memnew(VoxelMesher));
_map = Ref<VoxelMap>(memnew(VoxelMap));
_mesher = Ref<VoxelMesher>(memnew(VoxelMesher));
}
struct BlockUpdateComparator0 {
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) {
//Vector3i min = center - extents;
//Vector3i max = center + extents + Vector3i(1,1,1);
//Vector3i size = max - min;
//Vector3i min = center - extents;
//Vector3i max = center + extents + Vector3i(1,1,1);
//Vector3i size = max - min;
_block_update_queue.clear();
_block_update_queue.clear();
Vector3i pos;
for (pos.z = -extents.z; pos.z <= extents.z; ++pos.z) {
for (pos.x = -extents.x; pos.x <= extents.x; ++pos.x) {
for (pos.y = -extents.y; pos.y <= extents.y; ++pos.y) {
_block_update_queue.push_back(pos);
}
}
}
Vector3i pos;
for (pos.z = -extents.z; pos.z <= extents.z; ++pos.z) {
for (pos.x = -extents.x; pos.x <= extents.x; ++pos.x) {
for (pos.y = -extents.y; pos.y <= extents.y; ++pos.y) {
_block_update_queue.push_back(pos);
}
}
}
_block_update_queue.sort_custom<BlockUpdateComparator0>();
_block_update_queue.sort_custom<BlockUpdateComparator0>();
}
int VoxelTerrain::get_block_update_count() {
return _block_update_queue.size();
return _block_update_queue.size();
}
void VoxelTerrain::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
set_process(true);
break;
switch (p_what) {
case NOTIFICATION_PROCESS:
_process();
break;
case NOTIFICATION_ENTER_TREE:
set_process(true);
break;
case NOTIFICATION_EXIT_TREE:
break;
case NOTIFICATION_PROCESS:
_process();
break;
default:
break;
}
case NOTIFICATION_EXIT_TREE:
break;
default:
break;
}
}
void VoxelTerrain::_process() {
update_blocks();
update_blocks();
}
void VoxelTerrain::update_blocks() {
OS & os = *OS::get_singleton();
uint32_t time_before = os.get_ticks_msec();
uint32_t max_time = 1000 / 60;
OS & os = *OS::get_singleton();
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
// TODO Have VoxelTerrainGenerator in C++
// TODO Keep track of MeshInstances!
while (!_block_update_queue.empty() && (os.get_ticks_msec() - time_before) < max_time) {
// Get request
Vector3i block_pos = _block_update_queue[_block_update_queue.size() - 1];
// TODO Move this to a thread
// 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
ScriptInstance * script = get_script_instance();
if (script == NULL) {
return;
}
if (!_map->has_block(block_pos)) {
// Create buffer
Ref<VoxelBuffer> buffer_ref = Ref<VoxelBuffer>(memnew(VoxelBuffer));
const Vector3i block_size(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE);
buffer_ref->create(block_size.x, block_size.y, block_size.y);
// Get script
ScriptInstance * script = get_script_instance();
if (script == NULL) {
return;
}
// Call script to generate buffer
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);
// Create buffer
Ref<VoxelBuffer> buffer_ref = Ref<VoxelBuffer>(memnew(VoxelBuffer));
const Vector3i block_size(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE);
buffer_ref->create(block_size.x, block_size.y, block_size.y);
// Check script return
ERR_FAIL_COND(buffer_ref->get_size() != block_size);
// Call script to generate buffer
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
_map->set_block_buffer(block_pos, buffer_ref);
// Check script return
ERR_FAIL_COND(buffer_ref->get_size() != block_size);
// 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);
// Store buffer
_map->set_block_buffer(block_pos, buffer_ref);
}
// 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) {
Ref<VoxelBlock> block_ref = _map->get_block_ref(block_pos);
if (block_ref.is_null()) {
return;
}
if (block_ref->voxels->is_uniform(0) && block_ref->voxels->get_voxel(0, 0, 0, 0) == 0) {
return;
}
Ref<VoxelBlock> block_ref = _map->get_block_ref(block_pos);
if (block_ref.is_null()) {
return;
}
if (block_ref->voxels->is_uniform(0) && block_ref->voxels->get_voxel(0, 0, 0, 0) == 0) {
return;
}
// Create buffer padded with neighbor voxels
VoxelBuffer nbuffer;
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);
// Create buffer padded with neighbor voxels
VoxelBuffer nbuffer;
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);
// TEST
//if (block_pos == Vector3i(0, 0, 0)) {
// printf(">>>\n");
// String os;
// 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 x = 0; x < nbuffer.get_size().x; ++x) {
// if (nbuffer.get_voxel(x, y, z) == 0)
// os += '-';
// else
// os += 'O';
// }
// os += '\n';
// }
// os += '\n';
// }
// wprintf(os.c_str());
//}
// TEST
//if (block_pos == Vector3i(0, 0, 0)) {
// printf(">>>\n");
// String os;
// 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 x = 0; x < nbuffer.get_size().x; ++x) {
// if (nbuffer.get_voxel(x, y, z) == 0)
// os += '-';
// else
// os += 'O';
// }
// os += '\n';
// }
// os += '\n';
// }
// wprintf(os.c_str());
//}
// Build mesh (that part is the most CPU-intensive)
Ref<Mesh> mesh = _mesher->build(nbuffer);
// Build mesh (that part is the most CPU-intensive)
Ref<Mesh> mesh = _mesher->build(nbuffer);
MeshInstance * mesh_instance = block_ref->get_mesh_instance(*this);
if (mesh_instance == NULL) {
// Create and spawn mesh
mesh_instance = memnew(MeshInstance);
mesh_instance->set_mesh(mesh);
mesh_instance->set_translation(VoxelMap::block_to_voxel(block_pos).to_vec3());
add_child(mesh_instance);
block_ref->mesh_instance_path = mesh_instance->get_path();
}
else {
// Update mesh
mesh_instance->set_mesh(mesh);
}
MeshInstance * mesh_instance = block_ref->get_mesh_instance(*this);
if (mesh_instance == NULL) {
// Create and spawn mesh
mesh_instance = memnew(MeshInstance);
mesh_instance->set_mesh(mesh);
mesh_instance->set_translation(VoxelMap::block_to_voxel(block_pos).to_vec3());
add_child(mesh_instance);
block_ref->mesh_instance_path = mesh_instance->get_path();
}
else {
// Update mesh
mesh_instance->set_mesh(mesh);
}
}
//void VoxelTerrain::block_removed(VoxelBlock & block) {
@ -184,14 +184,14 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
void VoxelTerrain::_bind_methods() {
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_block_update_count"), &VoxelTerrain::get_block_update_count);
ObjectTypeDB::bind_method(_MD("get_mesher:VoxelMesher"), &VoxelTerrain::get_mesher);
// 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("block_to_voxel", "block_pos"), &VoxelTerrain::_block_to_voxel_binding);
// 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("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.
// It is loaded around VoxelTerrainStreamers.
class VoxelTerrain : public Node /*, public IVoxelMapObserver*/ {
OBJ_TYPE(VoxelTerrain, Node)
OBJ_TYPE(VoxelTerrain, Node)
// Parameters
int _min_y; // In blocks, not voxels
int _max_y;
// Parameters
int _min_y; // In blocks, not voxels
int _max_y;
// Voxel storage
Ref<VoxelMap> _map;
// Voxel storage
Ref<VoxelMap> _map;
Vector<Vector3i> _block_update_queue;
Ref<VoxelMesher> _mesher;
Vector<Vector3i> _block_update_queue;
Ref<VoxelMesher> _mesher;
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:
void _notification(int p_what);
void _process();
void _notification(int p_what);
void _process();
void update_blocks();
void update_block_mesh(Vector3i block_pos);
void update_blocks();
void update_block_mesh(Vector3i block_pos);
// Observer events
//void block_removed(VoxelBlock & block);
// Observer events
//void block_removed(VoxelBlock & block);
static void _bind_methods();
static void _bind_methods();
// Convenience
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(); }
void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); }
// Convenience
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(); }
void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); }
};