redo triangle 2d drawing api to use enums. split indexed+rgba variants
i'm not *entirely* sold on this particular enum-based api, but i think it could work. in the future i'd likely ALSO want something that could work with triangle data as an offset from a larger buffer, but we can solve that problem later when it comes up. mainly i just didn't want to have a bunch of different triangle_2d function variants exposed. same justification as with the blit enums, basically.
This commit is contained in:
parent
7a5ea75e1f
commit
3e4b9affa0
|
@ -10,28 +10,52 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
let (texture, _palette) =
|
||||
IndexedBitmap::load_gif_file(std::path::Path::new("./test-assets/gif/small.gif")).unwrap();
|
||||
|
||||
let big_v1 = Vector2::new(47.0, 23.0);
|
||||
let big_v2 = Vector2::new(60.0, 192.0);
|
||||
let big_v3 = Vector2::new(280.0, 153.0);
|
||||
|
||||
let small_v1 = Vector2::new(16.0, 16.0);
|
||||
let small_v2 = Vector2::new(16.0, 31.0);
|
||||
let small_v3 = Vector2::new(31.0, 31.0);
|
||||
|
||||
let texcoord_0_0 = Vector2::new(0.0, 0.0);
|
||||
let texcoord_1_0 = Vector2::new(1.0, 0.0);
|
||||
let texcoord_0_1 = Vector2::new(0.0, 1.0);
|
||||
let texcoord_1_1 = Vector2::new(1.0, 1.0);
|
||||
|
||||
c.bench_function("indexedbitmap_triangle_2d_solid_color", |b| {
|
||||
let triangle = IndexedTriangle2d::SolidSingleColor { position: [big_v1, big_v2, big_v3], color: 5 };
|
||||
b.iter(|| {
|
||||
dest.triangle_2d_solid_color(
|
||||
black_box(Vector2::new(47.0, 23.0)),
|
||||
black_box(Vector2::new(60.0, 192.0)),
|
||||
black_box(Vector2::new(280.0, 153.0)),
|
||||
black_box(5),
|
||||
);
|
||||
dest.triangle_2d(black_box(&triangle));
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("indexedbitmap_triangle_2d_solid_color_small", |b| {
|
||||
let triangle = IndexedTriangle2d::SolidSingleColor { position: [small_v1, small_v2, small_v3], color: 5 };
|
||||
b.iter(|| {
|
||||
dest.triangle_2d(black_box(&triangle));
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("indexedbitmap_triangle_2d_textured", |b| {
|
||||
let triangle = IndexedTriangle2d::SolidTextured {
|
||||
position: [big_v1, big_v2, big_v3],
|
||||
texcoord: [texcoord_0_0, texcoord_1_0, texcoord_1_1],
|
||||
bitmap: &texture,
|
||||
};
|
||||
b.iter(|| {
|
||||
dest.triangle_2d_textured(
|
||||
black_box(Vector2::new(47.0, 23.0)),
|
||||
black_box(Vector2::new(0.0, 0.0)),
|
||||
black_box(Vector2::new(60.0, 192.0)),
|
||||
black_box(Vector2::new(1.0, 0.0)),
|
||||
black_box(Vector2::new(280.0, 153.0)),
|
||||
black_box(Vector2::new(1.0, 1.0)),
|
||||
black_box(&texture),
|
||||
);
|
||||
dest.triangle_2d(black_box(&triangle));
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("indexedbitmap_triangle_2d_textured_small", |b| {
|
||||
let triangle = IndexedTriangle2d::SolidTextured {
|
||||
position: [small_v1, small_v2, small_v3],
|
||||
texcoord: [texcoord_0_0, texcoord_1_0, texcoord_1_1],
|
||||
bitmap: &texture,
|
||||
};
|
||||
b.iter(|| {
|
||||
dest.triangle_2d(black_box(&triangle));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::graphics::palette::Palette;
|
|||
|
||||
pub mod blit;
|
||||
pub mod primitives;
|
||||
pub mod triangles;
|
||||
|
||||
pub type IndexedBitmap = Bitmap<u8>;
|
||||
|
||||
|
|
47
ggdt/src/graphics/bitmap/indexed/triangles.rs
Normal file
47
ggdt/src/graphics/bitmap/indexed/triangles.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use crate::graphics::bitmap::indexed::IndexedBitmap;
|
||||
use crate::graphics::bitmap::triangles::{edge_function, per_pixel_triangle_2d};
|
||||
use crate::math::vector2::Vector2;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum IndexedTriangle2d<'a> {
|
||||
SolidSingleColor {
|
||||
position: [Vector2; 3], //
|
||||
color: u8,
|
||||
},
|
||||
SolidTextured {
|
||||
position: [Vector2; 3], //
|
||||
texcoord: [Vector2; 3],
|
||||
bitmap: &'a IndexedBitmap,
|
||||
},
|
||||
}
|
||||
|
||||
impl IndexedBitmap {
|
||||
pub fn triangle_2d(&mut self, triangle: &IndexedTriangle2d) {
|
||||
use IndexedTriangle2d::*;
|
||||
match triangle {
|
||||
SolidSingleColor { position, color } => {
|
||||
per_pixel_triangle_2d(
|
||||
self, //
|
||||
position[0],
|
||||
position[1],
|
||||
position[2],
|
||||
|dest_pixels, _w0, _w1, _w2| *dest_pixels = *color,
|
||||
)
|
||||
}
|
||||
SolidTextured { position, texcoord, bitmap } => {
|
||||
let inverse_area = 1.0 / edge_function(position[0], position[1], position[2]);
|
||||
per_pixel_triangle_2d(
|
||||
self, //
|
||||
position[0],
|
||||
position[1],
|
||||
position[2],
|
||||
|dest_pixels, w0, w1, w2| {
|
||||
let u = (w0 * texcoord[0].x + w1 * texcoord[1].x + w2 * texcoord[2].x) * inverse_area;
|
||||
let v = (w0 * texcoord[0].y + w1 * texcoord[1].y + w2 * texcoord[2].y) * inverse_area;
|
||||
*dest_pixels = bitmap.sample_at(u, v);
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ use crate::graphics::palette::Palette;
|
|||
|
||||
pub mod blit;
|
||||
pub mod primitives;
|
||||
pub mod triangles;
|
||||
|
||||
pub type RgbaBitmap = Bitmap<u32>;
|
||||
|
||||
|
|
70
ggdt/src/graphics/bitmap/rgb/triangles.rs
Normal file
70
ggdt/src/graphics/bitmap/rgb/triangles.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::bitmap::triangles::{edge_function, per_pixel_triangle_2d};
|
||||
use crate::math::vector2::Vector2;
|
||||
use crate::prelude::{from_rgb32, from_rgb32_normalized, to_rgb32_normalized};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RgbaTriangle2d<'a> {
|
||||
SolidSingleColor {
|
||||
position: [Vector2; 3], //
|
||||
color: u32,
|
||||
},
|
||||
SolidMultiColor {
|
||||
position: [Vector2; 3], //
|
||||
color: [u32; 3],
|
||||
},
|
||||
SolidTextured {
|
||||
position: [Vector2; 3], //
|
||||
texcoord: [Vector2; 3],
|
||||
bitmap: &'a RgbaBitmap,
|
||||
},
|
||||
}
|
||||
|
||||
impl RgbaBitmap {
|
||||
pub fn triangle_2d(&mut self, triangle: &RgbaTriangle2d) {
|
||||
use RgbaTriangle2d::*;
|
||||
match triangle {
|
||||
SolidSingleColor { position, color } => {
|
||||
per_pixel_triangle_2d(
|
||||
self, //
|
||||
position[0],
|
||||
position[1],
|
||||
position[2],
|
||||
|dest_pixels, _w0, _w1, _w2| *dest_pixels = *color,
|
||||
)
|
||||
}
|
||||
SolidMultiColor { position, color } => {
|
||||
let inverse_area = 1.0 / edge_function(position[0], position[1], position[2]);
|
||||
let (r1, g1, b1) = from_rgb32_normalized(color[0]);
|
||||
let (r2, g2, b2) = from_rgb32_normalized(color[1]);
|
||||
let (r3, g3, b3) = from_rgb32_normalized(color[2]);
|
||||
per_pixel_triangle_2d(
|
||||
self, //
|
||||
position[0],
|
||||
position[1],
|
||||
position[2],
|
||||
|dest_pixels, w0, w1, w2| {
|
||||
let r = (w0 * r1 + w1 * r2 + w2 * r3) * inverse_area;
|
||||
let g = (w0 * g1 + w1 * g2 + w2 * g3) * inverse_area;
|
||||
let b = (w0 * b1 + w1 * b2 + w2 * b3) * inverse_area;
|
||||
*dest_pixels = to_rgb32_normalized(r, g, b)
|
||||
},
|
||||
)
|
||||
}
|
||||
SolidTextured { position, texcoord, bitmap } => {
|
||||
let inverse_area = 1.0 / edge_function(position[0], position[1], position[2]);
|
||||
per_pixel_triangle_2d(
|
||||
self, //
|
||||
position[0],
|
||||
position[1],
|
||||
position[2],
|
||||
|dest_pixels, w0, w1, w2| {
|
||||
let u = (w0 * texcoord[0].x + w1 * texcoord[1].x + w2 * texcoord[2].x) * inverse_area;
|
||||
let v = (w0 * texcoord[0].y + w1 * texcoord[1].y + w2 * texcoord[2].y) * inverse_area;
|
||||
*dest_pixels = bitmap.sample_at(u, v);
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,48 +3,13 @@ use crate::graphics::Pixel;
|
|||
use crate::math::vector2::Vector2;
|
||||
|
||||
#[inline]
|
||||
fn cross(a: Vector2, b: Vector2, c: Vector2) -> f32 {
|
||||
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)
|
||||
}
|
||||
|
||||
impl<PixelType: Pixel> Bitmap<PixelType> {
|
||||
pub fn triangle_2d_solid_color(&mut self, a: Vector2, b: Vector2, c: Vector2, color: PixelType) {
|
||||
self.triangle_2d_custom(
|
||||
a, //
|
||||
b,
|
||||
c,
|
||||
|dest_pixels, _w0, _w1, _w2| {
|
||||
*dest_pixels = color;
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn triangle_2d_textured(
|
||||
&mut self,
|
||||
a: Vector2,
|
||||
a_tex: Vector2,
|
||||
b: Vector2,
|
||||
b_tex: Vector2,
|
||||
c: Vector2,
|
||||
c_tex: Vector2,
|
||||
texture: &Bitmap<PixelType>,
|
||||
) {
|
||||
let inverse_area = 1.0 / cross(a, b, c); // inverting to avoid division
|
||||
self.triangle_2d_custom(
|
||||
a, //
|
||||
b,
|
||||
c,
|
||||
|dest_pixels, w0, w1, w2| {
|
||||
let u = (w0 * a_tex.x + w1 * b_tex.x + w2 * c_tex.x) * inverse_area;
|
||||
let v = (w0 * a_tex.y + w1 * b_tex.y + w2 * c_tex.y) * inverse_area;
|
||||
*dest_pixels = texture.sample_at(u, v);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn triangle_2d_custom(
|
||||
&mut self,
|
||||
pub fn per_pixel_triangle_2d<PixelType: Pixel>(
|
||||
dest: &mut Bitmap<PixelType>,
|
||||
a: Vector2,
|
||||
b: Vector2,
|
||||
c: Vector2,
|
||||
|
@ -62,10 +27,10 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
let max_x = a.x.max(b.x).max(c.x).ceil() as i32;
|
||||
let max_y = a.y.max(b.y).max(c.y).ceil() as i32;
|
||||
|
||||
let min_x = std::cmp::max(self.clip_region().x, min_x);
|
||||
let min_y = std::cmp::max(self.clip_region().y, min_y);
|
||||
let max_x = std::cmp::min(self.clip_region().right(), max_x);
|
||||
let max_y = std::cmp::min(self.clip_region().bottom(), max_y);
|
||||
let min_x = std::cmp::max(dest.clip_region().x, min_x);
|
||||
let min_y = std::cmp::max(dest.clip_region().y, min_y);
|
||||
let max_x = std::cmp::min(dest.clip_region().right(), max_x);
|
||||
let max_y = std::cmp::min(dest.clip_region().bottom(), max_y);
|
||||
|
||||
let a01 = a.y - b.y;
|
||||
let b01 = b.x - a.x;
|
||||
|
@ -75,13 +40,13 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
let b20 = a.x - c.x;
|
||||
|
||||
let p = Vector2::new(min_x as f32, min_y as f32);
|
||||
let mut w0_row = cross(b, c, p);
|
||||
let mut w1_row = cross(c, a, p);
|
||||
let mut w2_row = cross(a, b, p);
|
||||
let mut w0_row = edge_function(b, c, p);
|
||||
let mut w1_row = edge_function(c, a, p);
|
||||
let mut w2_row = edge_function(a, b, p);
|
||||
|
||||
let draw_width = (max_x - min_x + 1) as usize;
|
||||
let next_row_inc = self.width() as usize;
|
||||
let mut pixels = unsafe { self.pixels_at_mut_ptr_unchecked(min_x, min_y) };
|
||||
let next_row_inc = dest.width() as usize;
|
||||
let mut pixels = unsafe { dest.pixels_at_mut_ptr_unchecked(min_x, min_y) };
|
||||
|
||||
for _ in min_y..=max_y {
|
||||
let mut w0 = w0_row;
|
||||
|
@ -107,4 +72,3 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
pixels = unsafe { pixels.add(next_row_inc) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,23 @@ pub use crate::graphics::{
|
|||
general::*,
|
||||
gif::*,
|
||||
iff::*,
|
||||
indexed::{blit::*, primitives::*, *},
|
||||
indexed::{
|
||||
//
|
||||
blit::*,
|
||||
primitives::*,
|
||||
triangles::*,
|
||||
*,
|
||||
},
|
||||
pcx::*,
|
||||
png::*,
|
||||
primitives::*,
|
||||
rgb::{blit::*, primitives::*, *},
|
||||
rgb::{
|
||||
//
|
||||
blit::*,
|
||||
primitives::*,
|
||||
triangles::*,
|
||||
*,
|
||||
},
|
||||
triangles::*,
|
||||
*,
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue