rust/lib-hedgewars-engine/src/render/atlas.rs
author Wuzzy <Wuzzy2@mail.ru>
Thu, 11 Jul 2019 16:24:09 +0200
changeset 15236 c10e9261ab9c
parent 15195 e2adb40c7988
child 15291 16bd389fc735
permissions -rw-r--r--
Make lowest line of Splash image frames transparent to work around scaling issues The Splash image is scaled. Sometimes, the lowest line is repeated on the top, which caused some weird lines to appear above big splashes (e.g. piano). This has been done fully automated with a script. Only the alpha channel was changed. The color information is preserved.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
     1
use integral_geometry::{Rect, Size};
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
     2
use itertools::Itertools;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
     3
use std::{
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
     4
    cmp::{max, min, Ordering},
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
     5
    ops::Index,
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
     6
};
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
     7
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
     8
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
     9
struct Fit {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    10
    short_side: u32,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    11
    long_side: u32,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    12
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    13
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    14
impl Fit {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    15
    fn new() -> Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    16
        Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    17
            short_side: u32::max_value(),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    18
            long_side: u32::max_value(),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    19
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    20
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    21
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    22
    fn measure(container: Size, size: Size) -> Option<Self> {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    23
        if container.contains(size) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    24
            let x_leftover = container.width - size.width;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    25
            let y_leftover = container.height - size.height;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    26
            Some(Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    27
                short_side: min(x_leftover, y_leftover) as u32,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    28
                long_side: max(x_leftover, y_leftover) as u32,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    29
            })
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    30
        } else {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    31
            None
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    32
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    33
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    34
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    35
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    36
#[derive(PartialEq, Eq)]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    37
pub struct UsedSpace {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    38
    used_area: usize,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    39
    total_area: usize,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    40
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    41
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    42
impl UsedSpace {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    43
    const fn new(used_area: usize, total_area: usize) -> Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    44
        Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    45
            used_area,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    46
            total_area,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    47
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    48
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    49
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    50
    const fn used(&self) -> usize {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    51
        self.used_area
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    52
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    53
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    54
    const fn total(&self) -> usize {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    55
        self.total_area
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    56
    }
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    57
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    58
    const fn free(&self) -> usize {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    59
        self.total_area - self.used_area
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    60
    }
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    61
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    62
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    63
impl std::fmt::Debug for UsedSpace {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    64
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    65
        write!(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    66
            f,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    67
            "{:.2}%",
15195
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
    68
            self.used() as f32 / self.total() as f32 * 100.0
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    69
        )?;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    70
        Ok(())
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    71
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    72
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    73
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    74
pub struct Atlas<T> {
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    75
    size: Size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    76
    free_rects: Vec<Rect>,
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    77
    used_rects: Vec<(Rect, T)>,
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    78
    splits: Vec<Rect>,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    79
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    80
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    81
impl<T: Copy> Atlas<T> {
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    82
    pub fn new(size: Size) -> Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    83
        Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    84
            size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    85
            free_rects: vec![Rect::at_origin(size)],
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    86
            used_rects: vec![],
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    87
            splits: vec![],
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    88
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    89
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    90
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    91
    pub fn size(&self) -> Size {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    92
        self.size
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    93
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    94
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    95
    pub fn used_space(&self) -> UsedSpace {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
    96
        let used = self.used_rects.iter().map(|(r, _)| r.size().area()).sum();
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    97
        UsedSpace::new(used, self.size.area())
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    98
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
    99
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   100
    fn find_position(&self, size: Size) -> Option<(Rect, Fit)> {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   101
        let mut best_rect = Rect::EMPTY;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   102
        let mut best_fit = Fit::new();
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   103
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   104
        for rect in &self.free_rects {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   105
            if let Some(fit) = Fit::measure(rect.size(), size) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   106
                if fit < best_fit {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   107
                    best_fit = fit;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   108
                    best_rect = Rect::from_size(rect.top_left(), size);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   109
                }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   110
            }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   111
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   112
            if let Some(fit) = Fit::measure(rect.size(), size.transpose()) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   113
                if fit < best_fit {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   114
                    best_fit = fit;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   115
                    best_rect = Rect::from_size(rect.top_left(), size.transpose());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   116
                }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   117
            }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   118
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   119
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   120
        if best_rect == Rect::EMPTY {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   121
            None
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   122
        } else {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   123
            Some((best_rect, best_fit))
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   124
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   125
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   126
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   127
    fn split_insert(&mut self, rect: Rect, value: T) {
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   128
        let mut splits = std::mem::replace(&mut self.splits, vec![]);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   129
        let mut buffer = [Rect::EMPTY; 4];
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   130
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   131
        for i in (0..self.free_rects.len()).rev() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   132
            if let Some(count) = split_rect(self.free_rects[i], rect, &mut splits, &mut buffer) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   133
                self.free_rects.swap_remove(i as usize);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   134
                splits.extend_from_slice(&buffer[0..count]);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   135
            }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   136
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   137
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   138
        filter_swap_remove(&mut splits, |s| {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   139
            self.free_rects.iter().any(|r| r.contains_rect(s))
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   140
        });
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   141
        self.free_rects.extend(splits.drain(..));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   142
        std::mem::replace(&mut self.splits, splits);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   143
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   144
        self.used_rects.push((rect, value));
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   145
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   146
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   147
    pub fn insert(&mut self, size: Size, value: T) -> Option<Rect> {
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   148
        let (rect, _) = self.find_position(size)?;
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   149
        self.split_insert(rect, value);
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   150
        Some(rect)
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   151
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   152
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   153
    pub fn insert_set<Iter>(&mut self, sizes: Iter) -> Vec<(Rect, T)>
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   154
    where
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   155
        Iter: Iterator<Item = (Size, T)>,
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   156
    {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   157
        let mut sizes: Vec<_> = sizes.collect();
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   158
        let mut result = Vec::with_capacity(sizes.len());
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   159
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   160
        while let Some((index, (rect, _), value)) = sizes
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   161
            .iter()
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   162
            .enumerate()
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   163
            .filter_map(|(i, (s, v))| self.find_position(*s).map(|res| (i, res, v)))
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   164
            .min_by_key(|(_, (_, fit), _)| fit.clone())
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   165
        {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   166
            self.split_insert(rect, *value);
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   167
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   168
            result.push((rect, *value));
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   169
            sizes.swap_remove(index);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   170
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   171
        result
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   172
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   173
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   174
    pub fn reset(&mut self) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   175
        self.free_rects.clear();
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   176
        self.used_rects.clear();
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   177
        self.free_rects.push(Rect::at_origin(self.size));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   178
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   179
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   180
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   181
pub type SpriteIndex = u32;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   182
pub type SpriteLocation = (u32, Rect);
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   183
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   184
pub struct AtlasCollection {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   185
    next_index: SpriteIndex,
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   186
    texture_size: Size,
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   187
    atlases: Vec<Atlas<SpriteIndex>>,
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   188
    rects: Vec<SpriteLocation>,
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   189
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   190
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   191
impl AtlasCollection {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   192
    pub fn new(texture_size: Size) -> Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   193
        Self {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   194
            next_index: 0,
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   195
            texture_size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   196
            atlases: vec![],
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   197
            rects: vec![],
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   198
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   199
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   200
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   201
    fn repack(&mut self, size: Size) -> bool {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   202
        for (atlas_index, atlas) in self.atlases.iter_mut().enumerate() {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   203
            if atlas.used_space().free() >= size.area() {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   204
                let mut temp_atlas = Atlas::new(atlas.size());
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   205
                let sizes = atlas
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   206
                    .used_rects
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   207
                    .iter()
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   208
                    .map(|(r, v)| (r.size(), *v))
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   209
                    .chain(std::iter::once((size, self.next_index)));
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   210
                let inserts = temp_atlas.insert_set(sizes);
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   211
                if inserts.len() > atlas.used_rects.len() {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   212
                    self.rects.push((0, Rect::EMPTY));
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   213
                    for (rect, index) in inserts {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   214
                        self.rects[index as usize] = (atlas_index as u32, rect);
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   215
                    }
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   216
                    std::mem::swap(atlas, &mut temp_atlas);
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   217
                    return true;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   218
                }
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   219
            }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   220
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   221
        false
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   222
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   223
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   224
    #[inline]
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   225
    fn consume_index(&mut self) -> Option<SpriteIndex> {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   226
        let result = Some(self.next_index);
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   227
        self.next_index += 1;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   228
        result
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   229
    }
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   230
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   231
    pub fn insert_sprite(&mut self, size: Size) -> Option<SpriteIndex> {
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   232
        if !self.texture_size.contains(size) {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   233
            None
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   234
        } else {
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   235
            let index = self.next_index;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   236
            if let Some(index_rect) = self
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   237
                .atlases
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   238
                .iter_mut()
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   239
                .enumerate()
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   240
                .find_map(|(i, a)| a.insert(size, index).map(|r| (i as u32, r)))
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   241
            {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   242
                self.rects.push(index_rect);
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   243
            } else if !self.repack(size) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   244
                let mut atlas = Atlas::new(self.texture_size);
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   245
                let rect = atlas.insert(size, index)?;
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   246
                self.atlases.push(atlas);
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   247
                self.rects.push(((self.atlases.len() - 1) as u32, rect))
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   248
            }
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   249
            self.consume_index()
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   250
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   251
    }
15195
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   252
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   253
    pub fn used_space(&self) -> String {
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   254
        self.atlases
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   255
            .iter()
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   256
            .enumerate()
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   257
            .map(|(i, a)| format!("{}: {:?}", i, a.used_space()))
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   258
            .join("\n")
e2adb40c7988 fill the atlas with sprites
alfadur
parents: 15191
diff changeset
   259
    }
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   260
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   261
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   262
impl Index<SpriteIndex> for AtlasCollection {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   263
    type Output = SpriteLocation;
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   264
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   265
    #[inline]
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   266
    fn index(&self, index: SpriteIndex) -> &Self::Output {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   267
        &self.rects[index as usize]
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   268
    }
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   269
}
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   270
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   271
#[inline]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   272
fn filter_swap_remove<T, F>(vec: &mut Vec<T>, predicate: F)
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   273
where
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   274
    F: Fn(&T) -> bool,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   275
{
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   276
    let mut i = 0;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   277
    while i < vec.len() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   278
        if predicate(&vec[i]) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   279
            vec.swap_remove(i);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   280
        } else {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   281
            i += 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   282
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   283
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   284
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   285
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   286
#[inline]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   287
fn prune_push(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   288
    previous_splits: &mut Vec<Rect>,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   289
    buffer: &mut [Rect; 4],
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   290
    buffer_size: &mut usize,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   291
    rect: Rect,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   292
) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   293
    if !previous_splits.iter().any(|r| r.contains_rect(&rect)) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   294
        filter_swap_remove(previous_splits, |s| rect.contains_rect(s));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   295
        buffer[*buffer_size] = rect;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   296
        *buffer_size += 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   297
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   298
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   299
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   300
fn split_rect(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   301
    free_rect: Rect,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   302
    rect: Rect,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   303
    previous_splits: &mut Vec<Rect>,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   304
    buffer: &mut [Rect; 4],
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   305
) -> Option<usize> {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   306
    let mut buffer_size = 0usize;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   307
    let split = free_rect.intersects(&rect);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   308
    if split {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   309
        if rect.left() > free_rect.left() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   310
            let trim = free_rect.right() - rect.left() + 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   311
            prune_push(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   312
                previous_splits,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   313
                buffer,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   314
                &mut buffer_size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   315
                free_rect.with_margins(0, -trim, 0, 0),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   316
            );
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   317
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   318
        if rect.right() < free_rect.right() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   319
            let trim = rect.right() - free_rect.left() + 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   320
            prune_push(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   321
                previous_splits,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   322
                buffer,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   323
                &mut buffer_size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   324
                free_rect.with_margins(-trim, 0, 0, 0),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   325
            );
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   326
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   327
        if rect.top() > free_rect.top() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   328
            let trim = free_rect.bottom() - rect.top() + 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   329
            prune_push(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   330
                previous_splits,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   331
                buffer,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   332
                &mut buffer_size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   333
                free_rect.with_margins(0, 0, 0, -trim),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   334
            );;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   335
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   336
        if rect.bottom() < free_rect.bottom() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   337
            let trim = rect.bottom() - free_rect.top() + 1;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   338
            prune_push(
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   339
                previous_splits,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   340
                buffer,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   341
                &mut buffer_size,
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   342
                free_rect.with_margins(0, 0, -trim, 0),
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   343
            );;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   344
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   345
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   346
    if split {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   347
        Some(buffer_size)
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   348
    } else {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   349
        None
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   350
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   351
}
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   352
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   353
#[cfg(test)]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   354
mod tests {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   355
    use super::Atlas;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   356
    use integral_geometry::{Rect, Size};
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   357
    use itertools::Itertools as _;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   358
    use proptest::prelude::*;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   359
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   360
    #[test]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   361
    fn insert() {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   362
        let atlas_size = Size::square(16);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   363
        let mut atlas = Atlas::new(atlas_size);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   364
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   365
        assert_eq!(None, atlas.insert(Size::square(20), ()));
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   366
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   367
        let rect_size = Size::new(11, 3);
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   368
        let rect = atlas.insert(rect_size, ()).unwrap();
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   369
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   370
        assert_eq!(rect, Rect::at_origin(rect_size));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   371
        assert_eq!(2, atlas.free_rects.len());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   372
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   373
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   374
    #[derive(Debug, Clone)]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   375
    struct TestRect(Size);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   376
    struct TestRectParameters(Size);
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   377
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   378
    impl Default for TestRectParameters {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   379
        fn default() -> Self {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   380
            Self(Size::square(64))
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   381
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   382
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   383
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   384
    impl Arbitrary for TestRect {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   385
        type Parameters = TestRectParameters;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   386
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   387
        fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   388
            (1..=args.0.width, 1..=args.0.height)
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   389
                .prop_map(|(w, h)| TestRect(Size::new(w, h)))
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   390
                .boxed()
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   391
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   392
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   393
        type Strategy = BoxedStrategy<TestRect>;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   394
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   395
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   396
    trait HasSize {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   397
        fn size(&self) -> Size;
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   398
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   399
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   400
    impl HasSize for TestRect {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   401
        fn size(&self) -> Size {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   402
            self.0
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   403
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   404
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   405
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   406
    impl HasSize for Rect {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   407
        fn size(&self) -> Size {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   408
            self.size()
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   409
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   410
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   411
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   412
    impl HasSize for (Rect, ()) {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   413
        fn size(&self) -> Size {
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   414
            self.0.size()
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   415
        }
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   416
    }
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   417
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   418
    fn sum_area<S: HasSize>(items: &[S]) -> usize {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   419
        items.iter().map(|s| s.size().area()).sum()
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   420
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   421
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   422
    proptest! {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   423
        #[test]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   424
        fn prop_insert(rects in Vec::<TestRect>::arbitrary()) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   425
            let container = Rect::at_origin(Size::square(2048));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   426
            let mut atlas = Atlas::new(container.size());
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   427
            let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size, ())).collect();
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   428
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   429
            let mut inserted_pairs = inserted.iter().cartesian_product(inserted.iter());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   430
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   431
            assert!(inserted.iter().all(|r| container.contains_rect(r)));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   432
            assert!(inserted_pairs.all(|(r1, r2)| r1 == r2 || r1 != r2 && !r1.intersects(r2)));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   433
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   434
            assert_eq!(inserted.len(), rects.len());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   435
            assert_eq!(sum_area(&inserted), sum_area(&rects));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   436
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   437
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   438
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   439
    proptest! {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   440
        #[test]
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   441
        fn prop_insert_set(rects in Vec::<TestRect>::arbitrary()) {
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   442
            let container = Rect::at_origin(Size::square(2048));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   443
            let mut atlas = Atlas::new(container.size());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   444
            let mut set_atlas = Atlas::new(container.size());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   445
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   446
            let inserted: Vec<_> = rects.iter().filter_map(|TestRect(size)| atlas.insert(*size, ())).collect();
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   447
            let set_inserted: Vec<_> = set_atlas.insert_set(rects.iter().map(|TestRect(size)| (*size, ())));
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   448
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   449
            let mut set_inserted_pairs = set_inserted.iter().cartesian_product(set_inserted.iter());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   450
15191
9cf0c2f44f0e add a way to reference atlas contents
alfadur
parents: 15125
diff changeset
   451
            assert!(set_inserted_pairs.all(|((r1, _), (r2, _))| r1 == r2 || r1 != r2 && !r1.intersects(r2)));
15125
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   452
            assert!(set_atlas.used_space().used() <= atlas.used_space().used());
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   453
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   454
            assert_eq!(sum_area(&set_inserted), sum_area(&inserted));
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   455
        }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   456
    }
febccab419b1 Apply dos2unix to rust sources
unc0rr
parents: 14748
diff changeset
   457
}