1use std::io::{self, Write};
2
3use crate::{
4 utils::{
5 cube_utils::Color,
6 geometry::{Point2D, Point3D, Triangle}
7 },
8 cube::{
9 slice::FaceSlice,
10 cube::Face
11 }
12};
13
14pub const SCREEN_X: usize = 320;
15pub const SCREEN_Y: usize = 320;
16
17const SCREEN_X_OFFSET: isize = (SCREEN_X / 2) as isize;
18const SCREEN_Y_OFFSET: isize = (SCREEN_Y / 2) as isize;
19
20const PRINT_CHAR: &str = "██";
21const ANSI_RESET: &str = "\x1b[0m";
22
23pub enum AnyFace {
24 Face(Face),
25 FaceSlice(FaceSlice),
26}
27
28impl AnyFace {
29 pub fn avg_z(&self) -> f32 {
30 match self {
31 AnyFace::Face(f) => f.avg_z(),
32 AnyFace::FaceSlice(fs) => fs.avg_z(),
33 }
34 }
35}
36
37pub trait Renderable {
38 fn get_visible_faces(&self) -> Vec<AnyFace>;
39
40 fn dist(&self) -> f32;
41}
42
43pub struct Screen {
44 screen: Box<[[Option<Color>; SCREEN_X]; SCREEN_Y]>,
45 zp: f32,
46 projection_scale: f32,
47}
48
49impl Screen {
50 pub fn new(zp: f32, projection_scale: f32) -> Screen {
51 Screen {
52 screen: Box::new([[None; SCREEN_X]; SCREEN_Y]),
53 zp,
54 projection_scale
55 }
56 }
57
58 pub fn color_at(&self, x: i16, y: i16) -> Option<Color> {
59 self.screen[SCREEN_Y - y as usize - 1][x as usize]
60 }
61
62 fn project_point(&self, p: Point3D) -> Point2D {
63 let multiplier = self.zp / p.z;
64 let xp = p.x * multiplier;
65 let yp = p.y * multiplier;
66
67 let x_proj = (xp * self.projection_scale) as isize + SCREEN_X_OFFSET;
68 let y_proj = (yp * self.projection_scale) as isize + SCREEN_Y_OFFSET;
69
70 Point2D {x: x_proj, y: y_proj}
71 }
72
73 fn rasterize_triangle(&mut self, triangle: Triangle, color: Color) {
74 let Triangle(a, b, c) = triangle;
75 let min_x = a.x.min(b.x.min(c.x)).max(0);
76 let max_x = a.x.max(b.x.max(c.x)).min(SCREEN_X as isize - 1);
77 let min_y = a.y.min(b.y.min(c.y)).max(0);
78 let max_y = a.y.max(b.y.max(c.y)).min(SCREEN_Y as isize - 1);
79
80 for y in min_y..=max_y {
81 for x in min_x..=max_x {
82 let p = Point2D {x, y};
83 if triangle.point_in_triangle(p) {
84 self.screen[y as usize][x as usize] = Some(color);
85 }
86 }
87 }
88 }
89
90 fn render_face(&mut self, face: &Face) {
91 let projected_markers: Vec<Point2D> = face.markers
92 .iter()
93 .map(|&p| self.project_point(p))
94 .collect();
95
96 for row in 0..3 {
97 for col in 0..3 {
98 let tris = [
99 Triangle(projected_markers.get(row * 4 + col).unwrap().clone(),
100 projected_markers.get(row * 4 + col + 1).unwrap().clone(),
101 projected_markers.get((row + 1) * 4 + col + 1).unwrap().clone()
102 ),
103 Triangle(projected_markers.get(row * 4 + col).unwrap().clone(),
104 projected_markers.get((row + 1) * 4 + col + 1).unwrap().clone(),
105 projected_markers.get((row + 1) * 4 + col).unwrap().clone()
106 ),
107 ];
108 let color = face.grid_face.grid[row][col];
109 for tri in tris {
110 self.rasterize_triangle(tri, color);
111 }
112 }
113 }
114 }
115
116 fn render_face_slice(&mut self, face_slice: &FaceSlice) {
117 let projected_markers: Vec<Point2D> = face_slice.markers
118 .iter()
119 .map(|&p| self.project_point(p))
120 .collect();
121
122 for row in 0..3 {
123 let tris = [
124 Triangle(projected_markers.get(row * 2).unwrap().clone(),
125 projected_markers.get(row * 2 + 1).unwrap().clone(),
126 projected_markers.get((row + 1) * 2 + 1).unwrap().clone()
127 ),
128 Triangle(projected_markers.get(row * 2).unwrap().clone(),
129 projected_markers.get((row + 1) * 2 + 1).unwrap().clone(),
130 projected_markers.get((row + 1) * 2).unwrap().clone()
131 ),
132 ];
133 let color = face_slice.colors[row];
134 for tri in tris {
135 self.rasterize_triangle(tri, color);
136 }
137 }
138 }
139
140 pub fn render(&mut self, mut renderables: Vec<&dyn Renderable>) {
141 renderables.sort_by(|a, b| a.dist().partial_cmp(&b.dist()).unwrap());
142
143 for renderable in renderables.into_iter().rev() {
144 let faces = renderable.get_visible_faces();
145 for face in faces.into_iter().take(3).rev() {
146 match face {
147 AnyFace::Face(f) => self.render_face(&f),
148 AnyFace::FaceSlice(fs) => self.render_face_slice(&fs),
149 };
150 }
151 }
152 }
153
154 pub fn print_screen(&self) {
155 for y in (0..(SCREEN_Y)).rev() {
156 for x in 0..(SCREEN_X) {
157 match self.screen[y][x] {
158 Some(color) => print!("{}{}{}", color.to_ansi(), PRINT_CHAR, ANSI_RESET),
159 _ => print!(" ")
160 };
161 }
162 println!();
163 }
164 io::stdout().flush().unwrap();
165 }
166
167 pub fn reset_terminal() {
168 print!("{esc}c", esc = 27 as char);
169 io::stdout().flush().unwrap();
170 }
171
172 pub fn clear_screen(&mut self) {
173 for row in self.screen.iter_mut() {
174 for cell in row.iter_mut() {
175 *cell = None;
176 }
177 }
178 }
179}