1extern crate nalgebra as na;
2
3use na::{Vector2, Matrix2};
4use crate::triangle::Triangle;
5
6const EPS: f32 = 5e-3;
7
8fn edge_function(a: &Vector2<f32>, b: &Vector2<f32>, p: &Vector2<f32>) -> f32 {
14 let b_p = p-b;
15 let b_a = a-b;
16 let mat = Matrix2::<f32>::from_rows(&[b_p.transpose(),b_a.transpose()]);
17 mat.determinant()
18}
19
20pub fn pixel_within_triangle_and_barycentric(triangle: &Triangle<2>, p: &Vector2<f32>) -> (f32,f32,f32,bool) {
24 let area = edge_function(&triangle.get_v0(),&triangle.get_v1(),&triangle.get_v2());
25 let f = match area > 0.0 {
26 true => 1.0,
27 false => -1.0
28 };
29
30 let w2 = edge_function(&triangle.get_v0(),&triangle.get_v1(),p)*f/area;
31 let w0 = edge_function(&triangle.get_v1(),&triangle.get_v2(),p)*f/area;
32 let w1 = edge_function(&triangle.get_v2(),&triangle.get_v0(),p)*f/area;
33
34 let inside = w2 >= -EPS && w0 >= -EPS && w1 >= -EPS;
35
36 (w0,w1,w2,inside)
37}
38
39pub fn calc_all_pixels_within_triangle(triangle: &Triangle<2>) -> Vec<(f32,f32,f32,Vector2<f32>)> {
44 let (min, max) = triangle.calculate_boudning_box();
45 let min_x_f = min.x.floor() as usize;
46 let min_y_f = min.y.floor() as usize;
47 let max_x_f = max.x.ceil() as usize;
48 let max_y_f = max.y.ceil() as usize;
49
50 let y_range = min_y_f..max_y_f;
51
52 y_range.map(|y| {
53 let x_range = min_x_f..max_x_f;
54 let y_c = y as f32 + 0.5f32;
55 x_range.map(move |x| {
56 let x_c = x as f32 + 0.5f32;
57 Vector2::new(x_c,y_c)
58 })
59 }).flatten()
60 .map(|p| (pixel_within_triangle_and_barycentric(&triangle,&p),p))
61 .filter(|&((_,_,_,inside),_)| inside)
62 .map(|((w0,w1,w2,_),p)| (w0,w1,w2,p)).collect()
63}
64
65pub fn calc_inv_z_for_all_pixels(barycentric_pixels: &Vec<(f32,f32,f32)>, triangle3d: &Triangle<3>) -> Vec<f32> {
69 barycentric_pixels.iter().map(|(w0,w1,w2)| {
70 let inv_z = (w0 / triangle3d.get_v0().z) + (w1 / triangle3d.get_v1().z) + (w2 / triangle3d.get_v2().z);
71 inv_z
72 }).collect()
73}