From 4fd24f03a15bb6f1720da5385c91ea07270d28e7 Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Tue, 29 Sep 2026 20:09:27 -0400 Subject: [PATCH] Slicing function now has multiple deferred stages. --- src/liborng/interfaces/i_damageable.cpp | 54 +- src/liborng/interfaces/i_damageable.h | 27 +- .../nodes/character_nodes/character_3d.cpp | 129 ++-- .../nodes/character_nodes/character_3d.h | 10 +- .../character_nodes/character_skeleton3d.cpp | 11 +- .../character_nodes/character_skeleton3d.h | 10 +- src/liborng/nodes/mesh_editing_library.cpp | 607 ++++++++++-------- src/liborng/nodes/mesh_editing_library.h | 114 +++- src/liborng/register_types.cpp | 1 + 9 files changed, 614 insertions(+), 349 deletions(-) diff --git a/src/liborng/interfaces/i_damageable.cpp b/src/liborng/interfaces/i_damageable.cpp index 8d705d6..b06ecc2 100644 --- a/src/liborng/interfaces/i_damageable.cpp +++ b/src/liborng/interfaces/i_damageable.cpp @@ -1,8 +1,60 @@ /* - * ©2023 Batty Bovine Productions, LLC. All Rights Reserved. + * ©2026 Batty Bovine Productions, LLC. All Rights Reserved. * * If this source code makes it to the public internet, this software can be * considered to be protected by the MIT licence. Have fun with it. */ #include "i_damageable.h" + +#include "orng_macros.h" + +#include "godot_cpp/classes/scene_tree.hpp" +#include "godot_cpp/classes/scene_tree_timer.hpp" + + +void IDamageable::_slice_meshes(Ref data) +{ + this->_is_slicing = true; + this->_input_queue.emplace_back(data); + if (this->_slice_state_queue.empty()) + this->_new_slice_loop(); +} + +void IDamageable::_new_slice_loop() +{ + this->_slice_state_queue.emplace_back(MeshEditingLibrary::slice_mesh(this->_input_queue.front())); + this->_slice_loop(); +} + +void IDamageable::_slice_loop() +{ + Ref current_state = this->_slice_state_queue.front(); + switch(current_state->current_stage) + { + case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_INIT: + MeshEditingLibrary::slice_mesh_init(current_state); + break; + case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_PLANE_SPLIT: + MeshEditingLibrary::slice_mesh_plane_split(current_state); + break; + case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_EDGE_SPLIT: + MeshEditingLibrary::slice_mesh_edge_split(current_state); + break; + case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_APPLY_CAP: + MeshEditingLibrary::slice_mesh_apply_cap(current_state); + break; + case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_COMPLETE: + this->_slice_complete(current_state->output); + this->_input_queue.erase(this->_input_queue.begin()); + this->_slice_state_queue.erase(this->_slice_state_queue.begin()); + if (!this->_input_queue.empty()) + return this->_new_slice_loop(); + break; + } + + if (!this->_input_queue.empty()) + CALL_NEXT_FRAME(callable_mp(this, &IDamageable::_slice_loop)); + else + this->_is_slicing = false; +} diff --git a/src/liborng/interfaces/i_damageable.h b/src/liborng/interfaces/i_damageable.h index e38c3a5..735b9b3 100644 --- a/src/liborng/interfaces/i_damageable.h +++ b/src/liborng/interfaces/i_damageable.h @@ -1,5 +1,5 @@ /* - * ©2023 Batty Bovine Productions, LLC. All Rights Reserved. + * ©2026 Batty Bovine Productions, LLC. All Rights Reserved. * * If this source code makes it to the public internet, this software can be * considered to be protected by the MIT licence. Have fun with it. @@ -7,9 +7,32 @@ #pragma once +#include "nodes/mesh_editing_library.h" -class IDamageable +#include "godot_cpp/classes/node.hpp" +using namespace godot; + + +class IDamageable : public Node3D { public: virtual void take_damage(const struct HurtboxDamage &hit_data) = 0; + +protected: + void _slice_meshes(Ref data); + + virtual void _slice_complete(Ref data) = 0; + +private: + void _new_slice_loop(); + void _slice_loop(); + + bool _is_slicing = false; + + std::vector> _slice_state_queue; + std::vector> _input_queue; + + // Godot boilerplate below +protected: + static void _bind_methods() {} }; diff --git a/src/liborng/nodes/character_nodes/character_3d.cpp b/src/liborng/nodes/character_nodes/character_3d.cpp index 607ba24..dc52176 100644 --- a/src/liborng/nodes/character_nodes/character_3d.cpp +++ b/src/liborng/nodes/character_nodes/character_3d.cpp @@ -42,8 +42,17 @@ void Character3D::set_meshes(TypedArray m) void Character3D::set_character_skeleton(CharacterSkeleton3D *cs) { - this->character_skeleton = cs; - this->_rebuild_mesh_instances(); + if (cs) + { + if (this->character_skeleton) + { + this->skeleton_set.erase(this->character_skeleton); + this->character_skeleton->queue_free(); + } + this->character_skeleton = cs; + this->skeleton_set.emplace(this->character_skeleton); + this->_rebuild_mesh_instances(); + } } @@ -66,58 +75,19 @@ void Character3D::_next_hurtbox_in_queue() Skeleton3D *skeleton = character_skeleton->get_skeleton(); const Plane &local_slice_plane = skeleton->get_global_transform().inverse().xform(Plane(hit_data.global_hit_transform.get_basis().get_column(1), hit_data.global_hit_transform.origin)); - std::vector sliced_mesh_instances = character_skeleton->get_mesh_instances(); + TypedArray sliced_mesh_instances = character_skeleton->get_mesh_instances(); const uint32_t num_mesh_instances = sliced_mesh_instances.size(); TypedArray first_half_meshes_to_add; TypedArray other_half_meshes_to_add; - for (uint32_t i = 0; i < num_mesh_instances; i++) - { - Ref input; input.instantiate(); - input->sliceable_mesh_instance = sliced_mesh_instances[i]; - input->sliceable_skeleton = skeleton; - input->original_aabb = this->_full_aabb; - input->local_plane = local_slice_plane; - input->cap_option = MeshEditingLibrary::CAP_UV_FILL_MESH_BOUNDS; - input->cap_materials = this->inner_materials; - Ref output = MeshEditingLibrary::slice_mesh(input); - - if (output->main_half->get_surface_count() <= 0 && output->secondary_half->get_surface_count() > 0) - { - Ref temp = output->main_half; - output->main_half = output->secondary_half; - output->secondary_half = temp; - } - - if (output->main_half->get_surface_count() > 0) - { - first_half_meshes_to_add.append(output->main_half); - } - - if (output->secondary_half->get_surface_count() > 0) - { - other_half_meshes_to_add.append(output->secondary_half); - } - } - character_skeleton->set_meshes(first_half_meshes_to_add); - if (other_half_meshes_to_add.size() > 0) - { - RandomNumberGenerator *rng = memnew(RandomNumberGenerator); - const float random_x = rng->randf_range(-0.05f, 0.05f); - const float random_z = rng->randf_range(-0.05f, 0.05f); - - CharacterSkeleton3D *new_character_skeleton = cast_to(this->character_skeleton->duplicate()); - this->character_skeleton->add_sibling(new_character_skeleton); - new_character_skeleton->set_position(Vector3(random_x, 0.0f, random_z)); - - PRINT_LOG(CHARACTER3D_TAG, "Adding new meshes:"); - for (uint16_t i = 0; i < other_half_meshes_to_add.size(); i++) - { - const Ref &new_array_mesh = other_half_meshes_to_add[i]; - PRINT_LOG(CHARACTER3D_TAG, " Mesh ", i+1, " size: ", new_array_mesh->get_surface_count()); - } - new_character_skeleton->set_meshes(other_half_meshes_to_add); - } + Ref input; input.instantiate(); + input->mesh_instance = cast_to(sliced_mesh_instances[0]); + input->skeleton = skeleton; + input->full_aabb = this->_full_aabb; + input->local_plane = local_slice_plane; + input->cap_option = MeshEditingLibrary::CAP_UV_FILL_MESH_BOUNDS; + input->cap_materials = this->inner_materials; + this->_slice_meshes(input); } else { @@ -128,6 +98,59 @@ void Character3D::_next_hurtbox_in_queue() CALL_NEXT_FRAME(callable_mp(this, &Character3D::_next_hurtbox_in_queue)); } +void Character3D::_slice_complete(Ref data) +{ + if (data->main_half->get_surface_count() <= 0 && data->secondary_half->get_surface_count() > 0) + { + Ref temp = data->main_half; + data->main_half = data->secondary_half; + data->secondary_half = temp; + } + + TypedArray first_half_meshes_to_add; + TypedArray other_half_meshes_to_add; + + if (data->main_half->get_surface_count() > 0) + { + first_half_meshes_to_add.append(data->main_half); + } + + if (data->secondary_half->get_surface_count() > 0) + { + other_half_meshes_to_add.append(data->secondary_half); + } + + for (CharacterSkeleton3D *skeleton : this->skeleton_set) + { + if (skeleton->get_skeleton() == data->original_skeleton) + { + skeleton->set_meshes(first_half_meshes_to_add); + break; + } + } + + if (other_half_meshes_to_add.size() > 0) + { + RandomNumberGenerator *rng = memnew(RandomNumberGenerator); + const float random_x = rng->randf_range(-0.05f, 0.05f); + const float random_z = rng->randf_range(-0.05f, 0.05f); + + CharacterSkeleton3D *new_character_skeleton = cast_to(this->character_skeleton->duplicate()); + this->character_skeleton->add_sibling(new_character_skeleton); + new_character_skeleton->set_position(Vector3(random_x, 0.0f, random_z)); + + PRINT_LOG(CHARACTER3D_TAG, "Adding new meshes:"); + for (uint16_t i = 0; i < other_half_meshes_to_add.size(); i++) + { + const Ref &new_array_mesh = other_half_meshes_to_add[i]; + PRINT_LOG(CHARACTER3D_TAG, " Mesh ", i+1, " size: ", new_array_mesh->get_surface_count()); + } + new_character_skeleton->set_meshes(other_half_meshes_to_add); + + this->skeleton_set.emplace(new_character_skeleton); + } +} + void Character3D::_on_fell_out_of_world() { @@ -140,11 +163,13 @@ void Character3D::_rebuild_mesh_instances() if (!this->character_skeleton || !this->is_node_ready()) return; - std::vector mesh_instances = this->character_skeleton->set_meshes(this->meshes); + TypedArray mesh_instances = this->character_skeleton->set_meshes(this->meshes); const uint32_t num_meshes = mesh_instances.size(); this->_full_aabb = AABB(); - for (const MeshInstance3D *mesh_instance : mesh_instances) + for (uint32_t i = 0; i < num_meshes; i++) { + const MeshInstance3D *mesh_instance = cast_to(mesh_instances[i]); + const Vector3 &full_aabb_position = this->_full_aabb.get_position(); const Vector3 &full_aabb_size = this->_full_aabb.get_size(); diff --git a/src/liborng/nodes/character_nodes/character_3d.h b/src/liborng/nodes/character_nodes/character_3d.h index c2fb51d..6085198 100644 --- a/src/liborng/nodes/character_nodes/character_3d.h +++ b/src/liborng/nodes/character_nodes/character_3d.h @@ -13,6 +13,8 @@ #include "nodes/character_nodes/character_skeleton3d.h" #include +#include + #include #include #include @@ -23,9 +25,9 @@ using namespace godot; #define CHARACTER3D_TAG "Character3D" -class Character3D : public CharacterBody3D, public IDamageable +class Character3D : public IDamageable { - GDCLASS(Character3D, CharacterBody3D); + GDCLASS(Character3D, IDamageable); public: virtual void _ready() override; @@ -49,9 +51,13 @@ private: void _rebuild_mesh_instances(); void _next_hurtbox_in_queue(); + virtual void _slice_complete(Ref data) override; + TypedArray meshes; CharacterSkeleton3D *character_skeleton = nullptr; + std::unordered_set skeleton_set; + AABB _full_aabb; TypedArray inner_materials; diff --git a/src/liborng/nodes/character_nodes/character_skeleton3d.cpp b/src/liborng/nodes/character_nodes/character_skeleton3d.cpp index 9204a5b..2c805cd 100644 --- a/src/liborng/nodes/character_nodes/character_skeleton3d.cpp +++ b/src/liborng/nodes/character_nodes/character_skeleton3d.cpp @@ -16,21 +16,22 @@ using namespace godot; -std::vector CharacterSkeleton3D::set_meshes(TypedArray meshes) +TypedArray CharacterSkeleton3D::set_meshes(TypedArray meshes) { if (this->skeleton) { - this->_old_mesh_instances = this->_mesh_instances; + this->_old_mesh_instances = this->_mesh_instances.duplicate(true); this->_mesh_instances.clear(); uint16_t num_new_meshes = meshes.size(); + this->_mesh_instances.resize(num_new_meshes); for (uint16_t i = 0; i < num_new_meshes; i++) { MeshInstance3D *mesh_instance = memnew(MeshInstance3D); mesh_instance->set_mesh(meshes[i]); mesh_instance->set_skeleton_path(this->skeleton->get_path()); this->skeleton->add_child(mesh_instance, false, Node::INTERNAL_MODE_BACK); - this->_mesh_instances.emplace_back(mesh_instance); + this->_mesh_instances[i] = mesh_instance; } CALL_NEXT_FRAME(callable_mp(this, &CharacterSkeleton3D::_delete_old_meshes)); @@ -40,8 +41,8 @@ std::vector CharacterSkeleton3D::set_meshes(TypedArray_old_mesh_instances) - old_mesh->queue_free(); + for (uint16_t i = 0; i < this->_old_mesh_instances.size(); i++) + cast_to(this->_old_mesh_instances[i])->queue_free(); this->_old_mesh_instances.clear(); } diff --git a/src/liborng/nodes/character_nodes/character_skeleton3d.h b/src/liborng/nodes/character_nodes/character_skeleton3d.h index 7a77049..731f10c 100644 --- a/src/liborng/nodes/character_nodes/character_skeleton3d.h +++ b/src/liborng/nodes/character_nodes/character_skeleton3d.h @@ -26,15 +26,15 @@ class CharacterSkeleton3D : public Node3D GDCLASS(CharacterSkeleton3D, Node3D); public: - std::vector set_meshes(TypedArray meshes); + TypedArray set_meshes(TypedArray meshes); Skeleton3D *get_skeleton() const { return this->skeleton; } PhysicalBoneSimulator3D *get_physical_bone_simulator() const { return this->physical_bone_simulator; } AnimationPlayer *get_animation_player() const { return this->animation_player; } AnimationTree *get_animation_tree() const { return this->animation_tree; } - void replace_mesh_instance(const uint16_t index, Ref new_mesh) { this->_mesh_instances[index]->set_mesh(new_mesh); } - std::vector get_mesh_instances() const { return this->_mesh_instances; } + void replace_mesh_instance(const uint16_t index, Ref new_mesh) { cast_to(this->_mesh_instances[index])->set_mesh(new_mesh); } + TypedArray get_mesh_instances() const { return this->_mesh_instances; } protected: void set_skeleton(Skeleton3D *s) { this->skeleton = s; } @@ -53,8 +53,8 @@ private: AnimationPlayer *animation_player = nullptr; AnimationTree *animation_tree = nullptr; - std::vector _mesh_instances; - std::vector _old_mesh_instances; + TypedArray _mesh_instances; + TypedArray _old_mesh_instances; // Godot boilerplate below protected: diff --git a/src/liborng/nodes/mesh_editing_library.cpp b/src/liborng/nodes/mesh_editing_library.cpp index 65bfb08..c9fc234 100644 --- a/src/liborng/nodes/mesh_editing_library.cpp +++ b/src/liborng/nodes/mesh_editing_library.cpp @@ -9,8 +9,6 @@ #include "orng_macros.h" #include "earcut.hpp" -#include - #include "godot_cpp/classes/immediate_mesh.hpp" #include "godot_cpp/classes/surface_tool.hpp" #include "godot_cpp/classes/time.hpp" @@ -18,277 +16,324 @@ using namespace godot; -Ref MeshEditingLibrary::slice_mesh(const Ref input) +Ref MeshEditingLibrary::slice_mesh(const Ref input) { - Ref out; out.instantiate(); + Ref fresh_state; + fresh_state.instantiate(); - Ref first_half; first_half.instantiate(); - Ref other_half; other_half.instantiate(); + fresh_state->input = input; - const Time *time = Time::get_singleton(); + fresh_state->output.instantiate(); - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Started slicing mesh at ", time->get_ticks_msec(), "ms"); + fresh_state->first_half.instantiate(); + fresh_state->other_half.instantiate(); - const Ref original_mesh = input->sliceable_mesh_instance->get_mesh(); - const uint8_t num_surfaces = original_mesh->get_surface_count(); - - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Got skinned vertices at ", time->get_ticks_msec(), "ms"); - - std::vector surface_arrays_list; surface_arrays_list.resize(num_surfaces); - std::vector skinned_vertex_positions; skinned_vertex_positions.resize(num_surfaces); - std::vector> skinned_vertex_transforms; skinned_vertex_transforms.resize(num_surfaces); - - std::vector surface_has_normal; surface_has_normal.resize(num_surfaces); - std::vector surface_has_tangent; surface_has_tangent.resize(num_surfaces); - std::vector surface_has_uv; surface_has_uv.resize(num_surfaces); - std::vector surface_has_uv2; surface_has_uv2.resize(num_surfaces); - std::vector surface_has_colour; surface_has_colour.resize(num_surfaces); - std::vector surface_has_bone; surface_has_bone.resize(num_surfaces); - std::vector surface_has_weight; surface_has_weight.resize(num_surfaces); - std::vector surface_has_custom0; surface_has_custom0.resize(num_surfaces); - - std::vector num_bones_per_vertex; num_bones_per_vertex.resize(num_surfaces); - std::vector num_custom0_per_vertex; num_custom0_per_vertex.resize(num_surfaces); - - std::vector first_half_vertices; first_half_vertices.resize(num_surfaces); - std::vector first_half_normals; first_half_normals.resize(num_surfaces); - std::vector first_half_tangents; first_half_tangents.resize(num_surfaces); - std::vector first_half_uvs; first_half_uvs.resize(num_surfaces); - std::vector first_half_uv2s; first_half_uv2s.resize(num_surfaces); - std::vector first_half_colours; first_half_colours.resize(num_surfaces); - std::vector first_half_bones; first_half_bones.resize(num_surfaces); - std::vector first_half_weights; first_half_weights.resize(num_surfaces); - std::vector first_half_custom0; first_half_custom0.resize(num_surfaces); - - std::vector other_half_vertices; other_half_vertices.resize(num_surfaces); - std::vector other_half_normals; other_half_normals.resize(num_surfaces); - std::vector other_half_tangents; other_half_tangents.resize(num_surfaces); - std::vector other_half_uvs; other_half_uvs.resize(num_surfaces); - std::vector other_half_uv2s; other_half_uv2s.resize(num_surfaces); - std::vector other_half_colours; other_half_colours.resize(num_surfaces); - std::vector other_half_bones; other_half_bones.resize(num_surfaces); - std::vector other_half_weights; other_half_weights.resize(num_surfaces); - std::vector other_half_custom0; other_half_custom0.resize(num_surfaces); - - std::vector first_half_indices; first_half_indices.resize(num_surfaces); - std::vector other_half_indices; other_half_indices.resize(num_surfaces); - - std::vector> vertex_distances; vertex_distances.resize(num_surfaces); - - std::vector> base_to_first_sliced_vert_indices; base_to_first_sliced_vert_indices.resize(num_surfaces); - std::vector> base_to_other_sliced_vert_indices; base_to_other_sliced_vert_indices.resize(num_surfaces); - - uint32_t first_half_split_map = 0x00000000; - uint32_t other_half_split_map = 0x00000000; - - std::vector clip_edges; - - for (uint8_t surface = 0; surface < num_surfaces; surface++) - { - std::vector surface_skinned_vertex_transforms; - const SkinnedVertices &surface_skinned_vertex_positions = MeshEditingLibrary::get_skinned_vertex_positions(surface, original_mesh, input->sliceable_skeleton, surface_skinned_vertex_transforms); - skinned_vertex_positions[surface] = surface_skinned_vertex_positions; - skinned_vertex_transforms[surface] = surface_skinned_vertex_transforms; + return fresh_state; +} + +void MeshEditingLibrary::slice_mesh_init(Ref state) +{ + { // Initialise the state here + // const Time *time = Time::get_singleton(); - const Array &surface_arrays = original_mesh->surface_get_arrays(surface); - const PackedVector3Array &surface_vertex_array = surface_arrays[ArrayMesh::ARRAY_VERTEX]; - const PackedVector3Array &surface_normal_array = surface_arrays[ArrayMesh::ARRAY_NORMAL]; - const PackedFloat32Array &surface_tangent_array = surface_arrays[ArrayMesh::ARRAY_TANGENT]; - const PackedVector2Array &surface_uv_array = surface_arrays[ArrayMesh::ARRAY_TEX_UV]; - const PackedVector2Array &surface_uv2_array = surface_arrays[ArrayMesh::ARRAY_TEX_UV2]; - const PackedColorArray &surface_colour_array = surface_arrays[ArrayMesh::ARRAY_COLOR]; - const PackedInt32Array &surface_bone_array = surface_arrays[ArrayMesh::ARRAY_BONES]; - const PackedFloat32Array &surface_weight_array = surface_arrays[ArrayMesh::ARRAY_WEIGHTS]; - const PackedFloat32Array &surface_custom0_array = surface_arrays[ArrayMesh::ARRAY_CUSTOM0]; - surface_arrays_list[surface] = surface_arrays; + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Started slicing mesh at ", time->get_ticks_msec(), "ms"); + + state->original_mesh = state->input->mesh_instance->get_mesh(); + state->num_surfaces = state->original_mesh->get_surface_count(); + + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Got skinned vertices at ", time->get_ticks_msec(), "ms"); + + state->surface_arrays_list.resize(state->num_surfaces); + state->skinned_vertex_positions.resize(state->num_surfaces); + state->skinned_vertex_transforms.resize(state->num_surfaces); + + state->has_normal.resize(state->num_surfaces); + state->has_tangent.resize(state->num_surfaces); + state->has_uv.resize(state->num_surfaces); + state->has_uv2.resize(state->num_surfaces); + state->has_colour.resize(state->num_surfaces); + state->has_bone.resize(state->num_surfaces); + state->has_weight.resize(state->num_surfaces); + state->has_custom0.resize(state->num_surfaces); + + state->num_bones_per_vertex.resize(state->num_surfaces); + state->num_custom0_per_vertex.resize(state->num_surfaces); + + state->first_half_vertices.resize(state->num_surfaces); + state->first_half_normals.resize(state->num_surfaces); + state->first_half_tangents.resize(state->num_surfaces); + state->first_half_uvs.resize(state->num_surfaces); + state->first_half_uv2s.resize(state->num_surfaces); + state->first_half_colours.resize(state->num_surfaces); + state->first_half_bones.resize(state->num_surfaces); + state->first_half_weights.resize(state->num_surfaces); + state->first_half_custom0.resize(state->num_surfaces); + + state->other_half_vertices.resize(state->num_surfaces); + state->other_half_normals.resize(state->num_surfaces); + state->other_half_tangents.resize(state->num_surfaces); + state->other_half_uvs.resize(state->num_surfaces); + state->other_half_uv2s.resize(state->num_surfaces); + state->other_half_colours.resize(state->num_surfaces); + state->other_half_bones.resize(state->num_surfaces); + state->other_half_weights.resize(state->num_surfaces); + state->other_half_custom0.resize(state->num_surfaces); + + state->first_half_indices.resize(state->num_surfaces); + state->other_half_indices.resize(state->num_surfaces); + + state->vertex_distances.resize(state->num_surfaces); + + state->base_to_first_sliced_vert_indices.resize(state->num_surfaces); + state->base_to_other_sliced_vert_indices.resize(state->num_surfaces); + } + + for (state->surface; state->surface < state->num_surfaces; state->surface++) + { + state->skinned_vertex_positions[state->surface] = MeshEditingLibrary::get_skinned_vertex_positions(state->surface, state->original_mesh, state->input->skeleton, state->skinned_vertex_transforms[state->surface]); + + state->surface_arrays_list[state->surface] = state->original_mesh->surface_get_arrays(state->surface); + const PackedVector3Array &surface_vertex_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_VERTEX]; + const PackedVector3Array &surface_normal_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_NORMAL]; + const PackedFloat32Array &surface_tangent_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TANGENT]; + const PackedVector2Array &surface_uv_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV]; + const PackedVector2Array &surface_uv2_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV2]; + const PackedColorArray &surface_colour_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_COLOR]; + const PackedInt32Array &surface_bone_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_BONES]; + const PackedFloat32Array &surface_weight_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_WEIGHTS]; + const PackedFloat32Array &surface_custom0_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_CUSTOM0]; const Vector3 *surface_vertex_array_ptr = surface_vertex_array.ptr(); const uint32_t num_vertices = surface_vertex_array.size(); - std::map &base_to_first_sliced_vert_index = base_to_first_sliced_vert_indices[surface]; - std::map &base_to_other_sliced_vert_index = base_to_other_sliced_vert_indices[surface]; + const int64_t &original_mesh_format_mask = (int64_t)state->original_mesh->surface_get_format(state->surface); - std::vector &vertex_distance = vertex_distances[surface]; - vertex_distance.resize(num_vertices); - - const int64_t &original_mesh_format_mask = (int64_t)original_mesh->surface_get_format(surface); - - const bool has_normal = surface_normal_array.size() >= num_vertices; surface_has_normal[surface] = has_normal; - const bool has_tangent = surface_tangent_array.size() >= num_vertices * 4; surface_has_tangent[surface] = has_tangent; - const bool has_uv = surface_uv_array.size() >= num_vertices; surface_has_uv[surface] = has_uv; - const bool has_uv2 = surface_uv2_array.size() >= num_vertices; surface_has_uv2[surface] = has_uv2; - const bool has_colour = surface_colour_array.size() >= num_vertices; surface_has_colour[surface] = has_colour; - const bool has_bone = original_mesh_format_mask & Mesh::ARRAY_FORMAT_BONES; surface_has_bone[surface] = has_bone; - const bool has_weight = original_mesh_format_mask & Mesh::ARRAY_FORMAT_WEIGHTS; surface_has_weight[surface] = has_weight; - const bool has_custom0 = original_mesh_format_mask & Mesh::ARRAY_FORMAT_CUSTOM0; surface_has_custom0[surface] = has_custom0; + const bool has_normal = surface_normal_array.size() >= num_vertices; state->has_normal[state->surface] = has_normal; + const bool has_tangent = surface_tangent_array.size() >= num_vertices * 4; state->has_tangent[state->surface] = has_tangent; + const bool has_uv = surface_uv_array.size() >= num_vertices; state->has_uv[state->surface] = has_uv; + const bool has_uv2 = surface_uv2_array.size() >= num_vertices; state->has_uv2[state->surface] = has_uv2; + const bool has_colour = surface_colour_array.size() >= num_vertices; state->has_colour[state->surface] = has_colour; + const bool has_bone = original_mesh_format_mask & Mesh::ARRAY_FORMAT_BONES; state->has_bone[state->surface] = has_bone; + const bool has_weight = original_mesh_format_mask & Mesh::ARRAY_FORMAT_WEIGHTS; state->has_weight[state->surface] = has_weight; + const bool has_custom0 = original_mesh_format_mask & Mesh::ARRAY_FORMAT_CUSTOM0; state->has_custom0[state->surface] = has_custom0; const uint8_t surface_num_bones_per_vertex = (has_bone && has_weight) ? ( (original_mesh_format_mask & Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4 ) : 0; - num_bones_per_vertex[surface] = surface_num_bones_per_vertex; + state->num_bones_per_vertex[state->surface] = surface_num_bones_per_vertex; const uint8_t surface_num_custom0_per_vertex = has_custom0 ? ( ((original_mesh_format_mask & (Mesh::ARRAY_FORMAT_CUSTOM_MASK << Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT)) == (Mesh::ARRAY_CUSTOM_RGBA_FLOAT << Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT)) ? 4 : 2 ) : 0; - num_custom0_per_vertex[surface] = surface_num_custom0_per_vertex; + state->num_custom0_per_vertex[state->surface] = surface_num_custom0_per_vertex; - for (uint32_t vertex = 0; vertex < num_vertices; vertex++) + state->vertex_distances[state->surface].resize(num_vertices); + } + + state->surface = 0; + state->element = 0; + state->current_stage = MeshEditSliceStage::SLICE_STAGE_PLANE_SPLIT; +} + +void MeshEditingLibrary::slice_mesh_plane_split(Ref state) +{ + for (state->surface; state->surface < state->num_surfaces; state->surface++) + { + const PackedVector3Array &surface_vertex_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_VERTEX]; + const PackedVector3Array &surface_normal_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_NORMAL]; + const PackedFloat32Array &surface_tangent_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TANGENT]; + const PackedVector2Array &surface_uv_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV]; + const PackedVector2Array &surface_uv2_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV2]; + const PackedColorArray &surface_colour_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_COLOR]; + const PackedInt32Array &surface_bone_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_BONES]; + const PackedFloat32Array &surface_weight_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_WEIGHTS]; + const PackedFloat32Array &surface_custom0_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_CUSTOM0]; + + const bool &has_normal = state->has_normal[state->surface]; + const bool &has_tangent = state->has_tangent[state->surface]; + const bool &has_uv = state->has_uv[state->surface]; + const bool &has_uv2 = state->has_uv2[state->surface]; + const bool &has_colour = state->has_colour[state->surface]; + const bool &has_bone = state->has_bone[state->surface]; + const bool &has_weight = state->has_weight[state->surface]; + const bool &has_custom0 = state->has_custom0[state->surface]; + + const Vector3 *surface_vertex_array_ptr = surface_vertex_array.ptr(); + const uint32_t num_vertices = surface_vertex_array.size(); + + const uint8_t &surface_num_bones_per_vertex = state->num_bones_per_vertex[state->surface]; + const uint8_t &surface_num_custom0_per_vertex = state->num_custom0_per_vertex[state->surface]; + + std::vector &vertex_distances = state->vertex_distances[state->surface]; + + std::map &base_to_first_sliced_vert_index = state->base_to_first_sliced_vert_indices[state->surface]; + std::map &base_to_other_sliced_vert_index = state->base_to_other_sliced_vert_indices[state->surface]; + + for (state->element; state->element < num_vertices; state->element++) { - vertex_distance[vertex] = input->local_plane.distance_to(surface_skinned_vertex_positions[vertex]); + vertex_distances[state->element] = state->input->local_plane.distance_to(state->skinned_vertex_positions[state->surface][state->element]); - if (vertex_distance[vertex] >= 0.0f) + if (vertex_distances[state->element] >= 0.0f) { - base_to_first_sliced_vert_index[vertex] = first_half_vertices[surface].size(); + base_to_first_sliced_vert_index[state->element] = state->first_half_vertices[state->surface].size(); - first_half_vertices[surface].append(surface_vertex_array_ptr[vertex]); - if (has_normal) { first_half_normals[surface].append(surface_normal_array.ptr()[vertex]); } - if (has_uv) { first_half_uvs[surface].append(surface_uv_array.ptr()[vertex]); } - if (has_uv2) { first_half_uv2s[surface].append(surface_uv2_array.ptr()[vertex]); } - if (has_colour) { first_half_colours[surface].append(surface_colour_array.ptr()[vertex]); } + state->first_half_vertices[state->surface].append(surface_vertex_array_ptr[state->element]); + if (has_normal) { state->first_half_normals[state->surface].append(surface_normal_array.ptr()[state->element]); } + if (has_uv) { state->first_half_uvs[state->surface].append(surface_uv_array.ptr()[state->element]); } + if (has_uv2) { state->first_half_uv2s[state->surface].append(surface_uv2_array.ptr()[state->element]); } + if (has_colour) { state->first_half_colours[state->surface].append(surface_colour_array.ptr()[state->element]); } if (has_tangent) { - first_half_tangents[surface].append(surface_tangent_array.ptr()[vertex * 4]); - first_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 1]); - first_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 2]); - first_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 3]); + state->first_half_tangents[state->surface].append(surface_tangent_array.ptr()[state->element * 4]); + state->first_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 1]); + state->first_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 2]); + state->first_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 3]); } if (has_custom0) { float hit_grid[] = { 0.0f, 0.0f }; for (uint8_t i = 0; i < surface_num_custom0_per_vertex; i++) { - const float value = surface_custom0_array.ptr()[(vertex * surface_num_custom0_per_vertex) + i]; - first_half_custom0[surface].append(value); + const float value = surface_custom0_array.ptr()[(state->element * surface_num_custom0_per_vertex) + i]; + state->first_half_custom0[state->surface].append(value); hit_grid[i] = value; } - first_half_split_map |= (0x00000001 << MeshEditingLibrary::uv_to_body_part_shift(hit_grid[0], hit_grid[1])); + state->first_half_split_map |= (0x00000001 << MeshEditingLibrary::uv_to_body_part_shift(hit_grid[0], hit_grid[1])); } if (has_bone) { for (uint8_t i = 0; i < surface_num_bones_per_vertex; i++) { - first_half_bones[surface].append(surface_bone_array.ptr()[(vertex * surface_num_bones_per_vertex) + i]); - first_half_weights[surface].append(surface_weight_array.ptr()[(vertex * surface_num_bones_per_vertex) + i]); + state->first_half_bones[state->surface].append(surface_bone_array.ptr()[(state->element * surface_num_bones_per_vertex) + i]); + state->first_half_weights[state->surface].append(surface_weight_array.ptr()[(state->element * surface_num_bones_per_vertex) + i]); } } } else { - base_to_other_sliced_vert_index[vertex] = other_half_vertices[surface].size(); + base_to_other_sliced_vert_index[state->element] = state->other_half_vertices[state->surface].size(); - other_half_vertices[surface].append(surface_vertex_array_ptr[vertex]); - if (has_normal) { other_half_normals[surface].append(surface_normal_array.ptr()[vertex]); } - if (has_uv) { other_half_uvs[surface].append(surface_uv_array.ptr()[vertex]); } - if (has_uv2) { other_half_uv2s[surface].append(surface_uv2_array.ptr()[vertex]); } - if (has_colour) { other_half_colours[surface].append(surface_colour_array.ptr()[vertex]); } + state->other_half_vertices[state->surface].append(surface_vertex_array_ptr[state->element]); + if (has_normal) { state->other_half_normals[state->surface].append(surface_normal_array.ptr()[state->element]); } + if (has_uv) { state->other_half_uvs[state->surface].append(surface_uv_array.ptr()[state->element]); } + if (has_uv2) { state->other_half_uv2s[state->surface].append(surface_uv2_array.ptr()[state->element]); } + if (has_colour) { state->other_half_colours[state->surface].append(surface_colour_array.ptr()[state->element]); } if (has_tangent) { - other_half_tangents[surface].append(surface_tangent_array.ptr()[vertex * 4]); - other_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 1]); - other_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 2]); - other_half_tangents[surface].append(surface_tangent_array.ptr()[(vertex * 4) + 3]); + state->other_half_tangents[state->surface].append(surface_tangent_array.ptr()[state->element * 4]); + state->other_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 1]); + state->other_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 2]); + state->other_half_tangents[state->surface].append(surface_tangent_array.ptr()[(state->element * 4) + 3]); } if (has_custom0) { float hit_grid[] = { 0.0f, 0.0f }; for (uint8_t i = 0; i < surface_num_custom0_per_vertex; i++) { - const float value = surface_custom0_array.ptr()[(vertex * surface_num_custom0_per_vertex) + i]; - other_half_custom0[surface].append(value); + const float value = surface_custom0_array.ptr()[(state->element * surface_num_custom0_per_vertex) + i]; + state->other_half_custom0[state->surface].append(value); hit_grid[i] = value; } - other_half_split_map |= (0x00000001 << MeshEditingLibrary::uv_to_body_part_shift(hit_grid[0], hit_grid[1])); + state->other_half_split_map |= (0x00000001 << MeshEditingLibrary::uv_to_body_part_shift(hit_grid[0], hit_grid[1])); } if (has_bone) { for (uint8_t i = 0; i < surface_num_bones_per_vertex; i++) { - other_half_bones[surface].append(surface_bone_array.ptr()[(vertex * surface_num_bones_per_vertex) + i]); - other_half_weights[surface].append(surface_weight_array.ptr()[(vertex * surface_num_bones_per_vertex) + i]); + state->other_half_bones[state->surface].append(surface_bone_array.ptr()[(state->element * surface_num_bones_per_vertex) + i]); + state->other_half_weights[state->surface].append(surface_weight_array.ptr()[(state->element * surface_num_bones_per_vertex) + i]); } } } } - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " sorted by plane distance at ", time->get_ticks_msec(), "ms"); + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " sorted by plane distance at ", time->get_ticks_msec(), "ms"); + + state->element = 0; } - out->hit_map = first_half_split_map & other_half_split_map; + state->output->hit_map = state->first_half_split_map & state->other_half_split_map; - for (uint8_t surface = 0; surface < num_surfaces; surface++) + state->surface = 0; + state->current_stage = MeshEditSliceStage::SLICE_STAGE_EDGE_SPLIT; +} + +void MeshEditingLibrary::slice_mesh_edge_split(Ref state) +{ + for (state->surface; state->surface < state->num_surfaces; state->surface++) { - Ref original_material = original_mesh->surface_get_material(surface); + Ref original_material = state->original_mesh->surface_get_material(state->surface); - const PackedVector3Array &surface_vertex_array = surface_arrays_list[surface][ArrayMesh::ARRAY_VERTEX]; - const PackedVector3Array &surface_normal_array = surface_arrays_list[surface][ArrayMesh::ARRAY_NORMAL]; - const PackedFloat32Array &surface_tangent_array = surface_arrays_list[surface][ArrayMesh::ARRAY_TANGENT]; - const PackedVector2Array &surface_uv_array = surface_arrays_list[surface][ArrayMesh::ARRAY_TEX_UV]; - const PackedVector2Array &surface_uv2_array = surface_arrays_list[surface][ArrayMesh::ARRAY_TEX_UV2]; - const PackedColorArray &surface_colour_array = surface_arrays_list[surface][ArrayMesh::ARRAY_COLOR]; - const PackedInt32Array &surface_bone_array = surface_arrays_list[surface][ArrayMesh::ARRAY_BONES]; - const PackedFloat32Array &surface_weight_array = surface_arrays_list[surface][ArrayMesh::ARRAY_WEIGHTS]; - const PackedFloat32Array &surface_custom0_array = surface_arrays_list[surface][ArrayMesh::ARRAY_CUSTOM0]; - const PackedInt32Array &surface_index_array = surface_arrays_list[surface][ArrayMesh::ARRAY_INDEX]; + const PackedVector3Array &surface_vertex_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_VERTEX]; + const PackedVector3Array &surface_normal_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_NORMAL]; + const PackedFloat32Array &surface_tangent_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TANGENT]; + const PackedVector2Array &surface_uv_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV]; + const PackedVector2Array &surface_uv2_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_TEX_UV2]; + const PackedColorArray &surface_colour_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_COLOR]; + const PackedInt32Array &surface_bone_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_BONES]; + const PackedFloat32Array &surface_weight_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_WEIGHTS]; + const PackedFloat32Array &surface_custom0_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_CUSTOM0]; + const PackedInt32Array &surface_index_array = state->surface_arrays_list[state->surface][ArrayMesh::ARRAY_INDEX]; - SkinnedVertices &surface_skinned_vertex_positions = skinned_vertex_positions[surface]; - std::vector &surface_skinned_vertex_transforms = skinned_vertex_transforms[surface]; + SkinnedVertices &surface_skinned_vertex_positions = state->skinned_vertex_positions[state->surface]; + std::vector &surface_skinned_vertex_transforms = state->skinned_vertex_transforms[state->surface]; - const std::vector &vertex_distance = vertex_distances[surface]; + const std::vector &vertex_distance = state->vertex_distances[state->surface]; - const bool has_normal = surface_has_normal[surface]; - const bool has_tangent = surface_has_tangent[surface]; - const bool has_uv = surface_has_uv[surface]; - const bool has_uv2 = surface_has_uv2[surface]; - const bool has_colour = surface_has_colour[surface]; - const bool has_bone = surface_has_bone[surface]; - const bool has_weight = surface_has_weight[surface]; - const bool has_custom0 = surface_has_custom0[surface]; + const bool &has_normal = state->has_normal[state->surface]; + const bool &has_tangent = state->has_tangent[state->surface]; + const bool &has_uv = state->has_uv[state->surface]; + const bool &has_uv2 = state->has_uv2[state->surface]; + const bool &has_colour = state->has_colour[state->surface]; + const bool &has_bone = state->has_bone[state->surface]; + const bool &has_weight = state->has_weight[state->surface]; + const bool &has_custom0 = state->has_custom0[state->surface]; - const uint8_t &surface_num_bones_per_vertex = num_bones_per_vertex[surface]; - const uint8_t &surface_num_custom0_per_vertex = num_custom0_per_vertex[surface]; + const uint8_t &surface_num_bones_per_vertex = state->num_bones_per_vertex[state->surface]; + const uint8_t &surface_num_custom0_per_vertex = state->num_custom0_per_vertex[state->surface]; - if (!(first_half_vertices[surface].size() > 0 && other_half_vertices[surface].size() > 0)) + if (!(state->first_half_vertices[state->surface].size() > 0 && state->other_half_vertices[state->surface].size() > 0)) { - if (first_half_vertices[surface].size() > 0) + if (state->first_half_vertices[state->surface].size() > 0) { - first_half_indices[surface] = surface_index_array; + state->first_half_indices[state->surface] = surface_index_array; } - else if (other_half_vertices[surface].size() > 0) + else if (state->other_half_vertices[state->surface].size() > 0) { - other_half_indices[surface] = surface_index_array; + state->other_half_indices[state->surface] = surface_index_array; } } else { const uint32_t num_triangles = surface_index_array.size(); - for (uint32_t triangle_index = 0; triangle_index < num_triangles; triangle_index += 3) + for (state->element; state->element < num_triangles; state->element += 3) { uint32_t base_v[3]; std::map::iterator sliced_v[3]; std::map::iterator sliced_other_v[3]; - const std::map::iterator base_to_first_sliced_end = base_to_first_sliced_vert_indices[surface].end(); - const std::map::iterator base_to_other_sliced_end = base_to_other_sliced_vert_indices[surface].end(); + const std::map::iterator base_to_first_sliced_end = state->base_to_first_sliced_vert_indices[state->surface].end(); + const std::map::iterator base_to_other_sliced_end = state->base_to_other_sliced_vert_indices[state->surface].end(); for (uint32_t i = 0; i < 3; i++) { - base_v[i] = surface_index_array.ptr()[triangle_index + i]; - sliced_v[i] = base_to_first_sliced_vert_indices[surface].find(base_v[i]); - sliced_other_v[i] = base_to_other_sliced_vert_indices[surface].find(base_v[i]); + base_v[i] = surface_index_array.ptr()[state->element + i]; + sliced_v[i] = state->base_to_first_sliced_vert_indices[state->surface].find(base_v[i]); + sliced_other_v[i] = state->base_to_other_sliced_vert_indices[state->surface].find(base_v[i]); // All vertex indices must be represented by one of the two slice index maps. - assert((sliced_v[i] != base_to_first_sliced_vert_indices[surface].end()) != (sliced_other_v[i] != base_to_other_sliced_vert_indices[surface].end())); + assert((sliced_v[i] != state->base_to_first_sliced_vert_indices[state->surface].end()) != (sliced_other_v[i] != state->base_to_other_sliced_vert_indices[state->surface].end())); } if (sliced_v[0] != base_to_first_sliced_end && sliced_v[1] != base_to_first_sliced_end && sliced_v[2] != base_to_first_sliced_end) { // If the triangle is entirely in the first slice, send all the vertices to the first slice. - first_half_indices[surface].append(sliced_v[0]->second); - first_half_indices[surface].append(sliced_v[1]->second); - first_half_indices[surface].append(sliced_v[2]->second); + state->first_half_indices[state->surface].append(sliced_v[0]->second); + state->first_half_indices[state->surface].append(sliced_v[1]->second); + state->first_half_indices[state->surface].append(sliced_v[2]->second); } else if (sliced_other_v[0] != base_to_other_sliced_end && sliced_other_v[1] != base_to_other_sliced_end && sliced_other_v[2] != base_to_other_sliced_end) { // If the triangle is entirely in the second slice, send all the vertices to the second slice. - other_half_indices[surface].append(sliced_other_v[0]->second); - other_half_indices[surface].append(sliced_other_v[1]->second); - other_half_indices[surface].append(sliced_other_v[2]->second); + state->other_half_indices[state->surface].append(sliced_other_v[0]->second); + state->other_half_indices[state->surface].append(sliced_other_v[1]->second); + state->other_half_indices[state->surface].append(sliced_other_v[2]->second); } else { // If the triangle is split by the slice plane, then slice the overlapping edges. @@ -328,15 +373,15 @@ Ref MeshEditingLibrary::slice_mesh(const Reffirst_half_vertices[state->surface].size(); + other_final_verts[num_other_final_verts++] = state->other_half_vertices[state->surface].size(); const Vector3 &skinned_interp_vert = surface_skinned_vertex_positions[base_v[this_vert]].lerp( surface_skinned_vertex_positions[base_v[next_vert]], alpha); MeshEditVert3D edge_vertex; - edge_vertex.surface = surface; - edge_vertex.index = first_half_vertices[surface].size(); + edge_vertex.surface = state->surface; + edge_vertex.index = state->first_half_vertices[state->surface].size(); edge_vertex.position = skinned_interp_vert; if (clipped_edges == 0) { @@ -349,14 +394,14 @@ Ref MeshEditingLibrary::slice_mesh(const Reffirst_half_vertices[state->surface].append(interp_vert); + state->other_half_vertices[state->surface].append(interp_vert); if (has_normal) { const Vector3 interp_normal = surface_normal_array.ptr()[base_v[this_vert]].slerp(surface_normal_array.ptr()[base_v[next_vert]], alpha); - first_half_normals[surface].append(interp_normal); - other_half_normals[surface].append(interp_normal); + state->first_half_normals[state->surface].append(interp_normal); + state->other_half_normals[state->surface].append(interp_normal); } if (has_tangent) @@ -371,29 +416,29 @@ Ref MeshEditingLibrary::slice_mesh(const Reffirst_half_tangents[state->surface].append(interp_tangent.x); + state->first_half_tangents[state->surface].append(interp_tangent.y); + state->first_half_tangents[state->surface].append(interp_tangent.z); + state->first_half_tangents[state->surface].append(interp_binormal); - other_half_tangents[surface].append(interp_tangent.x); - other_half_tangents[surface].append(interp_tangent.y); - other_half_tangents[surface].append(interp_tangent.z); - other_half_tangents[surface].append(interp_binormal); + state->other_half_tangents[state->surface].append(interp_tangent.x); + state->other_half_tangents[state->surface].append(interp_tangent.y); + state->other_half_tangents[state->surface].append(interp_tangent.z); + state->other_half_tangents[state->surface].append(interp_binormal); } if (has_uv) { const Vector2 &interp_uv = surface_uv_array.ptr()[base_v[this_vert]].lerp(surface_uv_array.ptr()[base_v[next_vert]], alpha); - first_half_uvs[surface].append(interp_uv); - other_half_uvs[surface].append(interp_uv); + state->first_half_uvs[state->surface].append(interp_uv); + state->other_half_uvs[state->surface].append(interp_uv); } if (has_uv2) { const Vector2 &interp_uv2 = surface_uv2_array.ptr()[base_v[this_vert]].lerp(surface_uv2_array.ptr()[base_v[next_vert]], alpha); - first_half_uv2s[surface].append(interp_uv2); - other_half_uv2s[surface].append(interp_uv2); + state->first_half_uv2s[state->surface].append(interp_uv2); + state->other_half_uv2s[state->surface].append(interp_uv2); } if (has_custom0) @@ -404,16 +449,16 @@ Ref MeshEditingLibrary::slice_mesh(const Reffirst_half_custom0[state->surface].append(interp_custom0); + state->other_half_custom0[state->surface].append(interp_custom0); } } if (has_colour) { const Color &interp_colour = surface_colour_array.ptr()[base_v[this_vert]].lerp(surface_colour_array.ptr()[base_v[next_vert]], alpha); - first_half_colours[surface].append(interp_colour); - other_half_colours[surface].append(interp_colour); + state->first_half_colours[state->surface].append(interp_colour); + state->other_half_colours[state->surface].append(interp_colour); } if (has_bone && has_weight) @@ -481,17 +526,17 @@ Ref MeshEditingLibrary::slice_mesh(const Reffirst_half_bones[state->surface].append(bone_weight_pairs[vertex_bone].first); + state->first_half_weights[state->surface].append(normalised_weight); + state->other_half_bones[state->surface].append(bone_weight_pairs[vertex_bone].first); + state->other_half_weights[state->surface].append(normalised_weight); } else { - first_half_bones[surface].append(0); - first_half_weights[surface].append(0.0f); - other_half_bones[surface].append(0); - other_half_weights[surface].append(0.0f); + state->first_half_bones[state->surface].append(0); + state->first_half_weights[state->surface].append(0.0f); + state->other_half_bones[state->surface].append(0); + state->other_half_weights[state->surface].append(0.0f); } } } @@ -504,23 +549,25 @@ Ref MeshEditingLibrary::slice_mesh(const Refclip_edges.emplace_back(new_clip_edge); for (uint32_t vertex_index = 2; vertex_index < num_final_verts; vertex_index++) { - first_half_indices[surface].append(final_verts[0]); - first_half_indices[surface].append(final_verts[vertex_index - 1]); - first_half_indices[surface].append(final_verts[vertex_index]); + state->first_half_indices[state->surface].append(final_verts[0]); + state->first_half_indices[state->surface].append(final_verts[vertex_index - 1]); + state->first_half_indices[state->surface].append(final_verts[vertex_index]); } for (uint32_t vertex_index = 2; vertex_index < num_other_final_verts; vertex_index++) { - other_half_indices[surface].append(other_final_verts[0]); - other_half_indices[surface].append(other_final_verts[vertex_index - 1]); - other_half_indices[surface].append(other_final_verts[vertex_index]); + state->other_half_indices[state->surface].append(other_final_verts[0]); + state->other_half_indices[state->surface].append(other_final_verts[vertex_index - 1]); + state->other_half_indices[state->surface].append(other_final_verts[vertex_index]); } } } + + state->element = 0; } int64_t array_format_bit_mask = Mesh::ARRAY_FORMAT_VERTEX; @@ -534,57 +581,60 @@ Ref MeshEditingLibrary::slice_mesh(const Ref array_format(array_format_bit_mask); - if (first_half_vertices[surface].size() > 0 && first_half_indices[surface].size() > 0) + if (state->first_half_vertices[state->surface].size() > 0 && state->first_half_indices[state->surface].size() > 0) { Array first_half_section; first_half_section.resize(ArrayMesh::ARRAY_MAX); - first_half_section[ArrayMesh::ARRAY_VERTEX] = first_half_vertices[surface]; - if (has_normal) first_half_section[ArrayMesh::ARRAY_NORMAL] = first_half_normals[surface]; - if (has_tangent) first_half_section[ArrayMesh::ARRAY_TANGENT] = first_half_tangents[surface]; - if (has_uv) first_half_section[ArrayMesh::ARRAY_TEX_UV] = first_half_uvs[surface]; - if (has_uv2) first_half_section[ArrayMesh::ARRAY_TEX_UV2] = first_half_uv2s[surface]; - if (has_colour) first_half_section[ArrayMesh::ARRAY_COLOR] = first_half_colours[surface]; - if (has_bone) first_half_section[ArrayMesh::ARRAY_BONES] = first_half_bones[surface]; - if (has_weight) first_half_section[ArrayMesh::ARRAY_WEIGHTS] = first_half_weights[surface]; - if (has_custom0) first_half_section[ArrayMesh::ARRAY_CUSTOM0] = first_half_custom0[surface]; - first_half_section[ArrayMesh::ARRAY_INDEX] = first_half_indices[surface]; + first_half_section[ArrayMesh::ARRAY_VERTEX] = state->first_half_vertices[state->surface]; + if (has_normal) first_half_section[ArrayMesh::ARRAY_NORMAL] = state->first_half_normals[state->surface]; + if (has_tangent) first_half_section[ArrayMesh::ARRAY_TANGENT] = state->first_half_tangents[state->surface]; + if (has_uv) first_half_section[ArrayMesh::ARRAY_TEX_UV] = state->first_half_uvs[state->surface]; + if (has_uv2) first_half_section[ArrayMesh::ARRAY_TEX_UV2] = state->first_half_uv2s[state->surface]; + if (has_colour) first_half_section[ArrayMesh::ARRAY_COLOR] = state->first_half_colours[state->surface]; + if (has_bone) first_half_section[ArrayMesh::ARRAY_BONES] = state->first_half_bones[state->surface]; + if (has_weight) first_half_section[ArrayMesh::ARRAY_WEIGHTS] = state->first_half_weights[state->surface]; + if (has_custom0) first_half_section[ArrayMesh::ARRAY_CUSTOM0] = state->first_half_custom0[state->surface]; + first_half_section[ArrayMesh::ARRAY_INDEX] = state->first_half_indices[state->surface]; - const uint16_t next_surface = first_half->get_surface_count(); - first_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, first_half_section, Array(), Dictionary(), array_format_bit_mask); - first_half->surface_set_material(next_surface, original_material); + const uint16_t next_surface = state->first_half->get_surface_count(); + state->first_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, first_half_section, Array(), Dictionary(), array_format_bit_mask); + state->first_half->surface_set_material(next_surface, original_material); } - if (other_half_vertices[surface].size() > 0 && other_half_indices[surface].size() > 0) + if (state->other_half_vertices[state->surface].size() > 0 && state->other_half_indices[state->surface].size() > 0) { Array other_half_section; other_half_section.resize(ArrayMesh::ARRAY_MAX); - other_half_section[ArrayMesh::ARRAY_VERTEX] = other_half_vertices[surface]; - if (has_normal) other_half_section[ArrayMesh::ARRAY_NORMAL] = other_half_normals[surface]; - if (has_tangent) other_half_section[ArrayMesh::ARRAY_TANGENT] = other_half_tangents[surface]; - if (has_uv) other_half_section[ArrayMesh::ARRAY_TEX_UV] = other_half_uvs[surface]; - if (has_uv2) other_half_section[ArrayMesh::ARRAY_TEX_UV2] = other_half_uv2s[surface]; - if (has_colour) other_half_section[ArrayMesh::ARRAY_COLOR] = other_half_colours[surface]; - if (has_bone) other_half_section[ArrayMesh::ARRAY_BONES] = other_half_bones[surface]; - if (has_weight) other_half_section[ArrayMesh::ARRAY_WEIGHTS] = other_half_weights[surface]; - if (has_custom0) other_half_section[ArrayMesh::ARRAY_CUSTOM0] = other_half_custom0[surface]; - other_half_section[ArrayMesh::ARRAY_INDEX] = other_half_indices[surface]; + other_half_section[ArrayMesh::ARRAY_VERTEX] = state->other_half_vertices[state->surface]; + if (has_normal) other_half_section[ArrayMesh::ARRAY_NORMAL] = state->other_half_normals[state->surface]; + if (has_tangent) other_half_section[ArrayMesh::ARRAY_TANGENT] = state->other_half_tangents[state->surface]; + if (has_uv) other_half_section[ArrayMesh::ARRAY_TEX_UV] = state->other_half_uvs[state->surface]; + if (has_uv2) other_half_section[ArrayMesh::ARRAY_TEX_UV2] = state->other_half_uv2s[state->surface]; + if (has_colour) other_half_section[ArrayMesh::ARRAY_COLOR] = state->other_half_colours[state->surface]; + if (has_bone) other_half_section[ArrayMesh::ARRAY_BONES] = state->other_half_bones[state->surface]; + if (has_weight) other_half_section[ArrayMesh::ARRAY_WEIGHTS] = state->other_half_weights[state->surface]; + if (has_custom0) other_half_section[ArrayMesh::ARRAY_CUSTOM0] = state->other_half_custom0[state->surface]; + other_half_section[ArrayMesh::ARRAY_INDEX] = state->other_half_indices[state->surface]; - const uint16_t next_surface = other_half->get_surface_count(); - other_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, other_half_section, Array(), Dictionary(), array_format_bit_mask); - other_half->surface_set_material(next_surface, original_material); + const uint16_t next_surface = state->other_half->get_surface_count(); + state->other_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, other_half_section, Array(), Dictionary(), array_format_bit_mask); + state->other_half->surface_set_material(next_surface, original_material); } - skinned_vertex_transforms.emplace_back(surface_skinned_vertex_transforms); - - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " split edges at ", time->get_ticks_msec(), "ms"); + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " split edges at ", time->get_ticks_msec(), "ms"); } - - if (clip_edges.size() > 0) + state->surface = 0; + state->current_stage = MeshEditSliceStage::SLICE_STAGE_APPLY_CAP; +} + +void MeshEditingLibrary::slice_mesh_apply_cap(Ref state) +{ + if (state->clip_edges.size() > 0) { MeshSlicePlaneOrientation uv_plane = MeshSlicePlaneOrientation::Z; - const Basis &mesh_instance_basis = input->sliceable_mesh_instance->get_basis(); - const Vector3 &local_plane_normal = input->local_plane.get_normal(); + const Basis &mesh_instance_basis = state->input->mesh_instance->get_basis(); + const Vector3 &local_plane_normal = state->input->local_plane.get_normal(); if (UtilityFunctions::absf(local_plane_normal.dot(mesh_instance_basis.xform(Vector3(0.0f, 1.0f, 0.0f)))) > 0.5f) { uv_plane = MeshSlicePlaneOrientation::Y; @@ -606,14 +656,14 @@ Ref MeshEditingLibrary::slice_mesh(const Ref edges_2d; std::vector polygon_set; std::vector error_polygons; - const Transform3D &plane_inverse_transform = MeshEditingLibrary::project_edges(edges_2d, clip_edges, input->local_plane); + const Transform3D &plane_inverse_transform = MeshEditingLibrary::project_edges(edges_2d, state->clip_edges, state->input->local_plane); MeshEditingLibrary::build_2d_polygons_from_edges(polygon_set, edges_2d, error_polygons); - MeshEditingLibrary::draw_debug_polygons(input->sliceable_mesh_instance, error_polygons, plane_inverse_transform, Color(1.0f, 0.0f, 0.0f, 1.0f)); + MeshEditingLibrary::draw_debug_polygons(state->input->mesh_instance, error_polygons, plane_inverse_transform, Color(1.0f, 0.0f, 0.0f, 1.0f)); - const Vector3 &mesh_bounds = input->original_aabb.get_size(); + const Vector3 &mesh_bounds = state->input->full_aabb.get_size(); const uint32_t num_polygons = polygon_set.size(); uint32_t polygon_vertex_base = 0; - for (uint32_t polygon_index = 0; polygon_index < num_polygons; polygon_index++) + for (state->element; state->element < num_polygons; state->element++) { using Point = std::array; using Polygon = std::vector>; @@ -624,47 +674,47 @@ Ref MeshEditingLibrary::slice_mesh(const Refelement].vertices) { - const Vector3 &position = first_half_vertices[vertex.surface][vertex.index]; + const Vector3 &position = state->first_half_vertices[vertex.surface][vertex.index]; - const Transform3D &skinned_vertex_transform = skinned_vertex_transforms[vertex.surface][vertex.index]; + const Transform3D &skinned_vertex_transform = state->skinned_vertex_transforms[vertex.surface][vertex.index]; const Vector2 &uv = MeshEditingLibrary::calculate_planar_uv(position, mesh_bounds, uv_plane); surface_tool_first_half->set_uv(uv); surface_tool_other_half->set_uv(uv); - if (surface_has_uv2[vertex.surface]) + if (state->has_uv2[vertex.surface]) { surface_tool_first_half->set_uv2(uv); surface_tool_other_half->set_uv2(uv); } - if (surface_has_custom0[vertex.surface]) + if (state->has_custom0[vertex.surface]) { const Color &custom_uv3 = Color( - first_half_custom0[vertex.surface][(vertex.index * 2)], - first_half_custom0[vertex.surface][(vertex.index * 2) + 1], + state->first_half_custom0[vertex.surface][(vertex.index * 2)], + state->first_half_custom0[vertex.surface][(vertex.index * 2) + 1], 0.0f, 0.0f); surface_tool_first_half->set_custom(0, custom_uv3); surface_tool_other_half->set_custom(0, custom_uv3); } - if (surface_has_colour[vertex.surface]) + if (state->has_colour[vertex.surface]) { - const Color &colour = first_half_colours[vertex.surface][vertex.index]; + const Color &colour = state->first_half_colours[vertex.surface][vertex.index]; surface_tool_first_half->set_color(colour); surface_tool_other_half->set_color(colour); } - if (surface_has_bone[vertex.surface] && surface_has_weight[vertex.surface]) + if (state->has_bone[vertex.surface] && state->has_weight[vertex.surface]) { PackedInt32Array bones; bones.resize(4); PackedFloat32Array weights; weights.resize(4); - for (uint8_t i = 0; i < num_bones_per_vertex[vertex.surface] && i < 4; i++) + for (uint8_t i = 0; i < state->num_bones_per_vertex[vertex.surface] && i < 4; i++) { - bones[i] = first_half_bones[vertex.surface][(vertex.index * num_bones_per_vertex[vertex.surface]) + i]; - weights[i] = first_half_weights[vertex.surface][(vertex.index * num_bones_per_vertex[vertex.surface]) + i]; + bones[i] = state->first_half_bones[vertex.surface][(vertex.index * state->num_bones_per_vertex[vertex.surface]) + i]; + weights[i] = state->first_half_weights[vertex.surface][(vertex.index * state->num_bones_per_vertex[vertex.surface]) + i]; } surface_tool_first_half->set_bones(bones); @@ -683,8 +733,8 @@ Ref MeshEditingLibrary::slice_mesh(const Refimpact_points.append(polygon_centroid); + polygon_centroid /= polygon_set[state->element].vertices.size(); + state->output->impact_points.append(polygon_centroid); earcut_polygon.push_back(sub_polygon); std::vector indices = mapbox::earcut(earcut_polygon); @@ -712,23 +762,28 @@ Ref MeshEditingLibrary::slice_mesh(const Refgenerate_tangents(); surface_tool_other_half->generate_tangents(); - surface_tool_first_half->set_material(input->cap_materials[uv_plane]); - surface_tool_other_half->set_material(input->cap_materials[uv_plane]); + surface_tool_first_half->set_material(state->input->cap_materials[uv_plane]); + surface_tool_other_half->set_material(state->input->cap_materials[uv_plane]); - first_half = surface_tool_first_half->commit(first_half); - other_half = surface_tool_other_half->commit(other_half); + state->first_half = surface_tool_first_half->commit(state->first_half); + state->other_half = surface_tool_other_half->commit(state->other_half); - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Created cap surfaces at ", time->get_ticks_msec(), "ms"); + memdelete(surface_tool_first_half); + memdelete(surface_tool_other_half); + + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Created cap surfaces at ", time->get_ticks_msec(), "ms"); } - PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Generated final cap surface at ", time->get_ticks_msec(), "ms"); + // PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Generated final cap surface at ", time->get_ticks_msec(), "ms"); - out->main_half = first_half; - out->secondary_half = other_half; + state->output->original_skeleton = state->input->skeleton; + state->output->main_half = state->first_half; + state->output->secondary_half = state->other_half; - return out; + state->current_stage = MeshEditSliceStage::SLICE_STAGE_COMPLETE; } + SkinnedVertices MeshEditingLibrary::get_skinned_vertex_positions(const uint8_t surface, const Ref mesh, const Skeleton3D *skeleton, std::vector &vertex_transforms) { const uint8_t num_surfaces = mesh->get_surface_count(); diff --git a/src/liborng/nodes/mesh_editing_library.h b/src/liborng/nodes/mesh_editing_library.h index 37050af..d085f11 100644 --- a/src/liborng/nodes/mesh_editing_library.h +++ b/src/liborng/nodes/mesh_editing_library.h @@ -15,6 +15,7 @@ #include using namespace godot; +#include #include #define MESH_EDITING_LIBRARY_TAG "MeshEditingLibrary" @@ -55,6 +56,11 @@ struct MeshEditPolygon2D }; +class MeshEditSliceInput; +class MeshEditSliceOutput; +class MeshSliceState; + + class MeshEditingLibrary : public Node { GDCLASS(MeshEditingLibrary, Node); @@ -63,6 +69,15 @@ public: MeshEditingLibrary(){} ~MeshEditingLibrary(){} + enum MeshEditSliceStage + { + SLICE_STAGE_INIT, + SLICE_STAGE_PLANE_SPLIT, + SLICE_STAGE_EDGE_SPLIT, + SLICE_STAGE_APPLY_CAP, + SLICE_STAGE_COMPLETE + }; + enum MeshEditCapUV { CAP_UV_FILL_MESH_BOUNDS, @@ -70,7 +85,12 @@ public: CAP_UV_TILED }; - static Ref slice_mesh(const Ref input); + static Ref slice_mesh(const Ref input); + + static void slice_mesh_init(Ref state); + static void slice_mesh_plane_split(Ref state); + static void slice_mesh_edge_split(Ref state); + static void slice_mesh_apply_cap(Ref state); protected: enum MeshSlicePlaneOrientation @@ -100,21 +120,30 @@ protected: { ClassDB::bind_static_method("MeshEditingLibrary", D_METHOD("slice_mesh", "input"), &MeshEditingLibrary::slice_mesh); + BIND_ENUM_CONSTANT(SLICE_STAGE_INIT); + BIND_ENUM_CONSTANT(SLICE_STAGE_PLANE_SPLIT); + BIND_ENUM_CONSTANT(SLICE_STAGE_EDGE_SPLIT); + BIND_ENUM_CONSTANT(SLICE_STAGE_APPLY_CAP); + BIND_ENUM_CONSTANT(SLICE_STAGE_COMPLETE); + BIND_ENUM_CONSTANT(CAP_UV_FILL_MESH_BOUNDS); BIND_ENUM_CONSTANT(CAP_UV_FILL_CAP_BOUNDS); BIND_ENUM_CONSTANT(CAP_UV_TILED); } }; +VARIANT_ENUM_CAST(MeshEditingLibrary::MeshEditSliceStage); +VARIANT_ENUM_CAST(MeshEditingLibrary::MeshEditCapUV); + class MeshEditSliceInput : public RefCounted { GDCLASS(MeshEditSliceInput, RefCounted); public: - MeshInstance3D *sliceable_mesh_instance = nullptr; - const Skeleton3D *sliceable_skeleton = nullptr; - AABB original_aabb; + MeshInstance3D *mesh_instance = nullptr; + const Skeleton3D *skeleton = nullptr; + AABB full_aabb; Plane local_plane; uint32_t hit_mask = 0b1111111111111111111111111; @@ -131,8 +160,8 @@ class MeshEditSliceOutput : public RefCounted GDCLASS(MeshEditSliceOutput, RefCounted); public: + const Skeleton3D *original_skeleton = nullptr; Ref main_half; - Ref secondary_half; PackedVector3Array impact_points; @@ -142,4 +171,77 @@ protected: static void _bind_methods(){} }; -VARIANT_ENUM_CAST(MeshEditingLibrary::MeshEditCapUV); + +class MeshSliceState : public RefCounted +{ + GDCLASS(MeshSliceState, RefCounted); + +public: + MeshEditingLibrary::MeshEditSliceStage current_stage = MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_INIT; + MeshInstance3D *current_mesh = nullptr; + + Ref input; + + uint8_t surface = 0; + uint32_t element = 0; + + Ref first_half; + Ref other_half; + + Ref original_mesh; + uint8_t num_surfaces; + + std::vector surface_arrays_list; + std::vector skinned_vertex_positions; + std::vector> skinned_vertex_transforms; + + std::vector has_normal; + std::vector has_tangent; + std::vector has_uv; + std::vector has_uv2; + std::vector has_colour; + std::vector has_bone; + std::vector has_weight; + std::vector has_custom0; + + std::vector num_bones_per_vertex; + std::vector num_custom0_per_vertex; + + std::vector first_half_vertices; + std::vector first_half_normals; + std::vector first_half_tangents; + std::vector first_half_uvs; + std::vector first_half_uv2s; + std::vector first_half_colours; + std::vector first_half_bones; + std::vector first_half_weights; + std::vector first_half_custom0; + + std::vector other_half_vertices; + std::vector other_half_normals; + std::vector other_half_tangents; + std::vector other_half_uvs; + std::vector other_half_uv2s; + std::vector other_half_colours; + std::vector other_half_bones; + std::vector other_half_weights; + std::vector other_half_custom0; + + std::vector first_half_indices; + std::vector other_half_indices; + + std::vector> vertex_distances; + + std::vector> base_to_first_sliced_vert_indices; + std::vector> base_to_other_sliced_vert_indices; + + uint32_t first_half_split_map = 0x00000000; + uint32_t other_half_split_map = 0x00000000; + + std::vector clip_edges; + + Ref output; + +protected: + static void _bind_methods(){} +}; diff --git a/src/liborng/register_types.cpp b/src/liborng/register_types.cpp index 86f57bd..cde42be 100644 --- a/src/liborng/register_types.cpp +++ b/src/liborng/register_types.cpp @@ -80,6 +80,7 @@ void initialize_orng_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); GDSINGLETON_REGISTER_CLASS(InputHandler, _input_handler_singleton); GDSINGLETON_REGISTER_CLASS(SaveManager, _save_manager_singleton);