// Copyright 2019 the Piet Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! A bunch of image test cases.

use crate::kurbo::{Rect, Size};
use crate::{Color, Error, ImageFormat, InterpolationMode, RenderContext};

pub const SIZE: Size = Size::new(200., 100.);

pub fn draw(rc: &mut impl RenderContext) -> Result<(), Error> {
    rc.clear(None, Color::WHITE);

    let mut y = 5.0;
    for &mode in &[
        InterpolationMode::NearestNeighbor,
        InterpolationMode::Bilinear,
    ] {
        let mut x = 5.0;
        for &format in &[
            ImageFormat::RgbaSeparate,
            ImageFormat::RgbaPremul,
            ImageFormat::Rgb,
            ImageFormat::Grayscale,
        ] {
            let image_data = make_image_data(16, 16, format);
            let image = rc.make_image(16, 16, &image_data, format)?;
            rc.draw_image(&image, Rect::new(x, y, x + 40.0, y + 40.0), mode);
            x += 50.0;
        }
        y += 50.0;
    }
    Ok(())
}

fn make_image_data(width: usize, height: usize, format: ImageFormat) -> Vec<u8> {
    let bytes_per_pixel = format.bytes_per_pixel();
    let mut result = vec![0; width * height * bytes_per_pixel];
    for y in 0..height {
        for x in 0..width {
            let ix = (y * width + x) * bytes_per_pixel;
            let r = (x * 255 / (width - 1)) as u8;
            let g = (y * 255 / (height - 1)) as u8;
            let b = !r;
            let r2 = ((x as f64) - 8.0).powi(2) + ((y as f64) - 8.0).powi(2);
            let a = (255.0 * (-0.01 * r2).exp()) as u8;

            // allows for nice vertical formatting for `result[ix + 0]`
            #[allow(clippy::identity_op)]
            match format {
                ImageFormat::RgbaSeparate => {
                    result[ix + 0] = r;
                    result[ix + 1] = g;
                    result[ix + 2] = b;
                    result[ix + 3] = a;
                }
                ImageFormat::RgbaPremul => {
                    fn premul(x: u8, a: u8) -> u8 {
                        let y = (x as u16) * (a as u16);
                        ((y + (y >> 8) + 0x80) >> 8) as u8
                    }
                    result[ix + 0] = premul(r, a);
                    result[ix + 1] = premul(g, a);
                    result[ix + 2] = premul(b, a);
                    result[ix + 3] = a;
                }
                ImageFormat::Rgb => {
                    result[ix + 0] = r;
                    result[ix + 1] = g;
                    result[ix + 2] = b;
                }
                ImageFormat::Grayscale => result[ix] = a,
            }
        }
    }
    result
}
