|
@@ -1,166 +0,0 @@
|
|
|
-use crate::{
|
|
|
- prelude::*,
|
|
|
- colour::{BlendMode, Colour},
|
|
|
- formats::{PixelFormatSpec, Rgba32, A8},
|
|
|
- math
|
|
|
-};
|
|
|
-
|
|
|
-mod helpers;
|
|
|
-mod impls;
|
|
|
-
|
|
|
-pub trait Readable<PF: PixelFormatSpec> {
|
|
|
- type ReadResult: Clone;
|
|
|
- fn get_pixel(&self, x: usize, y: usize) -> Self::ReadResult;
|
|
|
-}
|
|
|
-
|
|
|
-pub trait Writable<PF: PixelFormatSpec>: Readable<PF> {
|
|
|
- fn set_pixel(&mut self, x: usize, y: usize, to: Self::ReadResult);
|
|
|
-}
|
|
|
-
|
|
|
-/// Generic image manipulation functionality
|
|
|
-pub trait Paintable<PF: PixelFormatSpec>: BitmapMutAccess<PF> + Writable<PF> {
|
|
|
- fn fill(&mut self, with: Self::ReadResult) {
|
|
|
- for y in 0..self.height() {
|
|
|
- for x in 0..self.width() {
|
|
|
- self.set_pixel(x, y, with.clone());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Fill a region with a given value.
|
|
|
- fn fill_region(&mut self, region: &math::PixelBox, with: Self::ReadResult) {
|
|
|
- let image_box = math::PixelBox::from_size(self.size());
|
|
|
- let Some(isect) = region.intersection(&image_box) else {
|
|
|
- // nothing to do
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- for y in isect.y_range() {
|
|
|
- for x in isect.x_range() {
|
|
|
- self.set_pixel(x as usize, y as usize, with.clone());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Copy image data from another bitmap with the same pixel format.
|
|
|
- fn copy_from(
|
|
|
- &mut self,
|
|
|
- amap: &impl BitmapAccess<PF>,
|
|
|
- amap_region: &math::PixelBox,
|
|
|
- dst: &math::PixelPoint,
|
|
|
- ) {
|
|
|
- let Some((write_region, read_region)) = helpers::clip_to(
|
|
|
- self.size(),
|
|
|
- *dst,
|
|
|
- amap.size(),
|
|
|
- amap_region.min,
|
|
|
- amap_region.size(),
|
|
|
- ) else {
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- let row_width = write_region.width() as usize * PF::PIXEL_WIDTH;
|
|
|
- for y in 0..write_region.height() {
|
|
|
- let write_offset = ((y + write_region.min.y) * self.row_stride() as i32) as usize;
|
|
|
- let read_offset = ((y + read_region.min.y) * amap.row_stride() as i32) as usize;
|
|
|
-
|
|
|
- let write_offset = write_offset + (write_region.min.x as usize) * PF::PIXEL_WIDTH;
|
|
|
- let read_offset = read_offset + (read_region.min.x as usize) * PF::PIXEL_WIDTH;
|
|
|
-
|
|
|
- self.data_mut()[write_offset..(write_offset + row_width)]
|
|
|
- .copy_from_slice(&amap.data()[read_offset..(read_offset + row_width)]);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<PF: PixelFormatSpec, T: BitmapMutAccess<PF> + Writable<PF>> Paintable<PF> for T {}
|
|
|
-
|
|
|
-/// A8-specific painting trait.
|
|
|
-pub trait AlphaPaintable: BitmapMutAccess<A8> + Writable<A8, ReadResult = u8> {
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: BitmapMutAccess<A8>> AlphaPaintable for T {}
|
|
|
-
|
|
|
-/// RGBA32-specific painting trait.
|
|
|
-pub trait RgbaPaintable:
|
|
|
- BitmapAccess<Rgba32> + BitmapMutAccess<Rgba32> + Writable<Rgba32, ReadResult = Colour>
|
|
|
-{
|
|
|
- /// Fill a region with a given colour, using the values from an alphamap as the alpha value.
|
|
|
- fn fill_masked(
|
|
|
- &mut self,
|
|
|
- amap: &impl BitmapAccess<A8>,
|
|
|
- amap_region: &math::PixelBox,
|
|
|
- dst: &math::PixelPoint,
|
|
|
- col: Colour,
|
|
|
- mode: BlendMode,
|
|
|
- ) {
|
|
|
- let Some((write_box, read_box)) = helpers::clip_to(
|
|
|
- self.size(),
|
|
|
- *dst,
|
|
|
- amap.size(),
|
|
|
- amap_region.min,
|
|
|
- amap_region.size(),
|
|
|
- ) else {
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- for y in 0..read_box.height() {
|
|
|
- for x in 0..read_box.width() {
|
|
|
- let rx = (read_box.min.x + x) as usize;
|
|
|
- let ry = (read_box.min.y + y) as usize;
|
|
|
- let wx = (write_box.min.x + x) as usize;
|
|
|
- let wy = (write_box.min.y + y) as usize;
|
|
|
- let source = col.with_a(amap.get_pixel(rx, ry));
|
|
|
- let blended = mode.blend(&source, &self.get_pixel(wx, wy));
|
|
|
- self.set_pixel(wx, wy, blended);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Copy a region of an image to here, blending colours.
|
|
|
- fn blend(
|
|
|
- &mut self,
|
|
|
- src: &impl BitmapAccess<Rgba32>,
|
|
|
- src_area: &math::PixelBox,
|
|
|
- dst: &math::PixelPoint,
|
|
|
- mode: BlendMode,
|
|
|
- ) {
|
|
|
- let Some((write_box, read_box)) =
|
|
|
- helpers::clip_to(self.size(), *dst, src.size(), src_area.min, src_area.size())
|
|
|
- else {
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- for y in 0..read_box.height() {
|
|
|
- for x in 0..read_box.width() {
|
|
|
- let rx = (read_box.min.x + x) as usize;
|
|
|
- let ry = (read_box.min.y + y) as usize;
|
|
|
- let wx = (write_box.min.x + x) as usize;
|
|
|
- let wy = (write_box.min.y + y) as usize;
|
|
|
- let source = src.get_pixel(rx, ry);
|
|
|
- self.set_pixel(wx, wy, mode.blend(&self.get_pixel(wx, wy), &source));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn copy_from(
|
|
|
- &mut self,
|
|
|
- src: &impl BitmapAccess<Rgba32>,
|
|
|
- area: &math::PixelBox,
|
|
|
- dst: &math::PixelPoint,
|
|
|
- ) {
|
|
|
- let line_width = area.width() as usize * Rgba32::PIXEL_WIDTH;
|
|
|
- for y in 0..area.height() {
|
|
|
- let src_offset = y as usize * src.row_stride();
|
|
|
- let dst_offset = y as usize * self.row_stride();
|
|
|
-
|
|
|
- let src_start = src_offset + area.min.x as usize * Rgba32::PIXEL_WIDTH;
|
|
|
- let dst_start = dst_offset + dst.x as usize * Rgba32::PIXEL_WIDTH;
|
|
|
-
|
|
|
- self.data_mut()[dst_start..(dst_start + line_width)]
|
|
|
- .copy_from_slice(&src.data()[src_start..(src_start + line_width)]);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: BitmapMutAccess<Rgba32>> RgbaPaintable for T {}
|