#include "voxel_chunk.h" NodePath VoxelChunk::get_library_path() { return _library_path; } void VoxelChunk::set_library_path(NodePath value) { _library_path = value; } NodePath VoxelChunk::get_mesh_instance_path() { return _mesh_instance_path; } void VoxelChunk::set_mesh_instance_path(NodePath value) { _mesh_instance_path = value; } Ref VoxelChunk::get_library() { return _library; } void VoxelChunk::set_library(Ref value) { _library = value; } float VoxelChunk::get_voxel_scale() { return _voxel_scale; } void VoxelChunk::set_voxel_scale(float value) { _voxel_scale = value; } Ref VoxelChunk::get_mesher() const { return _mesher; } void VoxelChunk::set_mesher(Ref mesher) { _mesher = mesher; } bool VoxelChunk::get_build_mesh() { return _build_mesh; } void VoxelChunk::set_build_mesh(bool value) { _build_mesh = value; } bool VoxelChunk::get_create_collider() { return _create_collider; } void VoxelChunk::set_create_collider(bool value) { _create_collider = value; } bool VoxelChunk::get_bake_lights() { return _bake_lights; } void VoxelChunk::set_bake_lights(bool value) { _bake_lights = value; } NodePath VoxelChunk::get_debug_drawer_path() { return _debug_drawer_path; } void VoxelChunk::set_debug_drawer_path(NodePath value) { _debug_drawer_path = value; } Ref VoxelChunk::get_buffer() const { return _buffer; } void VoxelChunk::clear() { _voxel_lights.clear(); } void VoxelChunk::build() { ERR_FAIL_COND(!_library.is_valid()); if (!_mesher.is_valid()) { call("_create_mesher"); ERR_FAIL_COND(!_mesher.is_valid()); } _mesher->set_library(_library); if (_debug_drawer == NULL) { Node *n = get_node_or_null(_debug_drawer_path); if (n != NULL) { _debug_drawer = Object::cast_to(n); } } if (get_build_mesh()) { if (has_method("_create_mesh")) { call("_create_mesh"); } else { _mesher->add_buffer(_buffer); } finalize_mesh(); } if (get_create_collider()) { update_collider(); } } void VoxelChunk::_create_mesher() { _mesher = Ref(memnew(VoxelMesher())); } void VoxelChunk::finalize_mesh() { _mesher->set_library(_library); Node *node = get_node(_mesh_instance_path); ERR_FAIL_COND(node == NULL); _mesh_instance = Object::cast_to(node); ERR_FAIL_COND(_mesh_instance == NULL); //if (get_bake_ambient_occlusion()) { // set_enabled(true); //} else { Ref mesh = get_mesher()->build_mesh(); _mesh_instance->set_mesh(mesh); //} } void VoxelChunk::update_collider() { //_mesh_instance->create_trimesh_collision(); //StaticBody *static_body = Object::cast_to(create_trimesh_collision_node()); StaticBody *static_body = create_trimesh_collision_node(); ERR_FAIL_COND(!static_body); static_body->set_name(String(get_name()) + "_col"); add_child(static_body); if (get_owner()) { CollisionShape *cshape = Object::cast_to(static_body->get_child(0)); static_body->set_owner(get_owner()); cshape->set_owner(get_owner()); } } StaticBody *VoxelChunk::create_trimesh_collision_node() { Ref shape = memnew(ConcavePolygonShape); _mesher->create_trimesh_shape(shape); StaticBody *static_body = memnew(StaticBody); CollisionShape *cshape = memnew(CollisionShape); cshape->set_shape(shape); static_body->add_child(cshape); return static_body; } void VoxelChunk::set_enabled(bool p_enabled) { _enabled = p_enabled; if (is_inside_tree()) set_physics_process_internal(p_enabled); } bool VoxelChunk::is_enabled() const { return _enabled; } void VoxelChunk::add_voxel_light_bind(Vector3 position, Color color, float strength) { add_voxel_light(position, color, strength); } Ref VoxelChunk::add_voxel_light(Vector3i position, Color color, float strength, Vector3 offset) { Vector3 pos(position.x, position.y, position.z); Ref light = Ref(memnew(VoxelLight(position, color, strength, to_global(pos + Vector3((float)0.5, (float)0.5, (float)0.5) * _voxel_scale), offset))); _voxel_lights.push_back(light); return light; } void VoxelChunk::draw_cross_voxels(Vector3 pos) { pos *= _voxel_scale; _debug_drawer->add_vertex(pos + Vector3(0, 0, -0.2)); _debug_drawer->add_vertex(pos + Vector3(0, 0, 0.2)); _debug_drawer->add_vertex(pos + Vector3(0, -0.2, 0)); _debug_drawer->add_vertex(pos + Vector3(0, 0.2, 0)); _debug_drawer->add_vertex(pos + Vector3(-0.2, 0, 0)); _debug_drawer->add_vertex(pos + Vector3(0.2, 0, 0)); } void VoxelChunk::draw_cross_voxels(Vector3 pos, float fill) { pos *= _voxel_scale; _debug_drawer->add_vertex(pos + Vector3(0, 0, -0.5 * fill)); _debug_drawer->add_vertex(pos + Vector3(0, 0, 0.5 * fill)); _debug_drawer->add_vertex(pos + Vector3(0, -0.5 * fill, 0)); _debug_drawer->add_vertex(pos + Vector3(0, 0.5 * fill, 0)); _debug_drawer->add_vertex(pos + Vector3(-0.5 * fill, 0, 0)); _debug_drawer->add_vertex(pos + Vector3(0.5 * fill, 0, 0)); } void VoxelChunk::draw_debug_voxels(int max, Color color) { if (_debug_drawer == NULL) { Node *n = get_node(_debug_drawer_path); if (n != NULL) { _debug_drawer = Object::cast_to(n); } } ERR_FAIL_COND(_debug_drawer == NULL); _debug_drawer->clear(); _debug_drawer->begin(Mesh::PRIMITIVE_LINES); _debug_drawer->set_color(color); int a = 0; Vector3i size = _buffer->get_size(); for (int y = 0; y < size.y; ++y) { for (int z = 0; z < size.z; ++z) { for (int x = 0; x < size.x; ++x) { int type = _buffer->get_voxel(x, y, z, VoxelBuffer::CHANNEL_TYPE); if (type == 0) { continue; } draw_cross_voxels(Vector3(x, y, z), _buffer->get_voxel(x, y, z, VoxelBuffer::CHANNEL_ISOLEVEL) / 255.0); ++a; if (a > max) { break; } } } } _debug_drawer->end(); } void VoxelChunk::draw_debug_voxel_lights(int max, bool localPosition) { /* if (_debug_drawer == NULL) { Node *n = get_node(_debug_drawer_path); if (n != NULL) { _debug_drawer = Object::cast_to(n); } } if (_debug_drawer == NULL) { return; } _debug_drawer->clear(); _debug_drawer->begin(Mesh::PrimitiveType::PRIMITIVE_LINES); _debug_drawer->set_color(Color(1, 1, 1)); const int *k = NULL; Vector3 pos = get_transform().get_origin(); int a = 0; while ((k = _voxel_lights->next(k))) { Ref v = _voxel_lights->get(*k); if (localPosition) { Vector3i lp = v->get_local_position(); draw_cross_voxels(pos + Vector3(lp.x, lp.y, lp.z), (float)v->get_strength() / (float)10); } else { Vector3i wp = v->get_world_position(); draw_cross_voxels(pos + Vector3(wp.x, wp.y, wp.z), (float)v->get_strength() / (float)10); } ++a; if (a > max) { break; } } _debug_drawer->end();*/ } void VoxelChunk::_bind_methods() { BIND_VMETHOD(MethodInfo("_create_mesh")); BIND_VMETHOD(MethodInfo("_create_mesher")); ClassDB::bind_method(D_METHOD("_create_mesher"), &VoxelChunk::_create_mesher); ClassDB::bind_method(D_METHOD("get_library_path"), &VoxelChunk::get_library_path); ClassDB::bind_method(D_METHOD("set_library_path", "value"), &VoxelChunk::set_library_path); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "library_path"), "set_library_path", "get_library_path"); ClassDB::bind_method(D_METHOD("get_mesh_instance_path"), &VoxelChunk::get_mesh_instance_path); ClassDB::bind_method(D_METHOD("set_mesh_instance_path", "value"), &VoxelChunk::set_mesh_instance_path); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "mesh_instance_path"), "set_mesh_instance_path", "get_mesh_instance_path"); ClassDB::bind_method(D_METHOD("get_library"), &VoxelChunk::get_library); ClassDB::bind_method(D_METHOD("set_library", "value"), &VoxelChunk::set_library); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "VoxelmanLibrary"), "set_library", "get_library"); ClassDB::bind_method(D_METHOD("get_voxel_scale"), &VoxelChunk::get_voxel_scale); ClassDB::bind_method(D_METHOD("set_voxel_scale", "value"), &VoxelChunk::set_voxel_scale); ADD_PROPERTY(PropertyInfo(Variant::REAL, "voxel_scale"), "set_voxel_scale", "get_voxel_scale"); ClassDB::bind_method(D_METHOD("get_buffer"), &VoxelChunk::get_buffer); ADD_GROUP("Meshing", "meshing"); ClassDB::bind_method(D_METHOD("meshing_get_build_mesh"), &VoxelChunk::get_build_mesh); ClassDB::bind_method(D_METHOD("meshing_set_build_mesh", "value"), &VoxelChunk::set_build_mesh); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meshing_build_mesh"), "meshing_set_build_mesh", "meshing_get_build_mesh"); ClassDB::bind_method(D_METHOD("meshing_get_create_collider"), &VoxelChunk::get_create_collider); ClassDB::bind_method(D_METHOD("meshing_set_create_collider", "value"), &VoxelChunk::set_create_collider); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meshing_create_collider"), "meshing_set_create_collider", "meshing_get_create_collider"); ClassDB::bind_method(D_METHOD("meshing_get_bake_lights"), &VoxelChunk::get_bake_lights); ClassDB::bind_method(D_METHOD("meshing_set_bake_lights", "value"), &VoxelChunk::set_bake_lights); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meshing_bake_lights"), "meshing_set_bake_lights", "meshing_get_bake_lights"); ADD_GROUP("Settings", "setting"); ClassDB::bind_method(D_METHOD("get_debug_drawer_path"), &VoxelChunk::get_debug_drawer_path); ClassDB::bind_method(D_METHOD("set_debug_drawer_path", "value"), &VoxelChunk::set_debug_drawer_path); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "debug_drawer_path"), "set_debug_drawer_path", "get_debug_drawer_path"); ClassDB::bind_method(D_METHOD("get_mesher"), &VoxelChunk::get_mesher); ClassDB::bind_method(D_METHOD("set_mesher", "Mesher"), &VoxelChunk::set_mesher); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesher", PROPERTY_HINT_RESOURCE_TYPE, "VoxelMesher"), "set_mesher", "get_mesher"); ClassDB::bind_method(D_METHOD("build"), &VoxelChunk::build); ClassDB::bind_method(D_METHOD("finalize_mesh"), &VoxelChunk::finalize_mesh); ClassDB::bind_method(D_METHOD("clear"), &VoxelChunk::clear); ClassDB::bind_method(D_METHOD("draw_debug_voxels", "max"), &VoxelChunk::draw_debug_voxels, DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_debug_voxel_lights", "max", "localPosition"), &VoxelChunk::draw_debug_voxel_lights); } VoxelChunk::VoxelChunk() { _build_mesh = true; _create_collider = true; _bake_lights = true; _voxel_scale = 1; _buffer.instance(); _debug_drawer = NULL; } VoxelChunk::~VoxelChunk() { _voxel_lights.clear(); if (_mesher.is_valid()) { _mesher.unref(); } _buffer.unref(); _debug_drawer = NULL; if (_library.is_valid()) { _library.unref(); } if (_mesh.is_valid()) { _mesh.unref(); } }