there's a missing scanline in the white triangle
This commit is contained in:
parent
6d335f43ea
commit
9047b0196b
3 changed files with 102 additions and 29 deletions
124
src/main.rs
124
src/main.rs
|
@ -2,6 +2,8 @@
|
|||
extern crate justerror;
|
||||
|
||||
mod tga;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rand::Rng;
|
||||
use tga::*;
|
||||
|
||||
|
@ -32,25 +34,39 @@ const YELLOW: TGAColor = TGAColor {
|
|||
};
|
||||
|
||||
fn main() {
|
||||
let w = 800;
|
||||
let h = 800;
|
||||
let mut framebuffer = TGAImage::new(w, h, TGAFormat::RGB);
|
||||
let model = Model::from_obj("diablo3_pose.obj");
|
||||
let w = 128;
|
||||
let h = 128;
|
||||
let mut fb = TGAImage::new(w, h, TGAFormat::RGB);
|
||||
fill_triangles(&mut fb);
|
||||
fb.write_file("triangles.tga", true, true).unwrap();
|
||||
}
|
||||
|
||||
dbg!(model.verts.len());
|
||||
let mut max_face = 0usize;
|
||||
let mut min_face = usize::MAX;
|
||||
fn fill_triangles(fb: &mut TGAImage) {
|
||||
/*
|
||||
triangle( 7, 45, 35, 100, 45, 60, framebuffer, red);
|
||||
triangle(120, 35, 90, 5, 45, 110, framebuffer, white);
|
||||
triangle(115, 83, 80, 90, 85, 120, framebuffer, green);
|
||||
*/
|
||||
|
||||
for f in model.faces.iter() {
|
||||
for &f in f.iter() {
|
||||
max_face = f.max(max_face);
|
||||
min_face = f.min(min_face);
|
||||
}
|
||||
}
|
||||
let t1a = Point2i::new(7, 45);
|
||||
let t1b = Point2i::new(35, 100);
|
||||
let t1c = Point2i::new(45, 60);
|
||||
triangle_filled(t1a, t1b, t1c, RED, fb);
|
||||
|
||||
model.render_wireframe(&mut framebuffer);
|
||||
let t2a = Point2i::new(120, 35);
|
||||
let t2b = Point2i::new(90, 5);
|
||||
let t2c = Point2i::new(45, 110);
|
||||
triangle_filled(t2a, t2b, t2c, WHITE, fb);
|
||||
|
||||
framebuffer.write_file("diablo.tga", true, true).unwrap();
|
||||
let a = Point2i::new(115, 83);
|
||||
let b = Point2i::new(80, 90);
|
||||
let c = Point2i::new(85, 120);
|
||||
triangle_filled(a, b, c, GREEN, fb);
|
||||
}
|
||||
|
||||
fn _render_diablo(model: Model, fb: &mut TGAImage) {
|
||||
model.render_wireframe(fb);
|
||||
fb.write_file("diablo.tga", true, true).unwrap();
|
||||
}
|
||||
|
||||
fn _baseline(framebuffer: &mut TGAImage) {
|
||||
|
@ -69,10 +85,10 @@ fn _baseline(framebuffer: &mut TGAImage) {
|
|||
let b = Point2i::newu(bx, by);
|
||||
let c = Point2i::newu(cx, cy);
|
||||
|
||||
line(a, b, framebuffer, BLUE);
|
||||
line(c, b, framebuffer, GREEN);
|
||||
line(c, a, framebuffer, YELLOW);
|
||||
line(a, c, framebuffer, RED);
|
||||
line(a, b, BLUE, framebuffer);
|
||||
line(c, b, GREEN, framebuffer);
|
||||
line(c, a, YELLOW, framebuffer);
|
||||
line(a, c, RED, framebuffer);
|
||||
}
|
||||
|
||||
fn _bench(fb: &mut TGAImage) {
|
||||
|
@ -90,13 +106,20 @@ fn _bench(fb: &mut TGAImage) {
|
|||
line(
|
||||
a,
|
||||
b,
|
||||
fb,
|
||||
[rng.random(), rng.random(), rng.random(), rng.random()].into(),
|
||||
fb,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn line(mut a: Point2i, mut b: Point2i, fb: &mut TGAImage, color: TGAColor) {
|
||||
fn line(a: Point2i, b: Point2i, color: TGAColor, fb: &mut TGAImage) {
|
||||
let verts = line_verts(a, b);
|
||||
for v in verts.into_iter() {
|
||||
fb.set(v.x as u32, v.y as u32, color);
|
||||
}
|
||||
}
|
||||
|
||||
fn line_verts(mut a: Point2i, mut b: Point2i) -> Vec<Point2i> {
|
||||
let is_steep = (a.x - b.x).abs() < (a.y - b.y).abs();
|
||||
if is_steep {
|
||||
std::mem::swap(&mut a.x, &mut a.y);
|
||||
|
@ -107,14 +130,63 @@ fn line(mut a: Point2i, mut b: Point2i, fb: &mut TGAImage, color: TGAColor) {
|
|||
std::mem::swap(&mut a.y, &mut b.y);
|
||||
}
|
||||
|
||||
let mut y = a.y as f32;
|
||||
let mut verts: Vec<Point2i> = Vec::new();
|
||||
|
||||
let step = (b.y - a.y) as f32 / (b.x - a.x) as f32;
|
||||
let sign = step.signum() as i32;
|
||||
let mut y = a.y as f32;
|
||||
for x in (a.x)..b.x {
|
||||
if is_steep {
|
||||
fb.set(y as u32, x as u32, color);
|
||||
let p = if is_steep {
|
||||
Point2i::new(y.round_ties_even() as i32, x)
|
||||
} else {
|
||||
fb.set(x as u32, y as u32, color);
|
||||
}
|
||||
Point2i::new(x, y.round_ties_even() as i32)
|
||||
};
|
||||
verts.push(p);
|
||||
y += step;
|
||||
}
|
||||
|
||||
verts
|
||||
}
|
||||
|
||||
fn triangle_lines(a: Point2i, b: Point2i, c: Point2i, color: TGAColor, fb: &mut TGAImage) {
|
||||
line(a, b, color, fb);
|
||||
line(b, c, color, fb);
|
||||
line(c, a, color, fb);
|
||||
}
|
||||
|
||||
fn triangle_filled(a: Point2i, b: Point2i, c: Point2i, color: TGAColor, fb: &mut TGAImage) {
|
||||
let mut verts = line_verts(a, b);
|
||||
verts.extend(line_verts(b, c));
|
||||
verts.extend(line_verts(c, a));
|
||||
|
||||
let mut lines: BTreeMap<i32, Vec<i32>> = BTreeMap::new();
|
||||
for vert in verts.into_iter() {
|
||||
lines
|
||||
.entry(vert.y)
|
||||
.and_modify(|e| {
|
||||
e.push(vert.x);
|
||||
e.sort_unstable();
|
||||
})
|
||||
.or_insert(vec![vert.x]);
|
||||
}
|
||||
|
||||
let mut prev_y: Option<i32> = None;
|
||||
for (y, xs) in lines.iter_mut() {
|
||||
let len = xs.len();
|
||||
match len {
|
||||
0 => {}
|
||||
1 => fb.set(xs[0] as u32, *y as u32, color),
|
||||
_ => {
|
||||
let start = xs[0];
|
||||
let end = xs[len - 1];
|
||||
line(Point2i::new(start, *y), Point2i::new(end, *y), color, fb);
|
||||
}
|
||||
}
|
||||
if let Some(prev) = prev_y {
|
||||
if (y - prev).abs() > 1 {
|
||||
dbg!(y);
|
||||
}
|
||||
}
|
||||
prev_y = Some(*y)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,9 +87,9 @@ impl Model {
|
|||
let a = world2view(self.verts[face[0]], width, height);
|
||||
let b = world2view(self.verts[face[1]], width, height);
|
||||
let c = world2view(self.verts[face[2]], width, height);
|
||||
line(a, b, framebuffer, RED);
|
||||
line(b, c, framebuffer, RED);
|
||||
line(c, a, framebuffer, RED);
|
||||
line(a, b, RED, framebuffer);
|
||||
line(b, c, RED, framebuffer);
|
||||
line(c, a, RED, framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ impl Point2i {
|
|||
pub fn new(x: i32, y: i32) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
pub fn newu(x: u32, y: u32) -> Self {
|
||||
Self {
|
||||
x: x as i32,
|
||||
|
|
Loading…
Reference in a new issue