From 9dcfa915023332fae3567795a9f3d46665226624 Mon Sep 17 00:00:00 2001 From: gered Date: Tue, 21 Mar 2023 21:19:37 -0400 Subject: [PATCH] add graphics visual tests for RgbaBitmap drawing operations obviously only for the operations implemented so far. there are going to be more in the near future. --- ggdt/tests/graphics_rgba.rs | 895 ++++++++++++++++++ ggdt/tests/ref/rgba/circle_drawing.png | Bin 0 -> 2250 bytes ggdt/tests/ref/rgba/filled_circle_drawing.png | Bin 0 -> 2098 bytes ggdt/tests/ref/rgba/filled_rect_drawing.png | Bin 0 -> 2020 bytes ggdt/tests/ref/rgba/horiz_line_drawing.png | Bin 0 -> 1042 bytes ggdt/tests/ref/rgba/line_drawing.png | Bin 0 -> 1757 bytes ggdt/tests/ref/rgba/pixel_addressing.png | Bin 0 -> 2309 bytes ggdt/tests/ref/rgba/pixel_drawing.png | Bin 0 -> 1095 bytes ggdt/tests/ref/rgba/rect_drawing.png | Bin 0 -> 1909 bytes ggdt/tests/ref/rgba/rotozoom_blits.png | Bin 0 -> 3050 bytes .../ref/rgba/rotozoom_transparent_blits.png | Bin 0 -> 3200 bytes ggdt/tests/ref/rgba/solid_blits.png | Bin 0 -> 1897 bytes ggdt/tests/ref/rgba/solid_flipped_blits.png | Bin 0 -> 1900 bytes ggdt/tests/ref/rgba/text_drawing.png | Bin 0 -> 6189 bytes ggdt/tests/ref/rgba/transparent_blits.png | Bin 0 -> 1985 bytes .../ref/rgba/transparent_flipped_blits.png | Bin 0 -> 1950 bytes .../rgba/transparent_flipped_single_blits.png | Bin 0 -> 1797 bytes .../ref/rgba/transparent_single_blits.png | Bin 0 -> 1748 bytes ggdt/tests/ref/rgba/vert_line_drawing.png | Bin 0 -> 1461 bytes 19 files changed, 895 insertions(+) create mode 100644 ggdt/tests/graphics_rgba.rs create mode 100644 ggdt/tests/ref/rgba/circle_drawing.png create mode 100644 ggdt/tests/ref/rgba/filled_circle_drawing.png create mode 100644 ggdt/tests/ref/rgba/filled_rect_drawing.png create mode 100644 ggdt/tests/ref/rgba/horiz_line_drawing.png create mode 100644 ggdt/tests/ref/rgba/line_drawing.png create mode 100644 ggdt/tests/ref/rgba/pixel_addressing.png create mode 100644 ggdt/tests/ref/rgba/pixel_drawing.png create mode 100644 ggdt/tests/ref/rgba/rect_drawing.png create mode 100644 ggdt/tests/ref/rgba/rotozoom_blits.png create mode 100644 ggdt/tests/ref/rgba/rotozoom_transparent_blits.png create mode 100644 ggdt/tests/ref/rgba/solid_blits.png create mode 100644 ggdt/tests/ref/rgba/solid_flipped_blits.png create mode 100644 ggdt/tests/ref/rgba/text_drawing.png create mode 100644 ggdt/tests/ref/rgba/transparent_blits.png create mode 100644 ggdt/tests/ref/rgba/transparent_flipped_blits.png create mode 100644 ggdt/tests/ref/rgba/transparent_flipped_single_blits.png create mode 100644 ggdt/tests/ref/rgba/transparent_single_blits.png create mode 100644 ggdt/tests/ref/rgba/vert_line_drawing.png diff --git a/ggdt/tests/graphics_rgba.rs b/ggdt/tests/graphics_rgba.rs new file mode 100644 index 0000000..344162c --- /dev/null +++ b/ggdt/tests/graphics_rgba.rs @@ -0,0 +1,895 @@ +use std::path::{Path, PathBuf}; + +use ggdt::prelude::*; +use helpers::test_assets_file; + +pub mod helpers; + +const LIGHTER_BACKGROUND: u32 = 0xff2c3041; + +const BASE_PATH: &str = "./tests/ref/rgba/"; + +fn reference_file(file: &Path) -> PathBuf { + PathBuf::from(BASE_PATH).join(file) +} + +fn setup() -> RgbaBitmap { + RgbaBitmap::new(SCREEN_WIDTH, SCREEN_HEIGHT).unwrap() +} + +fn verify_visual(screen: &RgbaBitmap, source: &Path) -> bool { + let (source_bmp, _) = RgbaBitmap::load_file(source).unwrap(); + *screen == source_bmp +} + +#[test] +fn pixel_addressing() { + let mut screen = setup(); + + unsafe { + let mut pixels = screen.pixels_at_mut_ptr(10, 10).unwrap(); + let mut i = 0; + for _y in 0..16 { + for _x in 0..16 { + *pixels = to_rgb32(i, i, i); + i = i.wrapping_add(1); + pixels = pixels.offset(1); + } + pixels = pixels.offset((SCREEN_WIDTH - 16) as isize); + } + } + + unsafe { + let mut pixels = screen.pixels_at_mut_ptr(0, 0).unwrap(); + for _ in 0..10 { + *pixels = COLOR_BRIGHT_WHITE; + pixels = pixels.offset((SCREEN_WIDTH + 1) as isize); + } + } + + unsafe { + let mut pixels = screen.pixels_at_mut_ptr(10, 0).unwrap(); + for _ in 0..10 { + *pixels = COLOR_BRIGHT_WHITE; + pixels = pixels.offset(SCREEN_WIDTH as isize); + } + } + + unsafe { + let mut pixels = screen.pixels_at_mut_ptr(0, 10).unwrap(); + for _ in 0..10 { + *pixels = COLOR_BRIGHT_WHITE; + pixels = pixels.offset(1); + } + } + + let path = reference_file(Path::new("pixel_addressing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn pixel_drawing() { + let mut screen = setup(); + + screen.set_pixel(0, 0, COLOR_BLUE); + screen.set_pixel(319, 0, COLOR_GREEN); + screen.set_pixel(0, 239, COLOR_CYAN); + screen.set_pixel(319, 239, COLOR_RED); + + unsafe { + screen.set_pixel_unchecked(10, 0, COLOR_BLUE); + screen.set_pixel_unchecked(309, 0, COLOR_GREEN); + screen.set_pixel_unchecked(10, 239, COLOR_CYAN); + screen.set_pixel_unchecked(309, 239, COLOR_RED); + } + + let c1 = screen.get_pixel(0, 0).unwrap(); + let c2 = screen.get_pixel(319, 0).unwrap(); + let c3 = screen.get_pixel(0, 239).unwrap(); + let c4 = screen.get_pixel(319, 239).unwrap(); + + screen.set_pixel(1, 1, c1); + screen.set_pixel(318, 1, c2); + screen.set_pixel(1, 238, c3); + screen.set_pixel(318, 238, c4); + + unsafe { + let c1 = screen.get_pixel_unchecked(10, 0); + let c2 = screen.get_pixel_unchecked(309, 0); + let c3 = screen.get_pixel_unchecked(10, 239); + let c4 = screen.get_pixel_unchecked(309, 239); + + screen.set_pixel_unchecked(11, 1, c1); + screen.set_pixel_unchecked(308, 1, c2); + screen.set_pixel_unchecked(11, 238, c3); + screen.set_pixel_unchecked(308, 238, c4); + } + + ////// + + for i in 0..10 { + screen.set_pixel(5 - i, 100, COLOR_BRIGHT_WHITE); + screen.set_pixel(i + 314, 100, COLOR_BRIGHT_WHITE); + screen.set_pixel(160, 5 - i, COLOR_BRIGHT_WHITE); + screen.set_pixel(160, i + 234, COLOR_BRIGHT_WHITE); + } + + let path = reference_file(Path::new("pixel_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn horiz_line_drawing() { + let mut screen = setup(); + + screen.horiz_line(10, 100, 20, COLOR_BLUE); + screen.horiz_line(10, 100, 30, COLOR_GREEN); + + ////// + + screen.horiz_line(-50, 50, 6, COLOR_CYAN); + screen.horiz_line(300, 340, 130, COLOR_MAGENTA); + + screen.horiz_line(100, 200, -10, COLOR_BROWN); + screen.horiz_line(20, 80, 250, COLOR_DARK_GRAY); + + let path = reference_file(Path::new("horiz_line_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn vert_line_drawing() { + let mut screen = setup(); + + screen.vert_line(50, 10, 200, COLOR_BLUE); + screen.vert_line(60, 10, 200, COLOR_GREEN); + + ////// + + screen.vert_line(20, -32, 32, COLOR_CYAN); + screen.vert_line(270, 245, 165, COLOR_MAGENTA); + + screen.vert_line(-17, 10, 20, COLOR_BROWN); + screen.vert_line(400, 100, 300, COLOR_LIGHT_GRAY); + + let path = reference_file(Path::new("vert_line_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn line_drawing() { + let mut screen = setup(); + + screen.line(10, 10, 20, 20, COLOR_BLUE); + screen.line(10, 100, 20, 150, COLOR_GREEN); + screen.line(60, 150, 50, 100, COLOR_CYAN); + + ////// + + screen.line(50, 10, 100, 10, COLOR_MAGENTA); + screen.line(100, 50, 20, 50, COLOR_BROWN); + screen.line(290, 10, 290, 100, COLOR_LIGHT_GRAY); + screen.line(310, 100, 310, 10, COLOR_DARK_GRAY); + + ////// + + screen.line(50, 200, -50, 200, COLOR_MAGENTA); + screen.line(300, 210, 340, 210, COLOR_BROWN); + screen.line(120, -30, 120, 30, COLOR_LIGHT_GRAY); + screen.line(130, 200, 130, 270, COLOR_DARK_GRAY); + + screen.line(250, 260, 190, 200, COLOR_BRIGHT_BLUE); + screen.line(180, 30, 240, -30, COLOR_BRIGHT_GREEN); + screen.line(-20, 140, 20, 180, COLOR_BRIGHT_CYAN); + screen.line(300, 130, 340, 170, COLOR_BRIGHT_RED); + + screen.line(10, -30, 100, -30, COLOR_BLUE); + screen.line(70, 250, 170, 250, COLOR_GREEN); + screen.line(-100, 120, -100, 239, COLOR_CYAN); + screen.line(320, 99, 320, 199, COLOR_MAGENTA); + + let path = reference_file(Path::new("line_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn rect_drawing() { + let mut screen = setup(); + + screen.rect(10, 10, 90, 90, COLOR_BLUE); + screen.rect(10, 110, 90, 190, COLOR_GREEN); + screen.rect(190, 90, 110, 10, COLOR_CYAN); + + ////// + + screen.rect(-8, 10, 7, 25, COLOR_MAGENTA); + screen.rect(20, -8, 35, 7, COLOR_BROWN); + screen.rect(313, 170, 328, 185, COLOR_LIGHT_GRAY); + screen.rect(285, 233, 300, 248, COLOR_DARK_GRAY); + + screen.rect(-16, 30, -1, 46, COLOR_BRIGHT_BLUE); + screen.rect(40, -16, 55, -1, COLOR_BRIGHT_GREEN); + screen.rect(320, 150, 335, 165, COLOR_BRIGHT_CYAN); + screen.rect(265, 240, 280, 255, COLOR_BRIGHT_RED); + + screen.rect(300, 20, 340, -20, COLOR_BRIGHT_MAGENTA); + screen.rect(20, 220, -20, 260, COLOR_BRIGHT_YELLOW); + + let path = reference_file(Path::new("rect_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn filled_rect_drawing() { + let mut screen = setup(); + + screen.filled_rect(10, 10, 90, 90, COLOR_BLUE); + screen.filled_rect(10, 110, 90, 190, COLOR_GREEN); + screen.filled_rect(190, 90, 110, 10, COLOR_CYAN); + + ////// + + screen.filled_rect(-8, 10, 7, 25, COLOR_MAGENTA); + screen.filled_rect(20, -8, 35, 7, COLOR_BROWN); + screen.filled_rect(313, 170, 328, 185, COLOR_LIGHT_GRAY); + screen.filled_rect(285, 233, 300, 248, COLOR_DARK_GRAY); + + screen.filled_rect(-16, 30, -1, 46, COLOR_BRIGHT_BLUE); + screen.filled_rect(40, -16, 55, -1, COLOR_BRIGHT_GREEN); + screen.filled_rect(320, 150, 335, 165, COLOR_BRIGHT_CYAN); + screen.filled_rect(265, 240, 280, 255, COLOR_BRIGHT_RED); + + screen.filled_rect(300, 20, 340, -20, COLOR_BRIGHT_MAGENTA); + screen.filled_rect(20, 220, -20, 260, COLOR_BRIGHT_YELLOW); + + let path = reference_file(Path::new("filled_rect_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn circle_drawing() { + let mut screen = setup(); + + screen.circle(48, 48, 32, COLOR_BLUE); + screen.circle(128, 48, 24, COLOR_GREEN); + screen.circle(48, 128, 40, COLOR_CYAN); + + ////// + + screen.circle(0, 30, 16, COLOR_MAGENTA); + screen.circle(40, 2, 11, COLOR_BROWN); + screen.circle(319, 211, 17, COLOR_LIGHT_GRAY); + screen.circle(290, 241, 21, COLOR_DARK_GRAY); + + screen.circle(319, 1, 22, COLOR_BRIGHT_BLUE); + screen.circle(2, 242, 19, COLOR_BRIGHT_GREEN); + + let path = reference_file(Path::new("circle_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn filled_circle_drawing() { + let mut screen = setup(); + + screen.filled_circle(48, 48, 32, COLOR_BLUE); + screen.filled_circle(128, 48, 24, COLOR_GREEN); + screen.filled_circle(48, 128, 40, COLOR_CYAN); + + ////// + + screen.filled_circle(0, 30, 16, COLOR_MAGENTA); + screen.filled_circle(40, 2, 11, COLOR_BROWN); + screen.filled_circle(319, 211, 17, COLOR_LIGHT_GRAY); + screen.filled_circle(290, 241, 21, COLOR_DARK_GRAY); + + screen.filled_circle(319, 1, 22, COLOR_BRIGHT_BLUE); + screen.filled_circle(2, 242, 19, COLOR_BRIGHT_GREEN); + + let path = reference_file(Path::new("filled_circle_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn text_drawing() { + let mut screen = setup(); + + let font = BitmaskFont::new_vga_font().unwrap(); + let small_font = BitmaskFont::load_from_file(test_assets_file(Path::new("small.fnt")).as_path()).unwrap(); + let chunky_font = BitmaskFont::load_from_file(test_assets_file(Path::new("chunky.fnt")).as_path()).unwrap(); + + let message = "Hello, world! HELLO, WORLD!\nTesting 123"; + + screen.print_string(message, 20, 20, FontRenderOpts::Color(COLOR_BLUE), &font); + screen.print_string(message, 20, 40, FontRenderOpts::Color(COLOR_GREEN), &small_font); + screen.print_string(message, 20, 60, FontRenderOpts::Color(COLOR_CYAN), &chunky_font); + + screen.filled_rect(58, 218, 162, 230, COLOR_LIGHT_GRAY); + screen.print_string("transparency!", 60, 220, FontRenderOpts::Color(COLOR_BRIGHT_BLUE), &font); + + let mut s = String::with_capacity(256); + for i in 1..=127 { + if i % 8 == 0 { + s += "\n"; + } + if i == 10 { + s += " "; + } else { + s += &char::from(i).to_string(); + } + } + + screen.print_string(&s, 20, 80, FontRenderOpts::Color(COLOR_BRIGHT_WHITE), &font); + screen.print_string(&s, 110, 80, FontRenderOpts::Color(COLOR_BRIGHT_WHITE), &small_font); + screen.print_string(&s, 190, 80, FontRenderOpts::Color(COLOR_BRIGHT_WHITE), &chunky_font); + + ////// + + let message = "Hello, world!"; + + screen.print_string(message, -35, 10, FontRenderOpts::Color(COLOR_BRIGHT_BLUE), &font); + screen.print_string(message, 80, -4, FontRenderOpts::Color(COLOR_BRIGHT_GREEN), &font); + screen.print_string(message, 285, 120, FontRenderOpts::Color(COLOR_BRIGHT_CYAN), &font); + screen.print_string(message, 200, 236, FontRenderOpts::Color(COLOR_BRIGHT_RED), &font); + screen.print_string(message, -232, 10, FontRenderOpts::Color(COLOR_MAGENTA), &font); + screen.print_string(message, 80, -24, FontRenderOpts::Color(COLOR_BROWN), &font); + screen.print_string(message, 360, 120, FontRenderOpts::Color(COLOR_LIGHT_GRAY), &font); + screen.print_string(message, 200, 250, FontRenderOpts::Color(COLOR_DARK_GRAY), &font); + + let path = reference_file(Path::new("text_drawing.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +fn generate_bitmap(width: i32, height: i32) -> RgbaBitmap { + let x_third = width / 3; + let y_third = height / 3; + + let mut bitmap = RgbaBitmap::new(width as u32, height as u32).unwrap(); + + bitmap.filled_rect(0, 0, x_third, y_third, COLOR_BLUE); + bitmap.filled_rect(x_third * 2 + 1, y_third * 2 + 1, width - 1, height - 1, COLOR_GREEN); + bitmap.filled_rect(0, y_third * 2 + 1, x_third, height - 1, COLOR_CYAN); + bitmap.filled_rect(x_third * 2 + 1, 0, width - 1, y_third, COLOR_RED); + bitmap.filled_rect(x_third, y_third, x_third * 2 + 1, y_third * 2 + 1, COLOR_MAGENTA); + bitmap.rect(0, 0, width - 1, height - 1, COLOR_BROWN); + + bitmap +} + +#[test] +fn solid_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let bmp16 = generate_bitmap(16, 16); + let bmp12 = generate_bitmap(12, 12); + let bmp21 = generate_bitmap(21, 21); + let bmp3 = generate_bitmap(3, 3); + + let x = 40; + let y = 20; + screen.blit(Solid, &bmp16, x + 16, y + 48); + screen.blit(Solid, &bmp12, x + 80, y + 48); + screen.blit(Solid, &bmp21, x + 144, y + 48); + screen.blit(Solid, &bmp3, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(Solid, &bmp16, x + 16, y + 48); + screen.blit_unchecked(Solid, &bmp12, x + 80, y + 48); + screen.blit_unchecked(Solid, &bmp21, x + 144, y + 48); + screen.blit_unchecked(Solid, &bmp3, x + 208, y + 48); + } + + ////// + + screen.blit(Solid, &bmp16, -3, 46); + screen.blit(Solid, &bmp16, -4, 76); + screen.blit(Solid, &bmp16, -8, 106); + screen.blit(Solid, &bmp16, -12, 136); + screen.blit(Solid, &bmp16, -13, 166); + screen.blit(Solid, &bmp16, -14, 196); + screen.blit(Solid, &bmp16, -16, 226); + + screen.blit(Solid, &bmp16, 46, -3); + screen.blit(Solid, &bmp16, 76, -4); + screen.blit(Solid, &bmp16, 106, -8); + screen.blit(Solid, &bmp16, 136, -12); + screen.blit(Solid, &bmp16, 166, -13); + screen.blit(Solid, &bmp16, 196, -14); + screen.blit(Solid, &bmp16, 226, -16); + + screen.blit(Solid, &bmp16, 307, 46); + screen.blit(Solid, &bmp16, 308, 76); + screen.blit(Solid, &bmp16, 312, 106); + screen.blit(Solid, &bmp16, 316, 136); + screen.blit(Solid, &bmp16, 317, 166); + screen.blit(Solid, &bmp16, 318, 196); + screen.blit(Solid, &bmp16, 320, 226); + + screen.blit(Solid, &bmp16, 46, 227); + screen.blit(Solid, &bmp16, 76, 228); + screen.blit(Solid, &bmp16, 106, 232); + screen.blit(Solid, &bmp16, 136, 236); + screen.blit(Solid, &bmp16, 166, 237); + screen.blit(Solid, &bmp16, 196, 238); + screen.blit(Solid, &bmp16, 226, 240); + + let path = reference_file(Path::new("solid_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn solid_flipped_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit_unchecked(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit_unchecked(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit_unchecked(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, -3, 46); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, -4, 76); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, -8, 106); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, -12, 136); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, -13, 166); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, -14, 196); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, -16, 226); + + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 46, -3); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 76, -4); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 106, -8); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, 136, -12); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 166, -13); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 196, -14); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 226, -16); + + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 307, 46); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 308, 76); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 312, 106); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, 316, 136); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 317, 166); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 318, 196); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 320, 226); + + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 46, 227); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 76, 228); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 106, 232); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: true }, &bmp, 136, 236); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: false }, &bmp, 166, 237); + screen.blit(SolidFlipped { horizontal_flip: true, vertical_flip: false }, &bmp, 196, 238); + screen.blit(SolidFlipped { horizontal_flip: false, vertical_flip: true }, &bmp, 226, 240); + + let path = reference_file(Path::new("solid_flipped_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn transparent_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let transparent_color = to_rgb32(0, 0, 0); + + let bmp16 = generate_bitmap(16, 16); + let bmp12 = generate_bitmap(12, 12); + let bmp21 = generate_bitmap(21, 21); + let bmp3 = generate_bitmap(3, 3); + + let x = 40; + let y = 20; + screen.blit(Transparent(transparent_color), &bmp16, x + 16, y + 48); + screen.blit(Transparent(transparent_color), &bmp12, x + 80, y + 48); + screen.blit(Transparent(transparent_color), &bmp21, x + 144, y + 48); + screen.blit(Transparent(transparent_color), &bmp3, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(Transparent(transparent_color), &bmp16, x + 16, y + 48); + screen.blit_unchecked(Transparent(transparent_color), &bmp12, x + 80, y + 48); + screen.blit_unchecked(Transparent(transparent_color), &bmp21, x + 144, y + 48); + screen.blit_unchecked(Transparent(transparent_color), &bmp3, x + 208, y + 48); + } + + ////// + + screen.blit(Transparent(transparent_color), &bmp16, -3, 46); + screen.blit(Transparent(transparent_color), &bmp16, -4, 76); + screen.blit(Transparent(transparent_color), &bmp16, -8, 106); + screen.blit(Transparent(transparent_color), &bmp16, -12, 136); + screen.blit(Transparent(transparent_color), &bmp16, -13, 166); + screen.blit(Transparent(transparent_color), &bmp16, -14, 196); + screen.blit(Transparent(transparent_color), &bmp16, -16, 226); + + screen.blit(Transparent(transparent_color), &bmp16, 46, -3); + screen.blit(Transparent(transparent_color), &bmp16, 76, -4); + screen.blit(Transparent(transparent_color), &bmp16, 106, -8); + screen.blit(Transparent(transparent_color), &bmp16, 136, -12); + screen.blit(Transparent(transparent_color), &bmp16, 166, -13); + screen.blit(Transparent(transparent_color), &bmp16, 196, -14); + screen.blit(Transparent(transparent_color), &bmp16, 226, -16); + + screen.blit(Transparent(transparent_color), &bmp16, 307, 46); + screen.blit(Transparent(transparent_color), &bmp16, 308, 76); + screen.blit(Transparent(transparent_color), &bmp16, 312, 106); + screen.blit(Transparent(transparent_color), &bmp16, 316, 136); + screen.blit(Transparent(transparent_color), &bmp16, 317, 166); + screen.blit(Transparent(transparent_color), &bmp16, 318, 196); + screen.blit(Transparent(transparent_color), &bmp16, 320, 226); + + screen.blit(Transparent(transparent_color), &bmp16, 46, 227); + screen.blit(Transparent(transparent_color), &bmp16, 76, 228); + screen.blit(Transparent(transparent_color), &bmp16, 106, 232); + screen.blit(Transparent(transparent_color), &bmp16, 136, 236); + screen.blit(Transparent(transparent_color), &bmp16, 166, 237); + screen.blit(Transparent(transparent_color), &bmp16, 196, 238); + screen.blit(Transparent(transparent_color), &bmp16, 226, 240); + + let path = reference_file(Path::new("transparent_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn transparent_flipped_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let transparent_color = to_rgb32(0, 0, 0); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit_unchecked(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit_unchecked(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit_unchecked(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, -3, 46); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, -4, 76); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, -8, 106); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, -12, 136); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, -13, 166); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, -14, 196); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, -16, 226); + + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 46, -3); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 76, -4); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 106, -8); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, 136, -12); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 166, -13); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 196, -14); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 226, -16); + + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 307, 46); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 308, 76); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 312, 106); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, 316, 136); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 317, 166); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 318, 196); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 320, 226); + + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 46, 227); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 76, 228); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 106, 232); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: true }, &bmp, 136, 236); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: false }, &bmp, 166, 237); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: true, vertical_flip: false }, &bmp, 196, 238); + screen.blit(TransparentFlipped { transparent_color, horizontal_flip: false, vertical_flip: true }, &bmp, 226, 240); + + let path = reference_file(Path::new("transparent_flipped_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn transparent_single_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let transparent_color = to_rgb32(0, 0, 0); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BLUE }, &bmp, x + 16, y + 48); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_RED }, &bmp, x + 80, y + 48); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_LIGHT_GRAY }, &bmp, x + 144, y + 48); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_MAGENTA }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(TransparentSingle { transparent_color, draw_color: COLOR_BLUE }, &bmp, x + 16, y + 48); + screen.blit_unchecked(TransparentSingle { transparent_color, draw_color: COLOR_RED }, &bmp, x + 80, y + 48); + screen.blit_unchecked(TransparentSingle { transparent_color, draw_color: COLOR_LIGHT_GRAY }, &bmp, x + 144, y + 48); + screen.blit_unchecked(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_MAGENTA }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -3, 46); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -4, 76); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -8, 106); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -12, 136); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -13, 166); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -14, 196); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_CYAN }, &bmp, -16, 226); + + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 46, -3); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 76, -4); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 106, -8); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 136, -12); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 166, -13); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 196, -14); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_DARK_GRAY }, &bmp, 226, -16); + + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 307, 46); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 308, 76); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 312, 106); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 316, 136); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 317, 166); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 318, 196); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE }, &bmp, 320, 226); + + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 46, 227); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 76, 228); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 106, 232); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 136, 236); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 166, 237); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 196, 238); + screen.blit(TransparentSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN }, &bmp, 226, 240); + + let path = reference_file(Path::new("transparent_single_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn transparent_flipped_single_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let transparent_color = to_rgb32(0, 0, 0); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BLUE, horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_RED, horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_LIGHT_GRAY, horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_MAGENTA, horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BLUE, horizontal_flip: false, vertical_flip: false }, &bmp, x + 16, y + 48); + screen.blit_unchecked(TransparentFlippedSingle { transparent_color, draw_color: COLOR_RED, horizontal_flip: true, vertical_flip: false }, &bmp, x + 80, y + 48); + screen.blit_unchecked(TransparentFlippedSingle { transparent_color, draw_color: COLOR_LIGHT_GRAY, horizontal_flip: false, vertical_flip: true }, &bmp, x + 144, y + 48); + screen.blit_unchecked(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_MAGENTA, horizontal_flip: true, vertical_flip: true }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: false, vertical_flip: false }, &bmp, -3, 46); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: true, vertical_flip: false }, &bmp, -4, 76); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: false, vertical_flip: true }, &bmp, -8, 106); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: true, vertical_flip: true }, &bmp, -12, 136); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: false, vertical_flip: true }, &bmp, -13, 166); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: true, vertical_flip: false }, &bmp, -14, 196); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_CYAN, horizontal_flip: false, vertical_flip: true }, &bmp, -16, 226); + + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: false, vertical_flip: false }, &bmp, 46, -3); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: true, vertical_flip: false }, &bmp, 76, -4); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: false, vertical_flip: true }, &bmp, 106, -8); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: true, vertical_flip: true }, &bmp, 136, -12); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: false, vertical_flip: false }, &bmp, 166, -13); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: true, vertical_flip: false }, &bmp, 196, -14); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_DARK_GRAY, horizontal_flip: false, vertical_flip: true }, &bmp, 226, -16); + + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: false, vertical_flip: false }, &bmp, 307, 46); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: true, vertical_flip: false }, &bmp, 308, 76); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: false, vertical_flip: true }, &bmp, 312, 106); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: true, vertical_flip: true }, &bmp, 316, 136); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: false, vertical_flip: false }, &bmp, 317, 166); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: true, vertical_flip: false }, &bmp, 318, 196); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_WHITE, horizontal_flip: false, vertical_flip: true }, &bmp, 320, 226); + + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: false, vertical_flip: false }, &bmp, 46, 227); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: true, vertical_flip: false }, &bmp, 76, 228); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: false, vertical_flip: true }, &bmp, 106, 232); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: true, vertical_flip: true }, &bmp, 136, 236); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: false, vertical_flip: false }, &bmp, 166, 237); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: true, vertical_flip: false }, &bmp, 196, 238); + screen.blit(TransparentFlippedSingle { transparent_color, draw_color: COLOR_BRIGHT_GREEN, horizontal_flip: false, vertical_flip: true }, &bmp, 226, 240); + + let path = reference_file(Path::new("transparent_flipped_single_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn rotozoom_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, x + 16, y + 48); + screen.blit(RotoZoom { angle: 0.3, scale_x: 1.5, scale_y: 1.0 }, &bmp, x + 80, y + 48); + screen.blit(RotoZoom { angle: 0.6, scale_x: 1.0, scale_y: 1.5 }, &bmp, x + 144, y + 48); + screen.blit(RotoZoom { angle: 2.0, scale_x: 0.7, scale_y: 0.7 }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, x + 16, y + 48); + screen.blit_unchecked(RotoZoom { angle: 0.3, scale_x: 1.5, scale_y: 1.0 }, &bmp, x + 80, y + 48); + screen.blit_unchecked(RotoZoom { angle: 0.6, scale_x: 1.0, scale_y: 1.5 }, &bmp, x + 144, y + 48); + screen.blit_unchecked(RotoZoom { angle: 2.0, scale_x: 0.7, scale_y: 0.7 }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -3, 46); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -4, 76); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -8, 106); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -12, 136); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -13, 166); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -14, 196); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -16, 226); + + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 46, -3); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 76, -4); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 106, -8); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 136, -12); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 166, -13); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 196, -14); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 226, -16); + + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 307, 46); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 308, 76); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 312, 106); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 316, 136); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 317, 166); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 318, 196); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 320, 226); + + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 46, 227); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 76, 228); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 106, 232); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 136, 236); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 166, 237); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 196, 238); + screen.blit(RotoZoom { angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 226, 240); + + let path = reference_file(Path::new("rotozoom_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn rotozoom_transparent_blits() { + use RgbaBlitMethod::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let transparent_color = to_rgb32(0, 0, 0); + + let bmp = generate_bitmap(16, 16); + + let x = 40; + let y = 20; + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, x + 16, y + 48); + screen.blit(RotoZoomTransparent { transparent_color, angle: 0.3, scale_x: 1.5, scale_y: 1.0 }, &bmp, x + 80, y + 48); + screen.blit(RotoZoomTransparent { transparent_color, angle: 0.6, scale_x: 1.0, scale_y: 1.5 }, &bmp, x + 144, y + 48); + screen.blit(RotoZoomTransparent { transparent_color, angle: 2.0, scale_x: 0.7, scale_y: 0.7 }, &bmp, x + 208, y + 48); + + let x = 40; + let y = 110; + unsafe { + screen.blit_unchecked(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, x + 16, y + 48); + screen.blit_unchecked(RotoZoomTransparent { transparent_color, angle: 0.3, scale_x: 1.5, scale_y: 1.0 }, &bmp, x + 80, y + 48); + screen.blit_unchecked(RotoZoomTransparent { transparent_color, angle: 0.6, scale_x: 1.0, scale_y: 1.5 }, &bmp, x + 144, y + 48); + screen.blit_unchecked(RotoZoomTransparent { transparent_color, angle: 2.0, scale_x: 0.7, scale_y: 0.7 }, &bmp, x + 208, y + 48); + } + + ////// + + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -3, 46); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -4, 76); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -8, 106); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -12, 136); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -13, 166); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -14, 196); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, -16, 226); + + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 46, -3); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 76, -4); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 106, -8); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 136, -12); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 166, -13); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 196, -14); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 226, -16); + + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 307, 46); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 308, 76); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 312, 106); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 316, 136); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 317, 166); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 318, 196); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 320, 226); + + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 46, 227); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 76, 228); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 106, 232); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 136, 236); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 166, 237); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 196, 238); + screen.blit(RotoZoomTransparent { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0 }, &bmp, 226, 240); + + let path = reference_file(Path::new("rotozoom_transparent_blits.png")); + //screen.to_png_file(path.as_path()).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} diff --git a/ggdt/tests/ref/rgba/circle_drawing.png b/ggdt/tests/ref/rgba/circle_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..f1c2a2e36f54325502ca4ec4b4400398934d687a GIT binary patch literal 2250 zcmcJRSyWS57KU#|ZkUpw5XFHQ5Nrqmbwwyah!_L}L2(E;5s;x}l0h&sCKo8dfFKS) zF^kouB|?M(nF%Nm4Wg6^K@CI(8O20U!c9ddQh zP}Nlh06@dZk?sxvFq(2N1<}ei+_X6e0KjWb^u0$}1)s#;p&Re%uzLsZSa{~oyEp{i zD->10DJa6#qMqXQs@n`~jtv^fMr5qG!B27l)y%x7t1IBef?n~(H8hDaY@@ZA`Bgx( zh_KE9PD*# z6F#6xU^;UEu|i@66eQ!0e@SQhfx^v}4e@z<&^S8}Cwrujkj9meW%#`w9n(QlAN6US zb6iQf*O?ZyHEOXgXx_rkRRiOLU5XW!Z@8F1h`XB`QjHsJBub(&5?4OniW;5O)73i?9 zLyp!@m!9iv!W;Zni$R95JlQ^G%IOj+$fGv?2C)9oj_c45v9^WG*j%&??A< zp0#ju50Q-+JPDNM1R)X?^?bPKCSYeap7c#_QW+?guEN3Q*a!zPMM0w~d&lJ_H6ovfk_6#s}Fo6A`h?=GmhCF}y3L$x%2+NkBddc)d)8s}q+P)qcH1l=fA4Ri z`RqJDD=)_~gw=e*9UDRYp+MT2M zsMH(2WnG6U!bVt`OT)v|TntItn6~Sc)o~v%j>xVC6fK# zSntAQp~@&jmL;4$#njNo)=%`H`VPt2&a-jMO)1zqNsmh3VRO+~v@7ox)JCa|glg8R zM?WlFQ$99K%V|iTgVZUS7fOYeW&+7Djqq=v9+5X~X^|^V*-MGoG>)!rG#A)cjJ#(? z6VUa7sDcgMv%YNS_nixE-LB|5en^2{_lz%F?f(ZT>Je#waUo?h_5ZaQRdnO)9!#IR zxv1kmXJ8|Vu+sBz_<*3)&2gfRT90O15j^&F?4vY9a;QgbCaSEkg31rxIfFmZLN&0B z@*Y@3PyzG1&@3U#lW)+tpSDbFEJ=&za^!8Qkf9chSp4JtAbFcHWOQne=CF#%r1|7d zt@|lH9T(xdU0V*ACu5Jlxx|@~;cPtyG`POYV`W}n+BHK@k)01EW23|8pq+`H3sXsA z^%Jarh(NuWKq>l+tlo-N)`#-n(d!@M;55&!G!% zE2x3hz_q_j^Z&Hy*wqnvm;Ng?;6@BreDPx_PUHqn&`*RGsbQrP&3npZ5 z7!7?pA=DP~siR2F`S;o__ovUOdv`!BXpTkM@I}9s>$qKHV~Brt7HDa*lh5`x@xb=J z{auyedN4IEG5FjqId#T}c^H;#ijf3)$E#a1pbz85jpv;uS z8n%2+Nyab|H#IdPIpmvMd$#&}>re&{VSQEpQ2-}Kkkp)KX&$g ze$PAmyuXiqR-Gx>;Xw=_0s!E_Pf3CS0K-L}ZFpDoUcA9@7yxiD`ANJi$;J6GVc}dX zIr-7f;f7Jh$b9Kc==Q?gt*P+(;{NQDl-<#452FFS0t@=)XHG3*f0!vfF*Wqvngc0- z;!7wK5NCs7a!w?M!u4+ih;;Y4qnKMh38E+`F!l_Tuw=-(CU^4(cFZw+8(`8$twBg8 zoZ~OUPMSHU$(ITWVWFERrst5xbyj8V32HGs0UWurn|XK=M`JmQIY4tvA%Jy z5cxipi>;R|z*&#iBIPRAA|qbFvX(U?NBc1s1FU6j$Waxfk5aC;u#`ni6;vdIwp3@} zr>_RM>W?{+$emZ?<==!flZ|ydiduqZR}t!67Yajg$4u)@1^80Q^=$9Vx$-~s=3=T?!kAxZ@e_SKxC1Tk^jBjZ+C-)t#Aoyr)>FdK7fG%kuheC_ zxZ0xFrIsCynsjZhFBKJLCeZhWNAro!HgN3f;=_99{`b+i($^oksk5pBH(!lT)$GZ3 zENIc=Jni^4jQy6v*#{kazSsr#I_U}LE-(ipB4vTMN#VN-8!7sSz@$1b>yt?iJ6ExE z(}&vu8^rLvL@e4^nd0};8*-`sMv?_5od2R29tEGg;5kHfhG+p%SOhHICXIc2?76PD z`p#m+bmiq084rG{{F$N-$%=fJ7 zAlnZ*zcPF)*<|&UiSOD7L8tzTG%;^yKw<{&7K1HK#D`40bm4dT@cf6~yTD2oK;on= z`7M;_psF*zN17?GdsRL1MHBWrFX(GD$xV2Wl)RQ%odzgW%5-fzQ;A$Ty_PYU3Mul| z(gd2bcyOvf63fm6@zNWA>(|Aq>9(>6TB=5i2NQ%#nQ%QswojOF+T4=HNt~y2pPdWW z-XC5?6d7(*Rza{(twZ3yXfpq z`~Pl)I9E|H@&63ApgN;}L+8JU|B}Ow`}gBcxHXtYk{2s+)C~g7gNgFMIGbKn49oA2 ztv*z!Tw0-VNV!H4FMeAo$ z4m;I?b3Cq5HCPxjqztVi@hpJW@q0QOw&3C;#u@BA7MwI3ovVH5no@9<5`}?i#F#Wq zlO6MHZD{gNhp5EaHLovKo|*4`7ap%7ZSQ{WrVVDvI4xLoCbpn~b@tb$vE`fX)fU`x z@o-%=DR$~BEIzR4()NK`TG6K;SE^}xV?ED>)ZzDEn_Uw?ZG(S%9{yL#p7S5iUbvy# z20-pV28-P7nw^wT=Q#gkLU6JJBG)qHh#p-u0^oo*SCkFn-O-T|6X>X=K{cVj1Y3R%((ligo;b9S z1LC`5SmlRv!{l6{&=eC>bq#A@>`9P$%ie0c^0jSXW<$9290^%@Q;z7Z1RF% vO<7lEA9~L`U(uRj;(^}~obKC6K~4hSk5;PN560)9{{jF%S&-D3C{q3thURZ$ literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/filled_rect_drawing.png b/ggdt/tests/ref/rgba/filled_rect_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..77df87a60539b7c68d980aaf6859742fe9f86344 GIT binary patch literal 2020 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQqt36#DLn`LHy<(W>a+23I zFgIxS8sAfn?0q=`FJ{eh|HPuMyu_*g)4xAJaJQsxfAMeI12Xmd>%;%vsawFn^k0OL z<(iN~f-VZR_6GygpI{b&h}TsN=g>qE zOqnzqD`GFSC0yfh6MG~M3k-AgJog;tUFd-O=ir?`Wn$N zn@U1jd~*Ay?d8}IShxY0+fwzJazbR@05jOlZU$*lc57gs`lfWi?dU;ZHkvxBY&1X! zr4WNlme1>dY5rdbDtGs37))eX#t|ED}Ets&FCV7aQ{P_I+`|t0!h1oM~n9jhI&8e_q8c~$~-+%w=p1!JP5vcHFXxs{{ gKD`mtB&Hwop4ws_JZBDs0&8yuPgg&ebxsLQ00l5#OaK4? literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/horiz_line_drawing.png b/ggdt/tests/ref/rgba/horiz_line_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..63e070b1f5bef565805e6794f49a714b59251c92 GIT binary patch literal 1042 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQKH$7b(Ln`LHy|j_n$&rWk z;OqTUvW21)Dx7rcn@-BC(Vbs>j{CvFpp6XPDI%CbRGtXS-}&1tB*pj?e&V6(p3x}N57iSB%fHw)$@dmI+ZvMk z_$%V2K92R}jiOy0xf5}{_d$JsT)+>IExvY8|7YHP7aKU8|CYf z796oIA1gQwR;7bUGS%crY4CdYv4VnWAZs_mipzM#np0;7iA8LW)U{}iOSMhpcm+mo zIAnL;`huV|FL~5htDBOFMzCv3{=?OZ8dLkr21n6P2W;`rHv?5A`aif5CPDX*#!7dLpu{pT3U6WReu{tYyWf7|SojwbM%DuSa4$l+@2fTn^q+b+7~=f4nC&3(%IYWaSqr@~Nr`!Q#X^DNrTO;&I8G5rZvs z4u73`Yg@6&VC&04+?Qn=^iCM5sJM+S@>KzZ?~yeFAuqNe$8=3t@En=oE%Bv9S0!S$tDTXJQI zTp&Hoa7%927tEOil=WZvupsnkDPaTRjk39S}l36 z!}Os5Tm5^#13XPbyEDjpEyc$?)s)lXDGF8Dte+~u5be9SfIxZXi2wm69K6n^ap}FG zSz1zeW*=9AOIyq|#6Ru{gdE+mat!IsE`nNFbA&)mm3`-wN#bR%;sjXwCBNPeMaGF^PRE*@alge-Uiz)Y<*|fwH}Qg}Mzc zBQln49Um4vl6F9NErdntuxYr9ZGFZj5I62{;S$V-G1bK{rdNhC^1NhEbpTWDfFtTf;G8J=k48cqHw0t9m6-V@R=d} zXpTiiGhTVgA~k=e)xinAUdyz)rr~Q+&Ci$~fFgf10F9X8hV~rC&b<)5nM|4YHm1rG P{NC{zClr6jAp literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/pixel_addressing.png b/ggdt/tests/ref/rgba/pixel_addressing.png new file mode 100644 index 0000000000000000000000000000000000000000..b73ad496f3d2c52389574794a9b7e25f755caa96 GIT binary patch literal 2309 zcmeH}{ZkW17{`NHP!UnN+)*G+tyQK1((ocyg8_>oB2dMaX$7%jr4}e00m4g?Q*5Oa zHMM9N1%wurT3!#VRFe=Ccn}Fhi&HuR1q2KjViM3nOMq@2Gt>W|zc_PqbF;Ji*=N7c zXJ;;1So@$sXiL7K+V%vBKC+@iLaY zdB<$ZNhK2g1?C|LD-#se2Cz8F!?GU zff7yQ=wy>1oa`VbRXob2rg7d&)Ncb>RDc$Mu+IC24cO}~06vB#{n~O}S2j4owcIQgWxmuP~QG0t0 z{pgo+_@cZLFRyOMsGz}~et0exK8dYl##YNyE9yEo(2uWcAVX70XsQ+BxSAUlCe+|D z2S6!fC`K}_wrw>%cBudk7R2KP2@UCSbPG<8{ICZ;+7r**lORt)CtpWvul7J{Pdw3+ zpb(AMG%YcqhE8sTkd0bwqfW+0m9M2WRZ{p;s>P+c2Gp|FH)!?wOxT;LWoGK+f^n1} zt!tPD@wAqh)+s2*#7481sI-A2mf&Z}!YtXsM8~9CE6C9wv*FWh7M{%(r#X_%%gEtV z0e}o)2CzlRj(jDDL>mASf@oz^!otLx3r(m8IZhDhRD?Md3zG_yZofl5x?Bc_%8Kx^ zVsQqt=ymep*%ahDS2PqeLl43NKRoYd55HM-tspl&Ckc$=ZY( zI^hk$-hG&NzmVUHT1;vx>mk0r53lbRXZE6Vkm@1LaH5 zDT=FaG=GVDHgMDi-na3=YK?hS5?9L`!^d32!!yYiPDL4CjRcGMyR9n@Q$Q zDm@G+dq7A+#hVk#^f#?cs0X=jfaJs66viak#BFE8qw;D%3gOj?*$kNh91IT&5&((7 zOi;|E$|gHE8Xik^fZ9pu6mw#s{)VLqHJHr?)EkUV8A;(po0DOztQb(jcri7bE;O_d zhLQXzKshm^sF@UWU%U<4`hGyCCHkp3kx}1dV?qr{cz{aBcymU+aiZPLfE)%?0Iuz+ zmn>mz@NYfIDh(?OxqFST9{v4dP_p*E*Yy+)-X|4E-tfuroL+wTk9&XaQ=RuI4X@sN zS1Qnrc9n%b(e`-%{ZvEDOixM7%q^N5kC;c_De>c^=?CoG4{Te^+TeN2+5vCMwwa2` z@~vCLwEFJyZWrH6yJ*JQ?Je^Tyc&3w$15HFpWARwVfJ)fE?t$-xdQ#(Fao!P_*ZS- Gm-P><1PTWL literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/pixel_drawing.png b/ggdt/tests/ref/rgba/pixel_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbb9175a2a8bc874b7e2625ae45f3ce97c1a395 GIT binary patch literal 1095 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOUe4Z|jAr*7pUOCwL#6g55 z@MnJ4oH=*R64*^uL>AVv`Y*5Ni2bx{-S6kS*0ImKcd&SV_$$>1|6aZOY}hm>kzwYp z{rjwC&eWe}D2mXUHr=p6W?I+NR33%)rAd{N%qJ38Ml>u9(K!&LC6=Hm%DrJq7i)yq zQ6`eXb-u(IVcxfHe1M&TDVqUv5w2g-E2v2sWPuIk)oPOQ&=qDq# z35SC=?&)ECvLQrAKbgVu&HLy3=F8geZEojL@cw?i{8)c8k3#nSo(J+1-dnX*C0#uO QEFc&>UHx3vIVCg!06|QZqyPW_ literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/rect_drawing.png b/ggdt/tests/ref/rgba/rect_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1e9442d2ff56c434593e0e0c6eaff342764364 GIT binary patch literal 1909 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQqHl8kyAr*7p-f_&63Fl!6 zhz*)P$6L!lLZRD%P59EgMbCBbdHFow?IO14({UiUzU=yQ{0!XHESBa5QnA!JBQb4MXf!0KohI~;iPaa{^UaufzdYrM)z^py-{o@L z8(v;XW;B~yrE_3ea6jvfl2;oUX8YNSC0t&4oGFJ4MW*cWJ*oOkdlo-iz&vlFyh;|I z)dR_&j*CXQLo757D#xwAzTNJYe9-~pPtERsVoUC4)}3HHe}Z3bA%id#$%pd~dnwp^ zT#+dOS>$rok=;faiF;5y`DQo6`xn$rrer4g^VhFGzrHP)k>P#L_hv2uixldRKW3gk ze}3ZA?{EG+1Xf(elZApC4rFo(R74|VPu3seqS4(FQM#(E!0MF2)78&qol`;+0B)uW A-~a#s literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/rotozoom_blits.png b/ggdt/tests/ref/rgba/rotozoom_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..e61f9e4ba9a23fc0b0c0a2dac9fb55211cea59a0 GIT binary patch literal 3050 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 Bn^6D& literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/rotozoom_transparent_blits.png b/ggdt/tests/ref/rgba/rotozoom_transparent_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..660465a0cf1b283d31aa82b773bd30e2db136753 GIT binary patch literal 3200 zcmcJSeK^y5AIE>cJ=iK^dXVHPsyWF#9F>R06w#@uPA5W45}hT4#>TcNJ$bl`n~EsW zsWeMsVr&sBla-EP^RUiN9@^N1p<%ak&i&tgUFZCD|MPu+|M*;=>vMgt>;3w?zgG|X zc%haXE(ZVrwb$F@FaUt~rMnWTwRFZ>HxL0p+iS0f`;o-LvHnBkk~V$%A+30mj@4u| zZZ9TjybE^eIepjF(C%PenYzwGt9&C3jndZ4tA{y}SlVSxIzRkjO`mO0QIJBtUWPl- zU!@7*3|?cXO<#`BMKxEkhLbDm`l2gl6n*8gr;M35ig#5TI@1;+YHlREdQ?y6$%@iL zEv3pK-QSCl!g0-F;V|k$e1n_urdR61vyj=h=mXtzqe$z_%9`;9=2HfwB6RO6{)UqP zlWOImsF>+b5G-=O+0VvNPBf%@E5GG$rz_anMGJ1Dm5v)q5ci>uYR%;Nm)+u?-3e2^L5Jh?5e=ix^hvQR3!}=B8FyPJDjVN}>~9RT zlRjeN^Kt^h^gTT5V*)@~pkre)#vvonI()ejWUn-rtT_%tOV&V;rJLyZfd8*lujBFu zKVh5bKuyMh^?7G&ZEST9SEuqrl#<%+psV#8a>y*eO0SpViHmBFby zP|j>onGWHhm87e+c6IYsw~Zg?-q?=!J}$YaB>I@+dMr*hKn9KiUe!t096Crt4~FgX zhuf@%H+1@E{h9&k{%6fz$G*^hs|$7nWQuSQwfO3QEE|iq|OfPSlc%V_hD#clSbT9XfE7dK`P|-N~^;(%77a zys9*G_pJ)ECXcPYSyqzFxDWO<=Nj8&TMJW?nMRXOQVw?ZPE=nzKrZ`b?SxML@0 z5cYP;-d`D9z(m^60tc0qGu=#)U`7nKE3*t_C2~7OQkB>IxA;halH!-!?Kw9;Xz;4+ zb1Ub@U6WNcQM{S+z%WT4e?lY*%T$eT9}}qM8mpA`&#Blfqdap<>VliX+LS_EagVfr z*;!eClsJJVnBjw~camSIDr&~qoZ-69ahxV0)40@8LwyqI(#m}-`9)EgFsm4O1zo%KgcDBYo@eFex5sSW@a z9G>`Hs{a#l#s%;geK$RrGv+VItESH?mB!rP6jE~(jKK5);JV&JCR}e_LkV(e2b{l7 zC`D+;Yy|heo(R6RitE7^hZN^{XXl44lXxg%XPx1*^RU|9uv@2f=6|E)InxE*h>;n2 zPqiJk#g?!8Hr~}fgF-g6+%R91YSIHc)8S z2O~zL;a^2TxpBhg^R~v#;g1l{xyzE7fz2`-@1R{D?I@9LCSQ&!%0Bt!Z!mGS;H&nQ}XHTWW-%LKt+?8Fp}dp$kdi zwIQ)luxitJZ7`@Hd$e#0&8^)c6Qj1BgRu`va1WH4kb?PuwMjS=x^oW|$Gk4Q%#EvVHn(!Qs zW1AAQged^gcU-7Tw#i4-(&o!nav9Aa1I(~p!Xb&xs;{x$**eJEzSt3z+^}IYUACSo zL7lXsQ&h10M%u**zi7$^dW4B=!0D|a_m|?!+R?OV_|gKTfkD?LA5#pW2BF!JMkJZR zFJbS{SL`m{Fqu3ge%(Kn?hQ?fl1!&HReg3|PHg!Yrd81WS5lvB8ySTd|bt2)^w}e_N7e71ZTvSJMMTxd)-DZWy9l5*o>rOhBE>4 z=3@)hTF+D|9nO1#{ZNv`-MQ}U?IXjcCv0Me;v8s?jcn+FJeNRdWWh-H)XM{_xUtEp zGoobA#5wV|^y~&s-$RsvJOOuZ&B6t@`HWiN z4vY>6O^7c@ET=5sX47FuQtm{8h<$u7#SPjN^?7sJq5BQ{!T*jtjUaC*RF0Jig6aaZ2>QQG`Hu}PpTR*`? z7f}T3MBg+u9uS~|2^_J{52c8m6iGgRf7Huj zNi}DG%sZ>L}N-2O}mL--U*A*=RnPS>IRtN>|+r_VcAW5-;qB;G8IGjV(buC kdVPwb>@N<8U@jtl=r7&Nwy#fK`dI*bJ$*bXb`etl1L-I6&j0`b literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/solid_blits.png b/ggdt/tests/ref/rgba/solid_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..349237b5b4070bcb9610a536b70e8e5dccd2ec17 GIT binary patch literal 1897 zcmb`Ido+}37{K56^G!3xZ5UD_vr$%2(|xS)aY%Msx8!naP}#~-E+?0;d|KC7l2fU~ z?Al7m&+Dy0(Y)N;CDL@G0K%M2qk`&n&u_CM$BKkxHC=Xsy!Jn!@Vp65+>b#_#v z>(K!KYEGN%-2s3YxgVmKmB9ua?h=v3axS7~Ow@kxX$-8xPE-vMud3s+QST zIDtLS%UjP0T@lWcND4!JF}`}A7wC3H#?K7M%+$Znv&0o!()819)y^Vs?R@+-V17U? zF^mo^croUq|CAj8l4;R*u0S;U7(gmfM%rQ=GlS?(WftQHkm!xj8niIh@&DW8DXM?o z=(}2tac}6%@vCjJ#uH>QlvzV5Ew&;h5toVa(3u=WXMrRYWkiP*f&CE|f6)n>qJ}&$ z#fb&74W+SBe^xzP3(-E4&nb&yp}1c0*s#z%u#QV(4P`mQkK$)fxV00>H^)}B4>K_# z_cx?^+G{BTW3^Qwdo9d(heFI#*FFI-%lLDkPj_ExNDSud@eka0ku7%Sw3t>^H->w;z-^SW4zUY_o~00G?y_kn5pKUa2R-Ai?t{_ zIY*ib=t7xhXC%Nn^4dStBCBRl8g?z|M5B#D+=2TzpWFl!k3uiK4|C% zTwJ%s<9C*aBCY4bgf1};;lyB(T_(Kunr?bvR+88gz4Gg}IjZY{NmKxbXbcy8PIq9_^gl0^p@Co9p zHuy9e?8{p~Y<*Z1(O%9^*Ti_4Zop-uuAK_YHJyZgozgTHCC#rZcI&AUIkRbt<`FOK z@SSk)sROx3To9Ue*-v2dorq8Zdn$IOItl~WDlrB)k{y^+u~ zp@0h|m$bxo^u>Wt-S%kWHTdTSJd8cy%e435*zo-DDCtih=p>naCyt22{Ij?|atZo(D!k z3)z((l7E=(*PJ0`zs=mRy&7oE{({-^+U)L)ooWjA?oi9Y*>4sYML=|f_Ia9KM=QwD z+NVz}!Lfy3knn?Igce|tpjNKJI^sC{K6PH}!tUr?>X0=@1O*c{ zzbbiK2uL`cuX16Mk+RU^g$~9!I;|F3-O52jO9sAsXC%-Md=Dh?Jv-83YV+3PK8^*q vnp~FY5V<#*z2C*BqU_}YANav1C@TT75}_}#v#OT-LV=TmvwgXp|DnGD{;TwS literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/solid_flipped_blits.png b/ggdt/tests/ref/rgba/solid_flipped_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..80b2aef055ef3fbcbfbe9bf58b78521186da36a4 GIT binary patch literal 1900 zcmb_dYfw{16yAFi@2oz|MqSb~vXoHUe1~8OJKnz?ER0;*O zQjnLF7GWeHSP_&&q9Rm_pdt?;N|b4c;T2INfoOV>j{I<@9cMbTv%9l9d(OA#`_4IO z0sh`Pl%*5^fR3+^=T-n91lub}1Z%n5hvs zu%`Q7WjYrznx4sr+MNa-mrGm5dR}EY+d4~M){PqF4uysss`WTe6P1z3l4{k)kI{JJ z*RDhHITYr%oFHJ57T~;BJk&Pz4YY98)&5&JWuaXugDlA^dQQ>zB1_t%Dv4Bcny6@y zLNCk(W5x{dM1WVEh&skK&TVmFpH5*#u?5jYwsGFgCClsmt~;%(_+=ZgJf(GsDmvD( z2&q7T$&#Kr$BHKpFb~YEP6Cx_4dHi_>C`VkQXoufHbCe<1GpAXJ-!x2EdK8+em54g zs`mBn^c$-!Syhwu))A#yWV#~R%6-@_lDios8O(X+?}SFu@zmIeXeelS$Bg;YQ4@iA zIe@KYgVkd)zXNqFm{fS?9Z-HN+?%K=wH~kx6Y>lY$s!?9@oNZ|J1XDM#?Lis`4S{C z>eLKw^Q{ z)+fNKV<-6Yw6>)0r_%jIcG!_WN})ovSMKks@z^(0?ZVsYo)r9DDEkmlsO#q$-e;eLHedMRv%!g(~&a0jRCfIc@h#<4T# z&Vage$od`S!@YnInT0Ftksdtn;DbNcE0DW`By)_MI^H8z?-jF>>MGY4OwI?1g>}%G zZ?~Di48>Nt9)bA%P6wZ&$T1gLF@Wtc39{_bPVbu-MK^+gx3KZG4F|%v^ELS!slFhI zG%rpEVoj4qM1=7EBL<>`eVpqXEcVcll8npXQp}!}7Xh3@n$vS7baDCOfG&AVU`YM~ z(TNWc^_^D?5svzYv-clkgX3U(0m8y8%+tr*!Cz&&g_0f(*} z5sNYT(QtW+ao%i(EEGK)PkD=v83f$A^du`n@+(yZO{#&Z;$}RR>4Qa?0r5FP9P>vk zH>(e1Q0P?8xzJzHWj?oe10FY|aW+mLRJOXpQ?-6miFGR{aM_Sl&0`7x95v634lJ{> z$^L6lw+6s*^T#}`nnvvfd*k$&h6p`-u2M`IA^pKn*v9%BPMzt5_v^=h6w`7Y$-ryD zii2k_!vlj4pzx}WP#Q1X8>AY_sUl*_a!p)B_scpmU9cEB%nX83mf{sjQCigfW{X5u zWnzdks-MZ70GS;xBZ&(6kgks8eqJj<(XrakRQk04Jel4$+aex2OIKoj!uWH*&HMyq z?}8hm#UTWC)W{K7*0(xmwwolbM?3PzWf|YU;YS~eF&7A~L=zRhA)c_(4tnXvQ%07- uN?K2Ii+f<^*gbcu$b`(CQSI}0Y1L>1E)Mzjq#mq`0$(qG&+1Lg{+wk^{(|iYrXr~5B|L1bVy85 zOh7>3kc+eZMF9ap8~*bzk^TI8q&^lVARxzZvA4Y(U%6Hxj$U|+w5Mq&6=V8#s@GnL z9@>xiP2_ibkN(J7`;0$?)E{`ZuOavs^y2aebngLa)4E6^tbjnv8Oag!?lII>g2qiR zz~mRHku}1n8t#(f5C)k_voGunjhG{|4EMh<{e^zBENX@ z#QQm$?7ri{qJU?`?!!myoOS9dk7X8Ka5OtF0;tN3dMssUuCRC#kQrmxPwZjSm$xEb z&lj>Y3k!lCwd@J#UnRYTT?;s@wQ!#3F3^>sIfeh04?HVtW0!5a2Nez!9OtxNe;Mi( ztqmvI*6NAvjHfL37nw{)7s)_XO6hFraY>f*!E-uglDuQ%jh!>(EEV`McEo zva>PbwSTV{O;@VwZ}sYAMFd9ZvZ{9KF-1)9$k`)m9S?4P7!=Nt*fQ7|p^-kE13DjL z-AFEy)N6ja;T`>&g_ymwleMHf57zEJzCN+-{Lp>a1Y3%zxhD$9%Z*~~H}B?&0M7Bj_jgoz+lj0OJZj05 z8vAb;27LgJw%tHY3H9zi=7uOo<^SeAfX1doB_s;7Q_Sw*$X*~TY-#3qBXP6NXPTR~JnpAp5@3jn0?>4*im;S|8!o|!pOQ5?r)w+3 zmj-4z2#?c^rK4LtpQi>3eoYP%)IywZxf*i7v+t<8E1fak9M(4>dR z=5{x>0=3vp7~^nQc(~u?uYPGL;*%oaxo3M{Rw%f>hSL&Xb?k<(W!H6G9ux&|jl>h7 zrxgyNus;!t5y1yD3q@}nNzosi@`xGj*}VP9R;28`_O*s50ekwo^oVQDKL&X|s^aPZ z#Gv*y8s&GMW@2E|*XAWhQnlJkZ9sr-MJ9I7(On77n=s;B9F%~r4hF7e1du+l1huh(FPWOAO$m-cS=lx%_{&xXfTE0`5){Q3K1A67>Bh;E87bkr* zA<%J3wpo}HcO`+bxOPgzxE#AgS6j{eKJanfECUY^=WKa|xRQ=(#UqmhSo&BKZSe zNS13c78-eY^UjSUJjVI_-E-EQ0#;^W{Wq;$q_9+8g+pN>KSR6vsltwXRRw!IC)|Vo z+138N{r{y6avYF4uu>YyJX@0d#MK2W49v=|k{UaiE&IIRKNLU-xMNjyTwAMPvN=2D z5xqXj7AJ(wAUz*5Sj6au<33|?CTzqwnO=ZWUQqUgOrSvS-E;Zr%NE3FCU^V>(KB z#|tu*FQ95-%>tAhFqT3*vV&}VTn>%DnnJKsaeoWqj5cXtIkO{=L{%p?dG1v+&W=w^Eoyt{5-ty zlSsRiaG=f#o2Shr2=<9o6dlQfsd1*ur0v8QVvePNXz$UK z1|*V#1^dsuHG7W1Cab?Ap@OzHcQ5;ixQywA_~!PXZBPqSkr8w|tS`at53rv$+ zrfm5SCqa^_OHm$oifBa$9H*iC_L9Z8n+W>=He&)_dg7Gl>2af3?&IouHJJ|S9K^DZ zk?DBB_K~5jsO*J`!b6pm=_dG_D12@G)MT#OSpHxEM+!@^JpXY3U!0%?9RY2uoT9(k zT99AeQvJHV_7wcdvchC(welhAdcm!j?Wq6&Y4*F})l2BW!%mn(MD%WW; z36*!|{330{oIfvFMO8AZ@o#pMGTMP8lpLH8!G*v={a@Urc9xtUd9g?u8(s2Fseagg zjVfJWa$ji@5%K8-cA#T3BW0fK?clWJ*qt0~y-S@t zpAcv|OP2=Vla4uMrIeRy8(GidgRa3^@Q1djMJc^KDkQf>2qB$p+p<8>k?t=Eq16z$C$nFLGMDX4^1YRgPUv>`+ zN3a42wwxjjP5`fqHH-n}4Js7f!9A&;S2w7u^}V|yrNs}=c`z!jyKnL?u*N;A>&LMqicy$YH0eX zeD=Wc;65mB-`>puX!s3>y<+;x=hwtKI}dy#r*E!(5VR3NY^|STd*t{A`IVCE*Ad`d zL;q1G8gv2cl**f3wwCJ&w5Yo_1gFZee(Q)5F_$3v{$Y_R4II=tjS0Cu<}Of_P#|Ly zQ(UAGl4tfq-D>S_i5f*xd`+_C_!nF}QVp*&D|%4?1-*p_tG>&>Mv;`V`bB#CvzUoA zw^o`rSRm2b7z2t~j0AJ{)Z5cDW{lx90yP5gqTEB%M5fPkx!9}YnK*AirMg}Y-)?KBc&kf2_CAlqZRT2-Yrz1 zpN0zxFqyIVV}jYhLqy@oARLrk-6vN&pSMLImt-|@hpL+?{!AavlZgYTSf1WoDD8Sln?72dQ5W??WtgmRM*tQO;6qmpyhZOY&3q zQPF#qk1Hi!sANx^#fWPFr3^jCCwu!hs)ze_(s~ybe}rvCAw!eOUn0s?UGTsh<=-O4 zM?3JnF#pB_Wff&^A_}&s8n98ol%C~8Tibp^P!6Dzr{a~s*zAP4+TG`O85t4E!yu;A z4rYWN{2BFgd)N{d-e6rPgDk>>6c&`db|`B}G1|Jp`!^yvDVFxA@3%F(hHNEWVsIM1 zF)FU67F#!s)G*1o6q?l-oKydcQYpP~Fd+$n@pf~RYnCqYvkjNFko?n#kYq^Lgc^d@ zZJO2=1twlL8Y=+ZR@ko^Cz1Hoc{zUL48PwVO4tqS^pRxJZ!VA?1B(hEjcD2{`M70C zE2naO3sw9>H^e3a=CQJi&{8yArReDK_yP1U^ z<#4I{@I!}qch+*LnW{t2aZdg6`p1hCPJ6#u|9In+f=h{s(73axZo3%m zV6Y9d5Yx@&%w6B;u6~53Muh@y-ZN7n*k6E7z!a|pmcvWdj?F1GJOtKns z{_>OZtN1NLEKI3r#wcdI$Yf6P$hqDgi_z=o8w7bhQ}Q%5;@QqooT|o7qKZG(2}1Vj zaGNmBc0tu(63SfZz3LUp$it!WtVSCM+1XN1t~2^^HsACdd? zc%yU|?)PE#yN!B9Q21M8GW`S02U4x#y(eMR^O`oa5xd|GgYiOm06L1^wefiUQim;ldC_^mHh@kd z+#PP%c2Q3huFK0dF=|IF7-UkTyjay4b{O-Q-Ml~j{e;TKw)f=)aZAQ4B)7um7 znM|7g-5QW}s^5E4&iCGNU1xW}3WxwwD1z8PC&yAcNY8q6^4>GVG%Ds)YC5Z5cuKP)H*Wf$C+xo(d#Ne8+bA*{i@$^+0dsE?=Mr!(lR+QveJ_BJM zv)REKh$P3mwvXj=kdbah#7kfAFL+aC`PM7{uwHque&F|((1IYSZ-g8naWaLXQiTYI zMh7rws&s&s|A+A_HgBTW z{(u0}mIa<7wL}(wJ?lxGFpK-*f(zm})MZG?NT5U&$i+%4z-1~3G-h81{+)E$y0!Q9M=kcYvIfsk zhG4yiBn!aZ6`9s<WqIZwCfT;Vb99CAg0Y}x%FWVRw zuVKu>22zkCl+uLqN((y!J`YMAKqRj<+ohxwE-g#uPe_yClmqCi7B;Z8Z4?VQC& z*Q?=oFi7_HfRHmz^+%ZP%1LcKh}%(2W9sINUKBY#{K{qOh2cX0QI-hmO5yN;2max` zYd;-=(>1gL5N|y!7w!(9TXup}Q8ef4-)FdV7Y3`?h<%+<#ekQ6=!O)xPw=ur$t9ix zR_Hbcwzl%nQMfR4dyk0 zaB&T8oM3h%e;OfAXCC~{a|ryAO-71SeFM&)DOU^ifms!uW2-V9x`WAeP`mr5`iWog z)%Dz89OJ#(4%}Jf(45o$F}-Zr{jKperRcej0foEOE2e-fJn&uTc8u(|h{bXQ1=zEW zE5!qKfu*spMuirKMsjVJ!wR0K_ukSl45H2Se|Qji_~A3?W!VGBKWjc~mMh7e7%@c_ z_9YNmzRqf0AcZ<(&u%A}^p3n`N1cl#Z+(fQoL=_xSHMa#ZZE@*E9V#3&kl&7IcAOBR zJ~VL9vysdLDOdwsE0>P~za^5j*{-;|xlty<;(`FJtB+bv?HWH7~_W9fDQXs|+2>%zX-$(!W4# z&Xhu@yASj3zKlmIyb6q@R{8&{xd+*Mi$lm?WJ{Ti`R$ zr}y0_yquVM8>uP8F*2Tq;!GU|imRJt^ZmR!`u-)-cdkTev^m8HS~2DQ9=`$k*D4zZ zS1;S>etrcxWiEd5onKtCdwScyR-BldA1a1=lx6%trpum)xbt=IWxQwf(a(PYZK6c# zD)sLsr&ro64y*?3ojLu_?UYHwg|7)}6`bKmTrBpX-Eh^isNmY8mOyQpjEKOo1P!&1 z|EV4S?+SPOCJ!3zvzB|`7>G{&U7~KgD^iJ0r=J(WuO3gsb-5X&m2J01Ztg+8Qm3lZ zMA^R;3T0mzEfIR#A`ri!PJ!;2cYo(s)l7uBH%&eIDNN92`L>*(_xslFK{WxqywR6x ftR8FcSE^I;DN8E_pO^gK00J%!7wnttu4eofG}M&a literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/transparent_blits.png b/ggdt/tests/ref/rgba/transparent_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..2a0765d7f1bbbe496dacb7e320734435a2828d9b GIT binary patch literal 1985 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 I_F$*~0rGagvj6}9 literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/transparent_single_blits.png b/ggdt/tests/ref/rgba/transparent_single_blits.png new file mode 100644 index 0000000000000000000000000000000000000000..fd288a22b71f26954ed8eb9f5aa7775273ca8c59 GIT binary patch literal 1748 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fP9vproLLn`LHy_=hN+fAe` zP;Z6(u2wy#*-z9$EjpNQ&J%2x@2h!k%flCCP;xBXQBFc?R@}dz-}hI$Zoj=Y^UJNS z*L`(*^VhGn%D=R0&#|DFlWV_R{@2)JwfWt=^Qo_sSMNKw`QP79QkPi^o(b&Did9Ss zTgrUHYP#5>_k2wPhQ^FKTi#_Pv~V2bNLX0PDzHwqq4k=m!;WbTauMHqvR)rL^M)yY z%exm_?Z19)ae2qAvq`VOmJvek$+#Q1zG`p7`aSF%N3^6J8aA^Cbf`8s=rFP*aViLS zGc-mpaU2nHP?*NRw2|sk(^6yKSBFXooG5q_vF(srg9Gc{$2Ye!arihw?6s10n62Ot z>fUF+{a_E9KSSgE6<@F3+x+h^jac11Y&2#3#iHCL$30&v*U3wj>-Ecqz z=-g7PhI`B`tE`GD6tplsV_M5FJ=J#Ur8T;*H_Zvky!PzR>ng9Mk!tp3*G%aAS;z`zPb8=M);*R3^5?`Pmz!0?Up!LhBO&)x_+ zFp3{>>+3>bk~)*}nsFsCqM-@w7S94-frPN= zh1pRDO!!Qm_xiT~=TZ=GhZkkn<}=)4WxKS4mkp_;dwsaPi9vW}8Eg9$Me>cDO_g&@5B=H{yc2(O= zU)#TS!@C!+%fG(@mI9G#u#b=jT$`@c3~v6UUn$ zKNc`BSrZWcx0T`F!`=Jqlcft*lB$<9n+U0%AtlYB5HNd`91Vfd5I_%sIiG$n|Npiw zIGLHTC79)d6%)sDjt8YI0)B!AUUMkSQEIp@=wRW>uwJ>Lpo<~So#CMfgTe~DWM4f`RSmB literal 0 HcmV?d00001