Line data Source code
1 : #pragma once
2 : #include <cstdint>
3 : #include <math3d/math3d.hpp>
4 : #include "rbc/AABB.hpp"
5 :
6 : namespace rbc
7 : {
8 : // ── MeshData ──────────────────────────────────────────────────────────────
9 : // Triangle mesh in LOCAL space. The shape transform m3d::tf moves it into world.
10 : // Precomputed per-face normals are required for SAT-based collision.
11 : //
12 : // Memory layout:
13 : // vertices[i] — local-space vertex positions
14 : // indices[f*3 + {0,1,2}] — vertex indices of face f
15 : // face_normals[f] — unit normal of face f (consistent winding)
16 : struct MeshData
17 : {
18 : const m3d::vec3 *vertices;
19 : const uint32_t *indices;
20 : const m3d::vec3 *face_normals; // one per face, precomputed
21 : uint32_t vert_count;
22 : uint32_t face_count;
23 : AABB local_aabb; // precomputed local-space AABB
24 : };
25 :
26 : // ── Mesh shape ────────────────────────────────────────────────────────────
27 : // Non-owning pointer. MeshData must outlive the Mesh.
28 : struct Mesh
29 : {
30 : const MeshData *data;
31 :
32 : Mesh() : data(nullptr) {}
33 : explicit Mesh(const MeshData *data) : data(data) {}
34 :
35 : inline bool operator==(const Mesh &o) const { return data == o.data; }
36 : inline bool operator!=(const Mesh &o) const { return data != o.data; }
37 : };
38 :
39 : // ── Construction helper ───────────────────────────────────────────────────
40 : // Computes face normals and local AABB from raw arrays.
41 : // Assumes counter-clockwise winding (outward normals).
42 : // Caller owns the returned pointer; call mesh_data_destroy() to free.
43 : inline MeshData *mesh_data_create(const m3d::vec3 *vertices, uint32_t vert_count,
44 : const uint32_t *indices, uint32_t face_count)
45 : {
46 : auto *md = new MeshData;
47 : auto *norms = new m3d::vec3[face_count];
48 :
49 : md->vertices = vertices;
50 : md->indices = indices;
51 : md->face_normals = norms;
52 : md->vert_count = vert_count;
53 : md->face_count = face_count;
54 :
55 : // Compute face normals + local AABB
56 : m3d::vec3 mn(1e30f, 1e30f, 1e30f);
57 : m3d::vec3 mx(-1e30f, -1e30f, -1e30f);
58 :
59 : for (uint32_t f = 0; f < face_count; ++f)
60 : {
61 : const m3d::vec3 &A = vertices[indices[f * 3 + 0]];
62 : const m3d::vec3 &B = vertices[indices[f * 3 + 1]];
63 : const m3d::vec3 &C = vertices[indices[f * 3 + 2]];
64 : norms[f] = m3d::normalize(m3d::cross(B - A, C - A));
65 : }
66 :
67 : for (uint32_t v = 0; v < vert_count; ++v)
68 : {
69 : mn = m3d::vec3(m3d::min(mn.x, vertices[v].x),
70 : m3d::min(mn.y, vertices[v].y),
71 : m3d::min(mn.z, vertices[v].z));
72 : mx = m3d::vec3(m3d::max(mx.x, vertices[v].x),
73 : m3d::max(mx.y, vertices[v].y),
74 : m3d::max(mx.z, vertices[v].z));
75 : }
76 : md->local_aabb = {mn, mx};
77 : return md;
78 : }
79 :
80 : inline void mesh_data_destroy(MeshData *md)
81 : {
82 : delete[] md->face_normals;
83 : delete md;
84 : }
85 :
86 : // ── Support (convex-hull support — only valid for CONVEX meshes) ──────────
87 : // For concave meshes, use the per-triangle analytic collision in MeshCollision.hpp.
88 0 : inline m3d::vec3 support(const Mesh &m, const m3d::vec3 &dir)
89 : {
90 0 : if (!m.data || m.data->vert_count == 0)
91 0 : return m3d::vec3{};
92 0 : m3d::vec3 best = m.data->vertices[0];
93 0 : m3d::scalar best_d = m3d::dot(best, dir);
94 0 : for (uint32_t i = 1; i < m.data->vert_count; ++i)
95 : {
96 0 : const m3d::scalar d = m3d::dot(m.data->vertices[i], dir);
97 0 : if (d > best_d)
98 : {
99 0 : best_d = d;
100 0 : best = m.data->vertices[i];
101 : }
102 : }
103 0 : return best;
104 : }
105 :
106 : // ── AABB from precomputed local bounds + transform ────────────────────────
107 0 : inline AABB compute_aabb(const Mesh &m, const m3d::tf &tf)
108 : {
109 0 : if (!m.data)
110 0 : return AABB{};
111 : // Rotate local AABB into world space (conservative, same method as Box)
112 0 : const AABB &local = m.data->local_aabb;
113 0 : const m3d::vec3 centre = (local.min + local.max) * 0.5;
114 0 : const m3d::vec3 half = (local.max - local.min) * 0.5;
115 :
116 0 : const m3d::mat3 R = m3d::mat3_cast(tf.rot);
117 0 : const m3d::vec3 world_centre = tf.pos + tf.rotate_vector(centre);
118 : const m3d::vec3 extent(
119 0 : m3d::abs(R[0][0]) * half.x + m3d::abs(R[1][0]) * half.y + m3d::abs(R[2][0]) * half.z,
120 0 : m3d::abs(R[0][1]) * half.x + m3d::abs(R[1][1]) * half.y + m3d::abs(R[2][1]) * half.z,
121 0 : m3d::abs(R[0][2]) * half.x + m3d::abs(R[1][2]) * half.y + m3d::abs(R[2][2]) * half.z);
122 0 : return {world_centre - extent, world_centre + extent};
123 : }
124 : } // namespace rbc
|