use ferrix::{DotProduct, Matrix, Vector3};
use std::f64::consts::PI;
const WIDTH: usize = 80;
const HEIGHT: usize = 30;
const R1: f64 = 1.0; const R2: f64 = 2.0; const K1_X: f64 = 37.5;
const K1_Y: f64 = 18.75;
const K2: f64 = 5.0;
const THETA_SPACING: f64 = 0.07;
const PHI_SPACING: f64 = 0.02;
fn render_frame(theta_a: f64, theta_b: f64) {
let mut output = Matrix::<char, HEIGHT, WIDTH>::fill(' ');
let mut zbuffer = Matrix::<f64, HEIGHT, WIDTH>::fill(0.0);
let rot_a = Matrix::rotx(theta_a);
let rot_b = Matrix::rotz(theta_b);
let mut theta = 0.0;
while theta < (2.0 * PI) {
let sin_theta = theta.sin();
let cos_theta = theta.cos();
let mut phi = 0.0;
while phi < (2.0 * PI) {
let rot_phi = Matrix::roty(phi);
let circle = Vector3::from([cos_theta, sin_theta, 0.0]) * R1;
let circle = circle + Vector3::from([R2, 0.0, 0.0]);
let point = &rot_b * &rot_a * &rot_phi * &circle;
let ooz = 1.0 / (point[2] + K2);
let xp: usize = ((WIDTH as f64 / 2.0) + (point[0] * ooz * K1_X)) as usize;
let yp: usize = ((HEIGHT as f64 / 2.0) - (point[1] * ooz * K1_Y)) as usize;
let n_point = Vector3::from([cos_theta, sin_theta, 0.0]);
let normal = &rot_b * &rot_a * &rot_phi * &n_point;
let luminance: f64 = Vector3::from([0.0, 1.0, -1.0]).dot(&normal);
if luminance > 0.0 {
if ooz > zbuffer[(yp, xp)] {
zbuffer[(yp, xp)] = ooz;
let l_index = (luminance * 8.0) as usize;
output[(yp, xp)] = ".,-~:;=!*#$@".chars().nth(l_index).unwrap();
}
}
phi += PHI_SPACING;
}
theta += THETA_SPACING;
}
println!("\x1b[H");
for row in 0..HEIGHT {
for col in 0..WIDTH {
print!("{}", output[(row, col)]);
}
print!("\n");
}
}
fn main() {
let mut m_a = 1.0;
let mut m_b = 1.0;
loop {
render_frame(m_a, m_b);
m_a = (m_a + 0.07) % (2.0 * PI);
m_b = (m_b + 0.03) % (2.0 * PI);
}
}