Skip to content

Commit

Permalink
WIP VoxelMesherScript
Browse files Browse the repository at this point in the history
  • Loading branch information
Zylann committed Sep 23, 2024
1 parent 1fcdf60 commit e3c20df
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 82 deletions.
10 changes: 5 additions & 5 deletions meshers/blocky/voxel_mesher_blocky.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ StdVector<int> &get_tls_index_offsets() {
template <typename Type_T>
void generate_blocky_mesh( //
StdVector<VoxelMesherBlocky::Arrays> &out_arrays_per_material, //
VoxelMesher::Output::CollisionSurface *collision_surface, //
VoxelMesherOutput::CollisionSurface *collision_surface, //
const Span<const Type_T> type_buffer, //
const Vector3i block_size, //
const VoxelBlockyLibraryBase::BakedData &library, //
Expand Down Expand Up @@ -1094,7 +1094,7 @@ uint8_t VoxelMesherBlocky::get_shadow_occluder_mask() const {
return _parameters.shadow_occluders_mask;
}

void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
void VoxelMesherBlocky::build(VoxelMesherOutput &output, const VoxelMesherInput &input) {
const VoxelBuffer::ChannelId channel = VoxelBuffer::CHANNEL_TYPE;
Parameters params;
{
Expand Down Expand Up @@ -1163,7 +1163,7 @@ void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelMesher::In
const Vector3i block_size = voxels.get_size();
const VoxelBuffer::Depth channel_depth = voxels.get_channel_depth(channel);

VoxelMesher::Output::CollisionSurface *collision_surface = nullptr;
VoxelMesherOutput::CollisionSurface *collision_surface = nullptr;
if (input.collision_hint) {
collision_surface = &output.collision_surface;
}
Expand Down Expand Up @@ -1269,8 +1269,8 @@ void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelMesher::In
}
}

output.surfaces.push_back(Output::Surface());
Output::Surface &surface = output.surfaces.back();
output.surfaces.push_back(VoxelMesherOutput::Surface());
VoxelMesherOutput::Surface &surface = output.surfaces.back();
surface.arrays = mesh_arrays;
surface.material_index = material_index;
}
Expand Down
2 changes: 1 addition & 1 deletion meshers/blocky/voxel_mesher_blocky.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class VoxelMesherBlocky : public VoxelMesher {
bool get_shadow_occluder_side(Side side) const;
uint8_t get_shadow_occluder_mask() const;

void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
void build(VoxelMesherOutput &output, const VoxelMesherInput &input) override;

// TODO GDX: Resource::duplicate() cannot be overriden (while it can in modules).
// This will lead to performance degradation and maybe unexpected behavior
Expand Down
10 changes: 5 additions & 5 deletions meshers/cubes/voxel_mesher_cubes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ VoxelMesherCubes::Cache &VoxelMesherCubes::get_tls_cache() {
return cache;
}

void VoxelMesherCubes::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
void VoxelMesherCubes::build(VoxelMesherOutput &output, const VoxelMesherInput &input) {
ZN_PROFILE_SCOPE();
const int channel = VoxelBuffer::CHANNEL_COLOR;
Cache &cache = get_tls_cache();
Expand Down Expand Up @@ -1003,7 +1003,7 @@ void VoxelMesherCubes::build(VoxelMesher::Output &output, const VoxelMesher::Inp
const Arrays &arrays = cache.arrays_per_material[material_index];

if (arrays.positions.size() != 0) {
Output::Surface surface;
VoxelMesherOutput::Surface surface;
Array &mesh_arrays = surface.arrays;
mesh_arrays.resize(Mesh::ARRAY_MAX);

Expand Down Expand Up @@ -1188,8 +1188,8 @@ Ref<Mesh> VoxelMesherCubes::generate_mesh_from_image(Ref<Image> image, float vox

Ref<VoxelMesherCubes> mesher;
mesher.instantiate();
VoxelMesher::Output output;
VoxelMesher::Input input{ voxels, nullptr, Vector3i(), 0, false };
VoxelMesherOutput output;
VoxelMesherInput input{ voxels, nullptr, Vector3i(), 0, false };
mesher->build(output, input);

if (output.surfaces.size() == 0) {
Expand All @@ -1204,7 +1204,7 @@ Ref<Mesh> VoxelMesherCubes::generate_mesh_from_image(Ref<Image> image, float vox
for (unsigned int i = 0; i < output.surfaces.size(); ++i) {
using namespace zylann::godot;

VoxelMesher::Output::Surface &surface = output.surfaces[i];
VoxelMesherOutput::Surface &surface = output.surfaces[i];
Array arrays = surface.arrays;

if (arrays.is_empty()) {
Expand Down
2 changes: 1 addition & 1 deletion meshers/cubes/voxel_mesher_cubes.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class VoxelMesherCubes : public VoxelMesher {
VoxelMesherCubes();
~VoxelMesherCubes();

void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
void build(VoxelMesherOutput &output, const VoxelMesherInput &input) override;

void set_greedy_meshing_enabled(bool enable);
bool is_greedy_meshing_enabled() const;
Expand Down
49 changes: 49 additions & 0 deletions meshers/script/voxel_mesher_context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "voxel_mesher_context.h"
#include "../../storage/voxel_buffer.h"
#include "../voxel_mesher.h"

namespace zylann::voxel {

int VoxelMesherContext::get_voxel(Vector3i pos, const int channel) const {
ZN_ASSERT_RETURN_V(channel >= 0 && channel < static_cast<int>(VoxelBuffer::MAX_CHANNELS));
return input->voxels.get_voxel(pos, channel);
}

float VoxelMesherContext::get_voxel_f(Vector3i pos, const int channel) const {
ZN_ASSERT_RETURN_V(channel >= 0 && channel < static_cast<int>(VoxelBuffer::MAX_CHANNELS));
return input->voxels.get_voxel_f(pos, channel);
}

Vector3i VoxelMesherContext::get_voxel_resolution_with_padding() const {
return input->voxels.get_size();
}

int VoxelMesherContext::get_lod_index() const {
return input->lod_index;
}

void VoxelMesherContext::add_surface_from_arrays(Array p_arrays, const int p_material_index) {
ZN_ASSERT_RETURN(p_material_index >= 0 && p_material_index < 256);
const uint16_t material_index = static_cast<uint16_t>(p_material_index);
output->surfaces.push_back(VoxelMesherOutput::Surface{ p_arrays, material_index });
}

// This is not straightforward at the moment, lots of details can go wrong
// void VoxelMesherContext::add_mesher(Ref<VoxelMesher> mesher) {
// ZN_ASSERT_RETURN(mesher.is_valid());
// mesher->build(*output, *input);
// }

void VoxelMesherContext::_bind_methods() {
using Self = VoxelMesherContext;

ClassDB::bind_method(D_METHOD("get_voxel", "position", "channel"), &Self::get_voxel);
ClassDB::bind_method(D_METHOD("get_voxel_f", "position", "channel"), &Self::get_voxel_f);
ClassDB::bind_method(D_METHOD("get_voxel_resolution_with_padding"), &Self::get_voxel_resolution_with_padding);
ClassDB::bind_method(D_METHOD("get_lod_index"), &Self::get_lod_index);
ClassDB::bind_method(
D_METHOD("add_surface_from_arrays", "arrays", "material_index"), &Self::add_surface_from_arrays
);
}

} // namespace zylann::voxel
38 changes: 38 additions & 0 deletions meshers/script/voxel_mesher_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef VOXEL_MESHER_CONTEXT_H
#define VOXEL_MESHER_CONTEXT_H

#include "../../util/godot/classes/object.h"
#include "../voxel_mesher_input.h"
#include "../voxel_mesher_output.h"

namespace zylann::voxel {

// Data and functions provided to script when meshing one chunk of voxels.
// Must not be created or stored by scripts.
class VoxelMesherContext : public Object {
GDCLASS(VoxelMesherContext, Object)
public:
const VoxelMesherInput *input = nullptr;
VoxelMesherOutput *output = nullptr;

// TODO Maybe we need a VoxelBufferReadOnly?
// Ref<VoxelBuffer> voxels_wrapper;
// Ref<VoxelBuffer> get_voxels();

// Voxels access (read-only)
int get_voxel(Vector3i pos, const int channel) const;
float get_voxel_f(Vector3i pos, const int channel) const;
Vector3i get_voxel_resolution_with_padding() const;
int get_lod_index() const;

// Output
void add_surface_from_arrays(Array p_arrays, const int p_material_index);
// void add_mesher(Ref<VoxelMesher> mesher);

private:
static void _bind_methods();
};

} // namespace zylann::voxel

#endif // VOXEL_MESHER_CONTEXT_H
79 changes: 79 additions & 0 deletions meshers/script/voxel_mesher_script.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "voxel_mesher_script.h"
#include "../../storage/voxel_buffer_gd.h"
#include "../../util/profiling.h"

namespace zylann::voxel {

VoxelMesherScript::VoxelMesherScript() {
// Default padding
set_padding(1, 1);
}

VoxelMesherScript::~VoxelMesherScript() {
for (VoxelMesherContext *context : _context_pool) {
memdelete(context);
}
}

void VoxelMesherScript::build(VoxelMesherOutput &output, const VoxelMesherInput &input) {
ZN_PROFILE_SCOPE();

VoxelMesherContext *context = get_or_create_context();

context->input = &input;

if (!GDVIRTUAL_CALL(_build, context)) {
WARN_PRINT_ONCE("VoxelMesherScript::_build is unimplemented!");
}

return_context(context);
}

Ref<Material> VoxelMesherScript::get_material_by_index(unsigned int i) const {
Ref<Material> material;
if (!GDVIRTUAL_CALL(_get_material_by_index, i, material)) {
WARN_PRINT_ONCE("VoxelMesherScript::_get_material_by_index is unimplemented!");
}
return material;
}

unsigned int VoxelMesherScript::get_material_index_count() const {
int count = 0;
if (!GDVIRTUAL_CALL(_get_material_index_count, count)) {
WARN_PRINT_ONCE("VoxelMesherScript::_get_material_index_count is unimplemented!");
}
ZN_ASSERT_RETURN_V(count >= 0, 0);
return count;
}

VoxelMesherContext *VoxelMesherScript::get_or_create_context() {
{
MutexLock(_context_pool_mutex);
if (_context_pool.size() != 0) {
VoxelMesherContext *context = _context_pool.back();
_context_pool.pop_back();
return context;
}
}
return memnew(VoxelMesherContext);
}

void VoxelMesherScript::return_context(VoxelMesherContext *context) {
MutexLock mlock(_context_pool_mutex);
_context_pool.push_back(context);
}

void VoxelMesherScript::_b_set_padding(const int p_negative_padding, const int p_positive_padding) {
// Check for reasonable padding
ZN_ASSERT_RETURN(p_negative_padding >= 0 && p_negative_padding <= 2);
ZN_ASSERT_RETURN(p_positive_padding >= 0 && p_positive_padding <= 2);
set_padding(p_negative_padding, p_positive_padding);
}

void VoxelMesherScript::_bind_methods() {
GDVIRTUAL_BIND(_build, "context");
GDVIRTUAL_BIND(_get_material_by_index, "index");
GDVIRTUAL_BIND(_get_material_index_count);
}

} // namespace zylann::voxel
45 changes: 45 additions & 0 deletions meshers/script/voxel_mesher_script.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef VOXEL_MESHER_SCRIPT_H
#define VOXEL_MESHER_SCRIPT_H

#include "../../util/containers/std_vector.h"
#include "../../util/godot/core/gdvirtual.h"
#include "../../util/thread/mutex.h"
#include "../voxel_mesher.h"
// GDVIRTUAL requires complete definition of the class
#include "voxel_mesher_context.h"

namespace zylann::voxel {

// Allows to implement an entirely custom mesher using the scripting API.
// With GDScript it can be used for prototyping, and faster languages like C# could be used for viable performance.
// If you are creating a custom mesher with C++ using direct access to the module, prefer using VoxelMesher.
class VoxelMesherScript : public VoxelMesher {
GDCLASS(VoxelMesherScript, VoxelMesher)
public:
VoxelMesherScript();
~VoxelMesherScript();

void build(VoxelMesherOutput &output, const VoxelMesherInput &input) override;
Ref<Material> get_material_by_index(unsigned int i) const override;
unsigned int get_material_index_count() const override;

protected:
GDVIRTUAL1C(_build, VoxelMesherContext *)
GDVIRTUAL1RC(Ref<Material>, _get_material_by_index, int)
GDVIRTUAL0RC(int, _get_material_index_count)

private:
VoxelMesherContext *get_or_create_context();
void return_context(VoxelMesherContext *context);

void _b_set_padding(const int p_negative_padding, const int p_positive_padding);

static void _bind_methods();

StdVector<VoxelMesherContext *> _context_pool;
Mutex _context_pool_mutex;
};

} // namespace zylann::voxel

#endif // VOXEL_MESHER_SCRIPT_H
2 changes: 1 addition & 1 deletion meshers/transvoxel/voxel_mesher_transvoxel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void simplify(

} // namespace

void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
void VoxelMesherTransvoxel::build(VoxelMesherOutput &output, const VoxelMesherInput &input) {
ZN_PROFILE_SCOPE();

static thread_local transvoxel::Cache tls_cache;
Expand Down
2 changes: 1 addition & 1 deletion meshers/transvoxel/voxel_mesher_transvoxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class VoxelMesherTransvoxel : public VoxelMesher {
VoxelMesherTransvoxel();
~VoxelMesherTransvoxel();

void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
void build(VoxelMesherOutput &output, const VoxelMesherInput &input) override;
Ref<ArrayMesh> build_transition_mesh(Ref<godot::VoxelBuffer> voxels, int direction);

int get_used_channels_mask() const override;
Expand Down
12 changes: 6 additions & 6 deletions meshers/voxel_mesher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Ref<Mesh> VoxelMesher::build_mesh(
) {
ZN_PROFILE_SCOPE();

Output output;
Input input{ voxels, nullptr, Vector3i(), 0, false, false, false };
VoxelMesherOutput output;
VoxelMesherInput input{ voxels, nullptr, Vector3i(), 0, false, false, false };

DetailRenderingSettings detail_texture_settings;
detail_texture_settings.begin_lod_index = 0;
Expand Down Expand Up @@ -56,7 +56,7 @@ Ref<Mesh> VoxelMesher::build_mesh(

int gd_surface_index = 0;
for (unsigned int i = 0; i < output.surfaces.size(); ++i) {
Output::Surface &surface = output.surfaces[i];
VoxelMesherOutput::Surface &surface = output.surfaces[i];
Array &arrays = surface.arrays;

if (arrays.is_empty()) {
Expand Down Expand Up @@ -128,7 +128,7 @@ Ref<Mesh> VoxelMesher::build_mesh(
return mesh;
}

void VoxelMesher::build(Output &output, const Input &input) {
void VoxelMesher::build(VoxelMesherOutput &output, const VoxelMesherInput &input) {
ERR_PRINT("Not implemented");
}

Expand Down Expand Up @@ -157,11 +157,11 @@ unsigned int VoxelMesher::get_material_index_count() const {
return 0;
}

bool VoxelMesher::is_mesh_empty(const StdVector<Output::Surface> &surfaces) {
bool VoxelMesher::is_mesh_empty(const StdVector<VoxelMesherOutput::Surface> &surfaces) {
if (surfaces.size() == 0) {
return true;
}
for (const Output::Surface &surface : surfaces) {
for (const VoxelMesherOutput::Surface &surface : surfaces) {
if (is_surface_triangulated(surface.arrays)) {
return false;
}
Expand Down
Loading

0 comments on commit e3c20df

Please sign in to comment.