diff options
Diffstat (limited to 'scene/resources/surface_tool.cpp')
-rw-r--r-- | scene/resources/surface_tool.cpp | 164 |
1 files changed, 130 insertions, 34 deletions
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index d5e370568d..9829c7e86b 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,6 @@ #include "surface_tool.h" -#define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr; @@ -38,6 +37,44 @@ SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr; SurfaceTool::SimplifyWithAttribFunc SurfaceTool::simplify_with_attrib_func = nullptr; SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr; SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr; +SurfaceTool::GenerateRemapFunc SurfaceTool::generate_remap_func = nullptr; +SurfaceTool::RemapVertexFunc SurfaceTool::remap_vertex_func = nullptr; +SurfaceTool::RemapIndexFunc SurfaceTool::remap_index_func = nullptr; + +void SurfaceTool::strip_mesh_arrays(PackedVector3Array &r_vertices, PackedInt32Array &r_indices) { + ERR_FAIL_COND_MSG(!generate_remap_func || !remap_vertex_func || !remap_index_func, "Meshoptimizer library is not initialized."); + + Vector<uint32_t> remap; + remap.resize(r_vertices.size()); + uint32_t new_vertex_count = generate_remap_func(remap.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), (float *)r_vertices.ptr(), r_vertices.size(), sizeof(Vector3)); + remap_vertex_func(r_vertices.ptrw(), r_vertices.ptr(), r_vertices.size(), sizeof(Vector3), remap.ptr()); + r_vertices.resize(new_vertex_count); + remap_index_func((unsigned int *)r_indices.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), remap.ptr()); + + HashMap<const int *, bool, TriangleHasher, TriangleHasher> found_triangles; + int *idx_ptr = r_indices.ptrw(); + + int filtered_indices_count = 0; + for (int i = 0; i < r_indices.size() / 3; i++) { + const int *tri = idx_ptr + (i * 3); + + if (tri[0] == tri[1] || tri[1] == tri[2] || tri[2] == tri[0]) { + continue; + } + + if (found_triangles.has(tri)) { + continue; + } + + if (i != filtered_indices_count) { + memcpy(idx_ptr + (filtered_indices_count * 3), tri, sizeof(int) * 3); + } + + found_triangles[tri] = true; + filtered_indices_count++; + } + r_indices.resize(filtered_indices_count * 3); +} bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { if (vertex != p_vertex.vertex) { @@ -104,10 +141,61 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) { h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h); h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h); h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h); - h = hash_djb2_one_32(p_vtx.smooth_group, h); + h = hash_murmur3_one_32(p_vtx.smooth_group, h); + h = hash_fmix32(h); return h; } +uint32_t SurfaceTool::TriangleHasher::hash(const int *p_triangle) { + int t0 = p_triangle[0]; + int t1 = p_triangle[1]; + int t2 = p_triangle[2]; + + if (t0 > t1) { + SWAP(t0, t1); + } + if (t1 > t2) { + SWAP(t1, t2); + } + if (t0 > t1) { + SWAP(t0, t1); + } + + return (t0 * 73856093) ^ (t1 * 19349663) ^ (t2 * 83492791); +} + +bool SurfaceTool::TriangleHasher::compare(const int *p_lhs, const int *p_rhs) { + int r0 = p_rhs[0]; + int r1 = p_rhs[1]; + int r2 = p_rhs[2]; + + if (r0 > r1) { + SWAP(r0, r1); + } + if (r1 > r2) { + SWAP(r1, r2); + } + if (r0 > r1) { + SWAP(r0, r1); + } + + int l0 = p_lhs[0]; + int l1 = p_lhs[1]; + int l2 = p_lhs[2]; + + if (l0 > l1) { + SWAP(l0, l1); + } + if (l1 > l2) { + SWAP(l1, l2); + } + if (l0 > l1) { + SWAP(l0, l1); + } + + return l0 == r0 && l1 == r1 && l2 == r2; +} + void SurfaceTool::begin(Mesh::PrimitiveType p_primitive) { clear(); @@ -228,19 +316,17 @@ void SurfaceTool::set_uv2(const Vector2 &p_uv2) { last_uv2 = p_uv2; } -void SurfaceTool::set_custom(int p_index, const Color &p_custom) { - ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT); +void SurfaceTool::set_custom(int p_channel_index, const Color &p_custom) { + ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT); ERR_FAIL_COND(!begun); - ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX); + ERR_FAIL_COND(last_custom_format[p_channel_index] == CUSTOM_MAX); static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 }; - static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT }; - ERR_FAIL_COND(!first && !(format & mask[p_index])); + ERR_FAIL_COND(!first && !(format & mask[p_channel_index])); if (first) { - format |= mask[p_index]; - format |= last_custom_format[p_index] << shift[p_index]; + format |= mask[p_channel_index]; } - last_custom[p_index] = p_custom; + last_custom[p_channel_index] = p_custom; } void SurfaceTool::set_bones(const Vector<int> &p_bones) { @@ -602,7 +688,7 @@ Array SurfaceTool::commit_to_arrays() { return a; } -Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) { +Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_compress_flags) { Ref<ArrayMesh> mesh; if (p_existing.is_valid()) { mesh = p_existing; @@ -620,7 +706,15 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_ Array a = commit_to_arrays(); - mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), p_flags); + uint32_t compress_flags = (p_compress_flags >> RS::ARRAY_COMPRESS_FLAGS_BASE) << RS::ARRAY_COMPRESS_FLAGS_BASE; + static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT }; + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + if (last_custom_format[i] != CUSTOM_MAX) { + compress_flags |= last_custom_format[i] << shift[i]; + } + } + + mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), compress_flags); if (material.is_valid()) { mesh->surface_set_material(surface, material); @@ -901,9 +995,6 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) { if (format & custom_mask[j]) { CustomFormat new_format = (CustomFormat)((format >> custom_shift[j]) & RS::ARRAY_FORMAT_CUSTOM_MASK); - if (last_custom_format[j] != CUSTOM_MAX && last_custom_format[j] != new_format) { - WARN_PRINT(vformat("Custom %d format %d mismatch when appending format %d", j, last_custom_format[j], new_format)); - } last_custom_format[j] = new_format; } } @@ -1078,7 +1169,7 @@ void SurfaceTool::generate_normals(bool p_flip) { for (int i = 0; i < 3; i++) { Vector3 *lv = vertex_hash.getptr(v[i]); if (!lv) { - vertex_hash.set(v[i], normal); + vertex_hash.insert(v[i], normal); } else { (*lv) += normal; } @@ -1133,22 +1224,24 @@ SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const { return skin_weights; } -void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) { - ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT); - ERR_FAIL_COND(begun); - last_custom_format[p_index] = p_format; +void SurfaceTool::set_custom_format(int p_channel_index, CustomFormat p_format) { + ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT); + ERR_FAIL_COND(!begun); + ERR_FAIL_INDEX(p_format, CUSTOM_MAX + 1); + last_custom_format[p_channel_index] = p_format; } -Mesh::PrimitiveType SurfaceTool::get_primitive() const { +Mesh::PrimitiveType SurfaceTool::get_primitive_type() const { return primitive; } -SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const { - ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX); - return last_custom_format[p_index]; +SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_channel_index) const { + ERR_FAIL_INDEX_V(p_channel_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX); + return last_custom_format[p_channel_index]; } void SurfaceTool::optimize_indices_for_cache() { ERR_FAIL_COND(optimize_vertex_cache_func == nullptr); ERR_FAIL_COND(index_array.size() == 0); + ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES); ERR_FAIL_COND(index_array.size() % 3 != 0); LocalVector old_index_array = index_array; @@ -1156,8 +1249,8 @@ void SurfaceTool::optimize_indices_for_cache() { optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size()); } -float SurfaceTool::get_max_axis_length() const { - ERR_FAIL_COND_V(vertex_array.size() == 0, 0); +AABB SurfaceTool::get_aabb() const { + ERR_FAIL_COND_V(vertex_array.size() == 0, AABB()); AABB aabb; for (uint32_t i = 0; i < vertex_array.size(); i++) { @@ -1168,14 +1261,17 @@ float SurfaceTool::get_max_axis_length() const { } } - return aabb.get_longest_axis_size(); + return aabb; } Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) { Vector<int> lod; ERR_FAIL_COND_V(simplify_func == nullptr, lod); + ERR_FAIL_COND_V(p_target_index_count < 0, lod); ERR_FAIL_COND_V(vertex_array.size() == 0, lod); ERR_FAIL_COND_V(index_array.size() == 0, lod); + ERR_FAIL_COND_V(index_array.size() % 3 != 0, lod); + ERR_FAIL_COND_V(index_array.size() < (unsigned int)p_target_index_count, lod); lod.resize(index_array.size()); LocalVector<float> vertices; //uses floats @@ -1198,8 +1294,8 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count); ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count); - ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format); - ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format); + ClassDB::bind_method(D_METHOD("set_custom_format", "channel_index", "format"), &SurfaceTool::set_custom_format); + ClassDB::bind_method(D_METHOD("get_custom_format", "channel_index"), &SurfaceTool::get_custom_format); ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin); @@ -1211,7 +1307,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2); ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones); ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights); - ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom); + ClassDB::bind_method(D_METHOD("set_custom", "channel_index", "custom_color"), &SurfaceTool::set_custom); ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group); ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>())); @@ -1225,11 +1321,11 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache); - ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length); + ClassDB::bind_method(D_METHOD("get_aabb"), &SurfaceTool::get_aabb); ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3)); ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material); - ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive); + ClassDB::bind_method(D_METHOD("get_primitive_type"), &SurfaceTool::get_primitive_type); ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); |