From 6ba531a957e98dc468fca2435ea4089c62370b1b Mon Sep 17 00:00:00 2001 From: Ryan Kennedy Date: Sat, 28 Mar 2020 15:34:29 -0500 Subject: [PATCH] Some triangle testing --- src/drawing/bresenham.rs | 12 ++++----- src/drawing/device.rs | 41 +++++++++++++++++++++++++++++ src/drawing/mod.rs | 14 +++++++++- src/drawing/octant.rs | 36 ++++++++++++------------- src/writers/graphics_320x200x256.rs | 6 +++-- src/writers/graphics_640x480x16.rs | 6 +++-- 6 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 src/drawing/device.rs diff --git a/src/drawing/bresenham.rs b/src/drawing/bresenham.rs index 6a13e72..1dda93c 100644 --- a/src/drawing/bresenham.rs +++ b/src/drawing/bresenham.rs @@ -16,15 +16,15 @@ impl Bresenham { let start = octant.to(start); let end = octant.to(end); - let delta_x = end.0 - start.0; - let delta_y = end.1 - start.1; + let delta_x = end.x - start.x; + let delta_y = end.y - start.y; Self { delta_x, delta_y, octant, point: start, - end_x: end.0, + end_x: end.x, error: delta_y - delta_x, } } @@ -38,15 +38,15 @@ where #[inline] fn next(&mut self) -> Option { - if self.point.0 <= self.end_x { + if self.point.x <= self.end_x { let point = self.octant.from(self.point); if self.error >= T::zero() { - self.point.1 += T::one(); + self.point.y += T::one(); self.error -= self.delta_x; } - self.point.0 += T::one(); + self.point.x += T::one(); self.error += self.delta_y; Some(point) diff --git a/src/drawing/device.rs b/src/drawing/device.rs new file mode 100644 index 0000000..cb0938f --- /dev/null +++ b/src/drawing/device.rs @@ -0,0 +1,41 @@ +use super::Point; +use crate::writers::{GraphicsWriter, Screen}; +use core::cmp::{max, min}; + +pub trait Device +where + Self: Screen + GraphicsWriter, + Color: Clone + Copy, +{ + fn draw_triangle(&self, v0: &Point, v1: &Point, v2: &Point, 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, b: &Point, c: &Point) -> i32 { + (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) +} diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs index 5d15c03..8f1c9f9 100644 --- a/src/drawing/mod.rs +++ b/src/drawing/mod.rs @@ -3,13 +3,25 @@ use num_traits::{NumAssignOps, NumCast, Signed}; mod bresenham; +mod device; mod octant; pub(crate) use bresenham::Bresenham; +pub use device::Device; use octant::Octant; /// A point in 2D space. -pub type Point = (T, T); +#[derive(Copy, Clone)] +pub struct Point { + pub x: T, + pub y: T, +} + +impl Point { + pub fn new(x: T, y: T) -> Point { + Point { x, y } + } +} pub(crate) trait SignedNum: Signed + Ord + Copy + NumCast + NumAssignOps { fn cast(value: T) -> Self { diff --git a/src/drawing/octant.rs b/src/drawing/octant.rs index caf2431..00cdb48 100644 --- a/src/drawing/octant.rs +++ b/src/drawing/octant.rs @@ -15,8 +15,8 @@ impl Octant { T: Sub + Neg + PartialOrd + Zero, { let mut value = 0; - let mut dx = end.0 - start.0; - let mut dy = end.1 - start.1; + let mut dx = end.x - start.x; + let mut dy = end.y - start.y; if dy < T::zero() { dx = -dx; @@ -45,14 +45,14 @@ impl Octant { T: Neg, { match self.value { - 0 => (point.0, point.1), - 1 => (point.1, point.0), - 2 => (point.1, -point.0), - 3 => (-point.0, point.1), - 4 => (-point.0, -point.1), - 5 => (-point.1, -point.0), - 6 => (-point.1, point.0), - 7 => (point.0, -point.1), + 0 => Point::new(point.x, point.y), + 1 => Point::new(point.y, point.x), + 2 => Point::new(point.y, -point.x), + 3 => Point::new(-point.x, point.y), + 4 => Point::new(-point.x, -point.y), + 5 => Point::new(-point.y, -point.x), + 6 => Point::new(-point.y, point.x), + 7 => Point::new(point.x, -point.y), _ => unreachable!(), } } @@ -61,14 +61,14 @@ impl Octant { #[inline] pub fn from>(&self, point: Point) -> Point { match self.value { - 0 => (point.0, point.1), - 1 => (point.1, point.0), - 2 => (-point.1, point.0), - 3 => (-point.0, point.1), - 4 => (-point.0, -point.1), - 5 => (-point.1, -point.0), - 6 => (point.1, -point.0), - 7 => (point.0, -point.1), + 0 => Point::new(point.x, point.y), + 1 => Point::new(point.y, point.x), + 2 => Point::new(-point.y, point.x), + 3 => Point::new(-point.x, point.y), + 4 => Point::new(-point.x, -point.y), + 5 => Point::new(-point.y, -point.x), + 6 => Point::new(point.y, -point.x), + 7 => Point::new(point.x, -point.y), _ => unreachable!(), } } diff --git a/src/writers/graphics_320x200x256.rs b/src/writers/graphics_320x200x256.rs index 93e6f2f..08c8a75 100644 --- a/src/writers/graphics_320x200x256.rs +++ b/src/writers/graphics_320x200x256.rs @@ -1,7 +1,7 @@ use super::{GraphicsWriter, Screen}; use crate::{ colors::DEFAULT_PALETTE, - drawing::{Bresenham, Point}, + drawing::{Bresenham, Device, Point}, vga::{Vga, VideoMode, VGA}, }; use font8x8::UnicodeFonts; @@ -53,6 +53,8 @@ impl Screen for Graphics320x200x256 { } } +impl Device for Graphics320x200x256 {} + impl GraphicsWriter for Graphics320x200x256 { fn clear_screen(&self, color: u8) { for x in 0..WIDTH { @@ -62,7 +64,7 @@ impl GraphicsWriter for Graphics320x200x256 { } } fn draw_line(&self, start: Point, end: Point, 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); } } diff --git a/src/writers/graphics_640x480x16.rs b/src/writers/graphics_640x480x16.rs index 8000b6b..54c0ef9 100644 --- a/src/writers/graphics_640x480x16.rs +++ b/src/writers/graphics_640x480x16.rs @@ -1,7 +1,7 @@ use super::{GraphicsWriter, Screen}; use crate::{ colors::{Color16, DEFAULT_PALETTE}, - drawing::{Bresenham, Point}, + drawing::{Bresenham, Device, Point}, registers::{PlaneMask, WriteMode}, vga::{Vga, VideoMode, VGA}, }; @@ -51,6 +51,8 @@ impl Screen for Graphics640x480x16 { } } +impl Device for Graphics640x480x16 {} + impl GraphicsWriter for Graphics640x480x16 { fn clear_screen(&self, color: Color16) { self.set_write_mode_2(); @@ -64,7 +66,7 @@ impl GraphicsWriter for Graphics640x480x16 { fn draw_line(&self, start: Point, end: Point, color: Color16) { 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); } }