use image::RgbaImage; use palette::{Srgba, blend::Compose}; use crate::{Rect, Vec2, color}; pub struct View<'a> { area: Rect, buffer: &'a mut RgbaImage, } impl<'a> View<'a> { pub fn new(buffer: &'a mut RgbaImage) -> Self { let size = Vec2::from_u32(buffer.width(), buffer.height()); let area = Rect::from_nw(Vec2::ZERO, size); Self { area, buffer } } pub fn dup(&mut self) -> View<'_> { View { area: self.area, buffer: self.buffer, } } pub fn zoom(mut self, area: Rect) -> Self { self.area = area + self.area.corner_nw(); self } pub fn size(&self) -> Vec2 { self.area.size() } pub fn area(&self) -> Rect { Rect::from_nw(Vec2::ZERO, self.size()) } fn pos_to_buffer_pos(&self, pos: Vec2) -> Vec2 { pos + self.area.corner_nw() } pub fn get(&self, pos: Vec2) -> Option { let (x, y) = self.pos_to_buffer_pos(pos).to_u32_checked()?; let pixel = self.buffer.get_pixel_checked(x, y)?; Some(color::from_image_color(*pixel)) } pub fn set(&mut self, pos: Vec2, color: Srgba) { let Some((x, y)) = self.pos_to_buffer_pos(pos).to_u32_checked() else { return; }; let Some(pixel) = self.buffer.get_pixel_mut_checked(x, y) else { return; }; let below = color::from_image_color(*pixel); *pixel = color::to_image_color(color.atop(below)); } pub fn replace(&mut self, pos: Vec2, color: Srgba) { let Some((x, y)) = self.pos_to_buffer_pos(pos).to_u32_checked() else { return; }; let Some(pixel) = self.buffer.get_pixel_mut_checked(x, y) else { return; }; *pixel = color::to_image_color(color); } // More complicated drawing primitives pub fn rect(&mut self, area: Rect, color: Srgba) { for pos in area.points() { self.set(pos, color); } } pub fn image(&mut self, image: &RgbaImage) { for y in 0..image.height() { for x in 0..image.width() { let color = color::from_image_color(*image.get_pixel(x, y)); self.set(Vec2::from_u32(x, y), color); } } } }