Skip to main content

proof_engine/scene/
query.rs

1//! Scene query types and helpers.
2
3use crate::glyph::GlyphId;
4use glam::Vec3;
5
6/// Result of a raycast against scene geometry.
7#[derive(Debug, Clone)]
8pub struct RaycastHit {
9    pub glyph_id: GlyphId,
10    pub distance: f32,
11    pub point:    Vec3,
12    pub normal:   Vec3,
13}
14
15/// Parameters for a sphere overlap query.
16#[derive(Debug, Clone)]
17pub struct SphereQuery {
18    pub center: Vec3,
19    pub radius: f32,
20    pub mask:   u32,
21}
22
23/// Parameters for a frustum culling query.
24#[derive(Debug, Clone)]
25pub struct FrustumQuery {
26    /// 6 frustum planes (normal, distance).
27    pub planes: [(Vec3, f32); 6],
28}
29
30impl FrustumQuery {
31    /// Test if an AABB is inside (or overlapping) the frustum.
32    pub fn contains_aabb(&self, min: Vec3, max: Vec3) -> bool {
33        for (normal, d) in &self.planes {
34            // Find the positive vertex (furthest along normal)
35            let p = Vec3::new(
36                if normal.x >= 0.0 { max.x } else { min.x },
37                if normal.y >= 0.0 { max.y } else { min.y },
38                if normal.z >= 0.0 { max.z } else { min.z },
39            );
40            if normal.dot(p) + d < 0.0 { return false; }
41        }
42        true
43    }
44
45    /// Test if a sphere is inside or overlapping the frustum.
46    pub fn contains_sphere(&self, center: Vec3, radius: f32) -> bool {
47        for (normal, d) in &self.planes {
48            if normal.dot(center) + d < -radius { return false; }
49        }
50        true
51    }
52}
53
54/// High-level query interface that wraps scene state.
55pub struct SceneQuery;
56
57impl SceneQuery {
58    /// Build a perspective frustum query from a view-projection matrix.
59    pub fn frustum_from_vp(vp: &glam::Mat4) -> FrustumQuery {
60        let cols = vp.to_cols_array_2d();
61        // Gribb-Hartmann frustum plane extraction
62        let planes = [
63            // Left
64            (Vec3::new(cols[0][3] + cols[0][0], cols[1][3] + cols[1][0], cols[2][3] + cols[2][0]),
65             cols[3][3] + cols[3][0]),
66            // Right
67            (Vec3::new(cols[0][3] - cols[0][0], cols[1][3] - cols[1][0], cols[2][3] - cols[2][0]),
68             cols[3][3] - cols[3][0]),
69            // Bottom
70            (Vec3::new(cols[0][3] + cols[0][1], cols[1][3] + cols[1][1], cols[2][3] + cols[2][1]),
71             cols[3][3] + cols[3][1]),
72            // Top
73            (Vec3::new(cols[0][3] - cols[0][1], cols[1][3] - cols[1][1], cols[2][3] - cols[2][1]),
74             cols[3][3] - cols[3][1]),
75            // Near
76            (Vec3::new(cols[0][3] + cols[0][2], cols[1][3] + cols[1][2], cols[2][3] + cols[2][2]),
77             cols[3][3] + cols[3][2]),
78            // Far
79            (Vec3::new(cols[0][3] - cols[0][2], cols[1][3] - cols[1][2], cols[2][3] - cols[2][2]),
80             cols[3][3] - cols[3][2]),
81        ];
82        FrustumQuery { planes }
83    }
84}