1use std::f32::consts;
2
3use embedded_graphics_core::pixelcolor::Rgb565;
4use embedded_graphics_core::pixelcolor::RgbColor;
5use mesh::K3dMesh;
6use mesh::RenderMode;
7use nalgebra::Isometry3;
8use nalgebra::Matrix4;
9use nalgebra::Perspective3;
10use nalgebra::Point2;
11use nalgebra::Point3;
12use nalgebra::Similarity3;
13use nalgebra::UnitQuaternion;
14use nalgebra::Vector3;
15
16pub mod draw;
17pub mod framebuffer;
18pub mod mesh;
19pub mod perfcounter;
20
21#[derive(Debug)]
22pub enum DrawPrimitive {
23 ColoredPoint(Point2<i32>, Rgb565),
24 Line(Point2<i32>, Point2<i32>, Rgb565),
25 ColoredTriangle(Point2<i32>, Point2<i32>, Point2<i32>, Rgb565),
26}
27
28pub struct K3dCamera {
29 pub position: Point3<f32>,
30 fov: f32,
31 near: f32,
32 far: f32,
33 pub view_matrix: nalgebra::Matrix4<f32>,
34 projection_matrix: nalgebra::Matrix4<f32>,
35 vp_matrix: nalgebra::Matrix4<f32>,
36 target: Point3<f32>,
37 aspect_ratio: f32,
38}
39
40impl K3dCamera {
41 pub fn new(aspect_ratio: f32) -> K3dCamera {
42 let mut ret = K3dCamera {
43 position: Point3::new(0.0, 0.0, 0.0),
44 fov: consts::PI / 2.0,
45 view_matrix: nalgebra::Matrix4::identity(),
46 projection_matrix: nalgebra::Matrix4::identity(),
47 vp_matrix: nalgebra::Matrix4::identity(),
48 target: Point3::new(0.0, 0.0, 0.0),
49 aspect_ratio,
50 near: 0.4,
51 far: 20.0,
52 };
53
54 ret.update_projection();
55
56 ret
57 }
58
59 pub fn set_position(&mut self, pos: Point3<f32>) {
60 self.position = pos;
61
62 self.update_view();
63 }
64
65 pub fn set_fovy(&mut self, fovy: f32) {
66 self.fov = fovy;
67
68 self.update_projection();
69 }
70
71 pub fn set_target(&mut self, target: Point3<f32>) {
72 self.target = target;
73 self.update_view();
74 }
75
76 pub fn get_direction(&self) -> Vector3<f32> {
77 let transpose = self.view_matrix; Vector3::new(transpose[(2, 0)], transpose[(2, 1)], transpose[(2, 2)])
86 }
87
88 fn update_view(&mut self) {
96 let view = Isometry3::look_at_rh(&self.position, &self.target, &Vector3::y());
97
98 self.view_matrix = view.to_homogeneous();
99 self.vp_matrix = self.projection_matrix * self.view_matrix;
100 }
101
102 fn update_projection(&mut self) {
103 let projection = Perspective3::new(self.aspect_ratio, self.fov, self.near, self.far);
104 self.projection_matrix = projection.to_homogeneous();
105 self.vp_matrix = self.projection_matrix * self.view_matrix;
106 }
107}
108
109pub struct K3dengine {
110 pub camera: K3dCamera,
111 width: u16,
112 height: u16,
113}
114
115impl K3dengine {
116 pub fn new(width: u16, height: u16) -> K3dengine {
117 K3dengine {
118 camera: K3dCamera::new(width as f32 / height as f32),
119 width,
120 height,
121 }
122 }
123
124 fn transform_point(
125 &self,
126 point: &(f32, f32, f32),
127 model_matrix: Matrix4<f32>,
128 ) -> Option<Point3<i32>> {
129 let point = nalgebra::Vector4::new(point.0, point.1, point.2, 1.0);
130 let point = model_matrix * point;
131
132 if point.w < 0.0 {
133 return None;
134 }
135 if point.z < self.camera.near || point.z > self.camera.far {
136 return None;
137 }
138
139 let point = Point3::from_homogeneous(point)?;
140
141 Some(Point3::new(
142 ((1.0 + point.x) * 0.5 * self.width as f32) as i32,
143 ((1.0 - point.y) * 0.5 * self.height as f32) as i32,
144 (point.z * (self.camera.far - self.camera.near) + self.camera.near) as i32,
145 ))
146 }
147
148 pub fn render<'a, MS, F>(&self, meshes: MS, mut callback: F)
149 where
150 MS: IntoIterator<Item = &'a K3dMesh<'a>>,
151 F: FnMut(DrawPrimitive),
152 {
153 for mesh in meshes {
154 if mesh.geometry.vertices.is_empty() {
155 continue;
156 }
157
158 let transform_matrix = self.camera.vp_matrix * mesh.model_matrix;
159 let screen_space_points = mesh
160 .geometry
161 .vertices
162 .iter()
163 .filter_map(|v| self.transform_point(v, transform_matrix));
164
165 match mesh.render_mode {
166 RenderMode::Points
167 if mesh.geometry.colors.len() == mesh.geometry.vertices.len() =>
168 {
169 for (point, color) in screen_space_points.zip(mesh.geometry.colors) {
170 callback(DrawPrimitive::ColoredPoint(point.xy(), *color));
171 }
172 }
173
174 RenderMode::Points => {
175 for point in screen_space_points {
176 callback(DrawPrimitive::ColoredPoint(point.xy(), mesh.color));
177 }
178 }
179
180 RenderMode::Lines if !mesh.geometry.lines.is_empty() => {
181 for line in mesh.geometry.lines {
182 let p1 =
183 self.transform_point(&mesh.geometry.vertices[line.0], transform_matrix);
184 let p2 =
185 self.transform_point(&mesh.geometry.vertices[line.1], transform_matrix);
186
187 if let (Some(p1), Some(p2)) = (p1, p2) {
188 callback(DrawPrimitive::Line(p1.xy(), p2.xy(), mesh.color));
189 }
190 }
191 }
192
193 RenderMode::Lines if !mesh.geometry.faces.is_empty() => {
194 for face in mesh.geometry.faces {
195 let p1 =
196 self.transform_point(&mesh.geometry.vertices[face.0], transform_matrix);
197 let p2 =
198 self.transform_point(&mesh.geometry.vertices[face.1], transform_matrix);
199 let p3 =
200 self.transform_point(&mesh.geometry.vertices[face.2], transform_matrix);
201
202 if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
203 callback(DrawPrimitive::Line(p1.xy(), p2.xy(), mesh.color));
204 callback(DrawPrimitive::Line(p2.xy(), p3.xy(), mesh.color));
205 callback(DrawPrimitive::Line(p3.xy(), p1.xy(), mesh.color));
206 }
207 }
208 }
209
210 RenderMode::Lines => {}
211
212 RenderMode::SolidLightDir(direction) => {
213 for (face, normal) in mesh.geometry.faces.iter().zip(mesh.geometry.normals) {
214 let normal = Vector3::new(normal.0, normal.1, normal.2);
216
217 let transformed_normal = mesh.model_matrix.transform_vector(&normal);
218
219 if self.camera.get_direction().dot(&transformed_normal) < 0.0 {
220 continue;
221 }
222
223 let p1 =
224 self.transform_point(&mesh.geometry.vertices[face.0], transform_matrix);
225 let p2 =
226 self.transform_point(&mesh.geometry.vertices[face.1], transform_matrix);
227 let p3 =
228 self.transform_point(&mesh.geometry.vertices[face.2], transform_matrix);
229
230 if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
231 let color_as_float = Vector3::new(
232 mesh.color.r() as f32 / 32.0,
233 mesh.color.g() as f32 / 64.0,
234 mesh.color.b() as f32 / 32.0,
235 );
236
237 let mut final_color = Vector3::new(0.0f32, 0.0, 0.0);
238
239 let intensity = transformed_normal.dot(&direction);
240
241 let intensity = intensity.max(0.0);
242
243 final_color += color_as_float * intensity + color_as_float * 0.4;
244
245 let final_color = Vector3::new(
246 final_color.x.min(1.0).max(0.0),
247 final_color.y.min(1.0).max(0.0),
248 final_color.z.min(1.0).max(0.0),
249 );
250
251 let color = Rgb565::new(
252 (final_color.x * 31.0) as u8,
253 (final_color.y * 63.0) as u8,
254 (final_color.z * 31.0) as u8,
255 );
256 callback(DrawPrimitive::ColoredTriangle(
257 p1.xy(),
258 p2.xy(),
259 p3.xy(),
260 color,
261 ));
262 }
263 }
264 }
265
266 RenderMode::Solid => {
267 if mesh.geometry.normals.is_empty() {
268 for face in mesh.geometry.faces.iter() {
269 let p1 = self
270 .transform_point(&mesh.geometry.vertices[face.0], transform_matrix);
271 let p2 = self
272 .transform_point(&mesh.geometry.vertices[face.1], transform_matrix);
273 let p3 = self
274 .transform_point(&mesh.geometry.vertices[face.2], transform_matrix);
275
276 if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
277 callback(DrawPrimitive::ColoredTriangle(
278 p1.xy(),
279 p2.xy(),
280 p3.xy(),
281 mesh.color,
282 ));
283 }
284 }
285 } else {
286 for (face, normal) in mesh.geometry.faces.iter().zip(mesh.geometry.normals)
287 {
288 let normal = Vector3::new(normal.0, normal.1, normal.2);
290
291 let transformed_normal = mesh.model_matrix.transform_vector(&normal);
292
293 if self.camera.get_direction().dot(&transformed_normal) < 0.0 {
294 continue;
295 }
296
297 let p1 = self
298 .transform_point(&mesh.geometry.vertices[face.0], transform_matrix);
299 let p2 = self
300 .transform_point(&mesh.geometry.vertices[face.1], transform_matrix);
301 let p3 = self
302 .transform_point(&mesh.geometry.vertices[face.2], transform_matrix);
303
304 if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
305 callback(DrawPrimitive::ColoredTriangle(
306 p1.xy(),
307 p2.xy(),
308 p3.xy(),
309 mesh.color,
310 ));
311 }
312 }
313 }
314 }
315 }
316 }
317 }
318}