1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use super::{ColChar, Point, Vec2D};

/// Combine a vector of [`Vec2D`]s and a single `fill_char` into a vector of `(Vec2D, char)` tuples, ready to return for `ViewElement::active_pixels`. Useful if your [`ViewElement`](super::ViewElement) only has one fill character across all of it
pub fn points_to_pixels(points: Vec<Vec2D>, fill_char: ColChar) -> Vec<Point> {
    points
        .iter()
        .map(|e| Point::new(e.clone(), fill_char))
        .collect()
}

pub fn interpolate(i0: isize, d0: f64, i1: isize, d1: f64) -> Vec<isize> {
    if i0 == i1 {
        return vec![d0.round() as isize];
    }
    let mut values = vec![];

    let a = (d1 - d0) / (i1 - i0) as f64;
    let mut d = d0;
    for _i in i0..(i1 + 1) {
        values.push(d.clone().round() as isize);
        d += a;
    }
    values
}

/// Returns true if the points in the vector are arranged in a clockwise orientation
pub fn is_clockwise(points: &Vec<Vec2D>) -> bool {
    let mut m = vec![];
    for i in 0..points.len() {
        let (p1, p2) = (points[i], points[(i + 1) % points.len()]);
        m.push((p1.x - p2.x) * (p1.y + p2.y));
    }

    m.iter().sum::<isize>() <= 0
}

/// Wrapping is used to determine how you want to handle out-of-bounds pixels during plotting pixels to the screen. Here's how each possible value functions:
///
/// [`Wrapping::Wrap`] wraps any out of bounds pixels around to the other side. This is useful if you have an object that travels the entirety of the screen and appears on the other side when it reaches the end.
///
/// [`Wrapping::Ignore`] simply skips all out-of-bounds pixels. This is useful if you might have an object clipping through the edge of the screen.
///
/// [`Wrapping::Panic`] will `panic!` if any pixels are out of bounds. You should use this if you have your own wrapping system implemented
#[derive(Copy)]
pub enum Wrapping {
    Wrap,
    Ignore,
    Panic,
}

impl Clone for Wrapping {
    fn clone(&self) -> Self {
        match self {
            Wrapping::Wrap => Wrapping::Wrap,
            Wrapping::Ignore => Wrapping::Ignore,
            Wrapping::Panic => Wrapping::Panic,
        }
    }
}

/// `BlitCache` is used if there is chance that you might have to render the same thing multiple times without moving or changing it.
#[derive(Debug)]
pub struct BlitCache<T> {
    independent: Vec<T>,
    dependent: Vec<Vec2D>,
}

impl<T> BlitCache<T>
where
    T: PartialEq<T>,
{
    pub const DEFAULT: BlitCache<T> = BlitCache {
        independent: vec![],
        dependent: vec![],
    };

    pub fn new(independent: Vec<T>, dependent: Vec<Vec2D>) -> Self {
        Self {
            independent,
            dependent,
        }
    }

    pub fn is_default(&self) -> bool {
        self == &BlitCache::DEFAULT
    }

    /// Returns the stored dependent value. Returns None if the cache is set to its default
    pub fn dependent(&self) -> Option<Vec<Vec2D>> {
        match self.is_default() {
            false => Some(self.dependent.clone()),
            true => None,
        }
    }

    pub fn is_cache_valid(&self, other_independent: &Vec<T>) -> bool {
        if self.independent.len() != other_independent.len() {
            return false;
        }
        self.independent
            .iter()
            .zip(other_independent)
            .filter(|&(a, b)| a == b)
            .count()
            == self.independent.len()
    }
}

impl<T> Clone for BlitCache<T>
where
    T: PartialEq<T>,
    T: Clone,
{
    fn clone(&self) -> Self {
        Self {
            independent: self.independent.clone(),
            dependent: self.dependent.clone(),
        }
    }
}

impl<T> PartialEq for BlitCache<T>
where
    T: PartialEq<T>,
{
    fn eq(&self, other: &Self) -> bool {
        self.independent == other.independent && self.dependent == other.dependent
    }
}