23namespace mesh_optimizer
25const float CacheDecayPower = 1.5f;
26const float LastTriScore = 0.75f;
27const float ValenceBoostScale = 2.0f;
28const float ValenceBoostPower = 0.5f;
29const int32_t MaxVertexCacheSize = 32;
38 bool has_position = format.has(gfx::attribute::Position);
39 bool has_texcoord0 = format.has(gfx::attribute::TexCoord0);
40 bool has_normals = format.has(gfx::attribute::Normal);
41 bool has_tangents = format.has(gfx::attribute::Tangent);
42 bool has_bitangents = format.has(gfx::attribute::Bitangent);
43 uint16_t vertex_stride = format.getStride();
62 uint8_t* current_vertex_ptr = data.
vertex_data.data();
64 for(
const auto& v :
mesh.vertices())
66 math::vec3 position = v.position;
67 math::vec4
normal = math::vec4(v.normal, 0.0f);
68 math::vec2 texcoords0 = v.tex_coord;
73 gfx::attribute::Position,
80 gfx::attribute::Normal,
87 gfx::attribute::TexCoord0,
97 for(
const auto& triangle : mesh.
triangles())
99 const auto& indices = triangle.vertices;
101 tri.indices[0] = uint32_t(indices[0]);
102 tri.indices[1] = uint32_t(indices[1]);
103 tri.indices[2] = uint32_t(indices[2]);
207 vertex_format_ = format;
222 APPLOG_ERROR(
"Attempting to set a mesh vertex source without first calling "
223 "'prepareMesh' is not allowed.\n");
229 if(preparation_data_.owns_source)
233 preparation_data_.vertex_source =
nullptr;
234 preparation_data_.source_format = {};
235 preparation_data_.owns_source =
false;
236 preparation_data_.vertex_records.clear();
239 if(vertex_count == 0)
247 preparation_data_.source_format = source_format;
248 if(source_format.m_hash == vertex_format_.m_hash)
250 preparation_data_.vertex_source =
reinterpret_cast<uint8_t*
>(source.data());
255 preparation_data_.vertex_source =
new uint8_t[vertex_count * vertex_format_.getStride()];
256 preparation_data_.owns_source =
true;
258 preparation_data_.vertex_source,
260 reinterpret_cast<uint8_t*
>(source.data()),
267 if(!source_format.has(gfx::attribute::Normal) && vertex_format_.has(gfx::attribute::Normal))
269 preparation_data_.compute_normals =
true;
271 if(!source_format.has(gfx::attribute::Bitangent) && vertex_format_.has(gfx::attribute::Bitangent))
273 preparation_data_.compute_binormals =
true;
275 if(!source_format.has(gfx::attribute::Tangent) && vertex_format_.has(gfx::attribute::Tangent))
277 preparation_data_.compute_tangents =
true;
280#ifdef SET_VERTICES_WHEN_SETTING_PRIMITIVES
282 preparation_data_.vertex_records.clear();
283 preparation_data_.vertex_records.resize(vertex_count);
288 memset(preparation_data_.vertex_records.data(), 0xFF, vertex_count *
sizeof(uint32_t));
290 preparation_data_.vertex_data = std::move(source);
291 preparation_data_.vertex_count = vertex_count;
312 APPLOG_ERROR(
"Attempting to add primitives to a mesh without first calling "
313 "'prepareMesh' is not allowed.\n");
318 preparation_data_.submeshes = submeshes;
330 APPLOG_ERROR(
"Attempting to add primitives to a mesh without first calling "
331 "'prepareMesh' is not allowed.\n");
336#ifdef SET_VERTICES_WHEN_SETTING_PRIMITIVES
338 preparation_data_.triangle_count = 0;
339 preparation_data_.triangle_data.clear();
342 bool has_position = vertex_format_.has(gfx::attribute::Position);
343 bool has_normal = vertex_format_.has(gfx::attribute::Normal);
344 uint16_t vertex_stride = vertex_format_.getStride();
349 bool source_has_normals = preparation_data_.source_format.has(gfx::attribute::Normal);
350 bool source_has_binormal = preparation_data_.source_format.has(gfx::attribute::Bitangent);
351 bool source_has_tangent = preparation_data_.source_format.has(gfx::attribute::Tangent);
355 uint8_t vertex_flags = 0;
356 if(source_has_normals)
358 vertex_flags |= preparation_data::source_contains_normal;
360 if(source_has_binormal)
362 vertex_flags |= preparation_data::source_contains_binormal;
364 if(source_has_tangent)
366 vertex_flags |= preparation_data::source_contains_tangent;
370 uint8_t* src_vertices_ptr = preparation_data_.vertex_source;
372 for(
const auto& src_tri : triangles)
376 if(preparation_data_.check_for_degenerates)
382 gfx::vertex_unpack(vf1, gfx::attribute::Position, vertex_format_, src_vertices_ptr, src_tri.indices[0]);
385 gfx::vertex_unpack(vf2, gfx::attribute::Position, vertex_format_, src_vertices_ptr, src_tri.indices[1]);
388 gfx::vertex_unpack(vf3, gfx::attribute::Position, vertex_format_, src_vertices_ptr, src_tri.indices[2]);
389 std::memcpy(&v1[0], vf1, 3 *
sizeof(
float));
390 std::memcpy(&v2[0], vf2, 3 *
sizeof(
float));
391 std::memcpy(&v3[0], vf3, 3 *
sizeof(
float));
394 if(math::all(math::equal(v1, v2, math::epsilon<float>())) ||
395 math::all(math::equal(v1, v3, math::epsilon<float>())) ||
396 math::all(math::equal(v2, v3, math::epsilon<float>())))
403 preparation_data_.triangle_count++;
404 preparation_data_.triangle_data.resize(preparation_data_.triangle_count);
405 triangle& triangle_data = preparation_data_.triangle_data[preparation_data_.triangle_count - 1];
411 for(uint32_t j = 0; j < 3; ++j)
414 uint32_t orig_index = src_tri.indices[j];
417 uint32_t index = preparation_data_.vertex_records[orig_index];
420 if(index == 0xFFFFFFFF)
424 index = preparation_data_.vertex_count++;
425 preparation_data_.vertex_records[orig_index] = index;
428 size_t initial_size = preparation_data_.vertex_data.size();
429 preparation_data_.vertex_data.resize(initial_size + vertex_stride);
432 uint8_t* src_ptr = src_vertices_ptr + (orig_index * vertex_stride);
433 uint8_t* dst_ptr = &preparation_data_.vertex_data[initial_size];
434 std::memcpy(dst_ptr, src_ptr, vertex_stride);
437 preparation_data_.vertex_flags.push_back(vertex_flags);
456 bbox_.add_point(math::vec3(fpos[0], fpos[1], fpos[2]));
462 triangle_data.
indices[j] = index;
469 preparation_data_.triangle_count = triangles.size();
470 preparation_data_.triangle_data = std::move(triangles);
482 if(!bind_data.has_bones())
493 skin_bind_data_.clear();
494 skin_bind_data_ = bind_data;
497 skin_bind_data_.build_vertex_table(preparation_data_.vertex_count, preparation_data_.vertex_records, vertex_table);
498 skin_bind_data_.clear_vertex_influences();
503 bone_palettes_.clear();
507 bone_palettes_.reserve(preparation_data_.submeshes.size());
509 for(
size_t palette_id = 0; palette_id < preparation_data_.submeshes.size(); ++palette_id)
511 auto&
submesh = preparation_data_.submeshes[palette_id];
515 std::vector<uint32_t> faces;
522 for(uint32_t vertex_index : tri_data[i].indices)
524 const auto& data = vertex_table[vertex_index];
525 for(
const auto& influence : data.influences)
528 used_bones[
static_cast<uint32_t
>(influence)] =
true;
540 bone_palettes_.push_back(new_palette);
546 for(uint32_t i = face_start; i < face_end; ++i)
548 for(uint32_t k = 0; k < 3; ++k)
550 uint32_t vertex_index = tri_data[i].indices[k];
551 auto& data = vertex_table[vertex_index];
554 if(data.palette == -1)
556 data.palette =
static_cast<int32_t
>(palette_id);
568 else if(data.palette !=
static_cast<int32_t
>(palette_id))
571 uint32_t new_index =
static_cast<uint32_t
>(vertex_table.size());
576 new_vertex.
palette =
static_cast<int32_t
>(palette_id);
577 vertex_table.push_back(new_vertex);
590 tri_data[i].indices[k] = new_index;
600 bool has_weights = new_format.has(gfx::attribute::Weight);
601 bool has_indices = new_format.has(gfx::attribute::Indices);
602 if(!has_weights || !has_indices)
604 new_format.m_hash = 0;
607 new_format.add(gfx::attribute::Weight, 4, gfx::attribute_type::Float);
611 new_format.add(gfx::attribute::Indices, 4, gfx::attribute_type::Float,
false,
true);
616 vertex_format_ = new_format;
620 uint16_t vertex_stride = vertex_format_.getStride();
623 uint32_t original_vertex_count = preparation_data_.vertex_count;
624 if(vertex_format_.m_hash != original_format.m_hash)
627 byte_array_t original_buffer(preparation_data_.vertex_data);
628 preparation_data_.vertex_data.clear();
629 preparation_data_.vertex_data.resize(vertex_table.size() * vertex_stride);
630 preparation_data_.vertex_flags.resize(vertex_table.size());
633 preparation_data_.vertex_data.data(),
635 original_buffer.data(),
636 original_vertex_count);
641 preparation_data_.vertex_data.resize(vertex_table.size() * vertex_stride);
642 preparation_data_.vertex_flags.resize(vertex_table.size());
646 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data();
647 for(
size_t i = 0; i < vertex_table.size(); ++i)
649 auto& data = vertex_table[i];
652 int32_t palette_id = data.palette;
660 const auto& palette = bone_palettes_[
static_cast<size_t>(palette_id)];
663 if(i >= original_vertex_count)
665 std::memcpy(src_vertices_ptr + (i * vertex_stride),
666 src_vertices_ptr + (data.original_vertex * vertex_stride),
670 preparation_data_.vertex_flags[i] = preparation_data_.vertex_flags[data.original_vertex];
673 uint32_t max_bones = std::min<uint32_t>(4, uint32_t(data.influences.size()));
679 math::vec4 blend_weights(0.0f, 0.0f, 0.0f, 0.0f);
680 math::vec4 blend_indices(0.0f, 0.0f, 0.0f, 0.0f);
682 for(uint32_t j = 0; j < max_bones; ++j)
685 uint32_t palette_bone_index =
686 palette.translate_bone_to_palette(
static_cast<uint32_t
>(data.influences[j]));
688 blend_indices[
static_cast<math::vec4::length_type
>(j)] =
static_cast<float>(palette_bone_index);
689 blend_weights[
static_cast<math::vec4::length_type
>(j)] = data.weights[j];
694 gfx::attribute::Weight,
701 gfx::attribute::Indices,
709 preparation_data_.vertex_count =
static_cast<uint32_t
>(vertex_table.size());
719 root_ = std::move(root);
728 result &= prepare_mesh(data.vertex_format);
729 result &= set_bounding_box(data.bbox);
733 result &= bind_skin(data.skin_data);
734 result &= bind_armature(data.root_node);
735 result &= end_prepare();
743 uint32_t width_segments,
744 uint32_t height_segments,
746 bool hardware_copy ) ->
bool
749 prepare_mesh(format);
752 plane_mesh_t plane({width * 0.5f, height * 0.5f}, {width_segments, height_segments});
753 math::quat rot1(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
754 math::quat rot2(math::vec3(math::radians(90.0f), 0.f, 0.0f));
756 auto plane1 = rotate_mesh(plane, rot1);
757 auto plane2 = rotate_mesh(plane, rot2);
758 auto mesh = merge_mesh(plane1, plane2);
760 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
762 return end_prepare(hardware_copy);
769 uint32_t width_segments,
770 uint32_t height_segments,
771 uint32_t depth_segments,
773 bool hardware_copy ) ->
bool
776 prepare_mesh(format);
779 box_mesh_t box({width * 0.5f, height * 0.5f, depth * 0.5f}, {width_segments, height_segments, depth_segments});
780 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
781 auto mesh = rotate_mesh(
box, rot);
783 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
785 return end_prepare(hardware_copy);
793 uint32_t width_segments,
794 uint32_t height_segments,
795 uint32_t depth_segments,
797 bool hardware_copy ) ->
bool
800 prepare_mesh(format);
803 rounded_box_mesh_t rounded_box(0.05, {width * 0.5f, height * 0.5f, depth * 0.5f}, 4, {width_segments, height_segments, depth_segments});
804 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
805 auto mesh = rotate_mesh(rounded_box, rot);
807 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
809 return end_prepare(hardware_copy);
817 bool hardware_copy ) ->
bool
820 prepare_mesh(format);
824 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
827 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
829 return end_prepare(hardware_copy);
838 bool hardware_copy ) ->
bool
845 vertex_format_ = format;
848 capped_cylinder_mesh_t cylinder(radius, height * 0.5,
static_cast<int>(slices),
static_cast<int>(stacks));
849 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
850 auto mesh = rotate_mesh(cylinder, rot);
852 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
854 return end_prepare(hardware_copy);
863 bool hardware_copy ) ->
bool
866 prepare_mesh(format);
869 capsule_mesh_t capsule(radius, height * 0.5,
static_cast<int>(slices),
static_cast<int>(stacks));
870 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
871 auto mesh = rotate_mesh(capsule, rot);
873 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
875 return end_prepare(hardware_copy);
885 bool hardware_copy ) ->
bool
888 prepare_mesh(format);
891 capped_cone_mesh_t cone(radius, 1.0,
static_cast<int>(stacks),
static_cast<int>(slices));
892 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
893 auto mesh = rotate_mesh(cone, rot);
895 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
897 return end_prepare(hardware_copy);
906 bool hardware_copy ) ->
bool
909 prepare_mesh(format);
912 torus_mesh_t torus(inner_radius, outer_radius,
static_cast<int>(sides),
static_cast<int>(bands));
913 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
914 auto mesh = rotate_mesh(torus, rot);
916 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
918 return end_prepare(hardware_copy);
924 prepare_mesh(format);
928 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
929 auto mesh = rotate_mesh(teapot, rot);
931 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
933 return end_prepare(hardware_copy);
939 prepare_mesh(format);
943 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
944 auto mesh = rotate_mesh(icosahedron, rot);
946 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
948 return end_prepare(hardware_copy);
954 prepare_mesh(format);
958 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
959 auto mesh = rotate_mesh(dodecahedron, rot);
961 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
963 return end_prepare(hardware_copy);
970 prepare_mesh(format);
974 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
975 auto mesh = rotate_mesh(icosphere, rot);
977 create_mesh(vertex_format_,
mesh, preparation_data_, bbox_);
979 return end_prepare(hardware_copy);
985 uint16_t position_offset =
vertex_format_.getOffset(gfx::attribute::Position);
1003 std::memcpy(&v1[0], vf1, 3 *
sizeof(
float));
1004 std::memcpy(&v2[0], vf2, 3 *
sizeof(
float));
1005 std::memcpy(&v3[0], vf3, 3 *
sizeof(
float));
1007 math::vec3 c = math::cross(v2 - v1, v3 - v1);
1008 if(math::length2(c) < (4.0f * 0.000001f * 0.000001f))
1024 APPLOG_ERROR(
"Attempting to call 'end_prepare' on a mesh without first "
1025 "calling 'prepare_mesh' is not "
1032 check_for_degenerates();
1037 if(!generate_vertex_components(weld))
1043 vertex_count_ = preparation_data_.vertex_count;
1044 system_vb_ =
new uint8_t[vertex_count_ * vertex_format_.getStride()];
1047 std::memcpy(system_vb_, preparation_data_.vertex_data.data(), vertex_count_ * vertex_format_.getStride());
1048 preparation_data_.vertex_data.clear();
1049 preparation_data_.vertex_flags.clear();
1050 preparation_data_.vertex_count = 0;
1055 build_vb(hardware_copy);
1059 face_count_ = preparation_data_.triangle_count;
1060 system_ib_ =
new uint32_t[face_count_ * 3];
1064 if(!sort_mesh_data())
1072 build_ib(hardware_copy);
1075 if(preparation_data_.owns_source)
1079 preparation_data_.vertex_source =
nullptr;
1083 hardware_mesh_ = hardware_copy;
1084 optimize_mesh_ = optimize;
1110 auto buffer_size =
static_cast<uint32_t
>(size_t(
face_count_ * 3) *
sizeof(uint32_t));
1116 hardware_ib_ = std::make_shared<gfx::index_buffer>(mem, BGFX_BUFFER_INDEX32);
1120 auto ib = std::static_pointer_cast<gfx::index_buffer>(
hardware_ib_);
1124 hardware_ib_ = std::make_shared<gfx::index_buffer>(mem, BGFX_BUFFER_INDEX32);
1133 std::map<adjacent_edge_key, uint32_t> edge_tree;
1134 std::map<adjacent_edge_key, uint32_t>::iterator it_edge;
1140 if(preparation_data_.triangle_count == 0)
1146 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
1147 uint16_t vertex_stride = vertex_format_.getStride();
1150 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data() + position_offset;
1151 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
1156 const triangle& tri = preparation_data_.triangle_data[i];
1161 const math::vec3* v1 =
1162 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[0] * vertex_stride));
1163 const math::vec3* v2 =
1164 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[1] * vertex_stride));
1165 const math::vec3* v3 =
1166 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[2] * vertex_stride));
1171 edge_tree[edge] = i;
1176 edge_tree[edge] = i;
1181 edge_tree[edge] = i;
1186 adjacency.resize(preparation_data_.triangle_count * 3, 0xFFFFFFFF);
1189 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
1194 const triangle& tri = preparation_data_.triangle_data[i];
1201 const math::vec3* v1 =
1202 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[0] * vertex_stride));
1203 const math::vec3* v2 =
1204 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[1] * vertex_stride));
1205 const math::vec3* v3 =
1206 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[2] * vertex_stride));
1218 it_edge = edge_tree.find(edge);
1219 if(it_edge != edge_tree.end())
1221 adjacency[(i * 3)] = it_edge->second;
1229 it_edge = edge_tree.find(edge);
1230 if(it_edge != edge_tree.end())
1232 adjacency[(i * 3) + 1] = it_edge->second;
1240 it_edge = edge_tree.find(edge);
1241 if(it_edge != edge_tree.end())
1243 adjacency[(i * 3) + 2] = it_edge->second;
1252 if(face_count_ == 0)
1258 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
1259 uint16_t vertex_stride = vertex_format_.getStride();
1262 uint8_t* src_vertices_ptr = system_vb_ + position_offset;
1263 uint32_t* src_indices_ptr = system_ib_;
1264 for(uint32_t i = 0; i < face_count_; ++i, src_indices_ptr += 3)
1270 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[0] * vertex_stride));
1272 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[1] * vertex_stride));
1274 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[2] * vertex_stride));
1279 edge_tree[edge] = i;
1284 edge_tree[edge] = i;
1289 edge_tree[edge] = i;
1294 adjacency.resize(face_count_ * 3, 0xFFFFFFFF);
1297 src_indices_ptr = system_ib_;
1298 for(uint32_t i = 0; i < face_count_; ++i, src_indices_ptr += 3)
1303 const math::vec3* v1 =
1304 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[0] * vertex_stride));
1305 const math::vec3* v2 =
1306 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[1] * vertex_stride));
1307 const math::vec3* v3 =
1308 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (src_indices_ptr[2] * vertex_stride));
1320 it_edge = edge_tree.find(edge);
1321 if(it_edge != edge_tree.end())
1323 adjacency[(i * 3)] = it_edge->second;
1331 it_edge = edge_tree.find(edge);
1332 if(it_edge != edge_tree.end())
1334 adjacency[(i * 3) + 1] = it_edge->second;
1342 it_edge = edge_tree.find(edge);
1343 if(it_edge != edge_tree.end())
1345 adjacency[(i * 3) + 2] = it_edge->second;
1417 math::vec3 cen = bounds.get_center();
1418 math::vec3 ext = bounds.get_extents();
1419 std::array<math::vec2, 8> extent_points = {{
1420 cam.world_to_viewport(math::vec3(cen.x - ext.x, cen.y - ext.y, cen.z - ext.z)),
1421 cam.world_to_viewport(math::vec3(cen.x + ext.x, cen.y - ext.y, cen.z - ext.z)),
1422 cam.world_to_viewport(math::vec3(cen.x - ext.x, cen.y - ext.y, cen.z + ext.z)),
1423 cam.world_to_viewport(math::vec3(cen.x + ext.x, cen.y - ext.y, cen.z + ext.z)),
1424 cam.world_to_viewport(math::vec3(cen.x - ext.x, cen.y + ext.y, cen.z - ext.z)),
1425 cam.world_to_viewport(math::vec3(cen.x + ext.x, cen.y + ext.y, cen.z - ext.z)),
1426 cam.world_to_viewport(math::vec3(cen.x - ext.x, cen.y + ext.y, cen.z + ext.z)),
1427 cam.world_to_viewport(math::vec3(cen.x + ext.x, cen.y + ext.y, cen.z + ext.z)),
1430 math::vec2 min = extent_points[0];
1431 math::vec2 max = extent_points[0];
1432 for(
const auto& v : extent_points)
1434 min = math::min(min, v);
1435 max = math::max(max, v);
1455 return *mesh_submeshes_[submesh_index];
1461 for(
const auto&
submesh : mesh_submeshes_)
1480 auto it = skinned_submesh_indices_.find(data_group_id);
1481 if(it != skinned_submesh_indices_.end())
1497 auto it = non_skinned_submesh_indices_.find(data_group_id);
1498 if(it != non_skinned_submesh_indices_.end())
1525 uint32_t groups_count = 0;
1528 groups_count = std::max(groups_count, sub.data_group_id + 1);
1530 return groups_count;
1539 if(math::epsilonNotEqual(key1.vertex1->x, key2.vertex1->x, math::epsilon<float>()))
1541 return (key2.vertex1->x < key1.vertex1->x);
1543 if(math::epsilonNotEqual(key1.vertex1->y, key2.vertex1->y, math::epsilon<float>()))
1545 return (key2.vertex1->y < key1.vertex1->y);
1547 if(math::epsilonNotEqual(key1.vertex1->z, key2.vertex1->z, math::epsilon<float>()))
1549 return (key2.vertex1->z < key1.vertex1->z);
1552 if(math::epsilonNotEqual(key1.vertex2->x, key2.vertex2->x, math::epsilon<float>()))
1554 return (key2.vertex2->x < key1.vertex2->x);
1556 if(math::epsilonNotEqual(key1.vertex2->y, key2.vertex2->y, math::epsilon<float>()))
1558 return (key2.vertex2->y < key1.vertex2->y);
1560 if(math::epsilonNotEqual(key1.vertex2->z, key2.vertex2->z, math::epsilon<float>()))
1562 return (key2.vertex2->z < key1.vertex2->z);
1571 return key1.data_group_id < key2.data_group_id;
1576 auto vertex_compare =
1577 [](
const uint8_t* pVtx1,
const uint8_t* pVtx2,
const gfx::vertex_layout& layout,
float tolerance) ->
int
1582 for(uint16_t i = 0; i < gfx::attribute::Count; ++i)
1590 uint16_t offset = layout.getOffset(
static_cast<gfx::attribute>(i));
1593 const uint8_t* p1 = pVtx1 + offset;
1594 const uint8_t* p2 = pVtx2 + offset;
1597 uint8_t num_components{};
1598 bgfx::AttribType::Enum
type{};
1599 bool normalized{}, as_int{};
1600 layout.decode(
static_cast<gfx::attribute>(i), num_components,
type, normalized, as_int);
1605 case bgfx::AttribType::Float:
1607 for(uint8_t j = 0; j < num_components; ++j)
1609 diff = ((
float*)p1)[j] - ((
float*)p2)[j];
1610 if(fabsf(diff) > tolerance)
1611 return (diff < 0) ? -1 : 1;
1616 case bgfx::AttribType::Uint8:
1617 case bgfx::AttribType::Int16:
1621 ndifference = memcmp(p1, p2, num_components * (
type == bgfx::AttribType::Uint8 ? 1 : 2));
1622 if(ndifference != 0)
1624 return (ndifference < 0) ? -1 : 1;
1629 for(uint8_t j = 0; j < num_components; ++j)
1632 if(
type == bgfx::AttribType::Uint8)
1634 f1 = normalized ? ((float)p1[j] / 255.0f) : (float)p1[j];
1635 f2 = normalized ? ((float)p2[j] / 255.0f) : (float)p2[j];
1639 f1 = normalized ? ((float)((int16_t*)p1)[j] / 32767.0f) : (float)((int16_t*)p1)[j];
1640 f2 = normalized ? ((float)((int16_t*)p2)[j] / 32767.0f) : (float)((int16_t*)p2)[j];
1643 if(fabsf(diff) > tolerance)
1645 return (diff < 0) ? -1 : 1;
1662 int ndifference = vertex_compare(key1.vertex, key2.vertex, key1.format, key1.tolerance);
1663 if(ndifference != 0)
1665 return (ndifference < 0);
1675 if(key1.data_group_id != key2.data_group_id)
1677 return key1.data_group_id < key2.data_group_id;
1690 auto it_bone1 = p1->
bones.begin();
1691 auto it_bone2 = p2->
bones.begin();
1692 for(; it_bone1 != p1->
bones.end() && it_bone2 != p2->
bones.end(); ++it_bone1, ++it_bone2)
1694 if(it_bone1->first != it_bone2->first)
1696 return it_bone1->first < it_bone2->first;
1708 if(force_normal_generation_ || preparation_data_.compute_normals)
1711 std::vector<uint32_t> adjacency;
1712 if(!generate_adjacency(adjacency))
1714 APPLOG_ERROR(
"Failed to generate adjacency buffer mesh containing {0} faces.\n",
1715 preparation_data_.triangle_count);
1719 if(force_barycentric_generation_ || preparation_data_.compute_barycentric)
1722 if(!generate_vertex_barycentrics(&adjacency.front()))
1724 APPLOG_ERROR(
"Failed to generate vertex barycentric coords for mesh "
1725 "containing {0} faces.\n",
1726 preparation_data_.triangle_count);
1734 if(!generate_vertex_normals(&adjacency.front()))
1736 APPLOG_ERROR(
"Failed to generate vertex normals for mesh containing {0} faces.\n",
1737 preparation_data_.triangle_count);
1747 if(!weld_vertices())
1749 APPLOG_ERROR(
"Failed to weld vertices for mesh containing {0} faces.\n", preparation_data_.triangle_count);
1758 if(force_tangent_generation_ || preparation_data_.compute_binormals || preparation_data_.compute_tangents)
1761 if(vertex_format_.has(gfx::attribute::Normal))
1764 if(!generate_vertex_tangents())
1766 APPLOG_ERROR(
"Failed to generate vertex tangents for mesh containing "
1768 preparation_data_.triangle_count);
1784 uint32_t start_tri, previous_tri, current_tri;
1785 math::vec3 vec_edge1, vec_edge2, vec_normal;
1786 uint32_t i, j, k, index;
1789 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
1790 bool has_normals = vertex_format_.has(gfx::attribute::Normal);
1791 uint16_t vertex_stride = vertex_format_.getStride();
1800 uint32_t original_vertex_count = preparation_data_.vertex_count;
1803 remap_array_ptr->resize(preparation_data_.vertex_count);
1804 for(i = 0; i < preparation_data_.vertex_count; ++i)
1806 (*remap_array_ptr)[i] = i;
1812 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data();
1813 auto* normals_ptr =
new math::vec3[preparation_data_.triangle_count];
1814 memset(normals_ptr, 0, preparation_data_.triangle_count *
sizeof(math::vec3));
1815 for(i = 0; i < preparation_data_.triangle_count; ++i)
1818 const triangle& tri = preparation_data_.triangle_data[i];
1820 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[0] * vertex_stride) + position_offset);
1822 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[1] * vertex_stride) + position_offset);
1824 reinterpret_cast<const math::vec3*
>(src_vertices_ptr + (tri.
indices[2] * vertex_stride) + position_offset);
1828 vec_edge1 = math::normalize(*v2 - *v1);
1829 vec_edge2 = math::normalize(*v3 - *v1);
1832 vec_normal = math::cross(vec_edge1, vec_edge2);
1833 normals_ptr[i] = math::normalize(vec_normal);
1838 for(i = 0; i < preparation_data_.triangle_count; ++i)
1840 triangle& tri = preparation_data_.triangle_data[i];
1847 for(j = 0; j < 3; ++j)
1853 if(!force_normal_generation_ &&
1854 (preparation_data_.vertex_flags[index] & preparation_data::source_contains_normal))
1878 current_tri = adjacency_ptr[(i * 3) + ((j + 2) % 3)];
1883 if(current_tri == start_tri || current_tri == 0xFFFFFFFF)
1889 for(k = 0; k < 3; ++k)
1891 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1902 previous_tri = current_tri;
1903 current_tri = adjacency_ptr[(current_tri * 3) + ((k + 2) % 3)];
1918 if(current_tri != 0xFFFFFFFF)
1920 for(k = 0; k < 3; ++k)
1922 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1938 start_tri = current_tri;
1939 previous_tri = current_tri;
1940 current_tri = adjacency_ptr[(current_tri * 3) + k];
1941 vec_normal = normals_ptr[start_tri];
1946 if(current_tri == start_tri || current_tri == 0xFFFFFFFF)
1952 vec_normal += normals_ptr[current_tri];
1955 for(k = 0; k < 3; ++k)
1957 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1968 previous_tri = current_tri;
1969 current_tri = adjacency_ptr[(current_tri * 3) + ((k + 1) % 3)];
1983 vec_normal = math::normalize(vec_normal);
1991 gfx::vertex_unpack(fn, gfx::attribute::Normal, vertex_format_, src_vertices_ptr, index);
1992 math::vec3 ref_normal;
1993 ref_normal[0] = fn[0];
1994 ref_normal[1] = fn[1];
1995 ref_normal[2] = fn[2];
1996 if(ref_normal.x == 0.0f && ref_normal.y == 0.0f && ref_normal.z == 0.0f)
1998 gfx::vertex_pack(fn,
true, gfx::attribute::Normal, vertex_format_, src_vertices_ptr, index);
2003 if(math::abs(ref_normal.x - vec_normal.x) >= 1e-3f || math::abs(ref_normal.y - vec_normal.y) >= 1e-3f ||
2004 math::abs(ref_normal.z - vec_normal.z) >= 1e-3f)
2007 preparation_data_.vertex_data.resize(preparation_data_.vertex_data.size() + vertex_stride);
2014 src_vertices_ptr = preparation_data_.vertex_data.data();
2017 std::memcpy(src_vertices_ptr + (preparation_data_.vertex_count * vertex_stride),
2018 src_vertices_ptr + (index * vertex_stride),
2022 preparation_data_.vertex_flags.push_back(preparation_data_.vertex_flags[index]);
2027 (*remap_array_ptr)[index] = preparation_data_.vertex_count;
2032 index = preparation_data_.vertex_count++;
2033 math::vec4 norm(vec_normal, 0.0f);
2036 gfx::attribute::Normal,
2057 if(remap_array_ptr && original_vertex_count == preparation_data_.vertex_count)
2059 remap_array_ptr->clear();
2074 math::vec3 *tangents =
nullptr, *bitangents =
nullptr;
2075 uint32_t i, i1, i2, i3, num_faces, num_verts;
2076 math::vec3
P, Q, T, B, cross_vec, normal_vec;
2079 uint16_t vertex_stride = vertex_format_.getStride();
2081 bool has_normals = vertex_format_.has(gfx::attribute::Normal);
2089 bool requires_tangents = vertex_format_.has(gfx::attribute::Tangent);
2090 bool requires_bitangents = vertex_format_.has(gfx::attribute::Bitangent);
2091 if(!force_tangent_generation_ && !requires_bitangents && !requires_tangents)
2098 num_faces = preparation_data_.triangle_count;
2099 num_verts = preparation_data_.vertex_count;
2100 tangents =
new math::vec3[num_verts];
2101 bitangents =
new math::vec3[num_verts];
2102 memset(tangents, 0,
sizeof(math::vec3) * num_verts);
2103 memset(bitangents, 0,
sizeof(math::vec3) * num_verts);
2106 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data();
2107 for(i = 0; i < num_faces; ++i)
2109 triangle& tri = preparation_data_.triangle_data[i];
2120 gfx::vertex_unpack(fE, gfx::attribute::Position, vertex_format_, src_vertices_ptr, i1);
2123 gfx::vertex_unpack(fF, gfx::attribute::Position, vertex_format_, src_vertices_ptr, i2);
2126 gfx::vertex_unpack(fG, gfx::attribute::Position, vertex_format_, src_vertices_ptr, i3);
2127 std::memcpy(&E[0], fE, 3 *
sizeof(
float));
2128 std::memcpy(&F[0], fF, 3 *
sizeof(
float));
2129 std::memcpy(&G[0], fG, 3 *
sizeof(
float));
2136 gfx::vertex_unpack(&fEt[0], gfx::attribute::TexCoord0, vertex_format_, src_vertices_ptr, i1);
2139 gfx::vertex_unpack(&fFt[0], gfx::attribute::TexCoord0, vertex_format_, src_vertices_ptr, i2);
2142 gfx::vertex_unpack(&fGt[0], gfx::attribute::TexCoord0, vertex_format_, src_vertices_ptr, i3);
2143 std::memcpy(&Et[0], fEt, 2 *
sizeof(
float));
2144 std::memcpy(&Ft[0], fFt, 2 *
sizeof(
float));
2145 std::memcpy(&Gt[0], fGt, 2 *
sizeof(
float));
2156 float s1 = Ft.x - Et.x;
2157 float t1 = Ft.y - Et.y;
2158 float s2 = Gt.x - Et.x;
2159 float t2 = Gt.y - Et.y;
2165 float r = (s1 * t2 - s2 * t1);
2166 if(math::abs(r) < math::epsilon<float>())
2175 T.x = r * (t2 *
P.x - t1 * Q.x);
2176 T.y = r * (t2 *
P.y - t1 * Q.y);
2177 T.z = r * (t2 *
P.z - t1 * Q.z);
2178 B.x = r * (s1 * Q.x - s2 *
P.x);
2179 B.y = r * (s1 * Q.y - s2 *
P.y);
2180 B.z = r * (s1 * Q.z - s2 *
P.z);
2187 bitangents[i1] += B;
2188 bitangents[i2] += B;
2189 bitangents[i3] += B;
2194 for(i = 0; i < num_verts; i++, src_vertices_ptr += vertex_stride)
2198 bool has_bitangent = ((preparation_data_.vertex_flags[i] & preparation_data::source_contains_binormal) != 0);
2199 bool has_tangent = ((preparation_data_.vertex_flags[i] & preparation_data::source_contains_tangent) != 0);
2200 if(!force_tangent_generation_ && has_bitangent && has_tangent)
2209 std::memcpy(&normal_vec[0],
normal, 3 *
sizeof(
float));
2214 T = T - (normal_vec * math::dot(normal_vec, T));
2215 T = math::normalize(T);
2218 if(force_tangent_generation_ || (!has_tangent && requires_tangents))
2220 math::vec4 t(T, 1.0f);
2221 gfx::vertex_pack(math::value_ptr(t),
true, gfx::attribute::Tangent, vertex_format_, src_vertices_ptr);
2225 if(force_tangent_generation_ || (!has_bitangent && requires_bitangents))
2228 B = math::cross(normal_vec, T);
2229 B = math::normalize(B);
2234 cross_vec = math::cross(normal_vec, T);
2235 if(math::dot(cross_vec, bitangents[i]) < 0.0f)
2243 math::vec4
b(B, 1.0f);
2244 gfx::vertex_pack(math::value_ptr(
b),
true, gfx::attribute::Bitangent, vertex_format_, src_vertices_ptr);
2261 std::map<weld_key, uint32_t> vertex_tree;
2262 std::map<weld_key, uint32_t>::const_iterator it_key;
2264 uint32_t new_vertex_count = 0;
2267 if(vertex_remap_ptr)
2269 vertex_remap_ptr->resize(preparation_data_.vertex_count);
2271 auto collapse_map =
new uint32_t[preparation_data_.vertex_count];
2274 uint16_t vertex_stride = vertex_format_.getStride();
2277 for(uint32_t i = 0; i < preparation_data_.vertex_count; ++i)
2280 key.vertex = (&preparation_data_.vertex_data[0]) + (i * vertex_stride);
2281 key.format = vertex_format_;
2282 key.tolerance = tolerance;
2285 it_key = vertex_tree.find(key);
2286 if(it_key == vertex_tree.end())
2289 vertex_tree[key] = new_vertex_count;
2290 collapse_map[i] = new_vertex_count;
2291 if(vertex_remap_ptr)
2293 (*vertex_remap_ptr)[i] = new_vertex_count;
2297 new_vertex_data.resize((new_vertex_count + 1) * vertex_stride);
2298 std::memcpy(&new_vertex_data[new_vertex_count * vertex_stride], key.vertex, vertex_stride);
2299 new_vertex_flags.push_back(preparation_data_.vertex_flags[i]);
2307 collapse_map[i] = it_key->second;
2308 if(vertex_remap_ptr)
2310 (*vertex_remap_ptr)[i] = 0xFFFFFFFF;
2318 if(preparation_data_.vertex_count == new_vertex_count)
2322 if(vertex_remap_ptr)
2324 vertex_remap_ptr->clear();
2331 preparation_data_.vertex_data.clear();
2332 preparation_data_.vertex_data.resize(new_vertex_data.size());
2333 std::memcpy(preparation_data_.vertex_data.data(), new_vertex_data.data(), new_vertex_data.size());
2334 preparation_data_.vertex_flags.clear();
2335 preparation_data_.vertex_flags.resize(new_vertex_flags.size());
2336 std::memcpy(preparation_data_.vertex_flags.data(), new_vertex_flags.data(), new_vertex_flags.size());
2337 preparation_data_.vertex_count = new_vertex_count;
2340 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
2342 triangle& tri = preparation_data_.triangle_data[i];
2361 bones_.push_back(bone);
2366 for(
size_t i = 0; i < bones_.size();)
2368 if(bones_[i].influences.empty())
2370 bones_.erase(bones_.begin() +
static_cast<int>(i));
2383 for(
auto& bone : bones_)
2385 bone.influences.clear();
2397 for(
auto& bone : bones_)
2401 new_influences.reserve(influences.size());
2402 for(
auto& influence : influences)
2404 uint32_t new_index = remap[influence.vertex_index];
2405 if(new_index != 0xFFFFFFFF)
2412 if(new_index >= remap.size())
2414 new_influences.push_back(
vertex_influence{influence.vertex_index, influence.weight});
2420 bone.influences = new_influences;
2426 const std::vector<uint32_t>& vertex_remap,
2432 table.reserve(vertex_count);
2433 for(vertex = 0; vertex < vertex_count; ++vertex)
2438 table.push_back(data);
2443 for(
size_t i = 0; i < bones_.size(); ++i)
2446 for(
auto& influence : influences)
2449 if(!vertex_remap.empty())
2451 vertex = vertex_remap[influence.vertex_index];
2452 if(vertex == 0xFFFFFFFF)
2456 auto& data = table[vertex];
2458 data.influences.push_back(
static_cast<int32_t
>(i));
2459 data.weights.push_back(influence.weight);
2463 auto& data = table[influence.vertex_index];
2465 data.influences.push_back(
static_cast<int32_t
>(i));
2466 data.weights.push_back(influence.weight);
2492 auto it = std::find_if(std::begin(bones_),
2494 [
name](
const auto& bone)
2496 return name == bone.bone_id;
2498 if(it != std::end(bones_))
2500 query.bone = &(*it);
2501 query.index = std::distance(std::begin(bones_), it);
2518 , maximum_size_(palette_size)
2519 , maximum_blend_index_(-1)
2524 const skin_bind_data& bind_data)
const ->
const std::vector<math::mat4>&
2528 const auto& bind_list = bind_data.get_bones();
2531 auto count = std::min(bones_.size(), node_transforms.size());
2532 thread_local static std::vector<math::mat4> skinning_transforms_;
2533 skinning_transforms_.resize(bones_.size(), math::identity<math::mat4>());
2534 for(
size_t i = 0; i <
count; ++i)
2536 auto bone = bones_[i];
2537 const auto& bone_transform = node_transforms[bone];
2538 const auto& bone_data = bind_list[bone];
2539 auto& transform = skinning_transforms_[i];
2540 transform = bone_transform.get_matrix() * bone_data.bind_pose_transform.get_matrix();
2544 return skinning_transforms_;
2548 const skin_bind_data& bind_data)
const ->
const std::vector<math::mat4>&
2552 const auto& bind_list = bind_data.get_bones();
2555 auto count = std::min(bones_.size(), node_transforms.size());
2556 thread_local static std::vector<math::mat4> skinning_transforms_;
2557 skinning_transforms_.resize(bones_.size(), math::identity<math::mat4>());
2559 for(
size_t i = 0; i <
count; ++i)
2561 auto bone = bones_[i];
2562 const auto& bone_transform = node_transforms[bone];
2563 const auto& bone_data = bind_list[bone];
2564 auto& transform = skinning_transforms_[i];
2565 transform = bone_transform * bone_data.bind_pose_transform.get_matrix();
2569 return skinning_transforms_;
2574 bone_index_map_t::iterator it_bone, it_bone2;
2578 for(it_bone = bones.begin(); it_bone != bones.end(); ++it_bone)
2584 bones_.push_back(it_bone->first);
2594 std::memcpy(
faces_.data(), faces.data(), faces.size() *
sizeof(uint32_t));
2599 bone_index_map_t::iterator it_bone, it_bone2;
2604 for(
size_t i = 0, j = bones.size(); i < j; ++i)
2625 std::memcpy(
faces_.data(), faces.data(), faces.size() *
sizeof(uint32_t));
2630 bone_index_map_t::iterator it_bone;
2638 for(
size_t i = 0; i < bones.size(); ++i)
2644 bones_.push_back(bones[i]);
2652 int32_t& current_space,
2653 int32_t& common_bones,
2654 int32_t& additional_bones)
2657 current_space =
static_cast<int32_t
>(
maximum_size_ -
static_cast<uint32_t
>(
bones_.size()));
2659 additional_bones = 0;
2664 additional_bones =
static_cast<int32_t
>(
input.size());
2668 else if(
input.size() == 0)
2676 bone_index_map_t::iterator it_bone, it_bone2;
2677 for(it_bone =
input.begin(); it_bone !=
input.end(); ++it_bone)
2690 auto it_bone = bones_lut_.find(bone_index);
2691 if(it_bone == bones_lut_.end())
2693 return it_bone->second;
2741 if(preparation_data_.compute_per_triangle_material_data)
2746 triangle_data_.resize(face_count_);
2748 uint32_t* dst_indices_ptr = system_ib_;
2749 for(uint32_t i = 0; i < face_count_; ++i)
2752 const triangle& tri_in = preparation_data_.triangle_data[i];
2753 *dst_indices_ptr++ = tri_in.
indices[0];
2754 *dst_indices_ptr++ = tri_in.
indices[1];
2755 *dst_indices_ptr++ = tri_in.
indices[2];
2757 if(preparation_data_.compute_per_triangle_material_data)
2766 preparation_data_.triangle_count = 0;
2767 preparation_data_.triangle_data.clear();
2772 data_groups_.clear();
2774 for(
auto submesh : mesh_submeshes_)
2778 mesh_submeshes_.clear();
2780 skinned_submesh_indices_.clear();
2781 skinned_submesh_count_ = {};
2783 non_skinned_submesh_indices_.clear();
2784 non_skinned_submesh_count_ = {};
2786 for(
size_t i = 0; i < preparation_data_.submeshes.size(); ++i)
2788 const auto& s = preparation_data_.submeshes[i];
2793 skinned_submesh_count_++;
2794 skinned_submesh_indices_[sub->data_group_id].emplace_back(i);
2798 non_skinned_submesh_count_++;
2799 non_skinned_submesh_indices_[sub->data_group_id].emplace_back(i);
2802 mesh_submeshes_.emplace_back(sub);
2803 data_groups_[sub->data_group_id].emplace_back(sub);
2806 preparation_data_.submeshes.clear();
2819 auto vb = std::static_pointer_cast<gfx::vertex_buffer>(
hardware_vb_);
2820 auto ib = std::static_pointer_cast<gfx::index_buffer>(
hardware_ib_);
2832 std::memcpy(vb.data,
2842 std::memcpy(ib.data,
2852 uint32_t* src_buffer_ptr,
2853 uint32_t* dest_buffer_ptr,
2854 uint32_t min_vertex,
2855 uint32_t max_vertex)
2857 float best_score = 0.0f, score;
2858 int32_t best_triangle = -1;
2859 uint32_t vertex_cache_size = 0;
2860 uint32_t index, triangle_index, temp;
2863 uint32_t vertex_cache_ptr[mesh_optimizer::MaxVertexCacheSize + 1];
2864 std::memset(vertex_cache_ptr, 0,
sizeof(vertex_cache_ptr));
2867 uint32_t vertex_count = (max_vertex - min_vertex) + 1;
2876 index = src_buffer_ptr[i * 3] - min_vertex;
2877 vertex_info_ptr[index].unused_triangle_references++;
2878 vertex_info_ptr[index].triangle_references.push_back(i);
2879 index = src_buffer_ptr[(i * 3) + 1] - min_vertex;
2880 vertex_info_ptr[index].unused_triangle_references++;
2881 vertex_info_ptr[index].triangle_references.push_back(i);
2882 index = src_buffer_ptr[(i * 3) + 2] - min_vertex;
2883 vertex_info_ptr[index].unused_triangle_references++;
2884 vertex_info_ptr[index].triangle_references.push_back(i);
2889 for(uint32_t i = 0; i < vertex_count; ++i)
2900 index = src_buffer_ptr[i * 3] - min_vertex;
2901 score = vertex_info_ptr[index].vertex_score;
2902 index = src_buffer_ptr[(i * 3) + 1] - min_vertex;
2903 score += vertex_info_ptr[index].vertex_score;
2904 index = src_buffer_ptr[(i * 3) + 2] - min_vertex;
2905 score += vertex_info_ptr[index].vertex_score;
2906 triangle_info_ptr[i].triangle_score = score;
2909 if(score > best_score)
2912 best_triangle =
static_cast<int32_t
>(i);
2923 if(best_triangle < 0)
2931 if(!triangle_info_ptr[j].added)
2933 score = triangle_info_ptr[j].triangle_score;
2936 if(score > best_score)
2939 best_triangle =
static_cast<int32_t
>(j);
2950 triangle_index =
static_cast<uint32_t
>(best_triangle);
2957 tri_ptr->
added =
true;
2958 for(uint32_t j = 0; j < 3; ++j)
2961 index = src_buffer_ptr[(triangle_index * 3) + j];
2962 *dest_buffer_ptr++ = index;
2966 index = index - min_vertex;
2990 if(vertex_cache_size > 0)
2993 memmove(&vertex_cache_ptr[1], &vertex_cache_ptr[0], vertex_cache_size *
sizeof(uint32_t));
2998 if(vertex_cache_size < mesh_optimizer::MaxVertexCacheSize)
3000 vertex_cache_size++;
3006 vertex_info_ptr[vertex_cache_ptr[vertex_cache_size]].cache_position = -1;
3011 vertex_cache_ptr[0] = index;
3022 temp = vertex_cache_ptr[0];
3023 vertex_cache_ptr[0] = index;
3024 vertex_cache_ptr[1] = temp;
3030 memmove(&vertex_cache_ptr[1],
3031 &vertex_cache_ptr[0],
3032 static_cast<size_t>(vert_ptr->
cache_position) *
sizeof(uint32_t));
3035 vertex_cache_ptr[0] = index;
3042 for(uint32_t k = 0; k < vertex_cache_size; ++k)
3044 vertex_info_ptr[vertex_cache_ptr[k]].cache_position =
static_cast<int32_t
>(k);
3050 for(uint32_t j = 0; j < vertex_cache_size; ++j)
3059 for(uint32_t j = 0; j < vertex_cache_size; ++j)
3067 tri_ptr = &triangle_info_ptr[triangle_index];
3068 score = vertex_info_ptr[src_buffer_ptr[(triangle_index * 3)] - min_vertex].vertex_score;
3069 score += vertex_info_ptr[src_buffer_ptr[(triangle_index * 3) + 1] - min_vertex].vertex_score;
3070 score += vertex_info_ptr[src_buffer_ptr[(triangle_index * 3) + 2] - min_vertex].vertex_score;
3074 if(score > best_score)
3077 best_triangle =
static_cast<int32_t
>(triangle_index);
3097 if(vertex_info_ptr->unused_triangle_references == 0)
3102 int32_t cache_position = vertex_info_ptr->cache_position;
3103 if(cache_position < 0)
3109 if(cache_position < 3)
3116 score = mesh_optimizer::LastTriScore;
3121 const float scaler = 1.0f / (mesh_optimizer::MaxVertexCacheSize - 3);
3122 score = 1.0f - (cache_position - 3) * scaler;
3123 score = math::pow(score, mesh_optimizer::CacheDecayPower);
3130 float valence_boost =
3131 math::pow(
static_cast<float>(vertex_info_ptr->unused_triangle_references), -mesh_optimizer::ValenceBoostPower);
3132 score += mesh_optimizer::ValenceBoostScale * valence_boost;
void checked_array_delete(T *&x)
void checked_delete(T *&x)
A type erasing container that can store any mesh.
any_generator< triangle_t > triangles() const noexcept
Outlines a collection of bones that influence a given set of faces/vertices in the mesh.
std::map< uint32_t, uint32_t > bone_index_map_t
auto get_bones() const -> const std::vector< uint32_t > &
Retrieves the indices of the bones referenced by this palette.
auto get_maximum_size() const -> uint32_t
Retrieves the maximum size of the palette.
bone_index_map_t bones_lut_
< Sorted list of bones in this palette.
void clear_influenced_faces()
Clears out the temporary face influences array.
uint32_t data_group_id_
The maximum size of the palette.
void assign_bones(bone_index_map_t &bones, std::vector< uint32_t > &faces)
Assigns the specified bones (and faces) to this bone palette.
std::vector< uint32_t > faces_
The data group identifier used to separate the mesh data into submeshes relevant tothis bone palette.
auto get_maximum_blend_index() const -> int32_t
Retrieves the maximum vertex blend index for this palette.
auto get_influenced_faces() -> std::vector< uint32_t > &
Retrieves the list of faces assigned to this palette.
auto get_skinning_matrices(const std::vector< math::transform > &node_transforms, const skin_bind_data &bind_data) const -> const std::vector< math::mat4 > &
Gathers the bone/palette information and matrices ready for drawing the skinned mesh.
uint32_t maximum_size_
The maximum vertex blend index for this palette.
void compute_palette_fit(bone_index_map_t &input, int32_t ¤t_space, int32_t &common_base, int32_t &additional_bones)
Determines the relevant "fit" information that can be used to discover if and how the specified combi...
void set_data_group(uint32_t group)
Sets the identifier of the data group assigned to the submesh of the mesh reserved for this bone pale...
void set_maximum_blend_index(int index)
Sets the maximum vertex blend index for this palette.
int32_t maximum_blend_index_
auto translate_bone_to_palette(uint32_t bone_index) const -> uint32_t
Translates the specified bone index into its associated position in the palette.
bone_palette(uint32_t paletteSize)
Constructs a bone palette with the given size.
auto get_data_group() const -> uint32_t
Retrieves the identifier of the data group assigned to the submesh of the mesh reserved for this bone...
std::vector< uint32_t > bones_
List of faces assigned to this palette.
Class representing a camera. Contains functionality for manipulating and updating a camera....
Main class representing a 3D mesh with support for different LODs, submeshes, and skinning.
gfx::vertex_layout vertex_format_
The final system memory copy of the index buffer.
auto get_submesh_index(const submesh *s) const -> int
auto generate_vertex_normals(uint32_t *adjacency_ptr, std::vector< uint32_t > *remap_array_ptr=nullptr) -> bool
Generates vertex normals for the mesh.
auto create_dodecahedron(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates a dodecahedron geometry.
auto create_plane(const gfx::vertex_layout &format, float width, float height, uint32_t width_segments, uint32_t height_segments, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a plane geometry.
bone_palette_array_t bone_palettes_
List of armature nodes.
std::shared_ptr< void > hardware_vb_
The actual hardware index buffer resource.
auto set_vertex_source(void *source, uint32_t vertex_count, const gfx::vertex_layout &source_format) -> bool
Sets the source of the vertex buffer to pull data from while preparing the mesh.
std::unique_ptr< armature_node > root_
auto create_sphere(const gfx::vertex_layout &format, float radius, uint32_t stacks, uint32_t slices, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a sphere geometry.
auto create_capsule(const gfx::vertex_layout &format, float radius, float height, uint32_t stacks, uint32_t slices, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a capsule geometry.
submesh_array_t mesh_submeshes_
Indices in the subset array which are skinned.
auto get_bone_palettes() const -> const bone_palette_array_t &
Retrieves the compiled bone combination palette data if this mesh has been bound as a skin.
void check_for_degenerates()
auto create_icosahedron(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates an icosahedron geometry.
auto set_submeshes(const std::vector< submesh > &submeshes) -> bool
auto generate_vertex_barycentrics(uint32_t *adjacency) -> bool
Generates vertex barycentric coordinates for the mesh.
uint32_t face_count_
Total number of vertices in the prepared mesh.
std::vector< uint8_t > byte_array_t
auto get_system_ib() -> uint32_t *
Retrieves the underlying index data from the mesh.
auto get_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t &
auto get_non_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t &
auto get_submeshes_count() const -> size_t
Gets the number of submeshes for this mesh.
auto calculate_screen_rect(const math::transform &world, const camera &cam) const -> irect32_t
Calculates the screen rectangle of the mesh based on its world transform and the camera.
auto get_vertex_count() const -> uint32_t
Determines the number of vertices stored in the mesh.
auto set_primitives(triangle_array_t &&triangles) -> bool
Adds primitives (triangles) to the mesh.
auto create_teapot(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates a teapot geometry.
auto end_prepare(bool hardware_copy=true, bool build_buffers=true, bool weld=false, bool optimize=false) -> bool
Ends the preparation of the mesh and builds the render data.
auto get_bounds() const -> const math::bbox &
Gets the local bounding box for this mesh.
auto create_cone(const gfx::vertex_layout &format, float radius, float radius_tip, float height, uint32_t stacks, uint32_t slices, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a cone geometry.
static void build_optimized_index_buffer(const submesh *submesh, uint32_t *source_buffer_ptr, uint32_t *destination_buffer_ptr, uint32_t minimum_vertex, uint32_t maximum_vertex)
Calculates the best order for triangle data, optimizing for efficient use of the hardware vertex cach...
bool force_normal_generation_
Whether to force the generation of vertex barycentric coordinates.
math::bbox bbox_
Total number of faces in the prepared mesh.
auto get_non_skinned_submeshes_count() const -> size_t
data_group_submesh_map_t data_groups_
Whether the mesh uses a hardware vertex/index buffer.
auto sort_mesh_data() -> bool
Sorts the data in the mesh into material and data group order.
auto generate_vertex_tangents() -> bool
Generates vertex tangents for the mesh.
size_t skinned_submesh_count_
Indices in the subset array which are not skinned.
void bind_render_buffers_for_submesh(const submesh *submesh)
Binds the mesh data for rendering the selected batch of primitives.
auto generate_adjacency(std::vector< uint32_t > &adjacency) -> bool
Generates edge-triangle adjacency information for the mesh data.
std::shared_ptr< void > hardware_ib_
The actual list of submeshes maintained by this mesh.
uint8_t * system_vb_
The vertex format used for the mesh internal vertex data.
auto create_rounded_cube(const gfx::vertex_layout &format, float width, float height, float depth, uint32_t width_segments, uint32_t height_segments, uint32_t depth_segments, mesh_create_origin origin, bool hardware_copy=true) -> bool
auto get_vertex_format() const -> const gfx::vertex_layout &
Retrieves the format of the underlying mesh vertex data.
bool hardware_mesh_
Whether the mesh was optimized when it was prepared.
auto bind_skin(const skin_bind_data &bind_data) -> bool
Binds the mesh as a skin with the specified skin binding data.
bool force_tangent_generation_
< Whether to force the generation of tangent space vectors.
auto get_status() const -> mesh_status
Gets the preparation status for this mesh.
auto create_icosphere(const gfx::vertex_layout &format, int tesselation_level, bool hardware_copy=true) -> bool
Creates an icosphere geometry.
uint32_t vertex_count_
Preparation status of the mesh.
auto load_mesh(load_data &&data) -> bool
size_t non_skinned_submesh_count_
Lookup information mapping data groups to submeshes batched by material.
void dispose()
Clears out all the mesh data.
void build_vb(bool hardware_copy=true)
Builds the internal vertex buffer.
auto generate_vertex_components(bool weld) -> bool
Generates any vertex components that may be missing, such as normals, tangents, or binormals.
auto create_cube(const gfx::vertex_layout &format, float width, float height, float depth, uint32_t width_segments, uint32_t height_segments, uint32_t depth_segments, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a cube geometry.
auto weld_vertices(float tolerance=0.000001f, std::vector< uint32_t > *vertex_remap_ptr=nullptr) -> bool
Welds the vertices together that can be combined.
auto bind_armature(std::unique_ptr< armature_node > &root) -> bool
Binds the armature tree.
auto get_armature() const -> const std::unique_ptr< armature_node > &
Retrieves the armature tree of the mesh.
bool force_barycentric_generation_
Whether to disable the automatic re-sort operation.
skin_bind_data skin_bind_data_
List of unique combinations of bones to use during rendering.
auto create_cylinder(const gfx::vertex_layout &format, float radius, float height, uint32_t stacks, uint32_t slices, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a cylinder geometry.
preparation_data preparation_data_
Data describing how the mesh should be bound as a skin with supplied bone matrices.
auto get_skin_bind_data() const -> const skin_bind_data &
Retrieves the skin bind data if this mesh has been bound as a skin.
std::vector< size_t > submesh_array_indices_t
auto prepare_mesh(const gfx::vertex_layout &vertex_format) -> bool
Prepares the mesh with the specified vertex format.
auto set_bounding_box(const math::bbox &box) -> bool
mesh()
Constructs a mesh object.
uint32_t * system_ib_
Material and data group information for each triangle.
std::vector< bone_palette > bone_palette_array_t
std::vector< submesh * > submesh_array_t
static auto find_vertex_optimizer_score(const optimizer_vertex_info *vertex_info_ptr) -> float
Generates scores used to identify important vertices when ordering triangle data.
auto get_data_groups_count() const -> size_t
Gets the number of data groups(materials) for this mesh.
auto get_submesh(uint32_t submesh_index=0) const -> const mesh::submesh &
auto get_submeshes() const -> const submesh_array_t &
Retrieves information about the submesh of the mesh associated with the specified data group identifi...
void build_ib(bool hardware_copy=true)
Builds the internal index buffer.
std::vector< triangle > triangle_array_t
auto create_torus(const gfx::vertex_layout &format, float outer_radius, float inner_radius, uint32_t bands, uint32_t sides, mesh_create_origin origin, bool hardware_copy=true) -> bool
Creates a torus geometry.
mesh_status prepare_status_
Input data used for constructing the final mesh.
auto get_skinned_submeshes_count() const -> size_t
auto get_face_count() const -> uint32_t
Determines the number of faces stored in the mesh.
submesh_key_array_t triangle_data_
The actual hardware vertex buffer resource.
auto get_system_vb() -> uint8_t *
Retrieves the underlying vertex data from the mesh.
Structure describing how a skinned mesh should be bound to any bones that influence its vertices.
void build_vertex_table(uint32_t vertex_count, const std::vector< uint32_t > &vertex_remap, vertex_data_array_t &table)
Constructs a list of bone influences and weights for each vertex based on the binding data provided.
void remap_vertices(const std::vector< uint32_t > &remap)
Remaps the vertex references stored in the binding based on the supplied remap array.
auto get_bones() const -> const bone_influence_array_t &
Retrieves a list of all bones that influence the skin in some way.
std::vector< vertex_data > vertex_data_array_t
auto find_bone_by_id(const std::string &id) const -> bone_query
Finds a bone by its unique identifier.
void clear()
Clears out the bone information stored in this object.
auto has_bones() const -> bool
Checks whether the skin data has any bones.
void remove_empty_bones()
Removes any bones that do not contain any influences.
std::vector< vertex_influence > vertex_influence_array_t
void clear_vertex_influences()
Releases memory allocated for vertex influences in each stored bone.
void add_bone(const bone_influence &bone)
Adds influence information for a specific bone.
rect< std::int32_t > irect32_t
#define APPLOG_ERROR(...)
int count(const generator_t &generator) noexcept
Counts the number of steps left in the generator.
void alloc_transient_index_buffer(transient_index_buffer *_tib, uint32_t _num, bool _index32)
void alloc_transient_vertex_buffer(transient_vertex_buffer *_tvb, uint32_t _num, const vertex_layout &_decl)
void vertex_convert(const vertex_layout &_destDecl, void *_destData, const vertex_layout &_srcDecl, const void *_srcData, uint32_t _num)
bgfx::VertexLayout vertex_layout
uint32_t get_avail_transient_index_buffer(uint32_t _num, bool _index32)
bgfx::Attrib::Enum attribute
const memory_view * make_ref(const void *_data, uint32_t _size, release_fn _releaseFn, void *_userData)
bgfx::TransientVertexBuffer transient_vertex_buffer
void vertex_pack(const float _input[4], bool _inputNormalized, attribute _attr, const vertex_layout &_decl, void *_data, uint32_t _index)
bgfx::TransientIndexBuffer transient_index_buffer
void set_vertex_buffer(uint8_t _stream, vertex_buffer_handle _handle)
auto get_max_blend_transforms() -> uint32_t
void set_index_buffer(index_buffer_handle _handle)
uint32_t get_avail_transient_vertex_buffer(uint32_t _num, const vertex_layout &_decl)
void vertex_unpack(float _output[4], attribute _attr, const vertex_layout &_decl, const void *_data, uint32_t _index)
auto operator<(const mesh::adjacent_edge_key &key1, const mesh::adjacent_edge_key &key2) -> bool
@ sphere
Sphere type reflection probe.
@ box
Box type reflection probe.
Storage for box vector values and wraps up common functionality.
bbox & add_point(const vec3 &point)
Grows the bounding box based on the point passed.
void reset()
Resets the bounding box values.
bbox & mul(const transform &t)
Transforms an axis aligned bounding box by the specified matrix.
const math::vec3 * vertex2
const math::vec3 * vertex1
< Pointer to the first vertex in the edge.
bone_palette::bone_index_map_t bones
< List of unique bones that influence a given number of faces.
Struct used for mesh construction.
uint32_t data_group_id
< The data group identifier for this submesh.
float triangle_score
< The sum of all three child vertex scores.
uint32_t unused_triangle_references
List of all triangles referencing this vertex.
std::vector< uint32_t > triangle_references
int32_t cache_position
< The position of the vertex in the pseudo-cache.
float vertex_score
Total number of triangles that reference this vertex that have not yet been added.
bool owns_source
The format of the vertex data currently being used to prepare the mesh.
uint32_t vertex_count
Prepared substs information.
std::vector< uint32_t > vertex_records
Final vertex buffer currently being prepared.
uint32_t triangle_count
Total number of vertices currently stored.
bool compute_binormals
Whether to compute vertex tangents.
triangle_array_t triangle_data
Total number of triangles currently stored.
bool check_for_degenerates
gfx::vertex_layout source_format
Records the location in the vertex buffer that each vertex has been placed during data insertion.
bool compute_normals
Whether to compute vertex binormals.
uint8_t * vertex_source
Whether the source data is owned by this object.
bool compute_tangents
Whether to compute vertex barycentric coordinates.
std::vector< submesh > submeshes
Whether to compute vertex normals.
byte_array_t vertex_data
Additional descriptive information about the vertices.
byte_array_t vertex_flags
Stores the current face/triangle data.
Structure describing an individual "piece" of the mesh, often grouped by material,...
uint32_t vertex_count
The initial face, from the index buffer, to render in this batch.
int32_t vertex_start
Number of vertices included in this batch.
int32_t face_start
Number of faces to render in this batch.
uint32_t data_group_id
< The unique user assigned "data group" that can be used to separate submeshes.
Structure describing data for a single triangle in the mesh.
std::array< uint32_t, 3 > indices
Flags for this triangle.
uint32_t data_group_id
< Data group identifier for this triangle.
Describes the vertices that are connected to the referenced bone and how much influence it has on the...
Contains per-vertex influence and weight information.
int32_t palette
The index of the original vertex.
Describes how a bone influences a specific vertex.