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
14const PRINT_CHAR: &str = "██";
15const ANSI_RESET: &str = "\x1b[0m";
16
17pub enum AnyFace {
18 Face(Face),
19 FaceSlice(FaceSlice),
20}
21
22impl AnyFace {
23 pub fn avg_z(&self) -> f32 {
24 match self {
25 AnyFace::Face(f) => f.avg_z(),
26 AnyFace::FaceSlice(fs) => fs.avg_z(),
27 }
28 }
29}
30
31pub trait Renderable {
32 fn get_visible_faces(&self) -> Vec<AnyFace>;
33
34 fn dist(&self) -> f32;
35}
36
37pub struct Screen {
38 size_x: usize,
39 size_y: usize,
40 screen: Vec<Vec<Option<Color>>>,
41 zp: f32,
42 projection_scale: f32,
43}
44
45impl Screen {
46 pub fn new(size_x: usize, size_y: usize, zp: f32, projection_scale: f32) -> Screen {
47 Screen {
48 size_x,
49 size_y,
50 screen: vec![vec![None; size_x]; size_y],
51 zp,
52 projection_scale,
53 }
54 }
55
56 pub fn color_at(&self, x: i16, y: i16) -> Option<Color> {
57 self.screen[self.size_y - y as usize - 1][x as usize]
58 }
59
60 fn project_point(&self, p: Point3D) -> Point2D {
61 let screen_x_offset = (self.size_x / 2) as isize;
62 let screen_y_offset = (self.size_y / 2) as isize;
63
64 let multiplier = self.zp / p.z;
65 let xp = p.x * multiplier;
66 let yp = p.y * multiplier;
67
68 let x_proj = (xp * self.projection_scale) as isize + screen_x_offset;
69 let y_proj = (yp * self.projection_scale) as isize + screen_y_offset;
70
71 Point2D {x: x_proj, y: y_proj}
72 }
73
74 fn rasterize_triangle(&mut self, tri: Triangle, color: Color) {
76 let mut pts = [tri.0, tri.1, tri.2];
77 pts.sort_by_key(|p| p.y);
79
80 let (v1, v2, v3) = (pts[0], pts[1], pts[2]);
81
82 let inv_slope_1 = if v2.y != v1.y {
84 (v2.x - v1.x) as f32 / (v2.y - v1.y) as f32
85 } else { 0.0 };
86
87 let inv_slope_2 = if v3.y != v1.y {
88 (v3.x - v1.x) as f32 / (v3.y - v1.y) as f32
89 } else { 0.0 };
90
91 let inv_slope_3 = if v3.y != v2.y {
92 (v3.x - v2.x) as f32 / (v3.y - v2.y) as f32
93 } else { 0.0 };
94
95 let mut curx1 = v1.x as f32;
97 let mut curx2 = v1.x as f32;
98 for y in v1.y..=v2.y {
99 if y >= 0 && y < self.size_y as isize {
100 let x_start = curx1.min(curx2).max(0.0) as isize;
101 let x_end = curx1.max(curx2).min(self.size_x as f32 - 1.0) as isize;
102 for x in x_start..=x_end {
103 self.screen[y as usize][x as usize] = Some(color);
104 }
105 }
106 curx1 += inv_slope_1;
107 curx2 += inv_slope_2;
108 }
109
110 let mut curx1 = v2.x as f32;
112 let mut curx2 = v1.x as f32 + inv_slope_2 * (v2.y - v1.y) as f32;
113 for y in v2.y..=v3.y {
114 if y >= 0 && y < self.size_y as isize {
115 let x_start = curx1.min(curx2).max(0.0) as isize;
116 let x_end = curx1.max(curx2).min(self.size_x as f32 - 1.0) as isize;
117 for x in x_start..=x_end {
118 self.screen[y as usize][x as usize] = Some(color);
119 }
120 }
121 curx1 += inv_slope_3;
122 curx2 += inv_slope_2;
123 }
124 }
125
126
127 fn render_face(&mut self, face: &Face) {
128 let projected_markers: Vec<Point2D> = face.markers
129 .iter()
130 .map(|&p| self.project_point(p))
131 .collect();
132
133 for row in 0..3 {
134 for col in 0..3 {
135 let tris = [
136 Triangle(projected_markers.get(row * 4 + col).unwrap().clone(),
137 projected_markers.get(row * 4 + col + 1).unwrap().clone(),
138 projected_markers.get((row + 1) * 4 + col + 1).unwrap().clone()
139 ),
140 Triangle(projected_markers.get(row * 4 + col).unwrap().clone(),
141 projected_markers.get((row + 1) * 4 + col + 1).unwrap().clone(),
142 projected_markers.get((row + 1) * 4 + col).unwrap().clone()
143 ),
144 ];
145 let color = face.grid_face.grid[row][col];
146 for tri in tris {
147 self.rasterize_triangle(tri, color);
148 }
149 }
150 }
151 }
152
153 fn render_face_slice(&mut self, face_slice: &FaceSlice) {
154 let projected_markers: Vec<Point2D> = face_slice.markers
155 .iter()
156 .map(|&p| self.project_point(p))
157 .collect();
158
159 for row in 0..3 {
160 let tris = [
161 Triangle(projected_markers.get(row * 2).unwrap().clone(),
162 projected_markers.get(row * 2 + 1).unwrap().clone(),
163 projected_markers.get((row + 1) * 2 + 1).unwrap().clone()
164 ),
165 Triangle(projected_markers.get(row * 2).unwrap().clone(),
166 projected_markers.get((row + 1) * 2 + 1).unwrap().clone(),
167 projected_markers.get((row + 1) * 2).unwrap().clone()
168 ),
169 ];
170 let color = face_slice.colors[row];
171 for tri in tris {
172 self.rasterize_triangle(tri, color);
173 }
174 }
175 }
176
177 pub fn render(&mut self, mut renderables: Vec<&dyn Renderable>) {
178 renderables.sort_by(|a, b| a.dist().partial_cmp(&b.dist()).unwrap());
179
180 for renderable in renderables.into_iter().rev() {
181 let faces = renderable.get_visible_faces();
182 for face in faces.into_iter().take(3).rev() {
183 match face {
184 AnyFace::Face(f) => self.render_face(&f),
185 AnyFace::FaceSlice(fs) => self.render_face_slice(&fs),
186 };
187 }
188 }
189 }
190
191 pub fn print_screen(&self) {
192 for y in (0..(self.size_y)).rev() {
193 for x in 0..(self.size_x) {
194 match self.screen[y][x] {
195 Some(color) => print!("{}{}{}", color.to_ansi(), PRINT_CHAR, ANSI_RESET),
196 _ => print!(" ")
197 };
198 }
199 println!();
200 }
201 io::stdout().flush().unwrap();
202 }
203
204 pub fn reset_terminal() {
205 print!("{esc}c", esc = 27 as char);
206 io::stdout().flush().unwrap();
207 }
208
209 pub fn clear_screen(&mut self) {
210 for row in self.screen.iter_mut() {
211 for cell in row.iter_mut() {
212 *cell = None;
213 }
214 }
215 }
216}