kahlo 0.0.3

Optimized software rendering library.
Documentation
use crate::{
    bitmap::{BitmapAccess, BitmapRawDataMut},
    colour::{read_from_bytes, write_as_bytes, BlendMode, Colour},
    formats::{PixelFormatSpec, Rgba32, A8},
    math::{PixelBox, PixelPoint},
    op::binary_map_pixel_data_with,
};

use super::{
    dispatch::{GenericUnary, UnaryDispatch},
    UnaryOpSpec,
};

#[cfg(target_arch = "x86_64")]
mod x86_64;

pub struct FillRegionMaskedOp;

type OpParams<'l> = (
    &'l dyn BitmapAccess<A8>,
    PixelBox,
    PixelPoint,
    Colour,
    BlendMode,
);

#[cfg(any(test, feature = "benchmark"))]
const _: () = {
    use super::generate;
    impl generate::UnaryInputSpec for FillRegionMaskedOp {
        fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
            (
                generate::alphamap,
                generate::alphamap_area,
                generate::dst_point,
                generate::random_colour,
                generate::blend_mode,
            )
        }
    }
};

impl<'l> GenericUnary<OpParams<'l>> for FillRegionMaskedOp {
    fn perform<Format: PixelFormatSpec>(
        write_data: &mut dyn BitmapRawDataMut,
        params: &OpParams<'l>,
    ) {
        let (read_alphamap, read_box, dst, colour, blend) = params;

        binary_map_pixel_data_with::<0usize, Format, A8>(
            write_data,
            *read_alphamap,
            read_box.size(),
            *dst,
            read_box.min,
            |dst_slice, src_slice| {
                let mut dx = 0;
                let mut sx = 0;
                while dx < dst_slice.len() {
                    let existing = read_from_bytes::<Format>(&dst_slice[dx..]);
                    let new_alpha = src_slice[sx];

                    let new_colour = blend.blend(
                        &Colour {
                            a: new_alpha,
                            ..*colour
                        },
                        &existing,
                    );

                    write_as_bytes::<Format>(&new_colour, &mut dst_slice[dx..]);

                    dx += Format::PIXEL_STRIDE;
                    sx += A8::PIXEL_STRIDE;
                }
            },
        );
    }
}

impl UnaryOpSpec for FillRegionMaskedOp {
    type Params<'l> = OpParams<'l>;
    fn build<'l>() -> UnaryDispatch<Self::Params<'l>> {
        UnaryDispatch::from_generic::<Self>().with_avx::<Rgba32>(x86_64::avx_rbga32)
    }
}