mirror of
https://github.com/Relintai/godot_voxel.git
synced 2025-03-11 21:53:24 +01:00
Spaces to tabs
This commit is contained in:
parent
8acf40d338
commit
8d1c8cc339
@ -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>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
176
vector3i.h
176
vector3i.h
@ -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
280
voxel.cpp
@ -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
102
voxel.h
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
342
voxel_buffer.cpp
342
voxel_buffer.cpp
@ -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);
|
||||||
}
|
}
|
||||||
|
122
voxel_buffer.h
122
voxel_buffer.h
@ -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); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
300
voxel_map.cpp
300
voxel_map.cpp
@ -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 = ↦
|
//block->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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
122
voxel_map.h
122
voxel_map.h
@ -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); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user