use std::ops::{Deref, DerefMut, RangeInclusive};
use crate::util::vector::Vector;
/// Image with dimensions unknown at compile-time.
pub mod canvas;
/// Image with compile-time known dimensions.
pub mod sprite;
/// Pixel-perfect operations implementation.
pub mod pixel;
/// Subpixel-perfect operations implementation.
pub mod subpixel;
mod util;
/// Collection of drawing traits and functions compiles in a single prelude.
pub mod prelude {
pub use super::{paint, printer, stamp};
pub use super::{Image, Paint};
pub use super::{PaintTarget, Painter};
}
/// Mapper function accepts `x` and `y` coordinates and pixel value.
pub type Mapper
= dyn FnMut(i32, i32, P) -> P;
/// Helper paint function for pixel value override.
/// It ignores the value of original pixel and replaces it with `value`.
pub fn paint
(value: P) -> impl FnMut(i32, i32, P) -> P
where
P: Clone,
{
move |_, _, _| value.clone()
}
/// Helper printer mapper for the `Text` trait.
/// It breaks lines on newline symbol (`'\n'`) and ignores any special characters.
pub fn printer() -> impl FnMut(char, &U) -> Vector
where
U: Image,
{
let mut column = 0;
let mut line = 0;
move |code_point, representation| {
let result = (column, line).into();
if code_point == '\n' {
line += representation.height();
column = 0;
} else {
column += representation.width();
}
result
}
}
/// Helper stamper mapper for image-to-image mapping.
/// It stamps pixels of the drawn image ignoring values of the original.
pub fn stamp() -> impl FnMut(i32, i32, P, i32, i32, P) -> P {
move |_, _, _original, _, _, other| other
}
#[derive(Clone, Copy, Debug)]
enum Scan {
None,
Single(T),
Inclusive(T, T),
}
impl Scan {
fn rev(self) -> Self {
match self {
Scan::None => Scan::None,
Scan::Single(a) => Scan::Single(a),
Scan::Inclusive(a, b) => Scan::Inclusive(b, a),
}
}
fn start_unchecked(self) -> T {
match self {
Scan::None => unimplemented!("There is no start value for Scan with None variant"),
Scan::Single(a) => a,
Scan::Inclusive(a, _) => a,
}
}
fn end_unchecked(self) -> T {
match self {
Scan::None => unimplemented!("There is no end value for Scan with None variant"),
Scan::Single(a) => a,
Scan::Inclusive(_, b) => b,
}
}
}
impl Scan
where
T: Ord,
{
fn sorted(self) -> Self {
if let Scan::Inclusive(a, b) = self {
if a > b {
Scan::Inclusive(b, a)
} else {
Scan::Inclusive(a, b)
}
} else {
self
}
}
}
impl IntoIterator for Scan {
type Item = i32;
type IntoIter = ScanIterator;
fn into_iter(self) -> Self::IntoIter {
match self {
Scan::None => ScanIterator {
current: 0,
scan: self,
exhausted: true,
},
Scan::Single(a) => ScanIterator {
current: a,
scan: self,
exhausted: false,
},
Scan::Inclusive(a, b) if a == b => ScanIterator {
current: a,
scan: Scan::Single(a),
exhausted: false,
},
Scan::Inclusive(a, _) => ScanIterator {
current: a,
scan: self,
exhausted: false,
},
}
}
}
struct ScanIterator {
current: T,
scan: Scan,
exhausted: bool,
}
impl Iterator for ScanIterator {
type Item = i32;
fn next(&mut self) -> Option {
if self.exhausted {
None
} else {
let result = self.current;
match self.scan {
Scan::None => unreachable!(),
Scan::Single(_) => {
self.exhausted = true;
}
Scan::Inclusive(a, b) => {
self.current += (b - a).signum();
self.exhausted = result == b;
}
}
Some(result)
}
}
}
/// General image trait.
pub trait Image {
/// Pixel type of this image.
type Pixel;
/// Reference to pixel.
type PixelRef<'a>
where
Self: 'a;
/// Mutable reference to pixel.
type PixelMut<'a>
where
Self: 'a;
/// Get specific pixel reference.
fn pixel(&self, position: Vector) -> Option>;
/// Get specific pixel mutable reference.
fn pixel_mut(&mut self, position: Vector) -> Option>;
/// Get specific pixel reference without bounds check.
///
/// # Safety
/// - position must be in range [(0, 0), [width - 1, height - 1]]
unsafe fn unsafe_pixel(&self, position: Vector) -> Self::PixelRef<'_>;
/// Get specific pixel mutable reference without bounds check.
///
/// # Safety
/// - position must be in range [(0, 0), [width - 1, height - 1]]
unsafe fn unsafe_pixel_mut(&mut self, position: Vector) -> Self::PixelMut<'_>;
/// Get width of this image.
fn width(&self) -> i32;
/// Get height of this image.
fn height(&self) -> i32;
/// Clear this image with color provided.
fn clear(&mut self, color: Self::Pixel);
/// Get dimensions of this image.
fn dimensions(&self) -> Vector {
Vector::new(self.width(), self.height())
}
/// Get optional `FastHorizontalWriter` for faster horizontal line drawing.
fn fast_horizontal_writer(&mut self) -> Option> {
None::
}
}
/// Something that can be painted on.
pub trait PaintTarget {
/// Get painter for painting.
fn painter(&mut self) -> Painter
where
C: Clone + Default;
}
impl PaintTarget for T {
fn painter(&mut self) -> Painter
where
C: Clone + Default,
{
Painter::new(self)
}
}
/// Painter to draw on encapsulated target.
pub struct Painter<'a, I, C> {
target: &'a mut I,
offset: Vector,
}
impl<'a, I, C> Painter<'a, I, C>
where
C: Clone + Default,
{
fn new(target: &'a mut I) -> Self {
Self {
target,
offset: Default::default(),
}
}
/// Get new painter with desired offset.
pub fn with_offset(self, offset: Vector) -> Self {
Self { offset, ..self }
}
/// Set offset for this particular painter.
pub fn set_offset(&mut self, offset: Vector) -> &mut Self {
self.offset = offset;
self
}
/// Get offset of this painter.
pub fn offset(&self) -> Vector {
self.offset.clone()
}
/// Get mutable reference to offset in this painter.
pub fn offset_mut(&mut self) -> &mut Vector {
&mut self.offset
}
}
impl<'a, T, P, C> Painter<'a, T, C>
where
T: Image,
::Pixel: Clone,
for<'b> ::PixelRef<'b>: Deref::Pixel>,
for<'b> ::PixelMut<'b>: DerefMut::Pixel>,
{
/// Get target's width.
pub fn width(&self) -> i32 {
Image::width(self.target)
}
/// Get target's height.
pub fn height(&self) -> i32 {
Image::height(self.target)
}
/// Clear the target with provided color.
pub fn clear(&mut self, clear_color: P) {
Image::clear(self.target, clear_color)
}
fn map_on_pixel_raw P>(
&mut self,
point: Vector,
function: &mut F,
) {
if let Some(mut pixel) = self.target.pixel_mut(point) {
*pixel = function(point.x(), point.y(), pixel.clone());
}
}
fn map_vertical_line_raw P>(
&mut self,
x: i32,
from_y: i32,
to_y: i32,
function: &mut F,
skip: usize,
) {
if x < 0 || x >= self.target.width() {
return;
}
let mut iter = from_y..=to_y;
let mut iter_rev = (to_y..=from_y).rev();
let iter_ref: &mut dyn Iterator- = if from_y < to_y {
&mut iter
} else {
&mut iter_rev
};
for y in iter_ref.skip(skip) {
let pose = (x, y);
self.map_on_pixel_raw(pose.into(), function);
}
}
fn map_fast_horizontal_line_raw P>(
&mut self,
from_x: i32,
to_x: i32,
y: i32,
function: &mut F,
) {
if self
.target
.fast_horizontal_writer()
.map(|mut fast| fast.write_line(from_x..=to_x, y, function))
.is_none()
{
self.map_horizontal_line_raw(from_x, to_x, y, function, 0);
}
}
fn map_horizontal_line_raw P>(
&mut self,
from_x: i32,
to_x: i32,
y: i32,
function: &mut F,
skip: usize,
) {
if y < 0 || y >= self.target.height() {
return;
}
let mut iter = from_x..=to_x;
let mut iter_rev = (to_x..=from_x).rev();
let iter_ref: &mut dyn Iterator
- = if from_x < to_x {
&mut iter
} else {
&mut iter_rev
};
for x in iter_ref.skip(skip) {
let pose = (x, y);
self.map_on_pixel_raw(pose.into(), function);
}
}
fn map_on_filled_rect_raw P>(
&mut self,
from: Vector,
to: Vector,
function: &mut F,
) {
let start_x = from.x().max(0);
let start_y = from.y().max(0);
let end_x = (to.x()).min(self.target.width());
let end_y = (to.y()).min(self.target.height());
for x in start_x..end_x {
for y in start_y..end_y {
let step = (x, y).into();
// SAFETY: we start and end values are in proper bounds.
unsafe {
let pixel = function(x, y, self.target.unsafe_pixel(step).clone());
*self.target.unsafe_pixel_mut(step) = pixel;
}
}
}
}
}
/// Painter trait to generalize pixel-perfect and subpixel paint routines.
pub trait Paint
where
T: Image,
I: Into>,
{
/// Get reference to pixel.
fn pixel(&self, position: I) -> Option>;
/// Get mutable reference to pixel.
fn pixel_mut(&mut self, position: I) -> Option>;
/// Use passed function on a pixel at the given position.
fn mod_pixel(&mut self, position: I, function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel in line.
fn line(&mut self, from: I, to: I, function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel in filled rectangle.
/// The `dimensions` determine size of the rectangle, zero or negative value produces no rectangle.
fn rect_f(&mut self, from: I, dimensions: I, function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel of rectangle bounds.
/// The `dimensions` determine size of the rectangle, zero or negative value produces no rectangle.
fn rect_b(&mut self, from: I, dimensions: I, function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel in triangle.
fn triangle_f(&mut self, vertices: [I; 3], function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel of triangle bounds.
fn triangle_b(&mut self, vertices: [I; 3], function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel of polygon.
fn polygon_f(&mut self, vertices: &[I], function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel of polygon bounds.
fn polygon_b(&mut self, vertices: &[I], function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel in circle.
fn circle_f(&mut self, center: I, radius: C, function: F)
where
F: FnMut(i32, i32, P) -> P;
/// Use passed function on each pixel of circle bounds.
fn circle_b(&mut self, center: I, radius: C, function: F)
where
F: FnMut(i32, i32, P) -> P;
}
/// A helper utility for writing horizontal lines faster.
pub trait FastHorizontalWriter
where
I: Image + ?Sized,
{
/// Apply provided function to all pixels in a horizontal line.
fn write_line I::Pixel>(
&mut self,
x: RangeInclusive,
y: i32,
function: &mut F,
);
}
struct FastHorizontalWriterPlaceholder;
impl FastHorizontalWriter for FastHorizontalWriterPlaceholder
where
I: Image + ?Sized,
{
fn write_line I::Pixel>(
&mut self,
_: RangeInclusive,
_: i32,
_: &mut F,
) {
unreachable!()
}
}