172 lines
4.5 KiB
Rust

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::<Vec<_>>();
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<Item = (Tri3, V3, Color)> {
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
}
}