Added VoxelLibrary, texture coordinates and random stuff

master
Marc Gilleron 2016-05-01 22:20:27 +02:00
parent 1acabf1307
commit d1d685124f
8 changed files with 241 additions and 38 deletions

View File

@ -1,12 +1,14 @@
#include "register_types.h"
#include "voxel_buffer.h"
#include "voxel_mesh_builder.h"
#include "voxel_library.h"
void register_voxel_types() {
ObjectTypeDB::register_type<Voxel>();
ObjectTypeDB::register_type<VoxelBuffer>();
ObjectTypeDB::register_type<VoxelMeshBuilder>();
ObjectTypeDB::register_type<VoxelLibrary>();
}

127
voxel.cpp
View File

@ -1,15 +1,28 @@
#include "voxel.h"
#include "voxel_library.h"
#include "voxel_mesh_builder.h"
Voxel::Voxel() : Reference(), _id(0), _material_id(0), _is_transparent(false), _color(1.f, 1.f, 1.f) {
Voxel::Voxel() : Reference(),
_id(0),
_material_id(0),
_is_transparent(false),
_library(NULL),
_color(1.f, 1.f, 1.f)
{}
}
void Voxel::set_id(int id) {
ERR_FAIL_COND(id < 0 || id >= 256);
Ref<Voxel> Voxel::set_id(int id) {
ERR_FAIL_COND_V(id < 0 || id >= 256, Ref<Voxel>(this));
_id = id;
return Ref<Voxel>(this);
}
void Voxel::set_cube_geometry(float sy) {
Ref<Voxel> Voxel::set_material_id(unsigned int id) {
ERR_FAIL_COND_V(id >= VoxelMeshBuilder::MAX_MATERIALS, Ref<Voxel>(this));
_material_id = id;
return Ref<Voxel>(this);
}
Ref<Voxel> Voxel::set_cube_geometry(float sy) {
const Vector3 vertices[SIDE_COUNT][6] = {
{
// LEFT
@ -74,29 +87,113 @@ void Voxel::set_cube_geometry(float sy) {
w[i] = vertices[side][i];
}
}
return Ref<Voxel>(this);
}
void Voxel::set_cube_uv_all_sides(Vector3 atlas_pos) {
// TODO
Ref<Voxel> Voxel::_set_cube_uv_sides(const Vector2 atlas_pos[6]) {
ERR_FAIL_COND_V(_library == NULL, Ref<Voxel>());
float e = 0.001;
const Vector2 uv[4] = {
Vector2(e, e),
Vector2(1.f - e, e),
Vector2(e, 1.f - e),
Vector2(1.f - e, 1.f - e),
};
const int uv6[SIDE_COUNT][6] = {
{
// LEFT
//0,1,3,0,1,2
2,0,1,2,1,3
},
{
// RIGHT
//0,3,1,0,2,3
2,1,0,2,3,1
},
{
// BOTTOM
//0,3,1,0,2,3
0,3,1,0,2,3
},
{
// TOP
//0,1,3,0,3,2
0,1,3,0,3,2
},
{
// BACK
//0,1,3,0,3,2
2,3,1,2,1,0
},
{
// FRONT
//1,0,3,0,2,3
3,2,1,2,0,1
}
};
float s = 1.0 / (float)_library->get_atlas_size();
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
_model_side_uv[side].resize(6);
DVector<Vector2>::Write w = _model_side_uv[side].write();
for (unsigned int i = 0; i < 6; ++i) {
w[i] = (atlas_pos[side] + uv[uv6[side][i]]) * s;
}
}
return Ref<Voxel>(this);
}
void Voxel::set_cube_uv_tbs_sides(Vector3 top_atlas_pos, Vector3 side_atlas_pos, Vector3 bottom_atlas_pos) {
// TODO
Ref<Voxel> Voxel::set_cube_uv_all_sides(Vector2 atlas_pos) {
const Vector2 positions[6] = {
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos,
atlas_pos
};
return _set_cube_uv_sides(positions);
}
Ref<Voxel> Voxel::set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos) {
const Vector2 positions[6] = {
side_atlas_pos,
side_atlas_pos,
bottom_atlas_pos,
top_atlas_pos,
side_atlas_pos,
side_atlas_pos,
};
return _set_cube_uv_sides(positions);
}
//Ref<Voxel> Voxel::set_xquad_geometry(Vector2 atlas_pos) {
// // TODO
// return Ref<Voxel>(this);
//}
void Voxel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_name", "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("set_id", "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("set_color", "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("set_cube_geometry", "height"), &Voxel::set_cube_geometry, DEFVAL(1.f));
// TODO
ObjectTypeDB::bind_method(_MD("set_transparent:Voxel", "color"), &Voxel::set_transparent, DEFVAL(true));
ObjectTypeDB::bind_method(_MD("is_transparent"), &Voxel::is_transparent);
ObjectTypeDB::bind_method(_MD("set_cube_geometry:Voxel", "height"), &Voxel::set_cube_geometry, DEFVAL(1.f));
ObjectTypeDB::bind_method(_MD("set_cube_uv_all_sides:Voxel", "atlas_pos"), &Voxel::set_cube_uv_all_sides);
ObjectTypeDB::bind_method(_MD("set_cube_uv_tbs_sides:Voxel", "top_atlas_pos", "side_atlas_pos", "bottom_atlas_pos"), &Voxel::set_cube_uv_tbs_sides);
}

38
voxel.h
View File

@ -3,8 +3,11 @@
#include <reference.h>
class VoxelLibrary;
// Definition of one type of voxel.
// A voxel can be a simple coloured cube, or a more complex model.
// Important: it is recommended that you create voxels from a library rather than using new().
class Voxel : public Reference {
OBJ_TYPE(Voxel, Reference)
@ -21,11 +24,17 @@ public:
};
private:
VoxelLibrary * _library;
// Identifiers
int _id;
String _name;
// Properties
int _material_id;
bool _is_transparent;
// Model
Color _color;
DVector<Vector3> _model_vertices;
DVector<Vector3> _model_normals;
@ -36,24 +45,33 @@ private:
// TODO Child voxel types
public:
Voxel();
_FORCE_INLINE_ void set_name(String name) { _name = name; }
// Properties
_FORCE_INLINE_ Ref<Voxel> set_name(String name) { _name = name; return Ref<Voxel>(this); }
_FORCE_INLINE_ String get_name() const { return _name; }
void set_id(int id);
Ref<Voxel> set_id(int id);
_FORCE_INLINE_ int get_id() const { return _id; }
_FORCE_INLINE_ void set_color(Color color) { _color = color; }
_FORCE_INLINE_ Ref<Voxel> set_color(Color color) { _color = color; return Ref<Voxel>(this); }
_FORCE_INLINE_ Color get_color() const { return _color; }
_FORCE_INLINE_ void set_material_id(unsigned int id) { _material_id = id; }
Ref<Voxel> set_material_id(unsigned int id);
_FORCE_INLINE_ unsigned int get_material_id() const { return _material_id; }
void set_cube_geometry(float sy = 1);
void set_cube_uv_all_sides(Vector3 atlas_pos);
void set_cube_uv_tbs_sides(Vector3 top_atlas_pos, Vector3 side_atlas_pos, Vector3 bottom_atlas_pos);
_FORCE_INLINE_ Ref<Voxel> set_transparent(bool t = true) { _is_transparent = t; return Ref<Voxel>(this); }
_FORCE_INLINE_ bool is_transparent() const { return _is_transparent; }
// Built-in geometry generators
Ref<Voxel> set_cube_geometry(float sy = 1);
Ref<Voxel> set_cube_uv_all_sides(Vector2 atlas_pos);
Ref<Voxel> set_cube_uv_tbs_sides(Vector2 top_atlas_pos, Vector2 side_atlas_pos, Vector2 bottom_atlas_pos);
//Ref<Voxel> set_xquad_geometry(Vector2 atlas_pos);
// Getters for native usage only
const DVector<Vector3> & get_model_vertices() const { return _model_vertices; }
const DVector<Vector3> & get_model_normals() const { return _model_normals; }
@ -61,7 +79,11 @@ public:
const DVector<Vector3> & get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; }
const DVector<Vector2> & get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; }
void set_library_ptr(VoxelLibrary * lib) { _library = lib; }
protected:
Ref<Voxel> _set_cube_uv_sides(const Vector2 atlas_pos[6]);
static void _bind_methods();
};

