implement top-left fill rules in triangle rendering
This commit is contained in:
parent
49a8b23568
commit
68bbd8c13c
|
@ -1,12 +1,27 @@
|
|||
use crate::graphics::bitmap::Bitmap;
|
||||
use crate::graphics::Pixel;
|
||||
use crate::math::vector2::Vector2;
|
||||
use crate::math::NearlyEqual;
|
||||
|
||||
#[inline]
|
||||
pub fn edge_function(a: Vector2, b: Vector2, c: Vector2) -> f32 {
|
||||
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_bottom_right_edge(v1: Vector2, v2: Vector2) -> bool {
|
||||
// definitions of the different edges for counter-clockwise vertex winding
|
||||
// - top: is horizontal (v1.y - v2.y == 0) and X decreases as you go across the screen (the edge points left)
|
||||
// - left: Y increases as you go down the screen
|
||||
// - bottom: is horizontal (v1.y - v2.y == 0) and X increases as you go across the screen (the edge points right)
|
||||
// - right: Y decreases as you go up the screen
|
||||
// (basically, picture a box where each edge is a vector pointing in a direction, and then move from edge to edge
|
||||
// counter-clockwise and think of the X and Y directions as you move along each edge)
|
||||
|
||||
let edge = v1 - v2;
|
||||
edge.y < 0.0 || (edge.y.nearly_equal(0.0, f32::EPSILON) && edge.x > 0.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn per_pixel_triangle_2d<PixelType: Pixel>(
|
||||
dest: &mut Bitmap<PixelType>,
|
||||
|
@ -39,6 +54,10 @@ pub fn per_pixel_triangle_2d<PixelType: Pixel>(
|
|||
let a20 = c.y - a.y;
|
||||
let b20 = a.x - c.x;
|
||||
|
||||
let is_cb_bottom_right = is_bottom_right_edge(c, b);
|
||||
let is_ac_bottom_right = is_bottom_right_edge(a, c);
|
||||
let is_ba_bottom_right = is_bottom_right_edge(b, a);
|
||||
|
||||
let p = Vector2::new(min_x as f32, min_y as f32);
|
||||
let mut w0_row = edge_function(b, c, p);
|
||||
let mut w1_row = edge_function(c, a, p);
|
||||
|
@ -55,6 +74,15 @@ pub fn per_pixel_triangle_2d<PixelType: Pixel>(
|
|||
|
||||
let row_pixels = unsafe { std::slice::from_raw_parts_mut(pixels, draw_width) };
|
||||
for pixel in row_pixels.iter_mut() {
|
||||
// skip bottom-right edge pixels so we only draw pixels inside the triangle as well as those that lie
|
||||
// on the top-left edges. this fixes seam issues with triangles drawn with blending that share an edge
|
||||
if (w0.nearly_equal(0.0, f32::EPSILON) && is_cb_bottom_right)
|
||||
|| (w1.nearly_equal(0.0, f32::EPSILON) && is_ac_bottom_right)
|
||||
|| (w2.nearly_equal(0.0, f32::EPSILON) && is_ba_bottom_right)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// note that for a counter-clockwise vertex winding order with the direction of Y+ going down instead
|
||||
// of up, we need to test for *negative* area when checking if we're inside the triangle
|
||||
if w0 <= 0.0 && w1 <= 0.0 && w2 <= 0.0 {
|
||||
|
|
Loading…
Reference in a new issue