LCOV - code coverage report
Current view: top level - rbc/shapes - Mesh.hpp (source / functions) Coverage Total Hit
Test: coverage_clean.info Lines: 0.0 % 23 0
Test Date: 2026-03-30 03:13:12 Functions: 0.0 % 2 0

            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
        

Generated by: LCOV version 2.0-1