Show bounds and octrees of VoxelLodTerrain with debug drawing
parent
e70f87e4a7
commit
d158a92f57
1
SCsub
1
SCsub
|
@ -20,6 +20,7 @@ files = [
|
||||||
"server/*.cpp",
|
"server/*.cpp",
|
||||||
"math/*.cpp",
|
"math/*.cpp",
|
||||||
"edition/*.cpp",
|
"edition/*.cpp",
|
||||||
|
"editor/*.cpp",
|
||||||
"editor/graph/*.cpp",
|
"editor/graph/*.cpp",
|
||||||
"editor/terrain/*.cpp",
|
"editor/terrain/*.cpp",
|
||||||
"thirdparty/lz4/*.c"
|
"thirdparty/lz4/*.c"
|
||||||
|
|
|
@ -69,6 +69,11 @@ void VoxelTerrainEditorPlugin::set_node(Node *node) {
|
||||||
// Also moving the node around in the tree triggers exit/enter so have to listen for both.
|
// Also moving the node around in the tree triggers exit/enter so have to listen for both.
|
||||||
_node->disconnect("tree_entered", this, "_on_terrain_tree_entered");
|
_node->disconnect("tree_entered", this, "_on_terrain_tree_entered");
|
||||||
_node->disconnect("tree_exited", this, "_on_terrain_tree_exited");
|
_node->disconnect("tree_exited", this, "_on_terrain_tree_exited");
|
||||||
|
|
||||||
|
VoxelLodTerrain *vlt = Object::cast_to<VoxelLodTerrain>(_node);
|
||||||
|
if (vlt != nullptr) {
|
||||||
|
vlt->set_show_gizmos(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_node = node;
|
_node = node;
|
||||||
|
@ -76,12 +81,27 @@ void VoxelTerrainEditorPlugin::set_node(Node *node) {
|
||||||
if (_node != nullptr) {
|
if (_node != nullptr) {
|
||||||
_node->connect("tree_entered", this, "_on_terrain_tree_entered", varray(_node));
|
_node->connect("tree_entered", this, "_on_terrain_tree_entered", varray(_node));
|
||||||
_node->connect("tree_exited", this, "_on_terrain_tree_exited", varray(_node));
|
_node->connect("tree_exited", this, "_on_terrain_tree_exited", varray(_node));
|
||||||
|
|
||||||
|
VoxelLodTerrain *vlt = Object::cast_to<VoxelLodTerrain>(_node);
|
||||||
|
if (vlt != nullptr) {
|
||||||
|
vlt->set_show_gizmos(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTerrainEditorPlugin::make_visible(bool visible) {
|
void VoxelTerrainEditorPlugin::make_visible(bool visible) {
|
||||||
_restart_stream_button->set_visible(visible);
|
_restart_stream_button->set_visible(visible);
|
||||||
// Can't use `make_visible(false)` to reset our reference to the node,
|
|
||||||
|
if (_node != nullptr) {
|
||||||
|
VoxelLodTerrain *vlt = Object::cast_to<VoxelLodTerrain>(_node);
|
||||||
|
if (vlt != nullptr) {
|
||||||
|
vlt->set_show_gizmos(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO There are deselection problems I cannot fix cleanly!
|
||||||
|
|
||||||
|
// Can't use `make_visible(false)` to reset our reference to the node or reset gizmos,
|
||||||
// because of https://github.com/godotengine/godot/issues/40166
|
// because of https://github.com/godotengine/godot/issues/40166
|
||||||
// So we'll need to check if _node is null all over the place
|
// So we'll need to check if _node is null all over the place
|
||||||
}
|
}
|
||||||
|
@ -99,11 +119,11 @@ void VoxelTerrainEditorPlugin::_on_restart_stream_button_pressed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTerrainEditorPlugin::_on_terrain_tree_entered(Node *node) {
|
void VoxelTerrainEditorPlugin::_on_terrain_tree_entered(Node *node) {
|
||||||
// If the node exited the tree because it was deleted, signals we connected should automatically disconnect.
|
|
||||||
_node = node;
|
_node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelTerrainEditorPlugin::_on_terrain_tree_exited(Node *node) {
|
void VoxelTerrainEditorPlugin::_on_terrain_tree_exited(Node *node) {
|
||||||
|
// If the node exited the tree because it was deleted, signals we connected should automatically disconnect.
|
||||||
_node = nullptr;
|
_node = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
#include "voxel_debug.h"
|
||||||
|
#include "../util/direct_mesh_instance.h"
|
||||||
|
#include "../util/fixed_array.h"
|
||||||
|
#include "../util/utility.h"
|
||||||
|
#include <scene/resources/mesh.h>
|
||||||
|
|
||||||
|
namespace VoxelDebug {
|
||||||
|
|
||||||
|
FixedArray<Ref<Mesh>, ID_COUNT> g_wirecubes;
|
||||||
|
bool g_finalized = false;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void raw_copy_to(PoolVector<T> &dst, const T *src, unsigned int count) {
|
||||||
|
dst.resize(count);
|
||||||
|
PoolVector<T>::Write w = dst.write();
|
||||||
|
memcpy(w.ptr(), src, count * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color get_color(ColorID id) {
|
||||||
|
switch (id) {
|
||||||
|
case ID_VOXEL_BOUNDS:
|
||||||
|
return Color(1, 1, 1);
|
||||||
|
case ID_OCTREE_BOUNDS:
|
||||||
|
return Color(0.5, 0.5, 0.5);
|
||||||
|
default:
|
||||||
|
CRASH_NOW_MSG("Unexpected index");
|
||||||
|
}
|
||||||
|
return Color();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Mesh> get_wirecube(ColorID id) {
|
||||||
|
CRASH_COND(g_finalized);
|
||||||
|
|
||||||
|
Ref<Mesh> &wirecube = g_wirecubes[id];
|
||||||
|
|
||||||
|
if (wirecube.is_null()) {
|
||||||
|
const Vector3 positions_raw[] = {
|
||||||
|
Vector3(0, 0, 0),
|
||||||
|
Vector3(1, 0, 0),
|
||||||
|
Vector3(1, 0, 1),
|
||||||
|
Vector3(0, 0, 1),
|
||||||
|
Vector3(0, 1, 0),
|
||||||
|
Vector3(1, 1, 0),
|
||||||
|
Vector3(1, 1, 1),
|
||||||
|
Vector3(0, 1, 1)
|
||||||
|
};
|
||||||
|
PoolVector3Array positions;
|
||||||
|
raw_copy_to(positions, positions_raw, 8);
|
||||||
|
|
||||||
|
Color white(1.0, 1.0, 1.0);
|
||||||
|
PoolColorArray colors;
|
||||||
|
colors.resize(positions.size());
|
||||||
|
{
|
||||||
|
PoolColorArray::Write w = colors.write();
|
||||||
|
for (int i = 0; i < colors.size(); ++i) {
|
||||||
|
w[i] = white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int indices_raw[] = {
|
||||||
|
0, 1,
|
||||||
|
1, 2,
|
||||||
|
2, 3,
|
||||||
|
3, 0,
|
||||||
|
|
||||||
|
4, 5,
|
||||||
|
5, 6,
|
||||||
|
6, 7,
|
||||||
|
7, 4,
|
||||||
|
|
||||||
|
0, 4,
|
||||||
|
1, 5,
|
||||||
|
2, 6,
|
||||||
|
3, 7
|
||||||
|
};
|
||||||
|
PoolIntArray indices;
|
||||||
|
raw_copy_to(indices, indices_raw, 24);
|
||||||
|
|
||||||
|
Array arrays;
|
||||||
|
arrays.resize(Mesh::ARRAY_MAX);
|
||||||
|
arrays[Mesh::ARRAY_VERTEX] = positions;
|
||||||
|
arrays[Mesh::ARRAY_COLOR] = colors;
|
||||||
|
arrays[Mesh::ARRAY_INDEX] = indices;
|
||||||
|
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arrays);
|
||||||
|
|
||||||
|
Ref<SpatialMaterial> mat;
|
||||||
|
mat.instance();
|
||||||
|
mat->set_albedo(get_color(id));
|
||||||
|
mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
||||||
|
mesh->surface_set_material(0, mat);
|
||||||
|
|
||||||
|
wirecube = mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wirecube;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_resources() {
|
||||||
|
for (unsigned int i = 0; i < g_wirecubes.size(); ++i) {
|
||||||
|
g_wirecubes[i].unref();
|
||||||
|
}
|
||||||
|
g_finalized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugRenderer::~DebugRenderer() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRenderer::clear() {
|
||||||
|
for (auto it = _mesh_instances.begin(); it != _mesh_instances.end(); ++it) {
|
||||||
|
memdelete(*it);
|
||||||
|
}
|
||||||
|
_mesh_instances.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRenderer::set_world(World *world) {
|
||||||
|
_world = world;
|
||||||
|
for (auto it = _mesh_instances.begin(); it != _mesh_instances.end(); ++it) {
|
||||||
|
(*it)->set_world(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRenderer::begin() {
|
||||||
|
CRASH_COND(_inside_block);
|
||||||
|
CRASH_COND(_world == nullptr);
|
||||||
|
_current = 0;
|
||||||
|
_inside_block = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRenderer::draw_box(Transform t, ColorID color) {
|
||||||
|
DirectMeshInstance *mi;
|
||||||
|
if (_current >= _mesh_instances.size()) {
|
||||||
|
mi = memnew(DirectMeshInstance);
|
||||||
|
mi->create();
|
||||||
|
mi->set_world(_world);
|
||||||
|
_mesh_instances.push_back(mi);
|
||||||
|
} else {
|
||||||
|
mi = _mesh_instances[_current];
|
||||||
|
}
|
||||||
|
|
||||||
|
mi->set_mesh(get_wirecube(color));
|
||||||
|
mi->set_transform(t);
|
||||||
|
|
||||||
|
++_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRenderer::end() {
|
||||||
|
CRASH_COND(!_inside_block);
|
||||||
|
for (unsigned int i = _current; i < _mesh_instances.size(); ++i) {
|
||||||
|
DirectMeshInstance *mi = _mesh_instances[i];
|
||||||
|
mi->set_visible(false);
|
||||||
|
}
|
||||||
|
_inside_block = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VoxelDebug
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef VOXEL_DEBUG_H
|
||||||
|
#define VOXEL_DEBUG_H
|
||||||
|
|
||||||
|
#include <core/reference.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Mesh;
|
||||||
|
class DirectMeshInstance;
|
||||||
|
class World;
|
||||||
|
|
||||||
|
namespace VoxelDebug {
|
||||||
|
|
||||||
|
enum ColorID {
|
||||||
|
ID_VOXEL_BOUNDS = 0,
|
||||||
|
ID_OCTREE_BOUNDS,
|
||||||
|
ID_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
Ref<Mesh> get_wirecube(ColorID id);
|
||||||
|
void free_resources();
|
||||||
|
|
||||||
|
class DebugRenderer {
|
||||||
|
public:
|
||||||
|
~DebugRenderer();
|
||||||
|
|
||||||
|
void set_world(World *world);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void draw_box(Transform t, ColorID color);
|
||||||
|
void end();
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<DirectMeshInstance *> _mesh_instances;
|
||||||
|
unsigned int _current = 0;
|
||||||
|
bool _inside_block = false;
|
||||||
|
World *_world = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace VoxelDebug
|
||||||
|
|
||||||
|
#endif // VOXEL_DEBUG_H
|
|
@ -695,7 +695,8 @@ float VoxelGraphRuntime::generate_single(const Vector3i &position) {
|
||||||
|
|
||||||
case VoxelGeneratorGraph::NODE_IMAGE_2D: {
|
case VoxelGeneratorGraph::NODE_IMAGE_2D: {
|
||||||
const PNodeImage2D &n = read<PNodeImage2D>(_program, pc);
|
const PNodeImage2D &n = read<PNodeImage2D>(_program, pc);
|
||||||
// TODO Not great, but in Godot 4.0 we won't need to lock anymore. Otherwise, need to do it in a pre-run and post-run
|
// TODO Not great, but in Godot 4.0 we won't need to lock anymore.
|
||||||
|
// Otherwise, need to do it in a pre-run and post-run
|
||||||
n.p_image->lock();
|
n.p_image->lock();
|
||||||
memory[n.a_out] = get_pixel_repeat(*n.p_image, memory[n.a_x], memory[n.a_y]);
|
memory[n.a_out] = get_pixel_repeat(*n.p_image, memory[n.a_x], memory[n.a_y]);
|
||||||
n.p_image->unlock();
|
n.p_image->unlock();
|
||||||
|
|
|
@ -200,8 +200,8 @@ public:
|
||||||
|
|
||||||
inline Rect3i downscaled(int step_size) const {
|
inline Rect3i downscaled(int step_size) const {
|
||||||
Rect3i o;
|
Rect3i o;
|
||||||
o.pos = pos.udiv(step_size);
|
o.pos = pos.floordiv(step_size);
|
||||||
Vector3i max_pos = (pos + size - Vector3i(1)).udiv(step_size);
|
Vector3i max_pos = (pos + size - Vector3i(1)).floordiv(step_size);
|
||||||
o.size = max_pos - o.pos + Vector3i(1);
|
o.size = max_pos - o.pos + Vector3i(1);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,10 +134,6 @@ struct Vector3i {
|
||||||
::sort_min_max(a.z, b.z);
|
::sort_min_max(a.z, b.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vector3i udiv(int d) const {
|
|
||||||
return Vector3i(::udiv(x, d), ::udiv(y, d), ::udiv(z, d));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Vector3i udiv(const Vector3i d) const {
|
inline Vector3i udiv(const Vector3i d) const {
|
||||||
return Vector3i(::udiv(x, d.x), ::udiv(y, d.y), ::udiv(z, d.z));
|
return Vector3i(::udiv(x, d.x), ::udiv(y, d.y), ::udiv(z, d.z));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,10 @@
|
||||||
#include "voxel_string_names.h"
|
#include "voxel_string_names.h"
|
||||||
#include <core/engine.h>
|
#include <core/engine.h>
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
#include "editor/voxel_debug.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void register_voxel_types() {
|
void register_voxel_types() {
|
||||||
VoxelMemoryPool::create_singleton();
|
VoxelMemoryPool::create_singleton();
|
||||||
VoxelStringNames::create_singleton();
|
VoxelStringNames::create_singleton();
|
||||||
|
@ -94,8 +98,6 @@ void register_voxel_types() {
|
||||||
PRINT_VERBOSE(String("Size of VoxelBlock: {0}").format(varray((int)sizeof(VoxelBlock))));
|
PRINT_VERBOSE(String("Size of VoxelBlock: {0}").format(varray((int)sizeof(VoxelBlock))));
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
VoxelDebug::create_debug_box_mesh();
|
|
||||||
|
|
||||||
EditorPlugins::add_by_type<VoxelGraphEditorPlugin>();
|
EditorPlugins::add_by_type<VoxelGraphEditorPlugin>();
|
||||||
EditorPlugins::add_by_type<VoxelTerrainEditorPlugin>();
|
EditorPlugins::add_by_type<VoxelTerrainEditorPlugin>();
|
||||||
#endif
|
#endif
|
||||||
|
@ -122,7 +124,7 @@ void unregister_voxel_types() {
|
||||||
// TODO No remove?
|
// TODO No remove?
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
VoxelDebug::free_debug_box_mesh();
|
VoxelDebug::free_resources();
|
||||||
|
|
||||||
// TODO Seriously, no remove?
|
// TODO Seriously, no remove?
|
||||||
//EditorPlugins::remove_by_type<VoxelGraphEditorPlugin>();
|
//EditorPlugins::remove_by_type<VoxelGraphEditorPlugin>();
|
||||||
|
|
|
@ -440,6 +440,11 @@ void VoxelLodTerrain::_notification(int p_what) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_showing_gizmos()) {
|
||||||
|
_debug_renderer.set_world(is_visible_in_tree() ? world : nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_EXIT_WORLD: {
|
case NOTIFICATION_EXIT_WORLD: {
|
||||||
|
@ -450,6 +455,9 @@ void VoxelLodTerrain::_notification(int p_what) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
_debug_renderer.set_world(nullptr);
|
||||||
|
#endif
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||||
|
@ -461,6 +469,11 @@ void VoxelLodTerrain::_notification(int p_what) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_showing_gizmos()) {
|
||||||
|
_debug_renderer.set_world(is_visible_in_tree() ? *get_world() : nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// TODO Listen for transform changes
|
// TODO Listen for transform changes
|
||||||
|
@ -1154,6 +1167,12 @@ void VoxelLodTerrain::_process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_stats.time_process_update_responses = profiling_clock.restart();
|
_stats.time_process_update_responses = profiling_clock.restart();
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_showing_gizmos()) {
|
||||||
|
update_gizmos();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelLodTerrain::flush_pending_lod_edits() {
|
void VoxelLodTerrain::flush_pending_lod_edits() {
|
||||||
|
@ -1576,6 +1595,45 @@ Array VoxelLodTerrain::debug_get_octrees() const {
|
||||||
return positions;
|
return positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
|
void VoxelLodTerrain::update_gizmos() {
|
||||||
|
VOXEL_PROFILE_SCOPE();
|
||||||
|
|
||||||
|
VoxelDebug::DebugRenderer &dr = _debug_renderer;
|
||||||
|
dr.begin();
|
||||||
|
|
||||||
|
const int octree_size = get_block_size() << (get_lod_count() - 1);
|
||||||
|
for (Map<Vector3i, OctreeItem>::Element *E = _lod_octrees.front(); E; E = E->next()) {
|
||||||
|
Transform t = get_global_transform();
|
||||||
|
t.scale(Vector3(octree_size, octree_size, octree_size));
|
||||||
|
t.translate(E->key().to_vec3());
|
||||||
|
dr.draw_box(t, VoxelDebug::ID_OCTREE_BOUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float bounds_in_voxels_len = _bounds_in_voxels.size.length();
|
||||||
|
if (bounds_in_voxels_len < 10000) {
|
||||||
|
Transform t = get_global_transform();
|
||||||
|
Vector3 margin = Vector3(1, 1, 1) * bounds_in_voxels_len * 0.0025f;
|
||||||
|
t.scale(_bounds_in_voxels.size.to_vec3() + margin * 2.f);
|
||||||
|
t.origin = _bounds_in_voxels.pos.to_vec3() - margin;
|
||||||
|
dr.draw_box(t, VoxelDebug::ID_VOXEL_BOUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
dr.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelLodTerrain::set_show_gizmos(bool enable) {
|
||||||
|
_show_gizmos_enabled = enable;
|
||||||
|
if (_show_gizmos_enabled) {
|
||||||
|
_debug_renderer.set_world(is_visible_in_tree() ? *get_world() : nullptr);
|
||||||
|
} else {
|
||||||
|
_debug_renderer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Array VoxelLodTerrain::_b_debug_print_sdf_top_down(Vector3 center, Vector3 extents) const {
|
Array VoxelLodTerrain::_b_debug_print_sdf_top_down(Vector3 center, Vector3 extents) const {
|
||||||
Array image_array;
|
Array image_array;
|
||||||
image_array.resize(get_lod_count());
|
image_array.resize(get_lod_count());
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
#define VOXEL_LOD_TERRAIN_HPP
|
#define VOXEL_LOD_TERRAIN_HPP
|
||||||
|
|
||||||
#include "../server/voxel_server.h"
|
#include "../server/voxel_server.h"
|
||||||
|
#include "../util/direct_mesh_instance.h"
|
||||||
#include "lod_octree.h"
|
#include "lod_octree.h"
|
||||||
#include <core/set.h>
|
#include <core/set.h>
|
||||||
#include <scene/3d/spatial.h>
|
#include <scene/3d/spatial.h>
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
#include "../editor/voxel_debug.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class VoxelMap;
|
class VoxelMap;
|
||||||
class VoxelTool;
|
class VoxelTool;
|
||||||
class VoxelStream;
|
class VoxelStream;
|
||||||
|
@ -53,6 +58,7 @@ public:
|
||||||
|
|
||||||
unsigned int get_block_size_pow2() const;
|
unsigned int get_block_size_pow2() const;
|
||||||
void set_block_size_po2(unsigned int p_block_size_po2);
|
void set_block_size_po2(unsigned int p_block_size_po2);
|
||||||
|
unsigned int get_block_size() const;
|
||||||
|
|
||||||
// These must be called after an edit
|
// These must be called after an edit
|
||||||
void post_edit_area(Rect3i p_box);
|
void post_edit_area(Rect3i p_box);
|
||||||
|
@ -92,6 +98,11 @@ public:
|
||||||
Dictionary debug_get_block_info(Vector3 fbpos, int lod_index) const;
|
Dictionary debug_get_block_info(Vector3 fbpos, int lod_index) const;
|
||||||
Array debug_get_octrees() const;
|
Array debug_get_octrees() const;
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
void set_show_gizmos(bool enable);
|
||||||
|
bool is_showing_gizmos() const { return _show_gizmos_enabled; }
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
@ -99,7 +110,6 @@ protected:
|
||||||
void _process();
|
void _process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int get_block_size() const;
|
|
||||||
Spatial *get_viewer() const;
|
Spatial *get_viewer() const;
|
||||||
void immerge_block(Vector3i block_pos, int lod_index);
|
void immerge_block(Vector3i block_pos, int lod_index);
|
||||||
|
|
||||||
|
@ -132,11 +142,15 @@ private:
|
||||||
AABB _b_get_voxel_bounds() const;
|
AABB _b_get_voxel_bounds() const;
|
||||||
Array _b_debug_print_sdf_top_down(Vector3 center, Vector3 extents) const;
|
Array _b_debug_print_sdf_top_down(Vector3 center, Vector3 extents) const;
|
||||||
|
|
||||||
private:
|
|
||||||
struct OctreeItem {
|
struct OctreeItem {
|
||||||
LodOctree octree;
|
LodOctree octree;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
void update_gizmos();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
// This terrain type is a sparse grid of octrees.
|
// This terrain type is a sparse grid of octrees.
|
||||||
// Indexed by a grid coordinate whose step is the size of the highest-LOD block.
|
// Indexed by a grid coordinate whose step is the size of the highest-LOD block.
|
||||||
// Not using a pointer because Map storage is stable.
|
// Not using a pointer because Map storage is stable.
|
||||||
|
@ -188,6 +202,10 @@ private:
|
||||||
unsigned int _view_distance_voxels = 512;
|
unsigned int _view_distance_voxels = 512;
|
||||||
|
|
||||||
bool _run_stream_in_editor = true;
|
bool _run_stream_in_editor = true;
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
bool _show_gizmos_enabled = false;
|
||||||
|
VoxelDebug::DebugRenderer _debug_renderer;
|
||||||
|
#endif
|
||||||
|
|
||||||
Stats _stats;
|
Stats _stats;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,7 +48,9 @@ void DirectMeshInstance::set_mesh(Ref<Mesh> mesh) {
|
||||||
ERR_FAIL_COND(!_mesh_instance.is_valid());
|
ERR_FAIL_COND(!_mesh_instance.is_valid());
|
||||||
VisualServer &vs = *VisualServer::get_singleton();
|
VisualServer &vs = *VisualServer::get_singleton();
|
||||||
if (mesh.is_valid()) {
|
if (mesh.is_valid()) {
|
||||||
vs.instance_set_base(_mesh_instance, mesh->get_rid());
|
if (_mesh != mesh) {
|
||||||
|
vs.instance_set_base(_mesh_instance, mesh->get_rid());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vs.instance_set_base(_mesh_instance, RID());
|
vs.instance_set_base(_mesh_instance, RID());
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,55 +51,3 @@ bool try_call_script(const Object *obj, StringName method_name, const Variant **
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TOOLS_ENABLED
|
|
||||||
|
|
||||||
namespace VoxelDebug {
|
|
||||||
|
|
||||||
Ref<Mesh> g_debug_box_mesh;
|
|
||||||
|
|
||||||
void create_debug_box_mesh() {
|
|
||||||
PoolVector3Array positions;
|
|
||||||
positions.resize(8);
|
|
||||||
{
|
|
||||||
PoolVector3Array::Write w = positions.write();
|
|
||||||
for (int i = 0; i < positions.size(); ++i) {
|
|
||||||
w[i] = Cube::g_corner_position[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PoolIntArray indices;
|
|
||||||
indices.resize(Cube::EDGE_COUNT * 2);
|
|
||||||
{
|
|
||||||
PoolIntArray::Write w = indices.write();
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < Cube::EDGE_COUNT; ++i) {
|
|
||||||
w[j++] = Cube::g_edge_corners[i][0];
|
|
||||||
w[j++] = Cube::g_edge_corners[i][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Array arrays;
|
|
||||||
arrays.resize(Mesh::ARRAY_MAX);
|
|
||||||
arrays[Mesh::ARRAY_VERTEX] = positions;
|
|
||||||
arrays[Mesh::ARRAY_INDEX] = indices;
|
|
||||||
Ref<ArrayMesh> mesh;
|
|
||||||
mesh.instance();
|
|
||||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arrays);
|
|
||||||
Ref<SpatialMaterial> mat;
|
|
||||||
mat.instance();
|
|
||||||
mat->set_albedo(Color(0, 1, 0));
|
|
||||||
mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
|
||||||
mesh->surface_set_material(0, mat);
|
|
||||||
g_debug_box_mesh = mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_debug_box_mesh() {
|
|
||||||
g_debug_box_mesh.unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Mesh> get_debug_box_mesh() {
|
|
||||||
return g_debug_box_mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VoxelDebug
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -229,12 +229,4 @@ inline bool try_call_script(const Object *obj, StringName method_name, Variant a
|
||||||
return try_call_script(obj, method_name, args, 3, out_ret);
|
return try_call_script(obj, method_name, args, 3, out_ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TOOLS_ENABLED
|
|
||||||
namespace VoxelDebug {
|
|
||||||
void create_debug_box_mesh();
|
|
||||||
void free_debug_box_mesh();
|
|
||||||
Ref<Mesh> get_debug_box_mesh();
|
|
||||||
} // namespace VoxelDebug
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // HEADER_VOXEL_UTILITY_H
|
#endif // HEADER_VOXEL_UTILITY_H
|
||||||
|
|
Loading…
Reference in New Issue