add vertically and horizontally flipped BlitMethod variations

This commit is contained in:
Gered 2022-06-05 12:55:31 -04:00
parent d3e034d211
commit 51a9bddc33

View file

@ -5,21 +5,51 @@ use crate::math::*;
pub enum BlitMethod {
/// Solid blit, no transparency or other per-pixel adjustments.
Solid,
/// Same as [BlitMethod::Solid] but the drawn image can also be flipped horizontally
/// and/or vertically.
SolidFlipped {
horizontal_flip: bool,
vertical_flip: bool,
},
/// Transparent blit, the specified source color pixels are skipped.
Transparent(u8),
/// Same as [BlitMethod::Transparent] but the drawn image can also be flipped horizontally
/// and/or vertically.
TransparentFlipped {
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
},
/// Same as [BlitMethod::Transparent] except that the visible pixels on the destination are all
/// drawn using the same color.
TransparentSingle {
transparent_color: u8,
draw_color: u8,
},
/// Combination of [BlitMethod::TransparentFlipped] and [BlitMethod::TransparentSingle].
TransparentFlippedSingle {
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
draw_color: u8,
},
/// Same as [BlitMethod::Solid] except that the drawn pixels have their color indices offset
/// by the amount given.
SolidOffset(u8),
/// Combination of [BlitMethod::SolidFlipped] and [BlitMethod::SolidOffset].
SolidFlippedOffset {
horizontal_flip: bool,
vertical_flip: bool,
offset: u8,
},
/// Same as [BlitMethod::Transparent] except that the drawn pixels have their color indices
/// offset by the amount given.
TransparentOffset {
TransparentOffset { transparent_color: u8, offset: u8 },
/// Combination of [BlitMethod::TransparentFlipped] and [BlitMethod::TransparentOffset].
TransparentFlippedOffset {
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
offset: u8,
},
/// Rotozoom blit, works the same as [BlitMethod::Solid] except that rotation and scaling is
@ -131,6 +161,44 @@ pub fn clip_blit(
}
impl Bitmap {
#[inline]
fn get_flipped_blit_properties(
&self,
src: &Bitmap,
src_region: &Rect,
horizontal_flip: bool,
vertical_flip: bool,
) -> (isize, i32, i32, isize) {
let x_inc;
let src_start_x;
let src_start_y;
let src_next_row_inc;
if !horizontal_flip && !vertical_flip {
x_inc = 1;
src_start_x = src_region.x;
src_start_y = src_region.y;
src_next_row_inc = (src.width - src_region.width) as isize;
} else if horizontal_flip && !vertical_flip {
x_inc = -1;
src_start_x = src_region.right();
src_start_y = src_region.y;
src_next_row_inc = (src.width + src_region.width) as isize;
} else if !horizontal_flip && vertical_flip {
x_inc = 1;
src_start_x = src_region.x;
src_start_y = src_region.bottom();
src_next_row_inc = -((src.width + src_region.width) as isize);
} else {
x_inc = -1;
src_start_x = src_region.right();
src_start_y = src_region.bottom();
src_next_row_inc = -((src.width - src_region.width) as isize);
}
(x_inc, src_start_x, src_start_y, src_next_row_inc)
}
pub unsafe fn solid_blit(&mut self, src: &Bitmap, src_region: &Rect, dest_x: i32, dest_y: i32) {
let src_row_length = src_region.width as usize;
let src_pitch = src.width as usize;
@ -145,6 +213,34 @@ impl Bitmap {
}
}
pub unsafe fn solid_flipped_blit(
&mut self,
src: &Bitmap,
src_region: &Rect,
dest_x: i32,
dest_y: i32,
horizontal_flip: bool,
vertical_flip: bool,
) {
let dest_next_row_inc = (self.width - src_region.width) as usize;
let (x_inc, src_start_x, src_start_y, src_next_row_inc) =
self.get_flipped_blit_properties(src, src_region, horizontal_flip, vertical_flip);
let mut src_pixels = src.pixels_at_ptr_unchecked(src_start_x, src_start_y);
let mut dest_pixels = self.pixels_at_mut_ptr_unchecked(dest_x, dest_y);
for _ in 0..src_region.height {
for _ in 0..src_region.width {
*dest_pixels = *src_pixels;
src_pixels = src_pixels.offset(x_inc);
dest_pixels = dest_pixels.add(1);
}
src_pixels = src_pixels.offset(src_next_row_inc);
dest_pixels = dest_pixels.add(dest_next_row_inc);
}
}
pub unsafe fn solid_blit_palette_offset(
&mut self,
src: &Bitmap,
@ -170,6 +266,35 @@ impl Bitmap {
}
}
pub unsafe fn solid_flipped_palette_offset_blit(
&mut self,
src: &Bitmap,
src_region: &Rect,
dest_x: i32,
dest_y: i32,
horizontal_flip: bool,
vertical_flip: bool,
offset: u8,
) {
let dest_next_row_inc = (self.width - src_region.width) as usize;
let (x_inc, src_start_x, src_start_y, src_next_row_inc) =
self.get_flipped_blit_properties(src, src_region, horizontal_flip, vertical_flip);
let mut src_pixels = src.pixels_at_ptr_unchecked(src_start_x, src_start_y);
let mut dest_pixels = self.pixels_at_mut_ptr_unchecked(dest_x, dest_y);
for _ in 0..src_region.height {
for _ in 0..src_region.width {
*dest_pixels = (*src_pixels).wrapping_add(offset);
src_pixels = src_pixels.offset(x_inc);
dest_pixels = dest_pixels.add(1);
}
src_pixels = src_pixels.offset(src_next_row_inc);
dest_pixels = dest_pixels.add(dest_next_row_inc);
}
}
pub unsafe fn transparent_blit(
&mut self,
src: &Bitmap,
@ -199,6 +324,39 @@ impl Bitmap {
}
}
pub unsafe fn transparent_flipped_blit(
&mut self,
src: &Bitmap,
src_region: &Rect,
dest_x: i32,
dest_y: i32,
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
) {
let dest_next_row_inc = (self.width - src_region.width) as usize;
let (x_inc, src_start_x, src_start_y, src_next_row_inc) =
self.get_flipped_blit_properties(src, src_region, horizontal_flip, vertical_flip);
let mut src_pixels = src.pixels_at_ptr_unchecked(src_start_x, src_start_y);
let mut dest_pixels = self.pixels_at_mut_ptr_unchecked(dest_x, dest_y);
for _ in 0..src_region.height {
for _ in 0..src_region.width {
let pixel = *src_pixels;
if pixel != transparent_color {
*dest_pixels = pixel;
}
src_pixels = src_pixels.offset(x_inc);
dest_pixels = dest_pixels.add(1);
}
src_pixels = src_pixels.offset(src_next_row_inc);
dest_pixels = dest_pixels.add(dest_next_row_inc);
}
}
pub unsafe fn transparent_blit_palette_offset(
&mut self,
src: &Bitmap,
@ -229,6 +387,40 @@ impl Bitmap {
}
}
pub unsafe fn transparent_flipped_palette_offset_blit(
&mut self,
src: &Bitmap,
src_region: &Rect,
dest_x: i32,
dest_y: i32,
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
offset: u8,
) {
let dest_next_row_inc = (self.width - src_region.width) as usize;
let (x_inc, src_start_x, src_start_y, src_next_row_inc) =
self.get_flipped_blit_properties(src, src_region, horizontal_flip, vertical_flip);
let mut src_pixels = src.pixels_at_ptr_unchecked(src_start_x, src_start_y);
let mut dest_pixels = self.pixels_at_mut_ptr_unchecked(dest_x, dest_y);
for _ in 0..src_region.height {
for _ in 0..src_region.width {
let pixel = *src_pixels;
if pixel != transparent_color {
*dest_pixels = pixel.wrapping_add(offset);
}
src_pixels = src_pixels.offset(x_inc);
dest_pixels = dest_pixels.add(1);
}
src_pixels = src_pixels.offset(src_next_row_inc);
dest_pixels = dest_pixels.add(dest_next_row_inc);
}
}
pub unsafe fn transparent_single_color_blit(
&mut self,
src: &Bitmap,
@ -259,6 +451,40 @@ impl Bitmap {
}
}
pub unsafe fn transparent_flipped_single_color_blit(
&mut self,
src: &Bitmap,
src_region: &Rect,
dest_x: i32,
dest_y: i32,
transparent_color: u8,
horizontal_flip: bool,
vertical_flip: bool,
draw_color: u8,
) {
let dest_next_row_inc = (self.width - src_region.width) as usize;
let (x_inc, src_start_x, src_start_y, src_next_row_inc) =
self.get_flipped_blit_properties(src, src_region, horizontal_flip, vertical_flip);
let mut src_pixels = src.pixels_at_ptr_unchecked(src_start_x, src_start_y);
let mut dest_pixels = self.pixels_at_mut_ptr_unchecked(dest_x, dest_y);
for _ in 0..src_region.height {
for _ in 0..src_region.width {
let pixel = *src_pixels;
if pixel != transparent_color {
*dest_pixels = draw_color;
}
src_pixels = src_pixels.offset(x_inc);
dest_pixels = dest_pixels.add(1);
}
src_pixels = src_pixels.offset(src_next_row_inc);
dest_pixels = dest_pixels.add(dest_next_row_inc);
}
}
pub unsafe fn rotozoom_blit(
&mut self,
src: &Bitmap,
@ -442,16 +668,31 @@ impl Bitmap {
use BlitMethod::*;
match method {
Solid => self.solid_blit(src, src_region, dest_x, dest_y),
SolidFlipped { horizontal_flip, vertical_flip } => {
self.solid_flipped_blit(src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip)
}
SolidOffset(offset) => self.solid_blit_palette_offset(src, src_region, dest_x, dest_y, offset),
SolidFlippedOffset { horizontal_flip, vertical_flip, offset } => {
self.solid_flipped_palette_offset_blit(src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip, offset)
},
Transparent(transparent_color) => {
self.transparent_blit(src, src_region, dest_x, dest_y, transparent_color)
},
TransparentFlipped { transparent_color, horizontal_flip, vertical_flip } => {
self.transparent_flipped_blit(src, src_region, dest_x, dest_y, transparent_color, horizontal_flip, vertical_flip)
},
TransparentOffset { transparent_color, offset } => {
self.transparent_blit_palette_offset(src, src_region, dest_x, dest_y, transparent_color, offset)
},
TransparentFlippedOffset { transparent_color, horizontal_flip, vertical_flip, offset } => {
self.transparent_flipped_palette_offset_blit(src, src_region, dest_x, dest_y, transparent_color, horizontal_flip, vertical_flip, offset)
},
TransparentSingle { transparent_color, draw_color } => {
self.transparent_single_color_blit(src, src_region, dest_x, dest_y, transparent_color, draw_color)
},
TransparentFlippedSingle { transparent_color, horizontal_flip, vertical_flip, draw_color } => {
self.transparent_flipped_single_color_blit(src, src_region, dest_x, dest_y, transparent_color, horizontal_flip, vertical_flip, draw_color)
},
RotoZoom { angle, scale_x, scale_y } => {
self.rotozoom_blit(src, src_region, dest_x, dest_y, angle, scale_x, scale_y, None)
},