Unravel Engine C++ Reference
Loading...
Searching...
No Matches
mesh.cpp
Go to the documentation of this file.
1#include "mesh.h"
2#include "camera.h"
4
7#include <logging/logging.h>
9
10#include <algorithm>
11#include <cmath>
12#include <cstring>
13
14namespace unravel
15{
16
17namespace
18{
19//-----------------------------------------------------------------------------
20// Local Module Level Namespaces.
21//-----------------------------------------------------------------------------
22// Settings for the mesh optimizer.
23namespace mesh_optimizer
24{
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;
30}; // namespace mesh_optimizer
31
32void create_mesh(const gfx::vertex_layout& format,
35 math::bbox& bbox)
36{
37 // Determine the correct offset to any relevant elements in the vertex
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();
44
45 auto triangle_count = generator::count(mesh.triangles());
46 auto vertex_count = generator::count(mesh.vertices());
47 data.triangle_count = uint32_t(triangle_count);
48 data.vertex_count = uint32_t(vertex_count);
49
50 // Allocate enough space for the new vertex and triangle data
51 data.vertex_data.resize(data.vertex_count * vertex_stride);
52 data.vertex_flags.resize(data.vertex_count);
53 data.triangle_data.resize(data.triangle_count);
54 mesh::submesh submesh;
55 submesh.data_group_id = 0;
56 submesh.face_count = data.triangle_count;
57 submesh.face_start = 0;
58 submesh.vertex_count = data.vertex_count;
59 submesh.vertex_start = 0;
60 data.submeshes.emplace_back(submesh);
61
62 uint8_t* current_vertex_ptr = data.vertex_data.data();
63 size_t i = 0;
64 for(const auto& v : mesh.vertices())
65 {
66 math::vec3 position = v.position;
67 math::vec4 normal = math::vec4(v.normal, 0.0f);
68 math::vec2 texcoords0 = v.tex_coord;
69 // Store vertex components
70 if(has_position)
71 gfx::vertex_pack(math::value_ptr(position),
72 false,
73 gfx::attribute::Position,
74 format,
75 current_vertex_ptr,
76 uint32_t(i));
77 if(has_normals)
78 gfx::vertex_pack(math::value_ptr(normal),
79 true,
80 gfx::attribute::Normal,
81 format,
82 current_vertex_ptr,
83 uint32_t(i));
84 if(has_texcoord0)
85 gfx::vertex_pack(math::value_ptr(texcoords0),
86 true,
87 gfx::attribute::TexCoord0,
88 format,
89 current_vertex_ptr,
90 uint32_t(i));
91
92 bbox.add_point(position);
93 i++;
94 }
95
96 size_t tri_idx = 0;
97 for(const auto& triangle : mesh.triangles())
98 {
99 const auto& indices = triangle.vertices;
100 auto& tri = data.triangle_data[tri_idx];
101 tri.indices[0] = uint32_t(indices[0]);
102 tri.indices[1] = uint32_t(indices[1]);
103 tri.indices[2] = uint32_t(indices[2]);
104
105 tri_idx++;
106 }
107
108 // We need to generate binormals / tangents?
109 data.compute_binormals = has_bitangents;
110 data.compute_tangents = has_tangents;
111}
112
113} // namespace
114
115mesh::mesh() : hardware_vb_(std::make_shared<gfx::vertex_buffer>()), hardware_ib_(std::make_shared<gfx::index_buffer>())
116{
117}
118
120{
121 dispose();
122}
123
125{
126 // Iterate through the different submeshes in the mesh and clean up
127 for(auto submesh : mesh_submeshes_)
128 {
129 // Just perform a standard 'disconnect' in the
130 // regular unload case.
132 }
133
134 mesh_submeshes_.clear();
135 // submesh_lookup_.clear();
136 data_groups_.clear();
137
138 // Release bone palettes and skin data (if any)
139 bone_palettes_.clear();
141
142 // Clean up preparation data.
144 {
146 }
154
155 // Release mesh data memory
158
159 triangle_data_.clear();
160
161 // Release resources
162 hardware_vb_.reset();
163 hardware_ib_.reset();
164
165 // Clear variables
175 face_count_ = 0;
176 vertex_count_ = 0;
177 system_vb_ = nullptr;
178 vertex_format_ = {};
179 system_ib_ = nullptr;
183
184 // Reset structures
185 bbox_.reset();
186}
187
188auto mesh::prepare_mesh(const gfx::vertex_layout& format) -> bool
189{
190 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
191
192 // If we are already in the process of preparing, this is a no-op.
193 if(prepare_status_ == mesh_status::preparing)
194 {
195 return false;
196 }
197
198 if((prepare_status_ != mesh_status::preparing))
199 {
200 // Clear out anything which is currently loaded in the mesh.
201 dispose();
202
203 } // End if not rolling back or no need to roll back
204
205 // We are in the process of preparing the mesh
206 prepare_status_ = mesh_status::preparing;
207 vertex_format_ = format;
208
209 return true;
210}
211
212// #define SET_VERTICES_WHEN_SETTING_PRIMITIVES 1
213
214auto mesh::set_vertex_source(byte_array_t&& source, uint32_t vertex_count, const gfx::vertex_layout& source_format)
215 -> bool
216{
217 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
218
219 // We can only do this if we are in the process of preparing the mesh
220 if(prepare_status_ != mesh_status::preparing)
221 {
222 APPLOG_ERROR("Attempting to set a mesh vertex source without first calling "
223 "'prepareMesh' is not allowed.\n");
224 return false;
225
226 } // End if not preparing
227
228 // Clear any existing source information.
229 if(preparation_data_.owns_source)
230 {
231 checked_array_delete(preparation_data_.vertex_source);
232 }
233 preparation_data_.vertex_source = nullptr;
234 preparation_data_.source_format = {};
235 preparation_data_.owns_source = false;
236 preparation_data_.vertex_records.clear();
237
238 // Validate requirements
239 if(vertex_count == 0)
240 {
241 return false;
242 }
243
244 // If source format matches the format we're using to prepare
245 // then just store the pointer for this vertex source. Otherwise
246 // we need to allocate a temporary buffer and convert the data.
247 preparation_data_.source_format = source_format;
248 if(source_format.m_hash == vertex_format_.m_hash)
249 {
250 preparation_data_.vertex_source = reinterpret_cast<uint8_t*>(source.data());
251
252 } // End if matching
253 else
254 {
255 preparation_data_.vertex_source = new uint8_t[vertex_count * vertex_format_.getStride()];
256 preparation_data_.owns_source = true;
257 gfx::vertex_convert(vertex_format_,
258 preparation_data_.vertex_source,
259 source_format,
260 reinterpret_cast<uint8_t*>(source.data()),
261 vertex_count);
262 } // End if !matching
263
264 // Some data needs computing? These variables are essentially 'toggles'
265 // that are set largely so that we can early out if it was NEVER necessary
266 // to generate these components (i.e. not one single vertex needed it).
267 if(!source_format.has(gfx::attribute::Normal) && vertex_format_.has(gfx::attribute::Normal))
268 {
269 preparation_data_.compute_normals = true;
270 }
271 if(!source_format.has(gfx::attribute::Bitangent) && vertex_format_.has(gfx::attribute::Bitangent))
272 {
273 preparation_data_.compute_binormals = true;
274 }
275 if(!source_format.has(gfx::attribute::Tangent) && vertex_format_.has(gfx::attribute::Tangent))
276 {
277 preparation_data_.compute_tangents = true;
278 }
279
280#ifdef SET_VERTICES_WHEN_SETTING_PRIMITIVES
281 // Allocate the vertex records for the new vertex buffer
282 preparation_data_.vertex_records.clear();
283 preparation_data_.vertex_records.resize(vertex_count);
284
285 // Fill with 0xFFFFFFFF initially to indicate that no vertex
286 // originally in this location has yet been inserted into the
287 // final vertex list.
288 memset(preparation_data_.vertex_records.data(), 0xFF, vertex_count * sizeof(uint32_t));
289#else
290 preparation_data_.vertex_data = std::move(source);
291 preparation_data_.vertex_count = vertex_count;
292#endif
293 // Success!
294 return true;
295}
296
298{
299 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
300
301 bbox_ = box;
302 return true;
303}
304
305auto mesh::set_submeshes(const std::vector<submesh>& submeshes) -> bool
306{
307 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
308
309 // We can only do this if we are in the process of preparing the mesh
310 if(prepare_status_ != mesh_status::preparing)
311 {
312 APPLOG_ERROR("Attempting to add primitives to a mesh without first calling "
313 "'prepareMesh' is not allowed.\n");
314 return false;
315
316 } // End if not preparing
317
318 preparation_data_.submeshes = submeshes;
319
320 return true;
321}
322
323auto mesh::set_primitives(triangle_array_t&& triangles) -> bool
324{
325 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
326
327 // We can only do this if we are in the process of preparing the mesh
328 if(prepare_status_ != mesh_status::preparing)
329 {
330 APPLOG_ERROR("Attempting to add primitives to a mesh without first calling "
331 "'prepareMesh' is not allowed.\n");
332 return false;
333
334 } // End if not preparing
335
336#ifdef SET_VERTICES_WHEN_SETTING_PRIMITIVES
337
338 preparation_data_.triangle_count = 0;
339 preparation_data_.triangle_data.clear();
340
341 // Determine the correct offset to any relevant elements in the vertex
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();
345
346 // During the construction process we test to see if any specified
347 // vertex normal contains invalid data. If the original source vertex
348 // data did not contain a normal, we can optimize and skip this step.
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);
352
353 // In addition, we also record which of the required components each
354 // vertex actually contained based on the following information.
355 uint8_t vertex_flags = 0;
356 if(source_has_normals)
357 {
358 vertex_flags |= preparation_data::source_contains_normal;
359 }
360 if(source_has_binormal)
361 {
362 vertex_flags |= preparation_data::source_contains_binormal;
363 }
364 if(source_has_tangent)
365 {
366 vertex_flags |= preparation_data::source_contains_tangent;
367 }
368
369 // Loop through the specified faces and process them.
370 uint8_t* src_vertices_ptr = preparation_data_.vertex_source;
371
372 for(const auto& src_tri : triangles)
373 {
374 // Retrieve vertex positions (if there are any) so that we can perform
375 // degenerate testing.
376 if(preparation_data_.check_for_degenerates)
377 {
378 if(has_position)
379 {
380 math::vec3 v1;
381 float vf1[4];
382 gfx::vertex_unpack(vf1, gfx::attribute::Position, vertex_format_, src_vertices_ptr, src_tri.indices[0]);
383 math::vec3 v2;
384 float vf2[4];
385 gfx::vertex_unpack(vf2, gfx::attribute::Position, vertex_format_, src_vertices_ptr, src_tri.indices[1]);
386 math::vec3 v3;
387 float vf3[4];
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));
392
393 // Skip triangle if it is degenerate.
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>())))
397 {
398 continue;
399 }
400 } // End if has position.
401 }
402 // Prepare a triangle structure ready for population
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];
406
407 // Set triangle's submesh information.
408 triangle_data.data_group_id = src_tri.data_group_id;
409
410 // For each index in the face
411 for(uint32_t j = 0; j < 3; ++j)
412 {
413 // Extract the original index from the specified index buffer
414 uint32_t orig_index = src_tri.indices[j];
415
416 // Retrieve the vertex record for the original vertex
417 uint32_t index = preparation_data_.vertex_records[orig_index];
418
419 // Have we inserted this vertex into the vertex buffer previously?
420 if(index == 0xFFFFFFFF)
421 {
422 // Vertex does not yet exist in the vertex buffer we are preparing
423 // so copy the vertex in and record the index mapping for this vertex.
424 index = preparation_data_.vertex_count++;
425 preparation_data_.vertex_records[orig_index] = index;
426
427 // Resize the output vertex buffer ready to hold this new data.
428 size_t initial_size = preparation_data_.vertex_data.size();
429 preparation_data_.vertex_data.resize(initial_size + vertex_stride);
430
431 // Copy the data in.
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);
435
436 // Also record other pertenant details about this vertex.
437 preparation_data_.vertex_flags.push_back(vertex_flags);
438
439 // Clear any invalid normals (completely messes up HDR if ANY NaNs make
440 // it this far)
441 // if(has_normal && source_has_normals)
442 // {
443 // float fnorm[4];
444 // gfx::vertex_unpack(fnorm, gfx::attribute::Normal, vertex_format_, dst_ptr);
445 // if(std::isnan(fnorm[0]) || std::isnan(fnorm[1]) || std::isnan(fnorm[2]))
446 // {
447 // gfx::vertex_pack(fnorm, true, gfx::attribute::Normal, vertex_format_, dst_ptr);
448 // }
449 // } // End if have normal
450
451 // Grow the size of the bounding box
452 if(has_position)
453 {
454 float fpos[4];
455 gfx::vertex_unpack(fpos, gfx::attribute::Position, vertex_format_, dst_ptr);
456 bbox_.add_point(math::vec3(fpos[0], fpos[1], fpos[2]));
457 }
458
459 } // End if vertex not recorded in this buffer yet
460
461 // Copy the index in
462 triangle_data.indices[j] = index;
463
464 } // Next Index
465
466 } // Next Face
467
468#else
469 preparation_data_.triangle_count = triangles.size();
470 preparation_data_.triangle_data = std::move(triangles);
471
472#endif
473
474 // Success!
475 return true;
476}
477
478auto mesh::bind_skin(const skin_bind_data& bind_data) -> bool
479{
480 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
481
482 if(!bind_data.has_bones())
483 {
484 return true;
485 }
486
487 if(prepare_status_ == mesh_status::prepared)
488 {
489 return false;
490 }
491
493 skin_bind_data_.clear();
494 skin_bind_data_ = bind_data;
495
496 // Build a list of all bone indices and associated weights for each vertex.
497 skin_bind_data_.build_vertex_table(preparation_data_.vertex_count, preparation_data_.vertex_records, vertex_table);
498 skin_bind_data_.clear_vertex_influences(); // Clear unneeded data to save space.
499
500 uint32_t palette_size = gfx::get_max_blend_transforms();
501
502 // Destroy any previous palette entries.
503 bone_palettes_.clear();
504
505 triangle_array_t& tri_data = preparation_data_.triangle_data;
506
507 bone_palettes_.reserve(preparation_data_.submeshes.size());
508 // Iterate over each submesh to generate palettes.
509 for(size_t palette_id = 0; palette_id < preparation_data_.submeshes.size(); ++palette_id)
510 {
511 auto& submesh = preparation_data_.submeshes[palette_id];
512 // face_influences used_bones;
513
514 std::vector<bool> used_bones(gfx::get_max_blend_transforms(), false);
515 std::vector<uint32_t> faces; // Collect faces in this submesh
516 faces.reserve(submesh.face_count);
517 // Collect all unique bone indices influencing this submesh and the faces.
518 for(uint32_t i = submesh.face_start; i < submesh.face_start + submesh.face_count; ++i)
519 {
520 faces.push_back(i);
521
522 for(uint32_t vertex_index : tri_data[i].indices)
523 {
524 const auto& data = vertex_table[vertex_index];
525 for(const auto& influence : data.influences)
526 {
527 // used_bones.bones[static_cast<uint32_t>(influence)] = 1;
528 used_bones[static_cast<uint32_t>(influence)] = true;
529 }
530 }
531 }
532
533 // Create a bone palette for this submesh.
534 bone_palette new_palette(palette_size);
536
537 // Assign bones and faces to the palette.
538 // new_palette.assign_bones(used_bones.bones, faces);
539 new_palette.assign_bones(used_bones, faces);
540 bone_palettes_.push_back(new_palette);
541
542 // Assign the palette ID to each vertex in this submesh.
543
544 auto face_start = submesh.face_start;
545 auto face_end = submesh.face_start + submesh.face_count;
546 for(uint32_t i = face_start; i < face_end; ++i)
547 {
548 for(uint32_t k = 0; k < 3; ++k)
549 {
550 uint32_t vertex_index = tri_data[i].indices[k];
551 auto& data = vertex_table[vertex_index];
552
553 // If the vertex is not already assigned to a palette, assign it.
554 if(data.palette == -1)
555 {
556 data.palette = static_cast<int32_t>(palette_id);
557
558 // Check if the vertex index falls within the submesh's vertex range
559 if(submesh.vertex_start == -1 || vertex_index < submesh.vertex_start)
560 {
561 submesh.vertex_start = vertex_index;
562 }
563 if(vertex_index >= submesh.vertex_start + submesh.vertex_count)
564 {
565 submesh.vertex_count = (vertex_index - submesh.vertex_start) + 1;
566 }
567 }
568 else if(data.palette != static_cast<int32_t>(palette_id))
569 {
570 // Vertex is shared between submeshes, need to duplicate it.
571 uint32_t new_index = static_cast<uint32_t>(vertex_table.size());
572
573 // Create a new vertex_data.
574 skin_bind_data::vertex_data new_vertex(data);
575 new_vertex.original_vertex = vertex_index;
576 new_vertex.palette = static_cast<int32_t>(palette_id);
577 vertex_table.push_back(new_vertex);
578
579 // Update submesh's vertex range
580 if(submesh.vertex_start == -1 || new_index < submesh.vertex_start)
581 {
582 submesh.vertex_start = new_index;
583 }
584 if(new_index >= submesh.vertex_start + submesh.vertex_count)
585 {
586 submesh.vertex_count = (new_index - submesh.vertex_start) + 1;
587 }
588
589 // Update triangle index to point to new vertex.
590 tri_data[i].indices[k] = new_index;
591 }
592 // Else, the vertex is already assigned to this palette; no action needed.
593 }
594 }
595 }
596
597 // Adjust vertex format to include blend weights and indices if necessary.
598 gfx::vertex_layout new_format(vertex_format_);
599 gfx::vertex_layout original_format = vertex_format_;
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)
603 {
604 new_format.m_hash = 0;
605 if(!has_weights)
606 {
607 new_format.add(gfx::attribute::Weight, 4, gfx::attribute_type::Float);
608 }
609 if(!has_indices)
610 {
611 new_format.add(gfx::attribute::Indices, 4, gfx::attribute_type::Float, false, true);
612 }
613
614 new_format.end();
615 // Update the vertex format.
616 vertex_format_ = new_format;
617 }
618
619 // Get access to final data offset information.
620 uint16_t vertex_stride = vertex_format_.getStride();
621
622 // Now we need to update the vertex data as required.
623 uint32_t original_vertex_count = preparation_data_.vertex_count;
624 if(vertex_format_.m_hash != original_format.m_hash)
625 {
626 // Format has changed, run conversion.
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());
631
632 gfx::vertex_convert(vertex_format_,
633 preparation_data_.vertex_data.data(),
634 original_format,
635 original_buffer.data(),
636 original_vertex_count);
637 }
638 else
639 {
640 // No conversion required, just ensure buffer is large enough.
641 preparation_data_.vertex_data.resize(vertex_table.size() * vertex_stride);
642 preparation_data_.vertex_flags.resize(vertex_table.size());
643 }
644
645 // Update vertex data with new bone indices and weights.
646 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data();
647 for(size_t i = 0; i < vertex_table.size(); ++i)
648 {
649 auto& data = vertex_table[i];
650
651 // Determine which palette this vertex belongs to.
652 int32_t palette_id = data.palette;
653
654 // Skip if the vertex isn't assigned to any palette.
655 if(palette_id < 0)
656 {
657 continue;
658 }
659
660 const auto& palette = bone_palettes_[static_cast<size_t>(palette_id)];
661
662 // If this is a new vertex, duplicate data from original vertex.
663 if(i >= original_vertex_count)
664 {
665 std::memcpy(src_vertices_ptr + (i * vertex_stride),
666 src_vertices_ptr + (data.original_vertex * vertex_stride),
667 vertex_stride);
668
669 // Also duplicate additional vertex data.
670 preparation_data_.vertex_flags[i] = preparation_data_.vertex_flags[data.original_vertex];
671 }
672
673 uint32_t max_bones = std::min<uint32_t>(4, uint32_t(data.influences.size()));
674
675 if(max_bones > 0)
676 {
677 // Assign bone indices (the index to the relevant entry in the palette, not the main bone list index) and
678 // weights.
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);
681
682 for(uint32_t j = 0; j < max_bones; ++j)
683 {
684 // Map global bone index to local palette index.
685 uint32_t palette_bone_index =
686 palette.translate_bone_to_palette(static_cast<uint32_t>(data.influences[j]));
687
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];
690 }
691
692 gfx::vertex_pack(math::value_ptr(blend_weights),
693 false,
694 gfx::attribute::Weight,
695 vertex_format_,
696 src_vertices_ptr,
697 uint32_t(i));
698
699 gfx::vertex_pack(math::value_ptr(blend_indices),
700 false,
701 gfx::attribute::Indices,
702 vertex_format_,
703 src_vertices_ptr,
704 uint32_t(i));
705 }
706 }
707
708 // Update vertex count to match final size.
709 preparation_data_.vertex_count = static_cast<uint32_t>(vertex_table.size());
710
711 // Skin is now bound.
712 return true;
713}
714
715auto mesh::bind_armature(std::unique_ptr<armature_node>& root) -> bool
716{
717 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
718
719 root_ = std::move(root);
720 return true;
721}
722
723auto mesh::load_mesh(load_data&& data) -> bool
724{
725 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
726
727 bool result = true;
728 result &= prepare_mesh(data.vertex_format);
729 result &= set_bounding_box(data.bbox);
730 result &= set_vertex_source(std::move(data.vertex_data), data.vertex_count, data.vertex_format);
731 result &= set_primitives(std::move(data.triangle_data));
732 result &= set_submeshes(data.submeshes);
733 result &= bind_skin(data.skin_data);
734 result &= bind_armature(data.root_node);
735 result &= end_prepare();
736
737 return result;
738}
739
741 float width,
742 float height,
743 uint32_t width_segments,
744 uint32_t height_segments,
745 mesh_create_origin origin,
746 bool hardware_copy /* = true */) -> bool
747{
748 // We are in the process of preparing.
749 prepare_mesh(format);
750
751 using namespace generator;
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));
755
756 auto plane1 = rotate_mesh(plane, rot1);
757 auto plane2 = rotate_mesh(plane, rot2);
758 auto mesh = merge_mesh(plane1, plane2);
759
760 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
761 // Finish up
762 return end_prepare(hardware_copy);
763}
764
766 float width,
767 float height,
768 float depth,
769 uint32_t width_segments,
770 uint32_t height_segments,
771 uint32_t depth_segments,
772 mesh_create_origin origin,
773 bool hardware_copy /* = true */) -> bool
774{
775 // We are in the process of preparing.
776 prepare_mesh(format);
777
778 using namespace generator;
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);
782
783 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
784 // Finish up
785 return end_prepare(hardware_copy);
786}
787
788
790 float width,
791 float height,
792 float depth,
793 uint32_t width_segments,
794 uint32_t height_segments,
795 uint32_t depth_segments,
796 mesh_create_origin origin,
797 bool hardware_copy /* = true */) -> bool
798{
799 // We are in the process of preparing.
800 prepare_mesh(format);
801
802 using namespace generator;
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);
806
807 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
808 // Finish up
809 return end_prepare(hardware_copy);
810}
811
813 float radius,
814 uint32_t stacks,
815 uint32_t slices,
816 mesh_create_origin origin,
817 bool hardware_copy /* = true */) -> bool
818{
819 // We are in the process of preparing.
820 prepare_mesh(format);
821
822 using namespace generator;
823 sphere_mesh_t sphere(radius, static_cast<int>(slices), static_cast<int>(stacks));
824 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
825 auto mesh = rotate_mesh(sphere, rot);
826
827 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
828 // Finish up
829 return end_prepare(hardware_copy);
830}
831
833 float radius,
834 float height,
835 uint32_t stacks,
836 uint32_t slices,
837 mesh_create_origin origin,
838 bool hardware_copy /* = true */) -> bool
839{
840 // Clear out old data.
841 dispose();
842
843 // We are in the process of preparing.
844 prepare_status_ = mesh_status::preparing;
845 vertex_format_ = format;
846
847 using namespace generator;
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);
851
852 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
853 // Finish up
854 return end_prepare(hardware_copy);
855}
856
858 float radius,
859 float height,
860 uint32_t stacks,
861 uint32_t slices,
862 mesh_create_origin origin,
863 bool hardware_copy /* = true */) -> bool
864{
865 // We are in the process of preparing.
866 prepare_mesh(format);
867
868 using namespace generator;
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);
872
873 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
874 // Finish up
875 return end_prepare(hardware_copy);
876}
877
879 float radius,
880 float radius_tip,
881 float height,
882 uint32_t stacks,
883 uint32_t slices,
884 mesh_create_origin origin,
885 bool hardware_copy /* = true */) -> bool
886{
887 // We are in the process of preparing.
888 prepare_mesh(format);
889
890 using namespace generator;
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);
894
895 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
896 // Finish up
897 return end_prepare(hardware_copy);
898}
899
901 float outer_radius,
902 float inner_radius,
903 uint32_t bands,
904 uint32_t sides,
905 mesh_create_origin origin,
906 bool hardware_copy /* = true */) -> bool
907{
908 // We are in the process of preparing.
909 prepare_mesh(format);
910
911 using namespace generator;
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);
915
916 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
917 // Finish up
918 return end_prepare(hardware_copy);
919}
920
921auto mesh::create_teapot(const gfx::vertex_layout& format, bool hardware_copy /*= true*/) -> bool
922{
923 // We are in the process of preparing.
924 prepare_mesh(format);
925
926 using namespace generator;
927 teapot_mesh_t teapot;
928 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
929 auto mesh = rotate_mesh(teapot, rot);
930
931 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
932 // Finish up
933 return end_prepare(hardware_copy);
934}
935
936auto mesh::create_icosahedron(const gfx::vertex_layout& format, bool hardware_copy /*= true*/) -> bool
937{
938 // We are in the process of preparing.
939 prepare_mesh(format);
940
941 using namespace generator;
942 icosahedron_mesh_t icosahedron;
943 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
944 auto mesh = rotate_mesh(icosahedron, rot);
945
946 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
947 // Finish up
948 return end_prepare(hardware_copy);
949}
950
951auto mesh::create_dodecahedron(const gfx::vertex_layout& format, bool hardware_copy /*= true*/) -> bool
952{
953 // We are in the process of preparing.
954 prepare_mesh(format);
955
956 using namespace generator;
957 dodecahedron_mesh_t dodecahedron;
958 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
959 auto mesh = rotate_mesh(dodecahedron, rot);
960
961 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
962 // Finish up
963 return end_prepare(hardware_copy);
964}
965
966auto mesh::create_icosphere(const gfx::vertex_layout& format, int tesselation_level, bool hardware_copy /*= true*/)
967 -> bool
968{
969 // We are in the process of preparing.
970 prepare_mesh(format);
971
972 using namespace generator;
973 ico_sphere_mesh_t icosphere(1, tesselation_level + 1);
974 math::quat rot(math::vec3(math::radians(-90.0f), 0.f, 0.0f));
975 auto mesh = rotate_mesh(icosphere, rot);
976
977 create_mesh(vertex_format_, mesh, preparation_data_, bbox_);
978 // Finish up
979 return end_prepare(hardware_copy);
980}
981
983{
984 // Scan the preparation data for degenerate triangles.
985 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
986 // uint16_t vertex_stride = _vertex_format.getStride();
987 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data() + position_offset;
988
990 {
991 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
992 {
994 math::vec3 v1;
995 float vf1[4];
996 gfx::vertex_unpack(vf1, gfx::attribute::Position, vertex_format_, src_vertices_ptr, tri.indices[0]);
997 math::vec3 v2;
998 float vf2[4];
999 gfx::vertex_unpack(vf2, gfx::attribute::Position, vertex_format_, src_vertices_ptr, tri.indices[1]);
1000 math::vec3 v3;
1001 float vf3[4];
1002 gfx::vertex_unpack(vf3, gfx::attribute::Position, vertex_format_, src_vertices_ptr, tri.indices[2]);
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));
1006
1007 math::vec3 c = math::cross(v2 - v1, v3 - v1);
1008 if(math::length2(c) < (4.0f * 0.000001f * 0.000001f))
1009 {
1011 }
1012
1013 } // Next triangle
1014 }
1015}
1016
1017auto mesh::end_prepare(bool hardware_copy, bool build_buffers, bool weld, bool optimize) -> bool
1018{
1019 // APPLOG_TRACE_PERF(std::chrono::milliseconds);
1020
1021 // Were we previously preparing?
1022 if(prepare_status_ != mesh_status::preparing)
1023 {
1024 APPLOG_ERROR("Attempting to call 'end_prepare' on a mesh without first "
1025 "calling 'prepare_mesh' is not "
1026 "allowed.\n");
1027 return false;
1028
1029 } // End if previously preparing
1030
1031 // Check for degenerates
1032 check_for_degenerates();
1033
1034 // Process the vertex data in order to generate any additional components that
1035 // may be necessary
1036 // (i.e. Normal, Binormal and Tangent)
1037 if(!generate_vertex_components(weld))
1038 {
1039 return false;
1040 }
1041
1042 // Allocate the system memory vertex buffer ready for population.
1043 vertex_count_ = preparation_data_.vertex_count;
1044 system_vb_ = new uint8_t[vertex_count_ * vertex_format_.getStride()];
1045
1046 // Copy vertex data into the new buffer and dispose of the temporary data.
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;
1051
1052 // Index data has been updated and potentially needs to be serialized.
1053 if(build_buffers)
1054 {
1055 build_vb(hardware_copy);
1056 }
1057
1058 // Allocate the memory for our system memory index buffer
1059 face_count_ = preparation_data_.triangle_count;
1060 system_ib_ = new uint32_t[face_count_ * 3];
1061
1062 // Finally perform the final sort of the mesh data in order
1063 // to build the index buffer and submesh tables
1064 if(!sort_mesh_data())
1065 {
1066 return false;
1067 }
1068
1069 // Hardware versions of the final buffer were required?
1070 if(build_buffers)
1071 {
1072 build_ib(hardware_copy);
1073 }
1074
1075 if(preparation_data_.owns_source)
1076 {
1077 checked_array_delete(preparation_data_.vertex_source);
1078 }
1079 preparation_data_.vertex_source = nullptr;
1080
1081 // The mesh is now prepared
1082 prepare_status_ = mesh_status::prepared;
1083 hardware_mesh_ = hardware_copy;
1084 optimize_mesh_ = optimize;
1085
1086 // Success!
1087 return true;
1088}
1089
1090void mesh::build_vb(bool hardware_copy)
1091{
1092 // A video memory copy of the mesh was requested?
1093 if(hardware_copy)
1094 {
1095 // Calculate the required size of the vertex buffer
1096 auto buffer_size = vertex_count_ * vertex_format_.getStride();
1097
1098 const gfx::memory_view* mem = gfx::make_ref(system_vb_, buffer_size);
1099 hardware_vb_ = std::make_shared<gfx::vertex_buffer>(mem, vertex_format_);
1100
1101 } // End if video memory vertex buffer required
1102}
1103
1104void mesh::build_ib(bool hardware_copy)
1105{
1106 // Hardware versions of the final buffer were required?
1107 if(hardware_copy)
1108 {
1109 // Calculate the required size of the index buffer
1110 auto buffer_size = static_cast<uint32_t>(size_t(face_count_ * 3) * sizeof(uint32_t));
1111
1112 // Allocate hardware buffer if required (i.e. it does not already exist).
1113 if(!hardware_ib_)
1114 {
1115 const gfx::memory_view* mem = gfx::make_ref(system_ib_, buffer_size);
1116 hardware_ib_ = std::make_shared<gfx::index_buffer>(mem, BGFX_BUFFER_INDEX32);
1117 } // End if not allocated
1118 else
1119 {
1120 auto ib = std::static_pointer_cast<gfx::index_buffer>(hardware_ib_);
1121 if(!ib->is_valid())
1122 {
1123 const gfx::memory_view* mem = gfx::make_ref(system_ib_, buffer_size);
1124 hardware_ib_ = std::make_shared<gfx::index_buffer>(mem, BGFX_BUFFER_INDEX32);
1125 }
1126 }
1127
1128 } // End if hardware buffer required
1129}
1130
1131auto mesh::generate_adjacency(std::vector<uint32_t>& adjacency) -> bool
1132{
1133 std::map<adjacent_edge_key, uint32_t> edge_tree;
1134 std::map<adjacent_edge_key, uint32_t>::iterator it_edge;
1135
1136 // What is the status of the mesh?
1137 if(prepare_status_ != mesh_status::prepared)
1138 {
1139 // Validate requirements
1140 if(preparation_data_.triangle_count == 0)
1141 {
1142 return false;
1143 }
1144
1145 // Retrieve useful data offset information.
1146 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
1147 uint16_t vertex_stride = vertex_format_.getStride();
1148
1149 // Insert all edges into the edge tree
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)
1152 {
1153 adjacent_edge_key edge;
1154
1155 // Degenerate triangles cannot participate.
1156 const triangle& tri = preparation_data_.triangle_data[i];
1158 continue;
1159
1160 // Retrieve positions of each referenced vertex.
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));
1167
1168 // edge 1
1169 edge.vertex1 = v1;
1170 edge.vertex2 = v2;
1171 edge_tree[edge] = i;
1172
1173 // edge 2
1174 edge.vertex1 = v2;
1175 edge.vertex2 = v3;
1176 edge_tree[edge] = i;
1177
1178 // edge 3
1179 edge.vertex1 = v3;
1180 edge.vertex2 = v1;
1181 edge_tree[edge] = i;
1182
1183 } // Next Face
1184
1185 // Size the output array.
1186 adjacency.resize(preparation_data_.triangle_count * 3, 0xFFFFFFFF);
1187
1188 // Now, find any adjacent edges for each triangle edge
1189 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
1190 {
1191 adjacent_edge_key edge;
1192
1193 // Degenerate triangles cannot participate.
1194 const triangle& tri = preparation_data_.triangle_data[i];
1196 {
1197 continue;
1198 }
1199
1200 // Retrieve positions of each referenced vertex.
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));
1207
1208 // Note: Notice below that the order of the edge vertices
1209 // is swapped. This is because we want to find the
1210 // matching ADJACENT edge, rather than simply finding
1211 // the same edge that we're currently processing.
1212
1213 // edge 1
1214 edge.vertex2 = v1;
1215 edge.vertex1 = v2;
1216
1217 // Find the matching adjacent edge
1218 it_edge = edge_tree.find(edge);
1219 if(it_edge != edge_tree.end())
1220 {
1221 adjacency[(i * 3)] = it_edge->second;
1222 }
1223
1224 // edge 2
1225 edge.vertex2 = v2;
1226 edge.vertex1 = v3;
1227
1228 // Find the matching adjacent edge
1229 it_edge = edge_tree.find(edge);
1230 if(it_edge != edge_tree.end())
1231 {
1232 adjacency[(i * 3) + 1] = it_edge->second;
1233 }
1234
1235 // edge 3
1236 edge.vertex2 = v3;
1237 edge.vertex1 = v1;
1238
1239 // Find the matching adjacent edge
1240 it_edge = edge_tree.find(edge);
1241 if(it_edge != edge_tree.end())
1242 {
1243 adjacency[(i * 3) + 2] = it_edge->second;
1244 }
1245
1246 } // Next Face
1247
1248 } // End if not prepared
1249 else
1250 {
1251 // Validate requirements
1252 if(face_count_ == 0)
1253 {
1254 return false;
1255 }
1256
1257 // Retrieve useful data offset information.
1258 uint16_t position_offset = vertex_format_.getOffset(gfx::attribute::Position);
1259 uint16_t vertex_stride = vertex_format_.getStride();
1260
1261 // Insert all edges into the edge tree
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)
1265 {
1266 adjacent_edge_key edge;
1267
1268 // Retrieve positions of each referenced vertex.
1269 const auto* v1 =
1270 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (src_indices_ptr[0] * vertex_stride));
1271 const auto* v2 =
1272 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (src_indices_ptr[1] * vertex_stride));
1273 const auto* v3 =
1274 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (src_indices_ptr[2] * vertex_stride));
1275
1276 // edge 1
1277 edge.vertex1 = v1;
1278 edge.vertex2 = v2;
1279 edge_tree[edge] = i;
1280
1281 // edge 2
1282 edge.vertex1 = v2;
1283 edge.vertex2 = v3;
1284 edge_tree[edge] = i;
1285
1286 // edge 3
1287 edge.vertex1 = v3;
1288 edge.vertex2 = v1;
1289 edge_tree[edge] = i;
1290
1291 } // Next Face
1292
1293 // Size the output array.
1294 adjacency.resize(face_count_ * 3, 0xFFFFFFFF);
1295
1296 // Now, find any adjacent edges for each triangle edge
1297 src_indices_ptr = system_ib_;
1298 for(uint32_t i = 0; i < face_count_; ++i, src_indices_ptr += 3)
1299 {
1300 adjacent_edge_key edge;
1301
1302 // Retrieve positions of each referenced vertex.
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));
1309
1310 // Note: Notice below that the order of the edge vertices
1311 // is swapped. This is because we want to find the
1312 // matching ADJACENT edge, rather than simply finding
1313 // the same edge that we're currently processing.
1314
1315 // edge 1
1316 edge.vertex2 = v1;
1317 edge.vertex1 = v2;
1318
1319 // Find the matching adjacent edge
1320 it_edge = edge_tree.find(edge);
1321 if(it_edge != edge_tree.end())
1322 {
1323 adjacency[(i * 3)] = it_edge->second;
1324 }
1325
1326 // edge 2
1327 edge.vertex2 = v2;
1328 edge.vertex1 = v3;
1329
1330 // Find the matching adjacent edge
1331 it_edge = edge_tree.find(edge);
1332 if(it_edge != edge_tree.end())
1333 {
1334 adjacency[(i * 3) + 1] = it_edge->second;
1335 }
1336
1337 // edge 3
1338 edge.vertex2 = v3;
1339 edge.vertex1 = v1;
1340
1341 // Find the matching adjacent edge
1342 it_edge = edge_tree.find(edge);
1343 if(it_edge != edge_tree.end())
1344 {
1345 adjacency[(i * 3) + 2] = it_edge->second;
1346 }
1347
1348 } // Next Face
1349
1350 } // End if prepared
1351
1352 // Success!
1353 return true;
1354}
1355
1356auto mesh::get_face_count() const -> uint32_t
1357{
1359 {
1360 return face_count_;
1361 }
1363 {
1364 return static_cast<uint32_t>(preparation_data_.triangle_data.size());
1365 }
1366
1367 return 0;
1368}
1369
1370auto mesh::get_vertex_count() const -> uint32_t
1371{
1373 {
1374 return vertex_count_;
1375 }
1377 {
1379 }
1380
1381 return 0;
1382}
1383
1384auto mesh::get_system_vb() -> uint8_t*
1385{
1386 return system_vb_;
1387}
1388
1389auto mesh::get_system_ib() -> uint32_t*
1390{
1391 return system_ib_;
1392}
1393
1394auto mesh::get_vertex_format() const -> const gfx::vertex_layout&
1395{
1396 return vertex_format_;
1397}
1398
1400{
1401 return skin_bind_data_;
1402}
1403
1405{
1406 return bone_palettes_;
1407}
1408
1409auto mesh::get_armature() const -> const std::unique_ptr<mesh::armature_node>&
1410{
1411 return root_;
1412}
1413
1414auto mesh::calculate_screen_rect(const math::transform& world, const camera& cam) const -> irect32_t
1415{
1416 auto bounds = math::bbox::mul(get_bounds(), world);
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)),
1428 }};
1429
1430 math::vec2 min = extent_points[0];
1431 math::vec2 max = extent_points[0];
1432 for(const auto& v : extent_points)
1433 {
1434 min = math::min(min, v);
1435 max = math::max(max, v);
1436 }
1437 return irect32_t(irect32_t::value_type(min.x),
1438 irect32_t::value_type(min.y),
1439 irect32_t::value_type(max.x),
1440 irect32_t::value_type(max.y));
1441}
1442
1444{
1445 return mesh_submeshes_;
1446}
1447
1448auto mesh::get_submeshes_count() const -> size_t
1449{
1450 return mesh_submeshes_.size();
1451}
1452
1453auto mesh::get_submesh(uint32_t submesh_index) const -> const mesh::submesh&
1454{
1455 return *mesh_submeshes_[submesh_index];
1456}
1457
1458auto mesh::get_submesh_index(const submesh* s) const -> int
1459{
1460 int index = -1;
1461 for(const auto& submesh : mesh_submeshes_)
1462 {
1463 index++;
1464 if(submesh == s)
1465 {
1466 return index;
1467 }
1468 }
1469
1470 return -1;
1471}
1472
1474{
1476}
1477
1478auto mesh::get_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t&
1479{
1480 auto it = skinned_submesh_indices_.find(data_group_id);
1481 if(it != skinned_submesh_indices_.end())
1482 {
1483 return it->second;
1484 }
1485
1486 static const submesh_array_indices_t empty;
1487 return empty;
1488}
1489
1491{
1493}
1494
1495auto mesh::get_non_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t&
1496{
1497 auto it = non_skinned_submesh_indices_.find(data_group_id);
1498 if(it != non_skinned_submesh_indices_.end())
1499 {
1500 return it->second;
1501 }
1502
1503 static const submesh_array_indices_t empty;
1504 return empty;
1505}
1506
1507auto mesh::get_bounds() const -> const math::bbox&
1508{
1509 return bbox_;
1510}
1511
1513{
1514 return prepare_status_;
1515}
1516
1517auto mesh::get_data_groups_count() const -> size_t
1518{
1520 {
1521 return data_groups_.size();
1522 }
1524 {
1525 uint32_t groups_count = 0;
1526 for(const auto& sub : preparation_data_.submeshes)
1527 {
1528 groups_count = std::max(groups_count, sub.data_group_id + 1);
1529 }
1530 return groups_count;
1531 }
1532
1533 return 0;
1534}
1535
1536auto operator<(const mesh::adjacent_edge_key& key1, const mesh::adjacent_edge_key& key2) -> bool
1537{
1538 // Test vertex positions.
1539 if(math::epsilonNotEqual(key1.vertex1->x, key2.vertex1->x, math::epsilon<float>()))
1540 {
1541 return (key2.vertex1->x < key1.vertex1->x);
1542 }
1543 if(math::epsilonNotEqual(key1.vertex1->y, key2.vertex1->y, math::epsilon<float>()))
1544 {
1545 return (key2.vertex1->y < key1.vertex1->y);
1546 }
1547 if(math::epsilonNotEqual(key1.vertex1->z, key2.vertex1->z, math::epsilon<float>()))
1548 {
1549 return (key2.vertex1->z < key1.vertex1->z);
1550 }
1551
1552 if(math::epsilonNotEqual(key1.vertex2->x, key2.vertex2->x, math::epsilon<float>()))
1553 {
1554 return (key2.vertex2->x < key1.vertex2->x);
1555 }
1556 if(math::epsilonNotEqual(key1.vertex2->y, key2.vertex2->y, math::epsilon<float>()))
1557 {
1558 return (key2.vertex2->y < key1.vertex2->y);
1559 }
1560 if(math::epsilonNotEqual(key1.vertex2->z, key2.vertex2->z, math::epsilon<float>()))
1561 {
1562 return (key2.vertex2->z < key1.vertex2->z);
1563 }
1564
1565 // Exactly equal
1566 return false;
1567}
1568
1569auto operator<(const mesh::mesh_submesh_key& key1, const mesh::mesh_submesh_key& key2) -> bool
1570{
1571 return key1.data_group_id < key2.data_group_id;
1572}
1573
1574auto operator<(const mesh::weld_key& key1, const mesh::weld_key& key2) -> bool
1575{
1576 auto vertex_compare =
1577 [](const uint8_t* pVtx1, const uint8_t* pVtx2, const gfx::vertex_layout& layout, float tolerance) -> int
1578 {
1579 float diff{};
1580 int ndifference{};
1581
1582 for(uint16_t i = 0; i < gfx::attribute::Count; ++i)
1583 {
1584 if(!layout.has(static_cast<gfx::attribute>(i)))
1585 {
1586 continue; // Skip attributes not present in this layout.
1587 }
1588
1589 // Get the offset for this attribute in the vertex data
1590 uint16_t offset = layout.getOffset(static_cast<gfx::attribute>(i));
1591
1592 // Retrieve the vertex data pointers
1593 const uint8_t* p1 = pVtx1 + offset;
1594 const uint8_t* p2 = pVtx2 + offset;
1595
1596 // Decode the attribute information
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);
1601
1602 // Compare the attributes based on the type
1603 switch(type)
1604 {
1605 case bgfx::AttribType::Float:
1606 {
1607 for(uint8_t j = 0; j < num_components; ++j)
1608 {
1609 diff = ((float*)p1)[j] - ((float*)p2)[j];
1610 if(fabsf(diff) > tolerance)
1611 return (diff < 0) ? -1 : 1;
1612 }
1613 break;
1614 }
1615
1616 case bgfx::AttribType::Uint8:
1617 case bgfx::AttribType::Int16:
1618 {
1619 if(as_int)
1620 {
1621 ndifference = memcmp(p1, p2, num_components * (type == bgfx::AttribType::Uint8 ? 1 : 2));
1622 if(ndifference != 0)
1623 {
1624 return (ndifference < 0) ? -1 : 1;
1625 }
1626 }
1627 else
1628 {
1629 for(uint8_t j = 0; j < num_components; ++j)
1630 {
1631 float f1{}, f2{};
1632 if(type == bgfx::AttribType::Uint8)
1633 {
1634 f1 = normalized ? ((float)p1[j] / 255.0f) : (float)p1[j];
1635 f2 = normalized ? ((float)p2[j] / 255.0f) : (float)p2[j];
1636 }
1637 else // Int16
1638 {
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];
1641 }
1642 diff = f1 - f2;
1643 if(fabsf(diff) > tolerance)
1644 {
1645 return (diff < 0) ? -1 : 1;
1646 }
1647 }
1648 }
1649 break;
1650 }
1651
1652 default:
1653 // Handle other types if necessary.
1654 break;
1655 }
1656 }
1657
1658 // Both vertices are equal for the purposes of this test.
1659 return 0;
1660 };
1661
1662 int ndifference = vertex_compare(key1.vertex, key2.vertex, key1.format, key1.tolerance);
1663 if(ndifference != 0)
1664 {
1665 return (ndifference < 0);
1666 }
1667
1668 // Exactly equal
1669 return false;
1670}
1671
1673{
1674 // Data group id must match.
1675 if(key1.data_group_id != key2.data_group_id)
1676 {
1677 return key1.data_group_id < key2.data_group_id;
1678 }
1679
1680 const mesh::face_influences* p1 = key1.influences;
1681 const mesh::face_influences* p2 = key2.influences;
1682
1683 // The bone count must match.
1684 if(p1->bones.size() != p2->bones.size())
1685 {
1686 return p1->bones.size() < p2->bones.size();
1687 }
1688
1689 // Compare the bone indices in each list
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)
1693 {
1694 if(it_bone1->first != it_bone2->first)
1695 {
1696 return it_bone1->first < it_bone2->first;
1697 }
1698
1699 } // Next Bone
1700
1701 // Exact match (for the purposes of combining influences)
1702 return false;
1703}
1704
1706{
1707 // Vertex normals were requested (and at least some were not yet provided?)
1708 if(force_normal_generation_ || preparation_data_.compute_normals)
1709 {
1710 // Generate the adjacency information for vertex normal computation
1711 std::vector<uint32_t> adjacency;
1712 if(!generate_adjacency(adjacency))
1713 {
1714 APPLOG_ERROR("Failed to generate adjacency buffer mesh containing {0} faces.\n",
1715 preparation_data_.triangle_count);
1716 return false;
1717
1718 } // End if failed to generate
1719 if(force_barycentric_generation_ || preparation_data_.compute_barycentric)
1720 {
1721 // Generate any vertex barycentric coords that have not been provided
1722 if(!generate_vertex_barycentrics(&adjacency.front()))
1723 {
1724 APPLOG_ERROR("Failed to generate vertex barycentric coords for mesh "
1725 "containing {0} faces.\n",
1726 preparation_data_.triangle_count);
1727 return false;
1728
1729 } // End if failed to generate
1730
1731 } // End if compute
1732
1733 // Generate any vertex normals that have not been provided
1734 if(!generate_vertex_normals(&adjacency.front()))
1735 {
1736 APPLOG_ERROR("Failed to generate vertex normals for mesh containing {0} faces.\n",
1737 preparation_data_.triangle_count);
1738 return false;
1739
1740 } // End if failed to generate
1741
1742 } // End if compute
1743
1744 // Weld vertices at this point
1745 if(weld)
1746 {
1747 if(!weld_vertices())
1748 {
1749 APPLOG_ERROR("Failed to weld vertices for mesh containing {0} faces.\n", preparation_data_.triangle_count);
1750 return false;
1751
1752 } // End if failed to weld
1753
1754 } // End if optional weld
1755
1756 // Binormals and / or tangents were requested (and at least some where not yet
1757 // provided?)
1758 if(force_tangent_generation_ || preparation_data_.compute_binormals || preparation_data_.compute_tangents)
1759 {
1760 // Requires normals
1761 if(vertex_format_.has(gfx::attribute::Normal))
1762 {
1763 // Generate any vertex tangents that have not been provided
1764 if(!generate_vertex_tangents())
1765 {
1766 APPLOG_ERROR("Failed to generate vertex tangents for mesh containing "
1767 "{0} faces.\n",
1768 preparation_data_.triangle_count);
1769 return false;
1770
1771 } // End if failed to generate
1772
1773 } // End if has normals
1774
1775 } // End if compute
1776
1777 // Success!
1778 return true;
1779}
1780
1781auto mesh::generate_vertex_normals(uint32_t* adjacency_ptr, std::vector<uint32_t>* remap_array_ptr /* = nullptr */)
1782 -> bool
1783{
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;
1787
1788 // Get access to useful data offset information.
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();
1792
1793 // Final format requests vertex normals?
1794 if(!has_normals)
1795 {
1796 return true;
1797 }
1798
1799 // Size the remap array accordingly and populate it with the default mapping.
1800 uint32_t original_vertex_count = preparation_data_.vertex_count;
1801 if(remap_array_ptr)
1802 {
1803 remap_array_ptr->resize(preparation_data_.vertex_count);
1804 for(i = 0; i < preparation_data_.vertex_count; ++i)
1805 {
1806 (*remap_array_ptr)[i] = i;
1807 }
1808
1809 } // End if supplied
1810
1811 // Pre-compute surface normals for each triangle
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)
1816 {
1817 // Retrieve positions of each referenced vertex.
1818 const triangle& tri = preparation_data_.triangle_data[i];
1819 const auto* v1 =
1820 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (tri.indices[0] * vertex_stride) + position_offset);
1821 const auto* v2 =
1822 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (tri.indices[1] * vertex_stride) + position_offset);
1823 const auto* v3 =
1824 reinterpret_cast<const math::vec3*>(src_vertices_ptr + (tri.indices[2] * vertex_stride) + position_offset);
1825
1826 // Compute the two edge vectors required for generating our normal
1827 // We normalize here to prevent problems when the triangles are very small.
1828 vec_edge1 = math::normalize(*v2 - *v1);
1829 vec_edge2 = math::normalize(*v3 - *v1);
1830
1831 // Generate the normal
1832 vec_normal = math::cross(vec_edge1, vec_edge2);
1833 normals_ptr[i] = math::normalize(vec_normal);
1834
1835 } // Next Face
1836
1837 // Now compute the actual VERTEX normals using face adjacency information
1838 for(i = 0; i < preparation_data_.triangle_count; ++i)
1839 {
1840 triangle& tri = preparation_data_.triangle_data[i];
1842 {
1843 continue;
1844 }
1845
1846 // Process each vertex in the face
1847 for(j = 0; j < 3; ++j)
1848 {
1849 // Retrieve the index for this vertex.
1850 index = tri.indices[j];
1851
1852 // Skip this vertex if normal information was already provided.
1853 if(!force_normal_generation_ &&
1854 (preparation_data_.vertex_flags[index] & preparation_data::source_contains_normal))
1855 {
1856 continue;
1857 }
1858
1859 // To generate vertex normals using the adjacency information we first
1860 // need to walk backwards
1861 // through the list to find the first triangle that references this vertex
1862 // (using entrance/exit
1863 // edge strategy).
1864 // Once we have the first triangle, step forwards and sum the normals of
1865 // each of the faces
1866 // for each triangle we touch. This is essentially a flood fill through
1867 // all of the triangles
1868 // that touch this vertex, without ever having to test the entire set for
1869 // shared vertices.
1870 // The initial backwards traversal prevents us from having to store (and
1871 // test) a 'visited' flag
1872 // for
1873 // every triangle in the buffer.
1874
1875 // First walk backwards...
1876 start_tri = i;
1877 previous_tri = i;
1878 current_tri = adjacency_ptr[(i * 3) + ((j + 2) % 3)];
1879 for(;;)
1880 {
1881 // Stop walking if we reach the starting triangle again, or if there
1882 // is no connectivity out of this edge
1883 if(current_tri == start_tri || current_tri == 0xFFFFFFFF)
1884 {
1885 break;
1886 }
1887
1888 // Find the edge in the adjacency list that we came in through
1889 for(k = 0; k < 3; ++k)
1890 {
1891 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1892 {
1893 break;
1894 }
1895
1896 } // Next item in adjacency list
1897
1898 // If we found the edge we entered through, the exit edge will
1899 // be the edge counter-clockwise from this one when walking backwards
1900 if(k < 3)
1901 {
1902 previous_tri = current_tri;
1903 current_tri = adjacency_ptr[(current_tri * 3) + ((k + 2) % 3)];
1904
1905 } // End if found entrance edge
1906 else
1907 {
1908 break;
1909
1910 } // End if failed to find entrance edge
1911
1912 } // Next Test
1913
1914 // We should now be at the starting triangle, we can start to walk
1915 // forwards
1916 // collecting the face normals. First find the exit edge so we can start
1917 // walking.
1918 if(current_tri != 0xFFFFFFFF)
1919 {
1920 for(k = 0; k < 3; ++k)
1921 {
1922 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1923 {
1924 break;
1925 }
1926
1927 } // Next item in adjacency list
1928 }
1929 else
1930 {
1931 // Couldn't step back, so first triangle is the current triangle
1932 current_tri = i;
1933 k = j;
1934 }
1935
1936 if(k < 3)
1937 {
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];
1942 for(;;)
1943 {
1944 // Stop walking if we reach the starting triangle again, or if there
1945 // is no connectivity out of this edge
1946 if(current_tri == start_tri || current_tri == 0xFFFFFFFF)
1947 {
1948 break;
1949 }
1950
1951 // Add this normal.
1952 vec_normal += normals_ptr[current_tri];
1953
1954 // Find the edge in the adjacency list that we came in through
1955 for(k = 0; k < 3; ++k)
1956 {
1957 if(adjacency_ptr[(current_tri * 3) + k] == previous_tri)
1958 {
1959 break;
1960 }
1961
1962 } // Next item in adjacency list
1963
1964 // If we found the edge we came entered through, the exit edge will
1965 // be the edge clockwise from this one when walking forwards
1966 if(k < 3)
1967 {
1968 previous_tri = current_tri;
1969 current_tri = adjacency_ptr[(current_tri * 3) + ((k + 1) % 3)];
1970
1971 } // End if found entrance edge
1972 else
1973 {
1974 break;
1975
1976 } // End if failed to find entrance edge
1977
1978 } // Next Test
1979
1980 } // End if found entrance edge
1981
1982 // Normalize the new vertex normal
1983 vec_normal = math::normalize(vec_normal);
1984
1985 // If the normal we are about to store is significantly different from any
1986 // normal
1987 // already stored in this vertex (excepting the case where it is <0,0,0>),
1988 // we need
1989 // to split the vertex into two.
1990 float fn[4];
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)
1997 {
1998 gfx::vertex_pack(fn, true, gfx::attribute::Normal, vertex_format_, src_vertices_ptr, index);
1999 } // End if no normal stored here yet
2000 else
2001 {
2002 // Split and store in a new vertex if it is different (enough)
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)
2005 {
2006 // Make room for new vertex data.
2007 preparation_data_.vertex_data.resize(preparation_data_.vertex_data.size() + vertex_stride);
2008
2009 // Ensure that we update the 'src_vertices_ptr' pointer (used
2010 // throughout the
2011 // loop). The internal buffer wrapped by the resized vertex data
2012 // vector
2013 // may have been re-allocated.
2014 src_vertices_ptr = preparation_data_.vertex_data.data();
2015
2016 // Duplicate the vertex at the end of the buffer
2017 std::memcpy(src_vertices_ptr + (preparation_data_.vertex_count * vertex_stride),
2018 src_vertices_ptr + (index * vertex_stride),
2019 vertex_stride);
2020
2021 // Duplicate any other remaining information.
2022 preparation_data_.vertex_flags.push_back(preparation_data_.vertex_flags[index]);
2023
2024 // Record the split
2025 if(remap_array_ptr)
2026 {
2027 (*remap_array_ptr)[index] = preparation_data_.vertex_count;
2028 }
2029
2030 // Store the new normal and finally record the fact that we have
2031 // added a new vertex.
2032 index = preparation_data_.vertex_count++;
2033 math::vec4 norm(vec_normal, 0.0f);
2034 gfx::vertex_pack(math::value_ptr(norm),
2035 true,
2036 gfx::attribute::Normal,
2037 vertex_format_,
2038 src_vertices_ptr,
2039 index);
2040
2041 // Update the index
2042 tri.indices[j] = index;
2043
2044 } // End if normal is different
2045
2046 } // End if normal already stored here
2047
2048 } // Next Vertex
2049
2050 } // Next Face
2051
2052 // We're done with the surface normals
2053 checked_array_delete(normals_ptr);
2054
2055 // If no new vertices were introduced, then it is not necessary
2056 // for the caller to remap anything.
2057 if(remap_array_ptr && original_vertex_count == preparation_data_.vertex_count)
2058 {
2059 remap_array_ptr->clear();
2060 }
2061
2062 // Success!
2063 return true;
2064}
2065
2066auto mesh::generate_vertex_barycentrics(uint32_t* adjacency) -> bool
2067{
2068 (void)adjacency;
2069 return true;
2070}
2071
2073{
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;
2077
2078 // Get access to useful data offset information.
2079 uint16_t vertex_stride = vertex_format_.getStride();
2080
2081 bool has_normals = vertex_format_.has(gfx::attribute::Normal);
2082 // This will fail if we don't already have normals however.
2083 if(!has_normals)
2084 {
2085 return false;
2086 }
2087
2088 // Final format requests tangents?
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)
2092 {
2093 return true;
2094 }
2095
2096 // Allocate storage space for the tangent and bitangent vectors
2097 // that we will effectively need to average for shared vertices.
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);
2104
2105 // Iterate through each triangle in the mesh
2106 uint8_t* src_vertices_ptr = preparation_data_.vertex_data.data();
2107 for(i = 0; i < num_faces; ++i)
2108 {
2109 triangle& tri = preparation_data_.triangle_data[i];
2110
2111 // Compute the three indices for the triangle
2112 i1 = tri.indices[0];
2113 i2 = tri.indices[1];
2114 i3 = tri.indices[2];
2115
2116 // Retrieve references to the positions of the three vertices in the
2117 // triangle.
2118 math::vec3 E;
2119 float fE[4];
2120 gfx::vertex_unpack(fE, gfx::attribute::Position, vertex_format_, src_vertices_ptr, i1);
2121 math::vec3 F;
2122 float fF[4];
2123 gfx::vertex_unpack(fF, gfx::attribute::Position, vertex_format_, src_vertices_ptr, i2);
2124 math::vec3 G;
2125 float fG[4];
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));
2130
2131 // Retrieve references to the base texture coordinates of the three vertices
2132 // in the triangle.
2133 // TODO: Allow customization of which tex coordinates to generate from.
2134 math::vec2 Et;
2135 float fEt[4];
2136 gfx::vertex_unpack(&fEt[0], gfx::attribute::TexCoord0, vertex_format_, src_vertices_ptr, i1);
2137 math::vec2 Ft;
2138 float fFt[4];
2139 gfx::vertex_unpack(&fFt[0], gfx::attribute::TexCoord0, vertex_format_, src_vertices_ptr, i2);
2140 math::vec2 Gt;
2141 float fGt[4];
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));
2146
2147 // Compute the known variables P & Q, where "P = F-E" and "Q = G-E"
2148 // based on our original discussion of the tangent vector
2149 // calculation.
2150 P = F - E;
2151 Q = G - E;
2152
2153 // Also compute the know variables <s1,t1> and <s2,t2>. Recall that
2154 // these are the texture coordinate deltas similarly for "F-E"
2155 // and "G-E".
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;
2160
2161 // Next we can pre-compute part of the equation we developed
2162 // earlier: "1/(s1 * t2 - s2 * t1)". We do this in two separate
2163 // stages here in order to ensure that the texture coordinates
2164 // are not invalid.
2165 float r = (s1 * t2 - s2 * t1);
2166 if(math::abs(r) < math::epsilon<float>())
2167 {
2168 continue;
2169 }
2170 r = 1.0f / r;
2171
2172 // All that's left for us to do now is to run the matrix
2173 // multiplication and multiply the result by the scalar portion
2174 // we precomputed earlier.
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);
2181
2182 // Add the tangent and bitangent vectors (summed average) to
2183 // any previous values computed for each vertex.
2184 tangents[i1] += T;
2185 tangents[i2] += T;
2186 tangents[i3] += T;
2187 bitangents[i1] += B;
2188 bitangents[i2] += B;
2189 bitangents[i3] += B;
2190
2191 } // Next triangle
2192
2193 // Generate final tangent vectors
2194 for(i = 0; i < num_verts; i++, src_vertices_ptr += vertex_stride)
2195 {
2196 // Skip if the original imported data already provided a bitangent /
2197 // tangent.
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)
2201 {
2202 continue;
2203 }
2204
2205 // Retrieve the normal vector from the vertex and the computed
2206 // tangent vector.
2207 float normal[4];
2208 gfx::vertex_unpack(normal, gfx::attribute::Normal, vertex_format_, src_vertices_ptr);
2209 std::memcpy(&normal_vec[0], normal, 3 * sizeof(float));
2210
2211 T = tangents[i];
2212
2213 // GramSchmidt orthogonalize
2214 T = T - (normal_vec * math::dot(normal_vec, T));
2215 T = math::normalize(T);
2216
2217 // Store tangent if required
2218 if(force_tangent_generation_ || (!has_tangent && requires_tangents))
2219 {
2220 math::vec4 t(T, 1.0f);
2221 gfx::vertex_pack(math::value_ptr(t), true, gfx::attribute::Tangent, vertex_format_, src_vertices_ptr);
2222 }
2223
2224 // Compute and store bitangent if required
2225 if(force_tangent_generation_ || (!has_bitangent && requires_bitangents))
2226 {
2227 // Calculate the new orthogonal bitangent
2228 B = math::cross(normal_vec, T);
2229 B = math::normalize(B);
2230
2231 // Compute the "handedness" of the tangent and bitangent. This
2232 // ensures the inverted / mirrored texture coordinates still have
2233 // an accurate matrix.
2234 cross_vec = math::cross(normal_vec, T);
2235 if(math::dot(cross_vec, bitangents[i]) < 0.0f)
2236 {
2237 // Flip the bitangent
2238 B = -B;
2239
2240 } // End if coordinates inverted
2241
2242 // Store.
2243 math::vec4 b(B, 1.0f);
2244 gfx::vertex_pack(math::value_ptr(b), true, gfx::attribute::Bitangent, vertex_format_, src_vertices_ptr);
2245
2246 } // End if requires bitangent
2247
2248 } // Next vertex
2249
2250 // Cleanup
2251 checked_array_delete(tangents);
2252 checked_array_delete(bitangents);
2253
2254 // Return success
2255 return true;
2256}
2257
2258auto mesh::weld_vertices(float tolerance, std::vector<uint32_t>* vertex_remap_ptr /* = nullptr */) -> bool
2259{
2260 weld_key key;
2261 std::map<weld_key, uint32_t> vertex_tree;
2262 std::map<weld_key, uint32_t>::const_iterator it_key;
2263 byte_array_t new_vertex_data, new_vertex_flags;
2264 uint32_t new_vertex_count = 0;
2265
2266 // Allocate enough space to build the remap array for the existing vertices
2267 if(vertex_remap_ptr)
2268 {
2269 vertex_remap_ptr->resize(preparation_data_.vertex_count);
2270 }
2271 auto collapse_map = new uint32_t[preparation_data_.vertex_count];
2272
2273 // Retrieve useful data offset information.
2274 uint16_t vertex_stride = vertex_format_.getStride();
2275
2276 // For each vertex to be welded.
2277 for(uint32_t i = 0; i < preparation_data_.vertex_count; ++i)
2278 {
2279 // Build a new key structure for inserting
2280 key.vertex = (&preparation_data_.vertex_data[0]) + (i * vertex_stride);
2281 key.format = vertex_format_;
2282 key.tolerance = tolerance;
2283
2284 // Does a vertex with matching details already exist in the tree.
2285 it_key = vertex_tree.find(key);
2286 if(it_key == vertex_tree.end())
2287 {
2288 // No matching vertex. Insert into the tree (value = NEW index of vertex).
2289 vertex_tree[key] = new_vertex_count;
2290 collapse_map[i] = new_vertex_count;
2291 if(vertex_remap_ptr)
2292 {
2293 (*vertex_remap_ptr)[i] = new_vertex_count;
2294 }
2295
2296 // Store the vertex in the new buffer
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]);
2300 new_vertex_count++;
2301
2302 } // End if no matching vertex
2303 else
2304 {
2305 // A vertex already existed at this location.
2306 // Just mark the 'collapsed' index for this vertex in the remap array.
2307 collapse_map[i] = it_key->second;
2308 if(vertex_remap_ptr)
2309 {
2310 (*vertex_remap_ptr)[i] = 0xFFFFFFFF;
2311 }
2312
2313 } // End if vertex already existed
2314
2315 } // Next Vertex
2316
2317 // If nothing was welded, just bail
2318 if(preparation_data_.vertex_count == new_vertex_count)
2319 {
2320 checked_array_delete(collapse_map);
2321
2322 if(vertex_remap_ptr)
2323 {
2324 vertex_remap_ptr->clear();
2325 }
2326 return true;
2327
2328 } // End if nothing to do
2329
2330 // Otherwise, replace the old preparation vertices and remap
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;
2338
2339 // Now remap all the triangle indices
2340 for(uint32_t i = 0; i < preparation_data_.triangle_count; ++i)
2341 {
2342 triangle& tri = preparation_data_.triangle_data[i];
2343 tri.indices[0] = collapse_map[tri.indices[0]];
2344 tri.indices[1] = collapse_map[tri.indices[1]];
2345 tri.indices[2] = collapse_map[tri.indices[2]];
2346
2347 } // Next triangle
2348
2349 // Clean up
2350 checked_array_delete(collapse_map);
2351
2352 // Success!
2353 return true;
2354}
2355
2357// skin_bind_data Member Definitions
2360{
2361 bones_.push_back(bone);
2362}
2363
2365{
2366 for(size_t i = 0; i < bones_.size();)
2367 {
2368 if(bones_[i].influences.empty())
2369 {
2370 bones_.erase(bones_.begin() + static_cast<int>(i));
2371
2372 } // End if empty
2373 else
2374 {
2375 ++i;
2376 }
2377
2378 } // Next Bone
2379}
2380
2382{
2383 for(auto& bone : bones_)
2384 {
2385 bone.influences.clear();
2386 }
2387}
2388
2390{
2391 bones_.clear();
2392}
2393
2394void skin_bind_data::remap_vertices(const std::vector<uint32_t>& remap)
2395{
2396 // Iterate through all bone information and remap vertex indices.
2397 for(auto& bone : bones_)
2398 {
2399 vertex_influence_array_t new_influences;
2400 vertex_influence_array_t& influences = bone.influences;
2401 new_influences.reserve(influences.size());
2402 for(auto& influence : influences)
2403 {
2404 uint32_t new_index = remap[influence.vertex_index];
2405 if(new_index != 0xFFFFFFFF)
2406 {
2407 // Insert an influence at the new index
2408 new_influences.push_back(vertex_influence{new_index, influence.weight});
2409
2410 // If the vertex was split into two, we want to retain an
2411 // influence to the original index too.
2412 if(new_index >= remap.size())
2413 {
2414 new_influences.push_back(vertex_influence{influence.vertex_index, influence.weight});
2415 }
2416
2417 } // End if !removed
2418
2419 } // Next source influence
2420 bone.influences = new_influences;
2421
2422 } // Next bone
2423}
2424
2425void skin_bind_data::build_vertex_table(uint32_t vertex_count,
2426 const std::vector<uint32_t>& vertex_remap,
2427 vertex_data_array_t& table)
2428{
2429 uint32_t vertex{};
2430
2431 // Initialize the vertex table with the required number of vertices.
2432 table.reserve(vertex_count);
2433 for(vertex = 0; vertex < vertex_count; ++vertex)
2434 {
2435 vertex_data data;
2436 data.palette = -1;
2437 data.original_vertex = vertex;
2438 table.push_back(data);
2439
2440 } // Next Vertex
2441
2442 // Iterate through all bone information and populate the above array.
2443 for(size_t i = 0; i < bones_.size(); ++i)
2444 {
2445 vertex_influence_array_t& influences = bones_[i].influences;
2446 for(auto& influence : influences)
2447 {
2448 // Vertex data has been remapped?
2449 if(!vertex_remap.empty())
2450 {
2451 vertex = vertex_remap[influence.vertex_index];
2452 if(vertex == 0xFFFFFFFF)
2453 {
2454 continue;
2455 }
2456 auto& data = table[vertex];
2457 // Push influence data.
2458 data.influences.push_back(static_cast<int32_t>(i));
2459 data.weights.push_back(influence.weight);
2460 } // End if remap
2461 else
2462 {
2463 auto& data = table[influence.vertex_index];
2464 // Push influence data.
2465 data.influences.push_back(static_cast<int32_t>(i));
2466 data.weights.push_back(influence.weight);
2467 }
2468
2469 } // Next Influence
2470
2471 } // Next Bone
2472}
2473
2475{
2476 return bones_;
2477}
2478
2479auto skin_bind_data::get_bones() -> std::vector<skin_bind_data::bone_influence>&
2480{
2481 return bones_;
2482}
2483
2484auto skin_bind_data::has_bones() const -> bool
2485{
2486 return !get_bones().empty();
2487}
2488
2489auto skin_bind_data::find_bone_by_id(const std::string& name) const -> bone_query
2490{
2491 bone_query query{};
2492 auto it = std::find_if(std::begin(bones_),
2493 std::end(bones_),
2494 [name](const auto& bone)
2495 {
2496 return name == bone.bone_id;
2497 });
2498 if(it != std::end(bones_))
2499 {
2500 query.bone = &(*it);
2501 query.index = std::distance(std::begin(bones_), it);
2502 }
2503
2504 return query;
2505}
2506
2508// bone_palette Member Definitions
2510//-----------------------------------------------------------------------------
2511// Name : bone_palette() (Constructor)
2515//-----------------------------------------------------------------------------
2516bone_palette::bone_palette(uint32_t palette_size)
2517 : data_group_id_(0)
2518 , maximum_size_(palette_size)
2519 , maximum_blend_index_(-1)
2520{
2521}
2522
2523auto bone_palette::get_skinning_matrices(const std::vector<math::transform>& node_transforms,
2524 const skin_bind_data& bind_data) const -> const std::vector<math::mat4>&
2525{
2526 // Retrieve the main list of bones from the skin bind data that will
2527 // be referenced by the palette's bone index list.
2528 const auto& bind_list = bind_data.get_bones();
2529
2530 // Compute transformation matrix for each bone in the palette
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)
2535 {
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();
2541
2542 } // Next Bone
2543
2544 return skinning_transforms_;
2545}
2546
2547auto bone_palette::get_skinning_matrices(const std::vector<math::mat4>& node_transforms,
2548 const skin_bind_data& bind_data) const -> const std::vector<math::mat4>&
2549{
2550 // Retrieve the main list of bones from the skin bind data that will
2551 // be referenced by the palette's bone index list.
2552 const auto& bind_list = bind_data.get_bones();
2553
2554 // Compute transformation matrix for each bone in the palette
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>());
2558
2559 for(size_t i = 0; i < count; ++i)
2560 {
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();
2566
2567 } // Next Bone
2568
2569 return skinning_transforms_;
2570}
2571
2572void bone_palette::assign_bones(bone_index_map_t& bones, std::vector<uint32_t>& faces)
2573{
2574 bone_index_map_t::iterator it_bone, it_bone2;
2575
2576 // Iterate through newly specified input bones and add any unique ones to the
2577 // palette.
2578 for(it_bone = bones.begin(); it_bone != bones.end(); ++it_bone)
2579 {
2580 it_bone2 = bones_lut_.find(it_bone->first);
2581 if(it_bone2 == bones_lut_.end())
2582 {
2583 bones_lut_[it_bone->first] = static_cast<uint32_t>(bones_.size());
2584 bones_.push_back(it_bone->first);
2585
2586 } // End if not already added
2587
2588 } // Next Bone
2589
2590 // Merge the new face list with ours.
2591 // faces_.insert(faces_.end(), faces.begin(), faces.end());
2592
2593 faces_.resize(faces_.size() + faces.size());
2594 std::memcpy(faces_.data(), faces.data(), faces.size() * sizeof(uint32_t));
2595}
2596
2597void bone_palette::assign_bones(std::vector<bool>& bones, std::vector<uint32_t>& faces)
2598{
2599 bone_index_map_t::iterator it_bone, it_bone2;
2600
2601 // Iterate through newly specified input bones and add any unique ones to the
2602 // palette.
2603 // for(it_bone = bones.begin(); it_bone != bones.end(); ++it_bone)
2604 for(size_t i = 0, j = bones.size(); i < j; ++i)
2605 {
2606 if(!bones[i])
2607 {
2608 continue;
2609 }
2610
2611 it_bone2 = bones_lut_.find(i);
2612 if(it_bone2 == bones_lut_.end())
2613 {
2614 bones_lut_[i] = static_cast<uint32_t>(bones_.size());
2615 bones_.push_back(i);
2616
2617 } // End if not already added
2618
2619 } // Next Bone
2620
2621 // Merge the new face list with ours.
2622 // faces_.insert(faces_.end(), faces.begin(), faces.end());
2623
2624 faces_.resize(faces_.size() + faces.size());
2625 std::memcpy(faces_.data(), faces.data(), faces.size() * sizeof(uint32_t));
2626}
2627
2628void bone_palette::assign_bones(const std::vector<uint32_t>& bones)
2629{
2630 bone_index_map_t::iterator it_bone;
2631
2632 // Clear out prior data.
2633 bones_.clear();
2634 bones_lut_.clear();
2635
2636 // Iterate through newly specified input bones and add any unique ones to the
2637 // palette.
2638 for(size_t i = 0; i < bones.size(); ++i)
2639 {
2640 it_bone = bones_lut_.find(bones[i]);
2641 if(it_bone == bones_lut_.end())
2642 {
2643 bones_lut_[bones[i]] = static_cast<uint32_t>(bones_.size());
2644 bones_.push_back(bones[i]);
2645
2646 } // End if not already added
2647
2648 } // Next Bone
2649}
2650
2652 int32_t& current_space,
2653 int32_t& common_bones,
2654 int32_t& additional_bones)
2655{
2656 // Reset values
2657 current_space = static_cast<int32_t>(maximum_size_ - static_cast<uint32_t>(bones_.size()));
2658 common_bones = 0;
2659 additional_bones = 0;
2660
2661 // Early out if possible
2662 if(bones_.size() == 0)
2663 {
2664 additional_bones = static_cast<int32_t>(input.size());
2665 return;
2666
2667 } // End if no bones stored
2668 else if(input.size() == 0)
2669 {
2670 return;
2671
2672 } // End if no bones input
2673
2674 // Iterate through newly specified input bones and see how many
2675 // indices it has in common with our existing set.
2676 bone_index_map_t::iterator it_bone, it_bone2;
2677 for(it_bone = input.begin(); it_bone != input.end(); ++it_bone)
2678 {
2679 it_bone2 = bones_lut_.find(it_bone->first);
2680 if(it_bone2 != bones_lut_.end())
2681 common_bones++;
2682 else
2683 additional_bones++;
2684
2685 } // Next Bone
2686}
2687
2688auto bone_palette::translate_bone_to_palette(uint32_t bone_index) const -> uint32_t
2689{
2690 auto it_bone = bones_lut_.find(bone_index);
2691 if(it_bone == bones_lut_.end())
2692 return 0xFFFFFFFF;
2693 return it_bone->second;
2694}
2695
2696auto bone_palette::get_data_group() const -> uint32_t
2697{
2698 return data_group_id_;
2699}
2700
2702{
2703 data_group_id_ = group;
2704}
2705
2707{
2708 return maximum_blend_index_;
2709}
2710
2712{
2713 maximum_blend_index_ = nIndex;
2714}
2715
2716auto bone_palette::get_maximum_size() const -> uint32_t
2717{
2718 return maximum_size_;
2719}
2720
2721auto bone_palette::get_influenced_faces() -> std::vector<uint32_t>&
2722{
2723 return faces_;
2724}
2725
2727{
2728 faces_.clear();
2729}
2730
2731auto bone_palette::get_bones() const -> const std::vector<uint32_t>&
2732{
2733 return bones_;
2734}
2735
2737// Global Operator Definitions
2740{
2741 if(preparation_data_.compute_per_triangle_material_data)
2742 {
2743 // math::transform triangle indices, material and data group information
2744 // to the final triangle data arrays. We keep the latter two handy so
2745 // that we know precisely which material each triangle belongs to.
2746 triangle_data_.resize(face_count_);
2747 }
2748 uint32_t* dst_indices_ptr = system_ib_;
2749 for(uint32_t i = 0; i < face_count_; ++i)
2750 {
2751 // Copy indices.
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];
2756
2757 if(preparation_data_.compute_per_triangle_material_data)
2758 {
2759 // Copy triangle submesh information.
2760 mesh_submesh_key& tri_out = triangle_data_[i];
2761 tri_out.data_group_id = tri_in.data_group_id;
2762 }
2763
2764 } // Next triangle
2765
2766 preparation_data_.triangle_count = 0;
2767 preparation_data_.triangle_data.clear();
2768
2769 // Clear out any old data EXCEPT the old submesh index
2770 // We'll need this in order to understand how to update
2771 // the material reference counting later on.
2772 data_groups_.clear();
2773 // Destroy old submesh data.
2774 for(auto submesh : mesh_submeshes_)
2775 {
2777 }
2778 mesh_submeshes_.clear();
2779
2780 skinned_submesh_indices_.clear();
2781 skinned_submesh_count_ = {};
2782
2783 non_skinned_submesh_indices_.clear();
2784 non_skinned_submesh_count_ = {};
2785
2786 for(size_t i = 0; i < preparation_data_.submeshes.size(); ++i)
2787 {
2788 const auto& s = preparation_data_.submeshes[i];
2789 auto* sub = new submesh(s);
2790
2791 if(sub->skinned)
2792 {
2793 skinned_submesh_count_++;
2794 skinned_submesh_indices_[sub->data_group_id].emplace_back(i);
2795 }
2796 else
2797 {
2798 non_skinned_submesh_count_++;
2799 non_skinned_submesh_indices_[sub->data_group_id].emplace_back(i);
2800 }
2801
2802 mesh_submeshes_.emplace_back(sub);
2803 data_groups_[sub->data_group_id].emplace_back(sub);
2804 }
2805
2806 preparation_data_.submeshes.clear();
2807
2808 return true;
2809}
2810
2812{
2813 uint32_t index_start = submesh->face_start * 3;
2814 uint32_t index_count = submesh->face_count * 3;
2815 // Hardware or software rendering?
2816 if(hardware_mesh_)
2817 {
2818 // Render using hardware streams
2819 auto vb = std::static_pointer_cast<gfx::vertex_buffer>(hardware_vb_);
2820 auto ib = std::static_pointer_cast<gfx::index_buffer>(hardware_ib_);
2821
2822 gfx::set_vertex_buffer(0, vb->native_handle()); // submesh->vertex_start, submesh->vertex_count);
2823 gfx::set_index_buffer(ib->native_handle(), index_start, index_count);
2824
2825 } // End if has hardware copy
2826 else
2827 {
2829 {
2832 std::memcpy(vb.data,
2834 vb.size); // Adjust the pointer to start at the correct vertex
2836 }
2837
2838 if(index_count == gfx::get_avail_transient_index_buffer(index_count, true))
2839 {
2841 gfx::alloc_transient_index_buffer(&ib, index_count, true);
2842 std::memcpy(ib.data,
2843 system_ib_ + index_start * sizeof(uint32_t),
2844 ib.size); // Adjust the pointer to start at the correct index
2845 gfx::set_index_buffer(&ib, 0, index_count);
2846 }
2847
2848 } // End if software only copy
2849}
2850
2852 uint32_t* src_buffer_ptr,
2853 uint32_t* dest_buffer_ptr,
2854 uint32_t min_vertex,
2855 uint32_t max_vertex)
2856{
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;
2861
2862 // Declare vertex cache storage (plus one to allow them to drop "off the end")
2863 uint32_t vertex_cache_ptr[mesh_optimizer::MaxVertexCacheSize + 1];
2864 std::memset(vertex_cache_ptr, 0, sizeof(vertex_cache_ptr));
2865 // First allocate enough room for the optimization information for each vertex
2866 // and triangle
2867 uint32_t vertex_count = (max_vertex - min_vertex) + 1;
2868 auto vertex_info_ptr = new optimizer_vertex_info[vertex_count];
2869 auto triangle_info_ptr = new optimizer_triangle_info[submesh->face_count];
2870
2871 // The first pass is to initialize the vertex information with information
2872 // about the
2873 // faces which reference them.
2874 for(uint32_t i = 0; i < submesh->face_count; ++i)
2875 {
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);
2885
2886 } // Next triangle
2887
2888 // Initialize vertex scores
2889 for(uint32_t i = 0; i < vertex_count; ++i)
2890 {
2891 vertex_info_ptr[i].vertex_score = find_vertex_optimizer_score(&vertex_info_ptr[i]);
2892 }
2893
2894 // Compute the score for each triangle, and record the triangle with the best
2895 // score
2896 for(uint32_t i = 0; i < submesh->face_count; ++i)
2897 {
2898 // The triangle score is the sum of the scores of each of
2899 // its three vertices.
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;
2907
2908 // Record the triangle with the highest score
2909 if(score > best_score)
2910 {
2911 best_score = score;
2912 best_triangle = static_cast<int32_t>(i);
2913
2914 } // End if better than previous score
2915
2916 } // Next triangle
2917
2918 // Now we can start adding triangles, beginning with the previous highest
2919 // scoring triangle.
2920 for(uint32_t i = 0; i < submesh->face_count; ++i)
2921 {
2922 // If we don't know the best triangle, for whatever reason, find it
2923 if(best_triangle < 0)
2924 {
2925 best_triangle = -1;
2926 best_score = 0.0f;
2927
2928 // Iterate through the entire list of un-added faces
2929 for(uint32_t j = 0; j < submesh->face_count; ++j)
2930 {
2931 if(!triangle_info_ptr[j].added)
2932 {
2933 score = triangle_info_ptr[j].triangle_score;
2934
2935 // Record the triangle with the highest score
2936 if(score > best_score)
2937 {
2938 best_score = score;
2939 best_triangle = static_cast<int32_t>(j);
2940
2941 } // End if better than previous score
2942
2943 } // End if not added
2944
2945 } // Next triangle
2946
2947 } // End if best triangle is not known
2948
2949 // Use the best scoring triangle from last pass and reset score keeping
2950 triangle_index = static_cast<uint32_t>(best_triangle);
2951 optimizer_triangle_info* tri_ptr = &triangle_info_ptr[triangle_index];
2952 best_triangle = -1;
2953 best_score = 0.0f;
2954
2955 // This triangle can be added to the 'draw' list, and each
2956 // of the vertices it references should be updated.
2957 tri_ptr->added = true;
2958 for(uint32_t j = 0; j < 3; ++j)
2959 {
2960 // Extract the vertex index and store in the index buffer
2961 index = src_buffer_ptr[(triangle_index * 3) + j];
2962 *dest_buffer_ptr++ = index;
2963
2964 // Adjust the index so that it points into our info buffer
2965 // rather than the actual source vertex itself.
2966 index = index - min_vertex;
2967
2968 // Retrieve the referenced vertex information
2969 optimizer_vertex_info* vert_ptr = &vertex_info_ptr[index];
2970
2971 // Reduce the 'valence' of this vertex (one less triangle is now
2972 // referencing)
2973 vert_ptr->unused_triangle_references--;
2974
2975 // Remove this triangle from the list of references in the vertex
2976 auto it_reference =
2977 std::find(vert_ptr->triangle_references.begin(), vert_ptr->triangle_references.end(), triangle_index);
2978 if(it_reference != vert_ptr->triangle_references.end())
2979 {
2980 vert_ptr->triangle_references.erase(it_reference);
2981 }
2982
2983 // Now we must update the vertex cache to include this vertex. If it was
2984 // already in the cache, it should be moved to the head, otherwise it
2985 // should
2986 // be inserted (pushing one off the end).
2987 if(vert_ptr->cache_position == -1)
2988 {
2989 // Not in the vertex cache, insert it at the head.
2990 if(vertex_cache_size > 0)
2991 {
2992 // First shuffle EVERYONE up by one position in the cache.
2993 memmove(&vertex_cache_ptr[1], &vertex_cache_ptr[0], vertex_cache_size * sizeof(uint32_t));
2994
2995 } // End if any vertices exist in the cache
2996
2997 // Grow the cache if applicable
2998 if(vertex_cache_size < mesh_optimizer::MaxVertexCacheSize)
2999 {
3000 vertex_cache_size++;
3001 }
3002 else
3003 {
3004 // Set the associated index of the vertex which dropped "off the end"
3005 // of the cache.
3006 vertex_info_ptr[vertex_cache_ptr[vertex_cache_size]].cache_position = -1;
3007
3008 } // End if no more room
3009
3010 // Overwrite the first entry
3011 vertex_cache_ptr[0] = index;
3012
3013 } // End if not in cache
3014 else if(vert_ptr->cache_position > 0)
3015 {
3016 // Already in the vertex cache, move it to the head.
3017 // Note : If the cache position is already 0, we just ignore
3018 // it... hence the above 'else if' rather than just 'else'.
3019 if(vert_ptr->cache_position == 1)
3020 {
3021 // We were in the second slot, just swap the two
3022 temp = vertex_cache_ptr[0];
3023 vertex_cache_ptr[0] = index;
3024 vertex_cache_ptr[1] = temp;
3025
3026 } // End if simple swap
3027 else
3028 {
3029 // Shuffle EVERYONE up who came before us.
3030 memmove(&vertex_cache_ptr[1],
3031 &vertex_cache_ptr[0],
3032 static_cast<size_t>(vert_ptr->cache_position) * sizeof(uint32_t));
3033
3034 // Insert this vertex at the head
3035 vertex_cache_ptr[0] = index;
3036
3037 } // End if memory move required
3038
3039 } // End if already in cache
3040
3041 // Update the cache position records for all vertices in the cache
3042 for(uint32_t k = 0; k < vertex_cache_size; ++k)
3043 {
3044 vertex_info_ptr[vertex_cache_ptr[k]].cache_position = static_cast<int32_t>(k);
3045 }
3046
3047 } // Next Index
3048
3049 // Recalculate the of all vertices contained in the cache
3050 for(uint32_t j = 0; j < vertex_cache_size; ++j)
3051 {
3052 optimizer_vertex_info* vert_ptr = &vertex_info_ptr[vertex_cache_ptr[j]];
3053 vert_ptr->vertex_score = find_vertex_optimizer_score(vert_ptr);
3054
3055 } // Next entry in the vertex cache
3056
3057 // Update the score of the triangles which reference this vertex
3058 // and record the highest scoring.
3059 for(uint32_t j = 0; j < vertex_cache_size; ++j)
3060 {
3061 optimizer_vertex_info* vert_ptr = &vertex_info_ptr[vertex_cache_ptr[j]];
3062
3063 // For each triangle referenced
3064 for(uint32_t k = 0; k < vert_ptr->unused_triangle_references; ++k)
3065 {
3066 triangle_index = vert_ptr->triangle_references[k];
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;
3071 tri_ptr->triangle_score = score;
3072
3073 // Highest scoring so far?
3074 if(score > best_score)
3075 {
3076 best_score = score;
3077 best_triangle = static_cast<int32_t>(triangle_index);
3078
3079 } // End if better than previous score
3080
3081 } // Next triangle
3082
3083 } // Next entry in the vertex cache
3084
3085 } // Next triangle to Add
3086
3087 // Destroy the temporary arrays
3088 checked_array_delete(vertex_info_ptr);
3089 checked_array_delete(triangle_info_ptr);
3090}
3091
3093{
3094 float score = 0.0f;
3095
3096 // Do any remaining triangles use this vertex?
3097 if(vertex_info_ptr->unused_triangle_references == 0)
3098 {
3099 return -1.0f;
3100 }
3101
3102 int32_t cache_position = vertex_info_ptr->cache_position;
3103 if(cache_position < 0)
3104 {
3105 // Vertex is not in FIFO cache - no score.
3106 }
3107 else
3108 {
3109 if(cache_position < 3)
3110 {
3111 // This vertex was used in the last triangle,
3112 // so it has a fixed score, whichever of the three
3113 // it's in. Otherwise, you can get very different
3114 // answers depending on whether you add
3115 // the triangle 1,2,3 or 3,1,2 - which is silly.
3116 score = mesh_optimizer::LastTriScore;
3117 }
3118 else
3119 {
3120 // Points for being high in the cache.
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);
3124 }
3125
3126 } // End if already in vertex cache
3127
3128 // Bonus points for having a low number of tris still to
3129 // use the vert, so we get rid of lone verts quickly.
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;
3133
3134 // Return the final score
3135 return score;
3136}
3137} // namespace unravel
entt::handle b
manifold_type type
btVector3 normal
void checked_array_delete(T *&x)
void checked_delete(T *&x)
A type erasing container that can store any mesh.
Definition any_mesh.hpp:15
any_generator< triangle_t > triangles() const noexcept
Definition any_mesh.cpp:17
General purpose transformation class designed to maintain each component of the transformation separa...
Definition transform.hpp:27
Outlines a collection of bones that influence a given set of faces/vertices in the mesh.
Definition mesh.h:173
std::map< uint32_t, uint32_t > bone_index_map_t
Definition mesh.h:175
auto get_bones() const -> const std::vector< uint32_t > &
Retrieves the indices of the bones referenced by this palette.
Definition mesh.cpp:2731
auto get_maximum_size() const -> uint32_t
Retrieves the maximum size of the palette.
Definition mesh.cpp:2716
bone_index_map_t bones_lut_
< Sorted list of bones in this palette.
Definition mesh.h:293
void clear_influenced_faces()
Clears out the temporary face influences array.
Definition mesh.cpp:2726
uint32_t data_group_id_
The maximum size of the palette.
Definition mesh.h:299
void assign_bones(bone_index_map_t &bones, std::vector< uint32_t > &faces)
Assigns the specified bones (and faces) to this bone palette.
Definition mesh.cpp:2572
std::vector< uint32_t > faces_
The data group identifier used to separate the mesh data into submeshes relevant tothis bone palette.
Definition mesh.h:297
auto get_maximum_blend_index() const -> int32_t
Retrieves the maximum vertex blend index for this palette.
Definition mesh.cpp:2706
auto get_influenced_faces() -> std::vector< uint32_t > &
Retrieves the list of faces assigned to this palette.
Definition mesh.cpp:2721
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.
Definition mesh.cpp:2523
uint32_t maximum_size_
The maximum vertex blend index for this palette.
Definition mesh.h:301
void compute_palette_fit(bone_index_map_t &input, int32_t &current_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...
Definition mesh.cpp:2651
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...
Definition mesh.cpp:2701
void set_maximum_blend_index(int index)
Sets the maximum vertex blend index for this palette.
Definition mesh.cpp:2711
int32_t maximum_blend_index_
Definition mesh.h:303
auto translate_bone_to_palette(uint32_t bone_index) const -> uint32_t
Translates the specified bone index into its associated position in the palette.
Definition mesh.cpp:2688
bone_palette(uint32_t paletteSize)
Constructs a bone palette with the given size.
Definition mesh.cpp:2516
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...
Definition mesh.cpp:2696
std::vector< uint32_t > bones_
List of faces assigned to this palette.
Definition mesh.h:295
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:35
Main class representing a 3D mesh with support for different LODs, submeshes, and skinning.
Definition mesh.h:310
gfx::vertex_layout vertex_format_
The final system memory copy of the index buffer.
Definition mesh.h:1043
auto get_submesh_index(const submesh *s) const -> int
Definition mesh.cpp:1458
auto generate_vertex_normals(uint32_t *adjacency_ptr, std::vector< uint32_t > *remap_array_ptr=nullptr) -> bool
Generates vertex normals for the mesh.
Definition mesh.cpp:1781
auto create_dodecahedron(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates a dodecahedron geometry.
Definition mesh.cpp:951
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.
Definition mesh.cpp:740
bone_palette_array_t bone_palettes_
List of armature nodes.
Definition mesh.h:1086
std::shared_ptr< void > hardware_vb_
The actual hardware index buffer resource.
Definition mesh.h:1049
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_
Definition mesh.h:1088
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.
Definition mesh.cpp:812
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.
Definition mesh.cpp:857
submesh_array_t mesh_submeshes_
Indices in the subset array which are skinned.
Definition mesh.h:1054
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.
Definition mesh.cpp:1404
void check_for_degenerates()
Definition mesh.cpp:982
auto create_icosahedron(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates an icosahedron geometry.
Definition mesh.cpp:936
auto set_submeshes(const std::vector< submesh > &submeshes) -> bool
Definition mesh.cpp:305
auto generate_vertex_barycentrics(uint32_t *adjacency) -> bool
Generates vertex barycentric coordinates for the mesh.
Definition mesh.cpp:2066
uint32_t face_count_
Total number of vertices in the prepared mesh.
Definition mesh.h:1074
std::vector< uint8_t > byte_array_t
Definition mesh.h:368
auto get_system_ib() -> uint32_t *
Retrieves the underlying index data from the mesh.
Definition mesh.cpp:1389
auto get_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t &
Definition mesh.cpp:1478
auto get_non_skinned_submeshes_indices(uint32_t data_group_id) const -> const submesh_array_indices_t &
Definition mesh.cpp:1495
auto get_submeshes_count() const -> size_t
Gets the number of submeshes for this mesh.
Definition mesh.cpp:1448
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.
Definition mesh.cpp:1414
auto get_vertex_count() const -> uint32_t
Determines the number of vertices stored in the mesh.
Definition mesh.cpp:1370
auto set_primitives(triangle_array_t &&triangles) -> bool
Adds primitives (triangles) to the mesh.
Definition mesh.cpp:323
auto create_teapot(const gfx::vertex_layout &format, bool hardware_copy=true) -> bool
Creates a teapot geometry.
Definition mesh.cpp:921
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.
Definition mesh.cpp:1017
auto get_bounds() const -> const math::bbox &
Gets the local bounding box for this mesh.
Definition mesh.cpp:1507
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.
Definition mesh.cpp:878
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...
Definition mesh.cpp:2851
bool force_normal_generation_
Whether to force the generation of vertex barycentric coordinates.
Definition mesh.h:1034
math::bbox bbox_
Total number of faces in the prepared mesh.
Definition mesh.h:1072
auto get_non_skinned_submeshes_count() const -> size_t
Definition mesh.cpp:1490
data_group_submesh_map_t data_groups_
Whether the mesh uses a hardware vertex/index buffer.
Definition mesh.h:1065
auto sort_mesh_data() -> bool
Sorts the data in the mesh into material and data group order.
Definition mesh.cpp:2739
auto generate_vertex_tangents() -> bool
Generates vertex tangents for the mesh.
Definition mesh.cpp:2072
size_t skinned_submesh_count_
Indices in the subset array which are not skinned.
Definition mesh.h:1058
void bind_render_buffers_for_submesh(const submesh *submesh)
Binds the mesh data for rendering the selected batch of primitives.
Definition mesh.cpp:2811
auto generate_adjacency(std::vector< uint32_t > &adjacency) -> bool
Generates edge-triangle adjacency information for the mesh data.
Definition mesh.cpp:1131
std::shared_ptr< void > hardware_ib_
The actual list of submeshes maintained by this mesh.
Definition mesh.h:1051
uint8_t * system_vb_
The vertex format used for the mesh internal vertex data.
Definition mesh.h:1041
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
Definition mesh.cpp:789
auto get_vertex_format() const -> const gfx::vertex_layout &
Retrieves the format of the underlying mesh vertex data.
Definition mesh.cpp:1394
bool hardware_mesh_
Whether the mesh was optimized when it was prepared.
Definition mesh.h:1068
auto bind_skin(const skin_bind_data &bind_data) -> bool
Binds the mesh as a skin with the specified skin binding data.
Definition mesh.cpp:478
bool force_tangent_generation_
< Whether to force the generation of tangent space vectors.
Definition mesh.h:1032
auto get_status() const -> mesh_status
Gets the preparation status for this mesh.
Definition mesh.cpp:1512
auto create_icosphere(const gfx::vertex_layout &format, int tesselation_level, bool hardware_copy=true) -> bool
Creates an icosphere geometry.
Definition mesh.cpp:966
uint32_t vertex_count_
Preparation status of the mesh.
Definition mesh.h:1076
auto load_mesh(load_data &&data) -> bool
Definition mesh.cpp:723
size_t non_skinned_submesh_count_
Lookup information mapping data groups to submeshes batched by material.
Definition mesh.h:1062
void dispose()
Clears out all the mesh data.
Definition mesh.cpp:124
void build_vb(bool hardware_copy=true)
Builds the internal vertex buffer.
Definition mesh.cpp:1090
auto generate_vertex_components(bool weld) -> bool
Generates any vertex components that may be missing, such as normals, tangents, or binormals.
Definition mesh.cpp:1705
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.
Definition mesh.cpp:765
auto weld_vertices(float tolerance=0.000001f, std::vector< uint32_t > *vertex_remap_ptr=nullptr) -> bool
Welds the vertices together that can be combined.
Definition mesh.cpp:2258
auto bind_armature(std::unique_ptr< armature_node > &root) -> bool
Binds the armature tree.
Definition mesh.cpp:715
auto get_armature() const -> const std::unique_ptr< armature_node > &
Retrieves the armature tree of the mesh.
Definition mesh.cpp:1409
bool force_barycentric_generation_
Whether to disable the automatic re-sort operation.
Definition mesh.h:1036
skin_bind_data skin_bind_data_
List of unique combinations of bones to use during rendering.
Definition mesh.h:1084
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.
Definition mesh.cpp:832
preparation_data preparation_data_
Data describing how the mesh should be bound as a skin with supplied bone matrices.
Definition mesh.h:1081
auto get_skin_bind_data() const -> const skin_bind_data &
Retrieves the skin bind data if this mesh has been bound as a skin.
Definition mesh.cpp:1399
std::vector< size_t > submesh_array_indices_t
Definition mesh.h:364
auto prepare_mesh(const gfx::vertex_layout &vertex_format) -> bool
Prepares the mesh with the specified vertex format.
Definition mesh.cpp:188
auto set_bounding_box(const math::bbox &box) -> bool
Definition mesh.cpp:297
~mesh()
Destructor.
Definition mesh.cpp:119
mesh()
Constructs a mesh object.
Definition mesh.cpp:115
uint32_t * system_ib_
Material and data group information for each triangle.
Definition mesh.h:1045
std::vector< bone_palette > bone_palette_array_t
Definition mesh.h:363
std::vector< submesh * > submesh_array_t
Definition mesh.h:362
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.
Definition mesh.cpp:3092
auto get_data_groups_count() const -> size_t
Gets the number of data groups(materials) for this mesh.
Definition mesh.cpp:1517
auto get_submesh(uint32_t submesh_index=0) const -> const mesh::submesh &
Definition mesh.cpp:1453
auto get_submeshes() const -> const submesh_array_t &
Retrieves information about the submesh of the mesh associated with the specified data group identifi...
Definition mesh.cpp:1443
void build_ib(bool hardware_copy=true)
Builds the internal index buffer.
Definition mesh.cpp:1104
std::vector< triangle > triangle_array_t
Definition mesh.h:361
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.
Definition mesh.cpp:900
mesh_status prepare_status_
Input data used for constructing the final mesh.
Definition mesh.h:1079
auto get_skinned_submeshes_count() const -> size_t
Definition mesh.cpp:1473
auto get_face_count() const -> uint32_t
Determines the number of faces stored in the mesh.
Definition mesh.cpp:1356
submesh_key_array_t triangle_data_
The actual hardware vertex buffer resource.
Definition mesh.h:1047
auto get_system_vb() -> uint8_t *
Retrieves the underlying vertex data from the mesh.
Definition mesh.cpp:1384
Structure describing how a skinned mesh should be bound to any bones that influence its vertices.
Definition mesh.h:45
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.
Definition mesh.cpp:2425
void remap_vertices(const std::vector< uint32_t > &remap)
Remaps the vertex references stored in the binding based on the supplied remap array.
Definition mesh.cpp:2394
auto get_bones() const -> const bone_influence_array_t &
Retrieves a list of all bones that influence the skin in some way.
Definition mesh.cpp:2474
std::vector< vertex_data > vertex_data_array_t
Definition mesh.h:87
auto find_bone_by_id(const std::string &id) const -> bone_query
Finds a bone by its unique identifier.
Definition mesh.cpp:2489
void clear()
Clears out the bone information stored in this object.
Definition mesh.cpp:2389
auto has_bones() const -> bool
Checks whether the skin data has any bones.
Definition mesh.cpp:2484
void remove_empty_bones()
Removes any bones that do not contain any influences.
Definition mesh.cpp:2364
std::vector< vertex_influence > vertex_influence_array_t
Definition mesh.h:57
void clear_vertex_influences()
Releases memory allocated for vertex influences in each stored bone.
Definition mesh.cpp:2381
void add_bone(const bone_influence &bone)
Adds influence information for a specific bone.
Definition mesh.cpp:2359
rect< std::int32_t > irect32_t
std::string name
Definition hub.cpp:27
#define APPLOG_ERROR(...)
Definition logging.h:20
int count(const generator_t &generator) noexcept
Counts the number of steps left in the generator.
Definition utils.hpp:70
void alloc_transient_index_buffer(transient_index_buffer *_tib, uint32_t _num, bool _index32)
Definition graphics.cpp:413
void alloc_transient_vertex_buffer(transient_vertex_buffer *_tvb, uint32_t _num, const vertex_layout &_decl)
Definition graphics.cpp:418
void vertex_convert(const vertex_layout &_destDecl, void *_destData, const vertex_layout &_srcDecl, const void *_srcData, uint32_t _num)
Definition graphics.cpp:207
bgfx::VertexLayout vertex_layout
Definition vertex_decl.h:8
uint32_t get_avail_transient_index_buffer(uint32_t _num, bool _index32)
Definition graphics.cpp:398
bgfx::Attrib::Enum attribute
Definition vertex_decl.h:9
const memory_view * make_ref(const void *_data, uint32_t _size, release_fn _releaseFn, void *_userData)
Definition graphics.cpp:306
bgfx::TransientVertexBuffer transient_vertex_buffer
Definition graphics.h:54
void vertex_pack(const float _input[4], bool _inputNormalized, attribute _attr, const vertex_layout &_decl, void *_data, uint32_t _index)
Definition graphics.cpp:192
bgfx::TransientIndexBuffer transient_index_buffer
Definition graphics.h:55
void set_vertex_buffer(uint8_t _stream, vertex_buffer_handle _handle)
Definition graphics.cpp:838
auto get_max_blend_transforms() -> uint32_t
void set_index_buffer(index_buffer_handle _handle)
Definition graphics.cpp:808
uint32_t get_avail_transient_vertex_buffer(uint32_t _num, const vertex_layout &_decl)
Definition graphics.cpp:403
bgfx::Memory memory_view
Definition graphics.h:23
void vertex_unpack(float _output[4], attribute _attr, const vertex_layout &_decl, const void *_data, uint32_t _index)
Definition graphics.cpp:202
Definition bbox.cpp:5
mesh_status
Definition mesh.h:27
auto operator<(const mesh::adjacent_edge_key &key1, const mesh::adjacent_edge_key &key2) -> bool
Definition mesh.cpp:1536
@ sphere
Sphere type reflection probe.
@ box
Box type reflection probe.
mesh_create_origin
Definition mesh.h:34
Storage for box vector values and wraps up common functionality.
Definition bbox.h:21
bbox & add_point(const vec3 &point)
Grows the bounding box based on the point passed.
Definition bbox.cpp:924
void reset()
Resets the bounding box values.
Definition bbox.cpp:28
bbox & mul(const transform &t)
Transforms an axis aligned bounding box by the specified matrix.
Definition bbox.cpp:876
std::int32_t value_type
size< T1 > size() const
const math::vec3 * vertex2
Definition mesh.h:908
const math::vec3 * vertex1
< Pointer to the first vertex in the edge.
Definition mesh.h:906
bone_palette::bone_index_map_t bones
< List of unique bones that influence a given number of faces.
Definition mesh.h:933
Struct used for mesh construction.
Definition mesh.h:388
uint32_t data_group_id
< The data group identifier for this submesh.
Definition mesh.h:914
float triangle_score
< The sum of all three child vertex scores.
Definition mesh.h:898
uint32_t unused_triangle_references
List of all triangles referencing this vertex.
Definition mesh.h:890
std::vector< uint32_t > triangle_references
Definition mesh.h:892
int32_t cache_position
< The position of the vertex in the pseudo-cache.
Definition mesh.h:886
float vertex_score
Total number of triangles that reference this vertex that have not yet been added.
Definition mesh.h:888
bool owns_source
The format of the vertex data currently being used to prepare the mesh.
Definition mesh.h:851
uint32_t vertex_count
Prepared substs information.
Definition mesh.h:865
std::vector< uint32_t > vertex_records
Final vertex buffer currently being prepared.
Definition mesh.h:855
uint32_t triangle_count
Total number of vertices currently stored.
Definition mesh.h:863
bool compute_binormals
Whether to compute vertex tangents.
Definition mesh.h:871
triangle_array_t triangle_data
Total number of triangles currently stored.
Definition mesh.h:861
gfx::vertex_layout source_format
Records the location in the vertex buffer that each vertex has been placed during data insertion.
Definition mesh.h:853
bool compute_normals
Whether to compute vertex binormals.
Definition mesh.h:869
uint8_t * vertex_source
Whether the source data is owned by this object.
Definition mesh.h:849
bool compute_tangents
Whether to compute vertex barycentric coordinates.
Definition mesh.h:873
std::vector< submesh > submeshes
Whether to compute vertex normals.
Definition mesh.h:867
byte_array_t vertex_data
Additional descriptive information about the vertices.
Definition mesh.h:857
byte_array_t vertex_flags
Stores the current face/triangle data.
Definition mesh.h:859
Structure describing an individual "piece" of the mesh, often grouped by material,...
Definition mesh.h:317
uint32_t vertex_count
The initial face, from the index buffer, to render in this batch.
Definition mesh.h:323
int32_t vertex_start
Number of vertices included in this batch.
Definition mesh.h:321
int32_t face_start
Number of faces to render in this batch.
Definition mesh.h:325
uint32_t face_count
Definition mesh.h:327
uint32_t data_group_id
< The unique user assigned "data group" that can be used to separate submeshes.
Definition mesh.h:319
Structure describing data for a single triangle in the mesh.
Definition mesh.h:352
std::array< uint32_t, 3 > indices
Flags for this triangle.
Definition mesh.h:356
uint32_t data_group_id
< Data group identifier for this triangle.
Definition mesh.h:354
Describes the vertices that are connected to the referenced bone and how much influence it has on the...
Definition mesh.h:63
Contains per-vertex influence and weight information.
Definition mesh.h:77
int32_t palette
The index of the original vertex.
Definition mesh.h:83
Describes how a bone influences a specific vertex.
Definition mesh.h:51