move triangle stuff into module
This commit is contained in:
parent
20325e6a75
commit
7a4b11e2da
2 changed files with 144 additions and 137 deletions
140
src/main.rs
140
src/main.rs
|
@ -1,11 +1,6 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate justerror;
|
extern crate justerror;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use rand::Rng;
|
|
||||||
use rayon::prelude::*;
|
|
||||||
|
|
||||||
mod tga;
|
mod tga;
|
||||||
use tga::*;
|
use tga::*;
|
||||||
|
|
||||||
|
@ -13,7 +8,9 @@ mod point;
|
||||||
use point::*;
|
use point::*;
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
use model::*;
|
|
||||||
|
mod triangle;
|
||||||
|
use triangle::*;
|
||||||
|
|
||||||
const BLACK: TGAColor = TGAColor { bgra: [0u8; 4] };
|
const BLACK: TGAColor = TGAColor { bgra: [0u8; 4] };
|
||||||
|
|
||||||
|
@ -75,137 +72,6 @@ fn line(mut a: Point2i, mut b: Point2i, color: TGAColor, mut fb: &mut TGAImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
struct Triangle2i {
|
|
||||||
a: Point2i,
|
|
||||||
b: Point2i,
|
|
||||||
c: Point2i,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Triangle2i {
|
|
||||||
pub fn new(a: Point2i, b: Point2i, c: Point2i) -> Self {
|
|
||||||
Self { a, b, c }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signed_area(&self) -> f32 {
|
|
||||||
0.5 * ((self.b.y - self.a.y) * (self.a.x + self.b.x)
|
|
||||||
+ (self.c.y - self.b.y) * (self.c.x + self.b.x)
|
|
||||||
+ (self.a.y - self.c.y) * (self.a.x + self.c.x)) as f32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bb(&self) -> AABB {
|
|
||||||
let xmax = self.a.x.max(self.b.x.max(self.c.x));
|
|
||||||
let xmin = self.a.x.min(self.b.x.min(self.c.x));
|
|
||||||
|
|
||||||
let ymax = self.a.y.max(self.b.y.max(self.c.y));
|
|
||||||
let ymin = self.a.y.min(self.b.y.min(self.c.y));
|
|
||||||
AABB {
|
|
||||||
lower_left: Point2i::new(xmin, ymin),
|
|
||||||
upper_right: Point2i::new(xmax, ymax),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_filled(&self, color: TGAColor, fb: &mut TGAImage) {
|
|
||||||
let fb = Arc::new(Mutex::new(fb));
|
|
||||||
let bb = self.bb();
|
|
||||||
let total_area = self.signed_area();
|
|
||||||
if total_area < 1.0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let it = 1.0 / total_area;
|
|
||||||
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
|
||||||
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
|
||||||
let p = Point2i::new(x, y);
|
|
||||||
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
|
||||||
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
|
||||||
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
|
||||||
|
|
||||||
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
|
||||||
let color = if let Some(ca) = self.a.color
|
|
||||||
&& let Some(cb) = self.b.color
|
|
||||||
&& let Some(cc) = self.c.color
|
|
||||||
{
|
|
||||||
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
|
||||||
} else {
|
|
||||||
color
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(mut fb) = fb.lock() {
|
|
||||||
fb.set(x as u32, y as u32, color);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_lines(&self, thickness: i32, color: TGAColor, fb: &mut TGAImage) {
|
|
||||||
let fb = Arc::new(Mutex::new(fb));
|
|
||||||
let bb = self.bb();
|
|
||||||
let total_area = self.signed_area();
|
|
||||||
if total_area < 1.0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let it = 1.0 / total_area;
|
|
||||||
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
|
||||||
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
|
||||||
let p = Point2i::new(x, y);
|
|
||||||
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
|
||||||
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
|
||||||
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
|
||||||
|
|
||||||
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
|
||||||
let ad = ((self.b.y - self.a.y) * x - (self.b.x - self.a.x) * y
|
|
||||||
+ self.b.x * self.a.y
|
|
||||||
- self.b.y * self.a.x)
|
|
||||||
.abs()
|
|
||||||
/ ((self.b.y - self.a.y).pow(2) + (self.b.x - self.a.x).pow(2)).isqrt();
|
|
||||||
let bd = ((self.c.y - self.b.y) * x - (self.c.x - self.b.x) * y
|
|
||||||
+ self.c.x * self.b.y
|
|
||||||
- self.c.y * self.b.x)
|
|
||||||
.abs()
|
|
||||||
/ ((self.c.y - self.b.y).pow(2) + (self.c.x - self.b.x).pow(2)).isqrt();
|
|
||||||
let cd = ((self.a.y - self.c.y) * x - (self.a.x - self.c.x) * y
|
|
||||||
+ self.a.x * self.c.y
|
|
||||||
- self.a.y * self.c.x)
|
|
||||||
.abs()
|
|
||||||
/ ((self.a.y - self.c.y).pow(2) + (self.a.x - self.c.x).pow(2)).isqrt();
|
|
||||||
|
|
||||||
if ad <= thickness || bd <= thickness || cd <= thickness {
|
|
||||||
let color = if let Some(ca) = self.a.color
|
|
||||||
&& let Some(cb) = self.b.color
|
|
||||||
&& let Some(cc) = self.c.color
|
|
||||||
{
|
|
||||||
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
|
||||||
} else {
|
|
||||||
color
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(mut fb) = fb.lock() {
|
|
||||||
fb.set(x as u32, y as u32, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn centroid(&self) -> Point2i {
|
|
||||||
let x = self.a.x / 3 + self.b.x / 3 + self.c.x / 3;
|
|
||||||
let y = self.a.y / 3 + self.b.y / 3 + self.c.y / 3;
|
|
||||||
let has_color = self.a.color.is_some() || self.b.color.is_some() || self.c.color.is_some();
|
|
||||||
let denom = 1.0 / 3.0;
|
|
||||||
let color = if has_color {
|
|
||||||
let c = self.a.color.unwrap_or(BLACK) * denom
|
|
||||||
+ self.b.color.unwrap_or(BLACK) * denom
|
|
||||||
+ self.c.color.unwrap_or(BLACK) * denom;
|
|
||||||
Some(c)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Point2i { x, y, color }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
struct AABB {
|
struct AABB {
|
||||||
lower_left: Point2i,
|
lower_left: Point2i,
|
||||||
|
|
141
src/triangle.rs
Normal file
141
src/triangle.rs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
AABB, BLACK,
|
||||||
|
point::Point2i,
|
||||||
|
tga::{TGAColor, TGAImage},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Triangle2i {
|
||||||
|
a: Point2i,
|
||||||
|
b: Point2i,
|
||||||
|
c: Point2i,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Triangle2i {
|
||||||
|
pub fn new(a: Point2i, b: Point2i, c: Point2i) -> Self {
|
||||||
|
Self { a, b, c }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_area(&self) -> f32 {
|
||||||
|
0.5 * ((self.b.y - self.a.y) * (self.a.x + self.b.x)
|
||||||
|
+ (self.c.y - self.b.y) * (self.c.x + self.b.x)
|
||||||
|
+ (self.a.y - self.c.y) * (self.a.x + self.c.x)) as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bb(&self) -> AABB {
|
||||||
|
let xmax = self.a.x.max(self.b.x.max(self.c.x));
|
||||||
|
let xmin = self.a.x.min(self.b.x.min(self.c.x));
|
||||||
|
|
||||||
|
let ymax = self.a.y.max(self.b.y.max(self.c.y));
|
||||||
|
let ymin = self.a.y.min(self.b.y.min(self.c.y));
|
||||||
|
AABB {
|
||||||
|
lower_left: Point2i::new(xmin, ymin),
|
||||||
|
upper_right: Point2i::new(xmax, ymax),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_filled(&self, color: TGAColor, fb: &mut TGAImage) {
|
||||||
|
let fb = Arc::new(Mutex::new(fb));
|
||||||
|
let bb = self.bb();
|
||||||
|
let total_area = self.signed_area();
|
||||||
|
if total_area < 1.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let it = 1.0 / total_area;
|
||||||
|
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
||||||
|
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
||||||
|
let p = Point2i::new(x, y);
|
||||||
|
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
||||||
|
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
||||||
|
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
||||||
|
|
||||||
|
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
||||||
|
let color = if let Some(ca) = self.a.color
|
||||||
|
&& let Some(cb) = self.b.color
|
||||||
|
&& let Some(cc) = self.c.color
|
||||||
|
{
|
||||||
|
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
||||||
|
} else {
|
||||||
|
color
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut fb) = fb.lock() {
|
||||||
|
fb.set(x as u32, y as u32, color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_lines(&self, thickness: i32, color: TGAColor, fb: &mut TGAImage) {
|
||||||
|
let fb = Arc::new(Mutex::new(fb));
|
||||||
|
let bb = self.bb();
|
||||||
|
let total_area = self.signed_area();
|
||||||
|
if total_area < 1.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let it = 1.0 / total_area;
|
||||||
|
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
||||||
|
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
||||||
|
let p = Point2i::new(x, y);
|
||||||
|
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
||||||
|
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
||||||
|
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
||||||
|
|
||||||
|
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
||||||
|
// get the distance to the sides
|
||||||
|
let ad = ((self.b.y - self.a.y) * x - (self.b.x - self.a.x) * y
|
||||||
|
+ self.b.x * self.a.y
|
||||||
|
- self.b.y * self.a.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.b.y - self.a.y).pow(2) + (self.b.x - self.a.x).pow(2)).isqrt();
|
||||||
|
let bd = ((self.c.y - self.b.y) * x - (self.c.x - self.b.x) * y
|
||||||
|
+ self.c.x * self.b.y
|
||||||
|
- self.c.y * self.b.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.c.y - self.b.y).pow(2) + (self.c.x - self.b.x).pow(2)).isqrt();
|
||||||
|
let cd = ((self.a.y - self.c.y) * x - (self.a.x - self.c.x) * y
|
||||||
|
+ self.a.x * self.c.y
|
||||||
|
- self.a.y * self.c.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.a.y - self.c.y).pow(2) + (self.a.x - self.c.x).pow(2)).isqrt();
|
||||||
|
|
||||||
|
if ad <= thickness || bd <= thickness || cd <= thickness {
|
||||||
|
let color = if let Some(ca) = self.a.color
|
||||||
|
&& let Some(cb) = self.b.color
|
||||||
|
&& let Some(cc) = self.c.color
|
||||||
|
{
|
||||||
|
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
||||||
|
} else {
|
||||||
|
color
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut fb) = fb.lock() {
|
||||||
|
fb.set(x as u32, y as u32, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn centroid(&self) -> Point2i {
|
||||||
|
let x = self.a.x / 3 + self.b.x / 3 + self.c.x / 3;
|
||||||
|
let y = self.a.y / 3 + self.b.y / 3 + self.c.y / 3;
|
||||||
|
let has_color = self.a.color.is_some() || self.b.color.is_some() || self.c.color.is_some();
|
||||||
|
let denom = 1.0 / 3.0;
|
||||||
|
let color = if has_color {
|
||||||
|
let c = self.a.color.unwrap_or(BLACK) * denom
|
||||||
|
+ self.b.color.unwrap_or(BLACK) * denom
|
||||||
|
+ self.c.color.unwrap_or(BLACK) * denom;
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Point2i { x, y, color }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue