1use crate::math::{UVec2, Vec2, Vec4};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct Sheet {
11 columns: u32,
12 rows: u32,
13}
14
15impl Sheet {
16 pub fn new(size: UVec2) -> Self {
19 Self {
23 columns: size.x.max(1),
24 rows: size.y.max(1),
25 }
26 }
27
28 pub fn cell(&self, index: u32) -> Frame {
31 self.cell_at(UVec2::new(index % self.columns, index / self.columns))
32 }
33
34 pub fn cell_at(&self, at: UVec2) -> Frame {
37 let size = Vec2::new(1.0 / self.columns as f32, 1.0 / self.rows as f32);
38 let cell = Vec2::new((at.x % self.columns) as f32, (at.y % self.rows) as f32);
39
40 Frame {
41 min: cell * size,
42 max: (cell + Vec2::ONE) * size,
43 }
44 }
45}
46
47#[derive(Clone, Copy, Debug, PartialEq)]
53pub struct Frame {
54 min: Vec2,
55 max: Vec2,
56}
57
58impl Frame {
59 pub fn rect(min: Vec2, max: Vec2) -> Self {
64 Self { min, max }
65 }
66
67 pub fn mirrored(self) -> Self {
70 Self {
71 min: Vec2::new(self.max.x, self.min.y),
72 max: Vec2::new(self.min.x, self.max.y),
73 }
74 }
75
76 pub(crate) fn lane(self) -> Vec4 {
79 let size = self.max - self.min;
80
81 Vec4::new(self.min.x, self.min.y, size.x, size.y)
82 }
83}
84
85impl Default for Frame {
86 fn default() -> Self {
88 Self {
89 min: Vec2::ZERO,
90 max: Vec2::ONE,
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn the_whole_texture_is_what_a_draw_samples_until_it_asks_for_a_part() {
101 assert_eq!(Frame::default().lane(), Vec4::new(0.0, 0.0, 1.0, 1.0));
102 assert_eq!(
103 Frame::rect(Vec2::new(0.25, 0.5), Vec2::new(0.75, 1.0)).lane(),
104 Vec4::new(0.25, 0.5, 0.5, 0.5)
105 );
106 }
107
108 #[test]
109 fn the_cells_of_a_grid_are_counted_row_by_row_from_the_top_left() {
110 let sheet = Sheet::new(UVec2::new(4, 2));
111 let cell = |index| sheet.cell(index).lane();
112
113 assert_eq!(cell(0), Vec4::new(0.0, 0.0, 0.25, 0.5));
114 assert_eq!(cell(3), Vec4::new(0.75, 0.0, 0.25, 0.5));
115 assert_eq!(cell(4), Vec4::new(0.0, 0.5, 0.25, 0.5));
116 }
117
118 #[test]
119 fn a_cell_past_the_last_wraps_around_the_grid() {
120 let sheet = Sheet::new(UVec2::new(4, 2));
121
122 assert_eq!(sheet.cell(8), sheet.cell(0));
123 assert_eq!(sheet.cell(11), sheet.cell(3));
124 assert_eq!(sheet.cell(u32::MAX), sheet.cell(u32::MAX % 8));
125 }
126
127 #[test]
128 fn a_cell_named_by_its_two_axes_is_the_one_the_count_reaches() {
129 let sheet = Sheet::new(UVec2::new(4, 2));
130
131 assert_eq!(sheet.cell_at(UVec2::new(0, 0)), sheet.cell(0));
132 assert_eq!(sheet.cell_at(UVec2::new(3, 0)), sheet.cell(3));
133 assert_eq!(sheet.cell_at(UVec2::new(1, 1)), sheet.cell(5));
134 }
135
136 #[test]
137 fn a_column_or_row_past_the_grid_wraps_around_its_own_side() {
138 let sheet = Sheet::new(UVec2::new(4, 2));
139
140 assert_eq!(
141 sheet.cell_at(UVec2::new(4, 1)),
142 sheet.cell_at(UVec2::new(0, 1))
143 );
144 assert_eq!(
145 sheet.cell_at(UVec2::new(2, 2)),
146 sheet.cell_at(UVec2::new(2, 0))
147 );
148 assert_eq!(
149 sheet.cell_at(UVec2::new(u32::MAX, u32::MAX)),
150 sheet.cell_at(UVec2::new(u32::MAX % 4, u32::MAX % 2))
151 );
152 }
153
154 #[test]
155 fn a_grid_with_a_side_of_nothing_still_names_the_whole_texture() {
156 for sheet in [
157 Sheet::new(UVec2::new(0, 0)),
158 Sheet::new(UVec2::new(0, 1)),
159 Sheet::new(UVec2::new(1, 0)),
160 ] {
161 assert_eq!(sheet.cell(0), Frame::default());
162 assert_eq!(sheet.cell(7), Frame::default());
163 }
164 }
165
166 #[test]
167 fn a_mirrored_window_names_the_same_two_edges_the_other_way_round() {
168 let min = Vec2::new(0.25, 0.5);
169 let max = Vec2::new(0.75, 1.0);
170 let window = Frame::rect(min, max);
171
172 assert_eq!(
173 window.mirrored(),
174 Frame::rect(Vec2::new(max.x, min.y), Vec2::new(min.x, max.y))
175 );
176 assert_eq!(window.mirrored().mirrored(), window, "and twice is itself");
177 }
178
179 #[test]
180 fn a_mirrored_cell_starts_where_the_cell_it_came_from_ends() {
181 let sheet = Sheet::new(UVec2::new(3, 2));
182
183 for index in 0..6 {
184 let cell = sheet.cell(index);
185 let [x, y, width, height] = cell.lane().to_array();
186
187 assert_eq!(
188 cell.mirrored().lane(),
189 Vec4::new(x + width, y, -width, height)
190 );
191 assert_eq!(cell.mirrored().mirrored(), cell, "and twice is the cell");
192 }
193 }
194
195 #[test]
196 fn the_cells_of_a_grid_cover_it_and_nothing_twice() {
197 let sheet = Sheet::new(UVec2::new(2, 2));
198 let cells: Vec<Vec4> = (0..4).map(|index| sheet.cell(index).lane()).collect();
199
200 assert_eq!(
201 cells,
202 vec![
203 Vec4::new(0.0, 0.0, 0.5, 0.5),
204 Vec4::new(0.5, 0.0, 0.5, 0.5),
205 Vec4::new(0.0, 0.5, 0.5, 0.5),
206 Vec4::new(0.5, 0.5, 0.5, 0.5),
207 ]
208 );
209 }
210}