View File

@ -18,6 +18,7 @@ class VoxelBuffer : public Reference {
struct Channel {
// Allocated when the channel is populated.
// Array of array of arrays, in order [z][x][y] because it makes vertical-wise access faster (the engine is Y-up).
// SUGG: move to flat storage?
uint8_t *** data;
uint8_t defval; // Default value when data is null
@ -60,6 +61,7 @@ public:
void set_voxel_v(int value, Vector3 pos, unsigned int channel_index = 0);
void fill(int defval, unsigned int channel_index = 0);
//void fill_min_max(int value, int x0, int y0, int z0, int x1, int y1, int z1, unsigned int channel_index = 0);
bool is_uniform(unsigned int channel_index = 0);

36
voxel_library.cpp Normal file
View File

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

37
voxel_library.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef VOXEL_LIBRARY_H
#define VOXEL_LIBRARY_H
#include <reference.h>
#include "voxel.h"
class VoxelLibrary : public Reference {
OBJ_TYPE(VoxelLibrary, Reference)
public:
static const unsigned int MAX_VOXEL_TYPES = 256; // Required limit because voxel types are stored in 8 bits
VoxelLibrary();
~VoxelLibrary();
int get_atlas_size() const { return _atlas_size; }
void set_atlas_size(int s);
// Use this factory rather than creating voxels from scratch
Ref<Voxel> create_voxel(int id, String name);
// Internal getters
_FORCE_INLINE_ bool has_voxel(int id) const { return _voxel_types[id].is_valid(); }
_FORCE_INLINE_ const Voxel & get_voxel_const(int id) const { return **_voxel_types[id]; }
private:
Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES];
int _atlas_size;
protected:
static void _bind_methods();
};
#endif // VOXEL_LIBRARY_H

View File

@ -1,4 +1,5 @@
#include "voxel_mesh_builder.h"
#include "voxel_library.h"
static const Vector3i g_side_normals[Voxel::SIDE_COUNT] = {
Vector3i(-1, 0, 0),
@ -13,12 +14,9 @@ VoxelMeshBuilder::VoxelMeshBuilder() {
}
void VoxelMeshBuilder::add_voxel_type(Ref<Voxel> voxel) {
ERR_FAIL_COND(voxel.is_null());
ERR_FAIL_COND(voxel->get_id() >= MAX_VOXEL_TYPES);
ERR_FAIL_COND(voxel->get_material_id() >= MAX_MATERIALS);
unsigned int id = voxel->get_id();
_voxel_types[id] = voxel;
void VoxelMeshBuilder::set_library(Ref<VoxelLibrary> library) {
ERR_FAIL_COND(library.is_null());
_library = library;
}
void VoxelMeshBuilder::set_material(Ref<Material> material, unsigned int id) {
@ -29,8 +27,10 @@ void VoxelMeshBuilder::set_material(Ref<Material> material, unsigned int id) {
Ref<Mesh> VoxelMeshBuilder::build(Ref<VoxelBuffer> buffer_ref) {
ERR_FAIL_COND_V(buffer_ref.is_null(), Ref<Mesh>());
ERR_FAIL_COND_V(_library.is_null(), Ref<Mesh>());
const VoxelBuffer & buffer = **buffer_ref;
const VoxelLibrary & library = **_library;
for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
_surface_tool[i].begin(Mesh::PRIMITIVE_TRIANGLES);
@ -44,9 +44,9 @@ Ref<Mesh> VoxelMeshBuilder::build(Ref<VoxelBuffer> buffer_ref) {
int voxel_id = buffer.get_voxel_local(x, y, z, 0);
if (voxel_id != 0 && !_voxel_types[voxel_id].is_null()) {
if (voxel_id != 0 && library.has_voxel(voxel_id)) {
const Voxel & voxel = **_voxel_types[voxel_id];
const Voxel & voxel = library.get_voxel_const(voxel_id);
SurfaceTool & st = _surface_tool[voxel.get_material_id()];
@ -68,12 +68,14 @@ Ref<Mesh> VoxelMeshBuilder::build(Ref<VoxelBuffer> buffer_ref) {
// TODO Better face visibility test
if (neighbor_voxel_id == 0) {
DVector<Vector3>::Read r = vertices.read();
DVector<Vector3>::Read rv = vertices.read();
DVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read();
Vector3 pos(x - 1, y - 1, z - 1);
for (unsigned int i = 0; i < vertices.size(); ++i) {
st.add_normal(Vector3(normal.x, normal.y, normal.z));
st.add_vertex(r[i] + pos);
st.add_uv(rt[i]);
st.add_vertex(rv[i] + pos);
}
}
}
@ -85,10 +87,12 @@ Ref<Mesh> VoxelMeshBuilder::build(Ref<VoxelBuffer> buffer_ref) {
const DVector<Vector3> & vertices = voxel.get_model_vertices();
DVector<Vector3>::Read rv = voxel.get_model_vertices().read();
DVector<Vector3>::Read rn = voxel.get_model_normals().read();
DVector<Vector2>::Read rt = voxel.get_model_uv().read();
Vector3 pos(x - 1, y - 1, z - 1);
for (unsigned int i = 0; i < vertices.size(); ++i) {
st.add_normal(rn[i]);
st.add_uv(rt[i]);
st.add_vertex(rv[i] + pos);
}
}
@ -115,8 +119,8 @@ Ref<Mesh> VoxelMeshBuilder::build(Ref<VoxelBuffer> buffer_ref) {
void VoxelMeshBuilder::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_voxel_type", "voxel"), &VoxelMeshBuilder::add_voxel_type);
ObjectTypeDB::bind_method(_MD("set_material", "material", "id"), &VoxelMeshBuilder::set_material);
ObjectTypeDB::bind_method(_MD("set_library", "voxel_library"), &VoxelMeshBuilder::set_library);
ObjectTypeDB::bind_method(_MD("build", "voxel_buffer"), &VoxelMeshBuilder::build);
}

View File

@ -7,23 +7,26 @@
#include "voxel.h"
#include "voxel_buffer.h"
class VoxelLibrary;
class VoxelMeshBuilder : public Reference {
OBJ_TYPE(VoxelMeshBuilder, Reference);
static const unsigned int MAX_VOXEL_TYPES = 256; // Required limit because voxel types are stored in 8 bits
public:
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
Ref<Voxel> _voxel_types[MAX_VOXEL_TYPES];
private:
Ref<VoxelLibrary> _library;
Ref<Material> _materials[MAX_MATERIALS];
SurfaceTool _surface_tool[MAX_MATERIALS];
public:
VoxelMeshBuilder();
void add_voxel_type(Ref<Voxel> voxel);
void set_material(Ref<Material> material, unsigned int id);
void set_library(Ref<VoxelLibrary> library);
Ref<Mesh> build(Ref<VoxelBuffer> buffer_ref);
protected: