1use crate::camera::Camera3D;
2use crate::color::Color;
3use crate::renderer::{Renderer, SoftwareRenderer};
4use crate::scene::{Scene, Transform as SceneTransform};
5use crate::renderer::FrameBuffer;
6use crate::viewport::Viewport;
7
8pub struct Window {
14 pub viewport: Viewport,
15 renderer: SoftwareRenderer,
16 term_cols: usize,
17 term_rows: usize,
18}
19
20impl Window {
21 pub fn new(viewport: Viewport) -> Self {
22 Self {
23 viewport,
24 renderer: SoftwareRenderer::new(),
25 term_cols: 100,
26 term_rows: 40,
27 }
28 }
29
30 pub fn with_terminal_dimensions(mut self, cols: usize, rows: usize) -> Self {
31 self.term_cols = cols.max(10);
32 self.term_rows = rows.max(10);
33 self
34 }
35
36 pub fn render_scene(&mut self, scene: &Scene, camera: &Camera3D) -> FrameBuffer {
38 self.renderer.begin_frame(
39 self.viewport.width,
40 self.viewport.height,
41 self.viewport.clear_color,
42 );
43
44 for &root in scene.roots() {
45 self.render_node_recursive(scene, root, camera, &scene.node(root).transform, 1.0);
46 }
47
48 self.renderer.end_frame().clone()
49 }
50
51 fn render_node_recursive(
52 &mut self,
53 scene: &Scene,
54 node_id: usize,
55 camera: &Camera3D,
56 _parent_transform: &SceneTransform,
57 _dummy_depth: f32,
58 ) {
59 let node = scene.node(node_id);
60 if node.visible {
61 if let (Some(mesh), Some(material)) = (node.mesh.as_ref(), node.material.as_ref()) {
62 let global = scene.global_transform(node_id);
63 let _ = global;
64 self.renderer.draw_mesh(mesh, &node.transform, material, camera);
65 }
66 let children: Vec<usize> = node.children.clone();
68 let transform = node.transform.clone();
69 for child in children {
70 self.render_node_recursive(scene, child, camera, &transform, _dummy_depth);
71 }
72 }
73 }
74
75 pub fn present_terminal(&mut self) {
77 let fb = self.renderer.end_frame().clone();
80 self.present_framebuffer_ascii(&fb);
81 }
82
83 fn present_framebuffer_ascii(&self, fb: &FrameBuffer) {
84 let mut out = String::new();
85 out.push_str("\x1b[2J\x1b[H");
86
87 let w = fb.width as usize;
88 let h = fb.height as usize;
89 let step_x = (w / self.term_cols).max(1);
90 let step_y = (h / self.term_rows).max(1);
91
92 let chars = b" .:-=+*#%@";
94
95 for y in (0..h).step_by(step_y) {
96 for x in (0..w).step_by(step_x) {
97 let i = (y * w + x) * 4;
98 let r = fb.pixels[i] as f32 / 255.0;
99 let g = fb.pixels[i + 1] as f32 / 255.0;
100 let b = fb.pixels[i + 2] as f32 / 255.0;
101 let lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
102 let idx = ((lum.clamp(0.0, 1.0)) * ((chars.len() - 1) as f32)) as usize;
103 out.push(chars[idx] as char);
104 }
105 out.push('\n');
106 }
107
108 print!("{}", out);
109 }
110
111 pub fn run(
113 &mut self,
114 mut scene: Scene,
115 mut camera: Camera3D,
116 mut tick: impl FnMut(u64, &mut Scene, &mut Camera3D),
117 max_frames: u64,
118 ) {
119 for frame in 0..max_frames {
120 tick(frame, &mut scene, &mut camera);
121
122 let fb = self.render_scene(&scene, &camera);
126 self.present_framebuffer_ascii(&fb);
127 }
128 }
129}