From d1fb0c6b2e82d2ae7a845785071168ceb7ba7c6b Mon Sep 17 00:00:00 2001 From: gered Date: Tue, 4 Apr 2023 17:52:00 -0400 Subject: [PATCH] add new blend function and rgba triangle 2d visual reference tests --- ggdt/tests/graphics_rgba.rs | 690 ++++++++++++++++++ .../rgba/blend_function_multiplied_blend.png | Bin 0 -> 7703 bytes ggdt/tests/ref/rgba/triangle_2d.png | Bin 0 -> 2436 bytes .../ref/rgba/triangle_2d_solid_blended.png | Bin 0 -> 2860 bytes .../triangle_2d_solid_multicolor_blended.png | Bin 0 -> 33169 bytes .../ref/rgba/triangle_2d_solid_textured.png | Bin 0 -> 2130 bytes .../triangle_2d_solid_textured_blended.png | Bin 0 -> 5286 bytes .../triangle_2d_solid_textured_colored.png | Bin 0 -> 2075 bytes ...ngle_2d_solid_textured_colored_blended.png | Bin 0 -> 4688 bytes ...riangle_2d_solid_textured_multicolored.png | Bin 0 -> 11135 bytes ...2d_solid_textured_multicolored_blended.png | Bin 0 -> 16519 bytes .../triangle_2d_solid_textured_tinted.png | Bin 0 -> 2146 bytes 12 files changed, 690 insertions(+) create mode 100644 ggdt/tests/ref/rgba/blend_function_multiplied_blend.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_blended.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_multicolor_blended.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_blended.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored_blended.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_multicolored.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_multicolored_blended.png create mode 100644 ggdt/tests/ref/rgba/triangle_2d_solid_textured_tinted.png diff --git a/ggdt/tests/graphics_rgba.rs b/ggdt/tests/graphics_rgba.rs index b63822b..1192a66 100644 --- a/ggdt/tests/graphics_rgba.rs +++ b/ggdt/tests/graphics_rgba.rs @@ -2104,3 +2104,693 @@ fn blend_function_blend_source_with_alpha() { //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } + +#[test] +fn blend_function_multiplied_blend() { + let mut screen = setup_for_blending_half_solid_half_semi_transparent(); + + let bmp_solid = generate_bitmap(32, 32); + let bmp_solid_with_varied_alpha = generate_solid_bitmap_with_varied_alpha(32, 32); + let bmp_with_varied_alpha = generate_bitmap_with_varied_alpha(32, 32); + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(255, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 5); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 5); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 5); + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(127, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 40); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 40); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 40); + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(0, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 75); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 75); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 75); + + ////// + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(255, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 125); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 125); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 125); + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(127, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 160); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 160); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 160); + + let method = RgbaBlitMethod::SolidBlended(BlendFunction::MultipliedBlend(to_argb32(0, 242, 29, 81))); + screen.blit(method.clone(), &bmp_solid, 10, 195); + screen.blit(method.clone(), &bmp_solid_with_varied_alpha, 100, 195); + screen.blit(method.clone(), &bmp_with_varied_alpha, 200, 195); + + let path = reference_file(Path::new("blend_function_multiplied_blend.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[test] +fn triangle_2d() { + use RgbaTriangle2d::*; + + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let color = COLOR_BLUE; + let v1 = Vector2::new(32.0, 36.0); + let v2 = Vector2::new(32.0, 63.0); + let v3 = Vector2::new(73.0, 36.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(50.0, 0.0), // + v2 - Vector2::new(50.0, 0.0), + v3 - Vector2::new(50.0, 0.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, 50.0), // + v2 - Vector2::new(0.0, 50.0), + v3 - Vector2::new(0.0, 50.0), + ], + color, + }); + + let color = COLOR_GREEN; + let v1 = Vector2::new(123.0, 60.0); + let v2 = Vector2::new(162.0, 60.0); + let v3 = Vector2::new(144.0, 32.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, 45.0), // + v2 - Vector2::new(0.0, 45.0), + v3 - Vector2::new(0.0, 45.0), + ], + color, + }); + + let color = COLOR_CYAN; + let v1 = Vector2::new(265.0, 74.0); + let v2 = Vector2::new(265.0, 37.0); + let v3 = Vector2::new(231.0, 37.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(-70.0, 0.0), // + v2 - Vector2::new(-70.0, 0.0), + v3 - Vector2::new(-70.0, 0.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, 55.0), // + v2 - Vector2::new(0.0, 55.0), + v3 - Vector2::new(0.0, 55.0), + ], + color, + }); + + let color = COLOR_RED; + let v1 = Vector2::new(33.0, 108.0); + let v2 = Vector2::new(33.0, 137.0); + let v3 = Vector2::new(59.0, 122.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(45.0, 0.0), // + v2 - Vector2::new(45.0, 0.0), + v3 - Vector2::new(45.0, 0.0), + ], + color, + }); + + let color = COLOR_MAGENTA; + let v1 = Vector2::new(161.0, 132.0); + let v2 = Vector2::new(145.0, 92.0); + let v3 = Vector2::new(120.0, 115.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + + let color = COLOR_BROWN; + let v1 = Vector2::new(237.0, 120.0); + let v2 = Vector2::new(267.0, 136.0); + let v3 = Vector2::new(267.0, 105.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(-70.0, 0.0), // + v2 - Vector2::new(-70.0, 0.0), + v3 - Vector2::new(-70.0, 0.0), + ], + color, + }); + + let color = COLOR_LIGHT_GRAY; + let v1 = Vector2::new(29.0, 194.0); + let v2 = Vector2::new(62.0, 194.0); + let v3 = Vector2::new(29.0, 163.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(45.0, 0.0), // + v2 - Vector2::new(45.0, 0.0), + v3 - Vector2::new(45.0, 0.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, -55.0), // + v2 - Vector2::new(0.0, -55.0), + v3 - Vector2::new(0.0, -55.0), + ], + color, + }); + + let color = COLOR_DARK_GRAY; + let v1 = Vector2::new(130.0, 164.0); + let v2 = Vector2::new(155.0, 190.0); + let v3 = Vector2::new(177.0, 164.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, -60.0), // + v2 - Vector2::new(0.0, -60.0), + v3 - Vector2::new(0.0, -60.0), + ], + color, + }); + + let color = COLOR_BRIGHT_BLUE; + let v1 = Vector2::new(235.0, 193.0); + let v2 = Vector2::new(269.0, 193.0); + let v3 = Vector2::new(269.0, 163.0); + screen.triangle_2d(&Solid { position: [v1, v2, v3], color }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(-70.0, 0.0), // + v2 - Vector2::new(-70.0, 0.0), + v3 - Vector2::new(-70.0, 0.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + v1 - Vector2::new(0.0, -60.0), // + v2 - Vector2::new(0.0, -60.0), + v3 - Vector2::new(0.0, -60.0), + ], + color, + }); + + // totally off screen + + let color = COLOR_BRIGHT_RED; + + screen.triangle_2d(&Solid { + position: [ + Vector2::new(-32.0, 36.0), // + Vector2::new(-32.0, 63.0), + Vector2::new(-73.0, 36.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + Vector2::new(265.0, -26.0), // + Vector2::new(265.0, -63.0), + Vector2::new(231.0, -63.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + Vector2::new(29.0, 294.0), // + Vector2::new(62.0, 294.0), + Vector2::new(29.0, 263.0), + ], + color, + }); + screen.triangle_2d(&Solid { + position: [ + Vector2::new(335.0, 193.0), // + Vector2::new(369.0, 193.0), + Vector2::new(369.0, 163.0), + ], + color, + }); + + // wrong vertex winding (clockwise instead of counter-clockwise) + + let color = COLOR_BRIGHT_RED; + + screen.triangle_2d(&Solid { + position: [ + Vector2::new(120.0, 115.0), // + Vector2::new(145.0, 92.0), + Vector2::new(161.0, 132.0), + ], + color, + }); + + let path = reference_file(Path::new("triangle_2d.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum TriangleType { + Solid = 0, + SolidBlended = 1, + SolidMultiColorBlended = 2, + SolidTextured = 3, + SolidTexturedColored = 4, + SolidTexturedColoredBlended = 5, + SolidTexturedMultiColored = 6, + SolidTexturedMultiColoredBlended = 7, + SolidTexturedTinted = 8, + SolidTexturedBlended = 9, +} + +fn get_quad( + mode: TriangleType, + texture: Option<&RgbaBitmap>, + transform: Matrix3x3, + top_left: Vector2, + top_right: Vector2, + bottom_left: Vector2, + bottom_right: Vector2, +) -> [RgbaTriangle2d; 2] { + let top_left = transform * top_left; + let top_right = transform * top_right; + let bottom_left = transform * bottom_left; + let bottom_right = transform * bottom_right; + + let positions_1 = [top_left, bottom_left, bottom_right]; + let positions_2 = [top_left, bottom_right, top_right]; + let texcoords_1 = [Vector2::new(0.0, 0.0), Vector2::new(0.0, 1.0), Vector2::new(1.0, 1.0)]; + let texcoords_2 = [Vector2::new(0.0, 0.0), Vector2::new(1.0, 1.0), Vector2::new(1.0, 0.0)]; + let single_color = to_argb32(128, 255, 0, 255); + let colors_1 = [to_rgb32(255, 0, 0), to_rgb32(0, 255, 0), to_rgb32(0, 0, 255)]; + let colors_2 = [to_rgb32(255, 0, 0), to_rgb32(0, 0, 255), to_rgb32(255, 255, 255)]; + let tint_color = to_argb32(128, 192, 47, 160); + + match mode { + TriangleType::Solid => [ + RgbaTriangle2d::Solid { position: positions_1, color: to_rgb32(255, 0, 255) }, + RgbaTriangle2d::Solid { position: positions_2, color: to_rgb32(255, 0, 255) }, + ], + TriangleType::SolidBlended => [ + RgbaTriangle2d::SolidBlended { position: positions_1, color: single_color, blend: BlendFunction::Blend }, + RgbaTriangle2d::SolidBlended { position: positions_2, color: single_color, blend: BlendFunction::Blend }, + ], + TriangleType::SolidMultiColorBlended => [ + RgbaTriangle2d::SolidMultiColorBlended { + position: positions_1, + color: colors_1, + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + RgbaTriangle2d::SolidMultiColorBlended { + position: positions_2, + color: colors_2, + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + ], + TriangleType::SolidTextured => [ + RgbaTriangle2d::SolidTextured { position: positions_1, texcoord: texcoords_1, bitmap: &texture.unwrap() }, + RgbaTriangle2d::SolidTextured { position: positions_2, texcoord: texcoords_2, bitmap: &texture.unwrap() }, + ], + TriangleType::SolidTexturedColored => [ + RgbaTriangle2d::SolidTexturedColored { + position: positions_1, + texcoord: texcoords_1, + color: single_color, + bitmap: &texture.unwrap(), + }, + RgbaTriangle2d::SolidTexturedColored { + position: positions_2, + texcoord: texcoords_2, + color: single_color, + bitmap: &texture.unwrap(), + }, + ], + TriangleType::SolidTexturedColoredBlended => [ + RgbaTriangle2d::SolidTexturedColoredBlended { + position: positions_1, + texcoord: texcoords_1, + color: single_color, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + RgbaTriangle2d::SolidTexturedColoredBlended { + position: positions_2, + texcoord: texcoords_2, + color: single_color, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + ], + TriangleType::SolidTexturedMultiColored => [ + RgbaTriangle2d::SolidTexturedMultiColored { + position: positions_1, + texcoord: texcoords_1, + color: colors_1, + bitmap: &texture.unwrap(), + }, + RgbaTriangle2d::SolidTexturedMultiColored { + position: positions_2, + texcoord: texcoords_2, + color: colors_2, + bitmap: &texture.unwrap(), + }, + ], + TriangleType::SolidTexturedMultiColoredBlended => [ + RgbaTriangle2d::SolidTexturedMultiColoredBlended { + position: positions_1, + texcoord: texcoords_1, + color: colors_1, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(192), + }, + RgbaTriangle2d::SolidTexturedMultiColoredBlended { + position: positions_2, + texcoord: texcoords_2, + color: colors_2, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(192), + }, + ], + TriangleType::SolidTexturedTinted => [ + RgbaTriangle2d::SolidTexturedTinted { + position: positions_1, + texcoord: texcoords_1, + bitmap: &texture.unwrap(), + tint: tint_color, + }, + RgbaTriangle2d::SolidTexturedTinted { + position: positions_2, + texcoord: texcoords_2, + bitmap: &texture.unwrap(), + tint: tint_color, + }, + ], + TriangleType::SolidTexturedBlended => [ + RgbaTriangle2d::SolidTexturedBlended { + position: positions_1, + texcoord: texcoords_1, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + RgbaTriangle2d::SolidTexturedBlended { + position: positions_2, + texcoord: texcoords_2, + bitmap: &texture.unwrap(), + blend: BlendFunction::BlendSourceWithAlpha(128), + }, + ], + } +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_blended() { + let mut screen = setup_for_blending(); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidBlended; + + let triangles = get_quad(mode, None, Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, None, scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, None, scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_blended.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_multicolor_blended() { + let mut screen = setup_for_blending(); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidMultiColorBlended; + + let triangles = get_quad(mode, None, Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, None, scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, None, scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_multicolor_blended.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured() { + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTextured; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_colored() { + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedColored; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_colored.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_colored_blended() { + let mut screen = setup_for_blending(); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedColoredBlended; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_colored_blended.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_multicolored() { + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedMultiColored; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_multicolored.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_multicolored_blended() { + let mut screen = setup_for_blending(); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedMultiColoredBlended; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_multicolored_blended.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_tinted() { + let mut screen = setup(); + screen.clear(LIGHTER_BACKGROUND); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedTinted; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_tinted.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + +#[rustfmt::skip] +#[test] +fn triangle_2d_solid_textured_blended() { + let mut screen = setup_for_blending(); + + let texture = generate_bitmap(32, 32); + + let top_left = Vector2::new(0.0, 0.0); + let top_right = Vector2::new(32.0, 0.0); + let bottom_left = Vector2::new(0.0, 32.0); + let bottom_right = Vector2::new(32.0, 32.0); + + let rotate = Matrix3x3::new_2d_rotation(RADIANS_45); + let scale = Matrix3x3::new_2d_scaling(2.0, 2.0); + + let mode = TriangleType::SolidTexturedBlended; + + let triangles = get_quad(mode, Some(&texture), Matrix3x3::new_2d_translation(40.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * Matrix3x3::new_2d_translation(200.0, 40.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let triangles = get_quad(mode, Some(&texture), scale * rotate * Matrix3x3::new_2d_translation(120.0, 120.0), top_left, top_right, bottom_left, bottom_right); + screen.triangle_list_2d(&triangles); + + let path = reference_file(Path::new("triangle_2d_solid_textured_blended.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} diff --git a/ggdt/tests/ref/rgba/blend_function_multiplied_blend.png b/ggdt/tests/ref/rgba/blend_function_multiplied_blend.png new file mode 100644 index 0000000000000000000000000000000000000000..44febb712fe32958e74d6b9f783ecdc9cfad671d GIT binary patch literal 7703 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 literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_multicolor_blended.png b/ggdt/tests/ref/rgba/triangle_2d_solid_multicolor_blended.png new file mode 100644 index 0000000000000000000000000000000000000000..5ff76a6853eb25071e5bf3c1595988dc348263fc GIT binary patch literal 33169 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 AiU0rr literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_textured.png b/ggdt/tests/ref/rgba/triangle_2d_solid_textured.png new file mode 100644 index 0000000000000000000000000000000000000000..50354f2e5c66869929e841c6397a816fdcab0a36 GIT binary patch literal 2130 zcmc(hYfuwc6vyu_3+#eoHlQGa2^%0*Kp9a%4U+)j5wXaKN>sp%;5$~-5m6y5Q9B8m z0FHq80;{$vf>Em#jV5$dP^nRTAP$lktb+0g)<8yrbff*$erTOer(gE$J-`3?-+S(z zJ9FiU39%!cJe>dlBL#8%c>q8>>feMqP~Qzf*VY1njur4D=4T)3e*X2w*6B3z!HmQ) z>PVO3c;j9{i_)B~2u3hc{Ci;MqX z!`pr+aF{b`^MGztdTMT7Pu>|Cl*74`P?&lr4Raxz2g(*5Pxba8;f948&82Z&+pC_h zzw)Br-sJB%flP@8>D^T&z=^qJ=p&Mu3Qr)#=0R8OW~>sNf80A4H2ZxjeFdnA2lhqP5=uP@ za^qe4FoYSde1WJrgj^m5iE$QrLjA}~`z~7maIJ7~&BZw&@7bVV)K-*vRqd#1E<2rW z_q4m+O*`mS2{w*~_FO!>@XPx8YxBu6kk;8#!MH`Y&A53G{9J+rKe@gbW6noKXL2vn zc_(Q$;zuU>kmvdz&jv>$KksbhE^zBvasaf`>GML+(VsVmHu28}+0KTx*AHe5zpHr# zdUEdN>Nc5R^fvZ~eTTR9Rj7OSf)8{a57>3TLH~i{zh2Vc85HP!8YVW?C~3TtGPeLo z%qDq@Vf47)mj~y&rpWlPDBxbwS$#coADA?uz3P`2D3sDz-w{6kS2n)$HInJ0GqRZgl zkq~iNut$T8%9mpz8mpZx&F~|kMvCt(25qg46lg&Wid3A7`?^BvQ@Xx`3@sxhy67=x z7@4ckccIsHZV?Op$E7wCIfiq%Nr*fFOuo;RRO4Nt z)L;%^k8{^t!@F!`Heh=)G|9M^jl=buwlso3vB! z(UWM8LN7y0J@J>f5Y>g}eQ!PLo>bgK0LnFuCc$1i<;$3v2Rageb2Tzk$4Kpe&8+;(n zs@Vu*cb>b@dU-!M5(RvwzIIH6*!o>(l>rRk$e;P$9?8k7w;e%P7^g3_I zb9CLM7Gu39qB@p@i_yehbo{{}$qhDn*t@`x56lII+7@H17!KnlA#;%qF*4XVhHIp2 zBeJ4ZQKT|P)hq5}`9oeOJ?oUv8iip$rRKn4PamQ#=>0ZSd6+UINY|VKL%KS^I52&Q z73BkV?M$iBaVcitC$WTWEK9rY(Dj{^h zxqET#xYIGJ5&jZif($iJl`g0Eu`oz|PItEHK)khq2iEr#paqOYs0f6xCP*>}GNMsd zX(?6!hbdE}#@HCxqfurPU?N_)P2f*Pm~Dc?z#+?@>IL>_E2cPgE1g%#D=l@ipp+X& zs6>uG>3oVhFGB!z;V)1L4x4oT;KAwJ(Tf?ryD=)wRl7^hc!V*FN&&q3zYjx>>kcS0 U?ra^=NWB$+AUc6x6DgAZ4whR`p#T5? literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_textured_blended.png b/ggdt/tests/ref/rgba/triangle_2d_solid_textured_blended.png new file mode 100644 index 0000000000000000000000000000000000000000..a24b8f0e7267a326cdbd46dfaa0ac089a098c211 GIT binary patch literal 5286 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 SXaVn!5ceNEU1)m(;{O3K+Uvsr literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored.png b/ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c67f3b9d8ba19a6d625289104022ad9a296aee GIT binary patch literal 2075 zcmc&#Yfuwc7`?mQ!md?Gg2*dOLc&8)fdN|Zm4F5UDu^P2q7aojEtY^S0VKLC(IO!# zL`tm#0v1N?Kmq#@TQCXA%lZJdTB`_KWPDUK36!#!V7k!GIODH6&a{8_?mg#x=R4ob zy>pe(QQ{fXoTdQ)W<-RG)&c+p)Bgt4ivI3gaBc?x)&miukagMRPw!nS?G0k(uW<@c zWo%jEEPpik$CsSBvRGG)1ss`KJAdi=%PU_Kx{jplw*&UwO7OtWjSyS)*z2mRbDnqaAD^;~2D`o=^CWg* zRbV(pzZ#6Nf}z2ieYD!0fV*nXO?7;`I8L4me{lp%<2L;H0`c{MW(6lcoxmiC@EoG$ z&P$^}Kf;s&->x1K|ArLv5#L+qa!Sp9`>K)REFexzkpi(a32^-A7T&PKlf-k#8@6|a zvrnG1?2iAIj``RK?OTjV>g1!W;13wO__5#Ji5@O-`q|Bu;CKkwcCYpbShg2*{21p0 z?X!Xo$Qlx1bjIH?7*11JF>V0*ih*G!DcA=Ds+Xnt*P!yzE1}gGmrLYHW%)0ee{K54 zsa`d>@M7h3ufmL4e}v)0YhM9O7&rQJ0KfnGi)5>vriWF}(A9YDsr4y$C$Ly^$|pg~ zLCN^LIk^^_WFFdYs}pHdmFW3y#80zfjHP<(`xezmk`&QMbPx2RW#R! z_@0_)v<;z3fK>nw=b^B})hQfwD@0cYqMD*U-^j)Ew|Lfjwcr0Ku$!+BjX7%AzzA2@95Xqr1EP=lF2bF|FL zi}!psI0~7AA0p|+BgW?8ujiW>QvxNJnZ6XCV6yGB{>)x$WyZFTSvnOxSvDf>Z17Z= zBx-4-0M2fus6B_sI?6>!3LrdCzy}wK(=*K*nZ2H>4EZoaXZxU2zXOSD*Egfj zRH8dzAu2g3Gs?y3GBbXV)Wp{;U{r$4c#c+nerz$*%?BE4Tttj@>MPK&JIHBFax#ZG zOE}EZ+1?6kyxI?iO*)VfJ9zOAlk)iYDwZGy#ShH75jmljMtQ^8*UHgb<8I+K2_;2f zrtfSW{l4C${`xtHF#nA0<=F^NF?4bLJmX@Lt#ys8}oW34;mudGk zYGCC*DTsv~db%bBm?WA%DexrnHY=;BJdmH|p%}2vW$BO{8aH?l5o{W7)g!*@^+>yo zhNVl^sAyme@jX6~bj?;sRR9ln+;9|lc;G!A|JAEGYHeuCPjSY2qv%H;M1)3(>X%6r Fe*veZO^N^j literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored_blended.png b/ggdt/tests/ref/rgba/triangle_2d_solid_textured_colored_blended.png new file mode 100644 index 0000000000000000000000000000000000000000..6c7ae411fc740d3b405549ba52cc353969cbeb52 GIT binary patch literal 4688 zcmcIoX;hO}w@yH$%7Qq265~KvrD&-jDxyUpp;d9f8Y&elMl8^*4=boTzec!$JyKCM14 zpZ)CfUJlx~(|-Q4`7jvFe)q2J`(ZG+KX{gZHW&P#@~9=iV2hBuw}10PYTm>Ej*>8 zU*v+nCht=O4T~=o(GC}u`i7>F_0lY}fI~i<%cht|cTc6I`a0q19F2fuR{Ud`(k32n z{%~S6Ns;PXw~C?=RCD~au_han8badkLR^tTlWSoKx`QyWs9+0WIJC19P1YTpd4VgcR$CMa{w_u=pmEPiN3CCq z6a(jUFaVcbfcZC5W94$ol+7isD3t0N`w`YBjh(h&v|6p2-TMF0Se*t_Z=86Wd_2XI z{3KGB_YbCCEz)BsdFG!;3KEsJnZc*LBcA3l`m3c3&-an$6!m03Gve0~MSqTUB1J8l z!QRGA@@WvoM0D}NKGOHe1lK+55c0u+GJf@0^uE|Sn1J)l$Dl3y164O-fDy@Rr2-Pu zff*$e%SWAIau7o(6HU`PXsGqg;|LtYGUK3OHzZq^B-_fV8#HWnjJlj~ib7Jhs=1rl zbj8Yg8W)Oi62O<1dNXqcL)@|?(@0zg#T36o6h?icl!j4DmC|KAtlc$hY8?Eusa0mZ zBEBv0$v6<5`6!zB-ABx`axoS$g@^xWqG_dFVpewhGV&9j2Ka5r0K-7EKh{%5322yL zm~7M-#8C3w0Wl7vwD~jtDd(VrSa6tH5ncDQhcWT|#cd zCZ%}m`C>873roaDRYdC}UM8B>NUYzX6Q-0$!V1=ia~h5Y(CIBkok9xWp#lN|=IE1*?vr7R4n`zhHHhzZ(aR^t#TvDTQ_AB)=%m$EL%_DnA**m=&R% zppbI49#2FIBXe#pb9_e}vFmW!-F=b_J6&V(SDfQVNB~`6Z+8z1|K*wF*(~nc>3f8Tb0fGRnWo4m?8utzR24qt?Vd?L9)pBM`*?Ix{$yLkb^IZj%KZSCG%n zPR!0u+n#Alu3AvdCJa&lYO`1+vdT`ImW`gLORU{nk$AuWVwKXSBpr-d-E(;04q3ev zS(7JhBx9x7?PEUy*&3HM7r7Af&Y4@xm3akk``>`b1%=qspbrx^B`asD9(;hx_f1sY zLnQWovJs6I_LumOQXWmBx+_TJ`+!CUg$fUS1){^~ep2i8U;rw=+AJxGHAt*iWCD&c zJ-UaGt9-hq%h;_D3q!h?{9}Npw`eC?D6#MnKG1SR$j`E)`n(>nr&aKj1*hso48x(! zqRUTqeZE2a`P!}{6@alEo$amxb(mo;#{WA@fZ7;}LPSRejQz^uEdU^huAs-vQ62-9 z?*ZQ+wI7G})@7qf)ItjfBHDUvQ;~j?tSA!;j9IAcd4>7F*Q9RG8%x@l>O#b<2?>AF zdIh!sE8U59wuHAMIP>i^C__UEIArxB5#D|6?Q>C5+H8C*I^YS8!rGfx=)7|OlQVw{ zKx!*A^*J_+wm#B#%fM;*7h3*AqFqM@LI2=q2WYtp7T6{M4TRy=zh&hAOx6x|79Izu z;-5tSUuoGsT^Y_l%%S*_2{?3Aq3QLx#{^m#n#M@g!IrBKf&%GD1QzRS>H?d}G3!Pc z1h0{W*&`gKvOxrrsk{0XlQ3@zya18{ZHfsL%LmM|c1^(n0)_`6XiN|Pi8cTK@?05*vi_FLV3U|Ly~2Dy6eb+k!{~2 z(}{K+>ZjBEVKGhCTm@S*we6Q3m4=6Q9gpT{wW8`n)R+rn@@;31xryUw3Gjz8~eZhERDD;-V>Pjvg9 z(K9RYwh9JG0Prx6`k+IH$JG4Q?pMlQciN_|vH*@X?n8E@SC|tu)lYGmo86j9vUt)m z9MidO6W|q;;UR>(tzM42wzh0$Qg8Lnt%~f%FUBpv(~A*_(Ud+hlCJI?QN1Ult6*mr z@~=KM#c#?(6PrOU+1GL)99_|QOf}72i#1EUE>1~he!)^>16wv~{qB_~mVFS^fMY5r z8l;PGA~hvyb+oE*p$pi`eBhepsm)30Ou^l^F@_hYTBt1EfvVA*m1&bOkG+4RMS9kymMyU=1ErDXP7PE zQL^|Y18{!$bDZ9=zo2&wBYTi&<{31eQ;b;m z##3zA&m54p^pW<{jD*rntG}i_b3bMbk2dGB+UGqclI6!hk#MQ`Ld@n>rQ-_M=CTAt z_{kd2vC13jDy}-<^2XJ#v<=LL;LIYG0%XI^gMaRfI7-^n)yRgq`h3Gfo5BlhO5~jw z&W%i3D>ACZDm}cBc^1CtR+ELbO5~%V*nz6_2s`&pQpSj=l3Wq`Q3&H-#E&t(o1Nvi z=^C{US~ZUd+>-sLVL{AlA51dAf+jR3#Cfnl&lFFTcI#JsI6V&dnB{ zhM22F#fnY>H_mVm^}KHqTW1drN(P%!+j-3J1?qVqHz~E#i@ZoymqKhxaB~5B5l^Y$ ztIp{?HOVMWP(X*EfgRA~Io!a%3Td<(GV-v*eIOg=zrUI)*+4G6)OLF1+j9#U_Zi_^ zy@!sb^AH$z9K3Xx-~3sNUeg^(&BfGvJ35PP@$anMJqm+wg94H+vmQ1G0~IQG>3EUP z^E8(;<6h~(UK#756`T09=Fc9J&5C5O$<6XNd3VxQ?HbSdOJ~pad8NNC>^i42$UVR{*G~B+Pw3;70bqmy7>*JUfTWl?qsj*M z_^7pe7l5FQF-pMeBzWxsuh4CEAuxU(C`$x*d~w}043_8#+VA-WAN`!m&xGJ^UcblS z^WqIqnhtysGRz)dd=JQgy_av`>|i>R$eKt%4oh_2dW)$UV2agM_IkAi^;wXQjhG_b zH4N4l#AS@M*RnpfCK^8Fn3f;8__w=&VdLPN#IB@_U-A?nvbWWD^DIjY_ksTPvX*&o z#F^Y`px<6M;4aw7L_5hq)3j-92H;U-0i759z-nU8e{VGYH~0Tf-NqJo%U1(S!vosy r%czyUPBZ~%4gbgc|NpZwBQvcs$nR!3*%f>#g6-b1Z+q#tQ5pXMR8=Mv literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/triangle_2d_solid_textured_multicolored.png b/ggdt/tests/ref/rgba/triangle_2d_solid_textured_multicolored.png new file mode 100644 index 0000000000000000000000000000000000000000..9e5567e427c1d333cab39354047bbb46ddc67a1e GIT binary patch literal 11135 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