Skip to main content

drew_sim/
engine.rs

1//! Moteur de rendu haut niveau : alloue la zone de dessin, gère la caméra,
2//! dessine le sol/la grille, puis délègue le dessin de la scène à l'appelant.
3
4use crate::camera::OrbitCamera;
5use crate::render::Render3D;
6use eframe::egui;
7
8/// Options d'apparence de la grille au sol.
9#[derive(Clone, Copy, Debug)]
10pub struct GridStyle {
11    pub line_color: egui::Color32,
12    pub ground_color: egui::Color32,
13    pub background_color: egui::Color32,
14    pub step_px: f32,
15    pub half_lines: i32,
16}
17
18impl Default for GridStyle {
19    fn default() -> Self {
20        Self {
21            line_color: egui::Color32::from_rgb(40, 50, 70),
22            ground_color: egui::Color32::from_rgb(60, 70, 90),
23            background_color: egui::Color32::from_rgb(25, 28, 36),
24            step_px: 60.0,
25            half_lines: 10,
26        }
27    }
28}
29
30/// Moteur de rendu 3D : combine la caméra orbitale et l'affichage de la scène.
31pub struct Engine3D {
32    pub camera: OrbitCamera,
33    pub grid: GridStyle,
34}
35
36impl Default for Engine3D {
37    fn default() -> Self {
38        Self { camera: OrbitCamera::default(), grid: GridStyle::default() }
39    }
40}
41
42impl Engine3D {
43    /// Alloue la zone de rendu, met à jour la caméra selon l'entrée utilisateur,
44    /// dessine l'arrière-plan/la grille, puis appelle `draw_callback` avec le
45    /// contexte de rendu prêt à l'emploi pour dessiner la scène.
46    pub fn render<F>(&mut self, ui: &mut egui::Ui, draw_callback: F)
47    where
48        F: FnOnce(&Render3D),
49    {
50        let (rect, response) = ui.allocate_exact_size(ui.available_size(), egui::Sense::drag());
51        self.camera.handle_input(ui, &response);
52
53        let painter = ui.painter_at(rect);
54        painter.rect_filled(rect, 0.0, self.grid.background_color);
55
56        let center = rect.center() + self.camera.pan_offset;
57        let ground_y = center.y + (150.0 * self.camera.zoom);
58        let grid_step = self.grid.step_px * self.camera.zoom;
59
60        painter.line_segment(
61            [egui::pos2(rect.min.x, ground_y), egui::pos2(rect.max.x, ground_y)],
62            egui::Stroke::new(2.0, self.grid.ground_color),
63        );
64
65        for i in -self.grid.half_lines..=self.grid.half_lines {
66            let offset = i as f32 * grid_step + (self.camera.orbit.sin() * 40.0 * self.camera.zoom);
67            let start_x = center.x + offset;
68            if start_x >= rect.min.x && start_x <= rect.max.x {
69                painter.line_segment(
70                    [egui::pos2(start_x, ground_y), egui::pos2(start_x + (offset * 0.5), rect.max.y)],
71                    egui::Stroke::new(1.0, self.grid.line_color),
72                );
73            }
74        }
75
76        let render_ctx = Render3D {
77            painter: &painter,
78            center,
79            ground_y,
80            camera_orbit: self.camera.orbit,
81            zoom: self.camera.zoom,
82        };
83
84        draw_callback(&render_ctx);
85    }
86}