Line data Source code
1 : #pragma once
2 : #include <cstdint>
3 : #include <cmath>
4 : #include <limits>
5 : #include <math3d/math3d.hpp>
6 : #include "rbc/AABB.hpp"
7 :
8 : namespace rbc
9 : {
10 : // ── HeightmapData ─────────────────────────────────────────────────────────
11 : // Owns (or references) a row-major grid of height samples.
12 : // Vertex world position at grid index (row, col):
13 : // pos.x = origin.x + col * scale.x
14 : // pos.y = heights[row * cols + col] * scale.y
15 : // pos.z = origin.z + row * scale.z
16 : //
17 : // Two triangles per cell (row,col) → (row+1,col+1):
18 : // tri0: (r,c), (r,c+1), (r+1,c)
19 : // tri1: (r,c+1), (r+1,c+1), (r+1,c)
20 : struct HeightmapData
21 : {
22 : const float *heights; // [rows × cols] height samples (Y before scale)
23 : uint32_t rows;
24 : uint32_t cols;
25 : m3d::vec3 scale; // (cell_size_x, height_scale, cell_size_z)
26 : m3d::vec3 origin; // world position of the (0,0) vertex
27 : m3d::scalar min_height; // precomputed: min(heights)*scale.y + origin.y
28 : m3d::scalar max_height; // precomputed: max(heights)*scale.y + origin.y
29 : };
30 :
31 : // ── Heightmap shape ───────────────────────────────────────────────────────
32 : // Holds a POINTER — HeightmapData must outlive the Heightmap.
33 : // The transform tf is intentionally ignored for heightmap queries;
34 : // world position is baked into HeightmapData::origin.
35 : struct Heightmap
36 : {
37 : const HeightmapData *data; // non-owning pointer
38 :
39 : Heightmap() : data(nullptr) {}
40 : explicit Heightmap(const HeightmapData *data) : data(data) {}
41 :
42 : inline bool operator==(const Heightmap &o) const { return data == o.data; }
43 : inline bool operator!=(const Heightmap &o) const { return data != o.data; }
44 : };
45 :
46 : // ── Construction helper ───────────────────────────────────────────────────
47 : // Creates a HeightmapData on the heap and precomputes min/max height.
48 : // Caller owns the returned pointer and must call heightmap_data_destroy().
49 : inline HeightmapData *heightmap_data_create(const float *heights,
50 : uint32_t rows,
51 : uint32_t cols,
52 : const m3d::vec3 &scale,
53 : const m3d::vec3 &origin)
54 : {
55 : auto *hd = new HeightmapData;
56 : hd->heights = heights;
57 : hd->rows = rows;
58 : hd->cols = cols;
59 : hd->scale = scale;
60 : hd->origin = origin;
61 :
62 : float mn = std::numeric_limits<float>::max();
63 : float mx = std::numeric_limits<float>::lowest();
64 : const uint32_t n = rows * cols;
65 : for (uint32_t i = 0; i < n; ++i)
66 : {
67 : mn = std::min(mn, heights[i]);
68 : mx = std::max(mx, heights[i]);
69 : }
70 : hd->min_height = static_cast<m3d::scalar>(mn) * scale.y + origin.y;
71 : hd->max_height = static_cast<m3d::scalar>(mx) * scale.y + origin.y;
72 : return hd;
73 : }
74 :
75 : inline void heightmap_data_destroy(HeightmapData *hd) { delete hd; }
76 :
77 : // ── World position of a grid vertex ──────────────────────────────────────
78 : inline m3d::vec3 heightmap_vertex(const HeightmapData &hd, uint32_t row, uint32_t col)
79 : {
80 : return m3d::vec3(
81 : hd.origin.x + static_cast<m3d::scalar>(col) * hd.scale.x,
82 : static_cast<m3d::scalar>(hd.heights[row * hd.cols + col]) * hd.scale.y + hd.origin.y,
83 : hd.origin.z + static_cast<m3d::scalar>(row) * hd.scale.z);
84 : }
85 :
86 : // ── Support (not meaningful for GJK — use analytic collisions) ───────────
87 0 : inline m3d::vec3 support(const Heightmap & /*h*/, const m3d::vec3 & /*dir*/)
88 : {
89 0 : return m3d::vec3(0.0, 0.0, 0.0); // placeholder; not used directly
90 : }
91 :
92 : // ── AABB from precomputed min/max height ──────────────────────────────────
93 0 : inline AABB compute_aabb(const Heightmap &h, const m3d::tf & /*tf*/)
94 : {
95 0 : if (!h.data)
96 0 : return AABB{};
97 0 : const HeightmapData &hd = *h.data;
98 : return {
99 0 : m3d::vec3(hd.origin.x,
100 0 : hd.min_height,
101 0 : hd.origin.z),
102 0 : m3d::vec3(hd.origin.x + static_cast<m3d::scalar>(hd.cols - 1) * hd.scale.x,
103 0 : hd.max_height,
104 0 : hd.origin.z + static_cast<m3d::scalar>(hd.rows - 1) * hd.scale.z)};
105 : }
106 : } // namespace rbc
|