From 8041150363171222c04d68b27ea67320f1d662bd Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Sat, 1 Aug 2026 05:30:25 -0400 Subject: [PATCH] Started adding mesh editing functions to liborng. --- .gitignore | 1 - src/.sconsign.dblite | Bin 102112579 -> 102125491 bytes src/liborng/nodes/mesh_editing_library.cpp | 242 +++++++++++++++++++++ src/liborng/nodes/mesh_editing_library.h | 45 ++++ src/liborng/register_types.cpp | 4 + 5 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/liborng/nodes/mesh_editing_library.cpp create mode 100644 src/liborng/nodes/mesh_editing_library.h diff --git a/.gitignore b/.gitignore index 867d4b2..fd336db 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,3 @@ # ---> Platform Files *.sh -*.*.dblite diff --git a/src/.sconsign.dblite b/src/.sconsign.dblite index dc9a5b04a40d2f6cf69b0c7239e220b4b6a022aa..05d8171e27f1986e690bb722c1af2320aa343380 100644 GIT binary patch delta 11198 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 auUG8v*_u=d=v=sw>lgpG{i>z*tM(tRKFoXo diff --git a/src/liborng/nodes/mesh_editing_library.cpp b/src/liborng/nodes/mesh_editing_library.cpp new file mode 100644 index 0000000..a798068 --- /dev/null +++ b/src/liborng/nodes/mesh_editing_library.cpp @@ -0,0 +1,242 @@ +/* + * ©2023 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 "mesh_editing_library.h" + +#include + +#include "godot_cpp/variant/utility_functions.hpp" +using namespace godot; + + +MeshEditingLibrary::MeshEditingLibrary() +{ +} + +MeshEditingLibrary::~MeshEditingLibrary() +{ +} + + +bool MeshEditingLibrary::slice_mesh(const Mesh *original_mesh, const Plane &local_plane, Mesh *out_first_half, Mesh *out_other_half, const MeshSliceCapUVOption cap_option, const StandardMaterial3D *cap_material, Vector3 impact_point) +{ + const uint8_t num_surfaces = original_mesh->get_surface_count(); + + for (uint8_t surface = 0; surface < num_surfaces; surface++) + { + const Array &surface_arrays = original_mesh->surface_get_arrays(0); + const PackedVector3Array &surface_vertex_array = surface_arrays[Mesh::ARRAY_VERTEX]; + const PackedVector3Array &surface_normal_array = surface_arrays[Mesh::ARRAY_NORMAL]; + const PackedFloat32Array &surface_tangent_array = surface_arrays[Mesh::ARRAY_TANGENT]; + const PackedVector2Array &surface_uv_array = surface_arrays[Mesh::ARRAY_TEX_UV]; + const PackedVector2Array &surface_uv2_array = surface_arrays[Mesh::ARRAY_TEX_UV2]; + const PackedColorArray &surface_colour_array = surface_arrays[Mesh::ARRAY_COLOR]; + const PackedInt32Array &surface_bone_array = surface_arrays[Mesh::ARRAY_BONES]; + const PackedFloat32Array &surface_weight_array = surface_arrays[Mesh::ARRAY_WEIGHTS]; + + const Vector3 *surface_vertex_array_ptr = surface_vertex_array.ptr(); + + const uint8_t num_vertices = surface_vertex_array.size(); + + std::vector vertex_distance; + vertex_distance.reserve(num_vertices); + + std::map base_to_sliced_vert_index; + std::map base_to_other_sliced_vert_index; + + + const bool has_normal = surface_normal_array.size() >= num_vertices; + const bool has_tangent = surface_tangent_array.size() >= num_vertices * 4; + const bool has_uv = surface_uv_array.size() >= num_vertices; + const bool has_uv2 = surface_uv2_array.size() >= num_vertices; + const bool has_colour = surface_colour_array.size() >= num_vertices; + const bool has_bone = surface_bone_array.size() >= num_vertices * 4; + const bool has_weight = surface_weight_array.size() >= num_vertices * 4; + + const uint32_t bone_array_size = surface_bone_array.size(); + const uint8_t num_bones_in_array = bone_array_size / num_vertices; + + PackedVector3Array first_half_section_vertices; + PackedVector3Array first_half_section_normals; + PackedFloat32Array first_half_section_tangents; + PackedVector2Array first_half_section_uvs; + PackedVector2Array first_half_section_uv2s; + PackedColorArray first_half_section_colours; + PackedInt32Array first_half_section_bones; + PackedFloat32Array first_half_section_weights; + uint32_t num_first_half_verts = 0; + + PackedVector3Array other_half_section_vertices; + PackedVector3Array other_half_section_normals; + PackedFloat32Array other_half_section_tangents; + PackedVector2Array other_half_section_uvs; + PackedVector2Array other_half_section_uv2s; + PackedColorArray other_half_section_colours; + PackedInt32Array other_half_section_bones; + PackedFloat32Array other_half_section_weights; + uint32_t num_other_half_verts = 0; + for (uint8_t vertex = 0; vertex < num_vertices; vertex++) + { + vertex_distance[vertex] = local_plane.distance_to(surface_vertex_array_ptr[vertex]); + + if (vertex_distance[vertex] >= 0.0f) + { + base_to_sliced_vert_index[vertex] = num_first_half_verts; + num_first_half_verts++; + + first_half_section_vertices.append(surface_vertex_array_ptr[vertex]); + if (has_normal) { first_half_section_normals.append(surface_normal_array.ptr()[vertex]); } + if (has_uv) { first_half_section_uvs.append(surface_uv_array.ptr()[vertex]); } + if (has_uv2) { first_half_section_uv2s.append(surface_uv2_array.ptr()[vertex]); } + if (has_colour) { first_half_section_colours.append(surface_colour_array.ptr()[vertex]); } + if (has_tangent) + { + first_half_section_tangents.append(surface_tangent_array.ptr()[vertex * 4]); + first_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 1]); + first_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 2]); + first_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 3]); + } + if (has_bone) + { + for (uint8_t i = 0; i < num_bones_in_array; i++) + { + first_half_section_bones.append(surface_bone_array.ptr()[(vertex * num_bones_in_array) + i]); + first_half_section_weights.append(surface_weight_array.ptr()[(vertex * num_bones_in_array) + i]); + } + } + } + else + { + base_to_other_sliced_vert_index[vertex] = num_other_half_verts; + num_other_half_verts++; + + other_half_section_vertices.append(surface_vertex_array_ptr[vertex]); + if (has_normal) { other_half_section_normals.append(surface_normal_array.ptr()[vertex]); } + if (has_uv) { other_half_section_uvs.append(surface_uv_array.ptr()[vertex]); } + if (has_uv2) { other_half_section_uv2s.append(surface_uv2_array.ptr()[vertex]); } + if (has_colour) { other_half_section_colours.append(surface_colour_array.ptr()[vertex]); } + if (has_tangent) + { + other_half_section_tangents.append(surface_tangent_array.ptr()[vertex * 4]); + other_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 1]); + other_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 2]); + other_half_section_tangents.append(surface_tangent_array.ptr()[(vertex * 4) + 3]); + } + if (has_bone) + { + for (uint8_t i = 0; i < num_bones_in_array; i++) + { + other_half_section_bones.append(surface_bone_array.ptr()[(vertex * num_bones_in_array) + i]); + other_half_section_weights.append(surface_weight_array.ptr()[(vertex * num_bones_in_array) + i]); + } + } + } + } + + // std::vector<> clip_edges + + PackedInt32Array first_half_section_indices; + PackedInt32Array other_half_section_indices; + + const PackedInt32Array &surface_index_array = surface_arrays[Mesh::ARRAY_INDEX]; + const uint32_t num_triangles = surface_index_array.size(); + for (uint32_t triangle_index = 0; triangle_index < num_triangles; triangle_index += 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_sliced_end = base_to_sliced_vert_index.end(); + const std::map::iterator base_to_other_sliced_end = base_to_other_sliced_vert_index.end(); + for (uint32_t i = 0; i < 3; i++) + { + base_v[i] = surface_index_array.ptr()[triangle_index + i]; + sliced_v[i] = base_to_sliced_vert_index.find(base_v[i]); + sliced_other_v[i] = base_to_other_sliced_vert_index.find(base_v[i]); + if ((sliced_v[i] != base_to_sliced_vert_index.end()) == (sliced_other_v[i] != base_to_other_sliced_vert_index.end())) + { + UtilityFunctions::push_error("A vertex does not appear in either slice half. This is a severe error. We're leaving now", -1); + return false; + } + } + + if (sliced_v[0] != base_to_sliced_end && + sliced_v[1] != base_to_sliced_end && + sliced_v[2] != base_to_sliced_end) + { // If the triangle is entirely in the first slice, send all the vertices to the first slice. + first_half_section_indices.append(sliced_v[0]->second); + first_half_section_indices.append(sliced_v[1]->second); + first_half_section_indices.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_section_indices.append(sliced_other_v[0]->second); + other_half_section_indices.append(sliced_other_v[1]->second); + other_half_section_indices.append(sliced_other_v[2]->second); + } + else + { // If the triangle is split by the slice plane, then slice the overlapping edges. + uint32_t final_verts[4] = { 0, 0, 0, 0 }; + uint8_t num_final_verts = 0; + + uint32_t other_final_verts[4] = { 0, 0, 0, 0 }; + uint8_t num_other_final_verts = 0; + + //FUtilEdge3D new_clip_edge; + uint8_t clipped_edges = 0; + + float plane_distance[3] = { + vertex_distance[base_v[0]], + vertex_distance[base_v[1]], + vertex_distance[base_v[2]] + }; + + for (uint32_t this_vert = 0; this_vert < 3; this_vert++) + { + if (sliced_v[this_vert] != base_to_sliced_end) + { + final_verts[num_final_verts] = sliced_v[this_vert]->second; + num_final_verts++; + } + else + { + other_final_verts[num_other_final_verts] = sliced_other_v[this_vert]->second; + num_other_final_verts++; + } + + uint32_t next_vert = (this_vert + 1) % 3; + if ((sliced_v[this_vert] == base_to_sliced_end) != (sliced_v[next_vert] == base_to_sliced_end)) + { + float alpha = UtilityFunctions::clampf(-plane_distance[this_vert] / (plane_distance[next_vert] - plane_distance[this_vert]), 0.0f, 1.0f); + + const Vector3 interp_vert = surface_vertex_array_ptr[base_v[this_vert]].lerp( + surface_vertex_array_ptr[base_v[next_vert]], alpha); + + const Vector3 interp_normal = surface_normal_array.ptr()[base_v[this_vert]].lerp( + surface_normal_array.ptr()[base_v[next_vert]], alpha); + + const Vector2 interp_uv = surface_uv_array.ptr()[base_v[this_vert]].lerp( + surface_uv_array.ptr()[base_v[next_vert]], alpha); + const Vector2 interp_uv2 = surface_uv2_array.ptr()[base_v[this_vert]].lerp( + surface_uv2_array.ptr()[base_v[next_vert]], alpha); + + const Color interp_colour = surface_colour_array.ptr()[base_v[this_vert]].lerp( + surface_colour_array.ptr()[base_v[this_vert]], alpha); + + // Bones and weights will be interpolated here later + + UtilityFunctions::print("If you can see this millions of times, then this code is running fine. :)"); + } + } + } + } + } + + return false; +} diff --git a/src/liborng/nodes/mesh_editing_library.h b/src/liborng/nodes/mesh_editing_library.h new file mode 100644 index 0000000..65559ba --- /dev/null +++ b/src/liborng/nodes/mesh_editing_library.h @@ -0,0 +1,45 @@ +/* + * ©2023 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +using namespace godot; + + +class MeshEditingLibrary : public Node +{ + GDCLASS(MeshEditingLibrary, Node); + +public: + enum MeshSliceCapUVOption + { + FILL_MESH_BOUNDS, + FILL_CAP_BOUNDS + }; + +public: + MeshEditingLibrary(); + ~MeshEditingLibrary(); + + static bool slice_mesh(const Mesh *original_mesh, const Plane &local_plane, Mesh *out_first_half, Mesh *out_other_half, const MeshSliceCapUVOption cap_option, const StandardMaterial3D *cap_material, Vector3 impact_point); + +private: + + // Godot boilerplate below +protected: + static void _bind_methods() + { + ClassDB::bind_static_method("MeshEditingLibrary", D_METHOD("slice_mesh", "original_mesh", "local_plane", "out_first_half", "out_other_half", "cap_option", "cap_material", "impact_point"), &MeshEditingLibrary::slice_mesh); + } +}; + +VARIANT_ENUM_CAST(MeshEditingLibrary::MeshSliceCapUVOption); diff --git a/src/liborng/register_types.cpp b/src/liborng/register_types.cpp index fc1091e..ada301e 100644 --- a/src/liborng/register_types.cpp +++ b/src/liborng/register_types.cpp @@ -25,6 +25,8 @@ #include "resources/level_metadata_map.h" #include "resources/level_metadata_resource.h" +#include "nodes/mesh_editing_library.h" + #include "singletons/input_handler.h" #include "singletons/save_manager.h" #include "singletons/scene_loader.h" @@ -66,6 +68,8 @@ void initialize_orng_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); + + ClassDB::register_class(); GDSINGLETON_REGISTER_CLASS(InputHandler, _input_handler_singleton); GDSINGLETON_REGISTER_CLASS(SaveManager, _save_manager_singleton);