cubism 0.2.0

A basic pixel canvas for Rust
Documentation
use crate::{Canvas, Color};

pub struct Blit<'a, C> {
    canvas: &'a mut C,
    src_x: i32,
    src_y: i32,
    src_w: i32,
    src_h: i32,
    dst_x: i32,
    dst_y: i32,
    img_data: &'a [u8],
    img_stride: usize,
    mul_color: Color,
}

impl<'a, C> Blit<'a, C> {
    pub fn new(canvas: &'a mut C) -> Self {
        Self {
            canvas,
            src_x: 0,
            src_y: 0,
            src_w: 0,
            src_h: 0,
            dst_x: 0,
            dst_y: 0,
            img_data: &[],
            img_stride: 0,
            mul_color: Color::WHITE,
        }
    }

    pub fn image_full(mut self, img_data: &'a [u8], stride: usize) -> Self {
        self.img_data = img_data;
        self.img_stride = stride;

        self.src_w = stride as i32 / 4;
        self.src_h = img_data.len() as i32 / (4 * stride as i32);

        self
    }

    pub fn image_clip(
        mut self,
        img_data: &'a [u8],
        stride: usize,
        src_x: i32,
        src_y: i32,
        src_w: i32,
        src_h: i32,
    ) -> Self {
        self.img_data = img_data;
        self.img_stride = stride;

        self.src_x = src_x;
        self.src_y = src_y;
        self.src_w = src_w;
        self.src_h = src_h;
        self
    }

    pub fn color(mut self, mul_color: Color) -> Self {
        self.mul_color = mul_color;
        self
    }

    pub fn pos(mut self, dst_x: i32, dst_y: i32) -> Self {
        self.dst_x = dst_x;
        self.dst_y = dst_y;
        self
    }
}

impl<'a, C> Blit<'a, C>
where
    C: Canvas,
{
    pub fn finish(self) {
        let (dst_w, dst_h) = self.canvas.size();

        let sampler = BlitSampler::new(self.img_data, self.img_stride as i32);

        let mul_color = self.mul_color.as_rgba_f32();

        for x in 0..self.src_w {
            for y in 0..self.src_h {
                let src_x = self.src_x + x;
                let src_y = self.src_y + y;

                if src_x < 0 || src_x >= dst_w || src_y < 0 || src_y >= dst_h {
                    continue;
                }

                let dst_x = self.dst_x + x;
                let dst_y = self.dst_y + y;

                let color = sampler.sample(x, y);
                let color = color * mul_color;

                self.canvas.set(dst_x, dst_y, color);
            }
        }
    }
}

struct BlitSampler<'a> {
    img_data: &'a [u8],
    width: i32,
}

impl<'a> BlitSampler<'a> {
    fn new(img_data: &'a [u8], width: i32) -> Self {
        Self { img_data, width }
    }

    fn sample(&self, x: i32, y: i32) -> Color {
        let index = (y * self.width + x) as usize * 4;

        if index >= self.img_data.len() {
            return Color::rgba_u8(0, 0, 0, 0);
        }

        let r = self.img_data[index];
        let g = self.img_data[index + 1];
        let b = self.img_data[index + 2];
        let a = self.img_data[index + 3];

        Color::rgba_u8(r, g, b, a)
    }
}