Some triangle testing

This commit is contained in:
Ryan Kennedy 2020-03-28 15:34:29 -05:00
parent 225416353f
commit 6ba531a957
6 changed files with 86 additions and 29 deletions

View file

@ -16,15 +16,15 @@ impl<T: SignedNum> Bresenham<T> {
let start = octant.to(start); let start = octant.to(start);
let end = octant.to(end); let end = octant.to(end);
let delta_x = end.0 - start.0; let delta_x = end.x - start.x;
let delta_y = end.1 - start.1; let delta_y = end.y - start.y;
Self { Self {
delta_x, delta_x,
delta_y, delta_y,
octant, octant,
point: start, point: start,
end_x: end.0, end_x: end.x,
error: delta_y - delta_x, error: delta_y - delta_x,
} }
} }
@ -38,15 +38,15 @@ where
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.point.0 <= self.end_x { if self.point.x <= self.end_x {
let point = self.octant.from(self.point); let point = self.octant.from(self.point);
if self.error >= T::zero() { if self.error >= T::zero() {
self.point.1 += T::one(); self.point.y += T::one();
self.error -= self.delta_x; self.error -= self.delta_x;
} }
self.point.0 += T::one(); self.point.x += T::one();
self.error += self.delta_y; self.error += self.delta_y;
Some(point) Some(point)

41
src/drawing/device.rs Normal file
View file

@ -0,0 +1,41 @@
use super::Point;
use crate::writers::{GraphicsWriter, Screen};
use core::cmp::{max, min};
pub trait Device<Color>
where
Self: Screen + GraphicsWriter<Color>,
Color: Clone + Copy,
{
fn draw_triangle(&self, v0: &Point<i32>, v1: &Point<i32>, v2: &Point<i32>, color: Color) {
let screen_width = self.get_width() as i32;
let screen_height = self.get_height() as i32;
let mut min_x = min(v0.x, min(v1.x, v2.x));
let mut min_y = min(v0.y, min(v1.y, v2.y));
let mut max_x = max(v0.x, max(v1.x, v2.x));
let mut max_y = max(v0.y, max(v1.y, v2.y));
min_x = max(min_x, 0);
min_y = max(min_y, 0);
max_x = min(max_x, screen_width - 1);
max_y = min(max_y, screen_height - 1);
for x in min_x..=max_x {
for y in min_y..=max_y {
let p = Point::new(x, y);
let w0 = orient2d(v1, v2, &p);
let w1 = orient2d(v2, v0, &p);
let w2 = orient2d(&v0, &v1, &p);
if w0 >= 0 && w1 >= 0 && w2 >= 0 {
self.set_pixel(x as usize, y as usize, color);
}
}
}
}
}
#[inline]
fn orient2d(a: &Point<i32>, b: &Point<i32>, c: &Point<i32>) -> i32 {
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
}

View file

@ -3,13 +3,25 @@
use num_traits::{NumAssignOps, NumCast, Signed}; use num_traits::{NumAssignOps, NumCast, Signed};
mod bresenham; mod bresenham;
mod device;
mod octant; mod octant;
pub(crate) use bresenham::Bresenham; pub(crate) use bresenham::Bresenham;
pub use device::Device;
use octant::Octant; use octant::Octant;
/// A point in 2D space. /// A point in 2D space.
pub type Point<T> = (T, T); #[derive(Copy, Clone)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T> Point<T> {
pub fn new(x: T, y: T) -> Point<T> {
Point { x, y }
}
}
pub(crate) trait SignedNum: Signed + Ord + Copy + NumCast + NumAssignOps { pub(crate) trait SignedNum: Signed + Ord + Copy + NumCast + NumAssignOps {
fn cast<T: NumCast>(value: T) -> Self { fn cast<T: NumCast>(value: T) -> Self {

View file

@ -15,8 +15,8 @@ impl Octant {
T: Sub<Output = T> + Neg<Output = T> + PartialOrd + Zero, T: Sub<Output = T> + Neg<Output = T> + PartialOrd + Zero,
{ {
let mut value = 0; let mut value = 0;
let mut dx = end.0 - start.0; let mut dx = end.x - start.x;
let mut dy = end.1 - start.1; let mut dy = end.y - start.y;
if dy < T::zero() { if dy < T::zero() {
dx = -dx; dx = -dx;
@ -45,14 +45,14 @@ impl Octant {
T: Neg<Output = T>, T: Neg<Output = T>,
{ {
match self.value { match self.value {
0 => (point.0, point.1), 0 => Point::new(point.x, point.y),
1 => (point.1, point.0), 1 => Point::new(point.y, point.x),
2 => (point.1, -point.0), 2 => Point::new(point.y, -point.x),
3 => (-point.0, point.1), 3 => Point::new(-point.x, point.y),
4 => (-point.0, -point.1), 4 => Point::new(-point.x, -point.y),
5 => (-point.1, -point.0), 5 => Point::new(-point.y, -point.x),
6 => (-point.1, point.0), 6 => Point::new(-point.y, point.x),
7 => (point.0, -point.1), 7 => Point::new(point.x, -point.y),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -61,14 +61,14 @@ impl Octant {
#[inline] #[inline]
pub fn from<T: Neg<Output = T>>(&self, point: Point<T>) -> Point<T> { pub fn from<T: Neg<Output = T>>(&self, point: Point<T>) -> Point<T> {
match self.value { match self.value {
0 => (point.0, point.1), 0 => Point::new(point.x, point.y),
1 => (point.1, point.0), 1 => Point::new(point.y, point.x),
2 => (-point.1, point.0), 2 => Point::new(-point.y, point.x),
3 => (-point.0, point.1), 3 => Point::new(-point.x, point.y),
4 => (-point.0, -point.1), 4 => Point::new(-point.x, -point.y),
5 => (-point.1, -point.0), 5 => Point::new(-point.y, -point.x),
6 => (point.1, -point.0), 6 => Point::new(point.y, -point.x),
7 => (point.0, -point.1), 7 => Point::new(point.x, -point.y),
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -1,7 +1,7 @@
use super::{GraphicsWriter, Screen}; use super::{GraphicsWriter, Screen};
use crate::{ use crate::{
colors::DEFAULT_PALETTE, colors::DEFAULT_PALETTE,
drawing::{Bresenham, Point}, drawing::{Bresenham, Device, Point},
vga::{Vga, VideoMode, VGA}, vga::{Vga, VideoMode, VGA},
}; };
use font8x8::UnicodeFonts; use font8x8::UnicodeFonts;
@ -53,6 +53,8 @@ impl Screen for Graphics320x200x256 {
} }
} }
impl Device<u8> for Graphics320x200x256 {}
impl GraphicsWriter<u8> for Graphics320x200x256 { impl GraphicsWriter<u8> for Graphics320x200x256 {
fn clear_screen(&self, color: u8) { fn clear_screen(&self, color: u8) {
for x in 0..WIDTH { for x in 0..WIDTH {
@ -62,7 +64,7 @@ impl GraphicsWriter<u8> for Graphics320x200x256 {
} }
} }
fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: u8) { fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: u8) {
for (x, y) in Bresenham::new(start, end) { for Point { x, y } in Bresenham::new(start, end) {
self.set_pixel(x as usize, y as usize, color); self.set_pixel(x as usize, y as usize, color);
} }
} }

View file

@ -1,7 +1,7 @@
use super::{GraphicsWriter, Screen}; use super::{GraphicsWriter, Screen};
use crate::{ use crate::{
colors::{Color16, DEFAULT_PALETTE}, colors::{Color16, DEFAULT_PALETTE},
drawing::{Bresenham, Point}, drawing::{Bresenham, Device, Point},
registers::{PlaneMask, WriteMode}, registers::{PlaneMask, WriteMode},
vga::{Vga, VideoMode, VGA}, vga::{Vga, VideoMode, VGA},
}; };
@ -51,6 +51,8 @@ impl Screen for Graphics640x480x16 {
} }
} }
impl Device<Color16> for Graphics640x480x16 {}
impl GraphicsWriter<Color16> for Graphics640x480x16 { impl GraphicsWriter<Color16> for Graphics640x480x16 {
fn clear_screen(&self, color: Color16) { fn clear_screen(&self, color: Color16) {
self.set_write_mode_2(); self.set_write_mode_2();
@ -64,7 +66,7 @@ impl GraphicsWriter<Color16> for Graphics640x480x16 {
fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: Color16) { fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: Color16) {
self.set_write_mode_0(color); self.set_write_mode_0(color);
for (x, y) in Bresenham::new(start, end) { for Point { x, y } in Bresenham::new(start, end) {
self._set_pixel(x as usize, y as usize, color); self._set_pixel(x as usize, y as usize, color);
} }
} }