1use crate::camera::OrbitCamera;
5use crate::render::Render3D;
6use eframe::egui;
7
8#[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
30pub 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 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}