use std::f64::consts::PI; use obj::Obj; use crate::{ m3x3::M3x3, quats::RadianQuat, tri2::Tri2, tri3::Tri3, v3::V3, window::{Color, Renderer}, }; pub struct Scene { tris: Vec<(Tri3, V3, Color)>, } impl Scene { pub fn new() -> Self { Self { tris: Vec::new() } } pub fn render( &self, r: &mut impl Renderer, camera_pos: V3, camera_rot: M3x3, screen_rel_pos: V3, ) { let mut indices_with_scores = self .tris .iter() .enumerate() .map(|(i, (tri, ..))| { let mut score = (camera_pos - tri.middle()).len(); (i, score) }) .rev() .collect::>(); indices_with_scores.sort_by(|a, b| b.1.total_cmp(&a.1)); for (i, _) in indices_with_scores { let (tri3, normal, color) = &self.tris[i]; // if !(tri3.0.2 >= -1.0 && tri3.1.2 >= -1.0 && tri3.2.2 >= -1.0) { // continue; // } if normal.dot(camera_pos - tri3.0) < 0.0 { continue; } let light = V3(1.0, 1.0, -1.0); let exposure = 1.5 - normal.angle(light) / PI; let (red, green, blue) = color.rgb(); let color = Color::RGB( (red as f64 * exposure).clamp(0.0, 255.0) as _, (green as f64 * exposure).clamp(0.0, 255.0) as _, (blue as f64 * exposure).clamp(0.0, 255.0) as _, ); let tri2 = tri3.project_2d(camera_pos, camera_rot, screen_rel_pos); r.draw_triangles(&[tri2], color); // r.draw_line(tri2.0, tri2.1, Color::BLACK); // r.draw_line(tri2.1, tri2.2, Color::BLACK); // r.draw_line(tri2.2, tri2.0, Color::BLACK); } } pub fn draw_model(&mut self, model: Model) { self.tris.extend(model.tris()); } pub fn draw_triangle(&mut self, tri: Tri3, color: Color) { self.tris.push((tri, tri.normal(), color)); } } pub struct Model { tris: Vec<(Tri3, V3, Color)>, } impl Model { pub fn new() -> Self { Self { tris: Vec::new() } } pub fn tris(&self) -> impl Iterator { self.tris.iter().copied() } pub fn translate(&mut self, offset: V3) -> &mut Self { for tri in &mut self.tris { tri.0 = tri.0.translate(offset); } self } pub fn rotate_by_m3x3(&mut self, rot: M3x3) -> &mut Self { for tri in &mut self.tris { tri.0 = tri.0.rotate_by_m3x3(rot); tri.1 = tri.1.rotate_by_m3x3(rot); } self } pub fn rotate_by_quat(&mut self, rot: RadianQuat) -> &mut Self { for tri in &mut self.tris { tri.0 = tri.0.rotate_by_quat(rot); tri.1 = tri.1.rotate_by_quat(rot); } self } pub fn scale(&mut self, scale: V3) -> &mut Self { for tri in &mut self.tris { tri.0 = tri.0.scale(scale); } self } pub fn add_tri(&mut self, tri: Tri3, color: Color) -> &mut Self { self.tris.push((tri, tri.normal(), color)); self } pub fn add_obj(&mut self, obj: &Obj, color: Color) -> &mut Self { // if our triangle definition convention is [0, 1, 2] // obj's is [2, 1, 0]. // // likewise, if our coordinate system is [x, y, z], // obj's is [x, z, y]. let count = obj.indices.len() / 3; for i in 0..count { let v2 = obj.vertices[obj.indices[i * 3] as usize]; let v1 = obj.vertices[obj.indices[i * 3 + 1] as usize]; let v0 = obj.vertices[obj.indices[i * 3 + 2] as usize]; let tri = Tri3( V3( v0.position[0] as _, v0.position[2] as _, v0.position[1] as _, ), V3( v1.position[0] as _, v1.position[2] as _, v1.position[1] as _, ), V3( v2.position[0] as _, v2.position[2] as _, v2.position[1] as _, ), ); let normal = V3(v0.normal[0] as _, v0.normal[2] as _, v0.normal[1] as _) + V3(v1.normal[0] as _, v1.normal[2] as _, v1.normal[1] as _) + V3(v2.normal[0] as _, v2.normal[2] as _, v2.normal[1] as _); self.tris.push((tri, normal, color)); } self } }