1use std::cmp::Ordering;
6use std::{fmt, mem};
7
8use crate::{MAX_HEIGHT_SHIFT, MAX_WIDTH_SHIFT, PIXEL_WIDTH};
9
10const TILE_BIAS: i16 = 1;
13
14pub const fn bit_field_lens<const TW: usize, const TH: usize>() -> [usize; 7] {
15 const fn log2_round_up(n: usize) -> usize {
16 if n.count_ones() == 1 {
17 n.trailing_zeros() as usize
18 } else {
19 mem::size_of::<usize>() * 8 - n.leading_zeros() as usize
20 }
21 }
22
23 let tile_width_shift = TW.trailing_zeros() as usize;
24 let tile_height_shift = TH.trailing_zeros() as usize;
25
26 let mut bit_field_lens = [
27 MAX_HEIGHT_SHIFT - tile_height_shift,
28 MAX_WIDTH_SHIFT - tile_width_shift,
29 0,
30 tile_width_shift,
31 tile_height_shift,
32 log2_round_up((PIXEL_WIDTH + 1) * 2),
33 log2_round_up((PIXEL_WIDTH + 1) * 2),
34 ];
35
36 let layer_id_len = mem::size_of::<PixelSegment<TW, TH>>() * 8
37 - bit_field_lens[0]
38 - bit_field_lens[1]
39 - bit_field_lens[3]
40 - bit_field_lens[4]
41 - bit_field_lens[5]
42 - bit_field_lens[6];
43
44 bit_field_lens[2] = layer_id_len;
45
46 bit_field_lens
47}
48
49const fn shift_left_for<const TW: usize, const TH: usize>(bit_field_index: usize) -> u32 {
50 let mut amount = 0;
51 let mut i = 0;
52
53 while i < bit_field_index {
54 amount += bit_field_lens::<TW, TH>()[i];
55 i += 1;
56 }
57
58 amount as u32
59}
60
61const fn shift_right_for<const TW: usize, const TH: usize>(bit_field_index: usize) -> u32 {
62 (mem::size_of::<PixelSegment<TW, TH>>() * 8 - bit_field_lens::<TW, TH>()[bit_field_index])
63 as u32
64}
65
66macro_rules! extract {
67 ( $tw:expr , $th:expr , $pixel_segment:expr , $bit_field_index:expr ) => {{
68 $pixel_segment << shift_left_for::<$tw, $th>($bit_field_index)
69 >> shift_right_for::<$tw, $th>($bit_field_index)
70 }};
71}
72
73#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
74pub struct PixelSegment<const TW: usize, const TH: usize>(u64);
75
76impl<const TW: usize, const TH: usize> PixelSegment<TW, TH> {
77 const BIT_FIELD_LENGTH: [usize; 7] = bit_field_lens::<TW, TH>();
78
79 #[inline]
80 pub fn new(
81 layer_id: u32,
82 tile_x: i16,
83 tile_y: i16,
84 local_x: u8,
85 local_y: u8,
86 double_area_multiplier: u8,
87 cover: i8,
88 ) -> Self {
89 let mut val = 0;
90
91 val |= ((1 << Self::BIT_FIELD_LENGTH[0]) - 1) & (tile_y + TILE_BIAS).max(0) as u64;
92
93 val <<= Self::BIT_FIELD_LENGTH[1];
94 val |= ((1 << Self::BIT_FIELD_LENGTH[1]) - 1) as u64 & (tile_x + TILE_BIAS).max(0) as u64;
95
96 val <<= Self::BIT_FIELD_LENGTH[2];
97 val |= ((1 << Self::BIT_FIELD_LENGTH[2]) - 1) as u64 & u64::from(layer_id);
98
99 val <<= Self::BIT_FIELD_LENGTH[3];
100 val |= ((1 << Self::BIT_FIELD_LENGTH[3]) - 1) as u64 & u64::from(local_x);
101
102 val <<= Self::BIT_FIELD_LENGTH[4];
103 val |= ((1 << Self::BIT_FIELD_LENGTH[4]) - 1) as u64 & u64::from(local_y);
104
105 val <<= Self::BIT_FIELD_LENGTH[5];
106 val |= ((1 << Self::BIT_FIELD_LENGTH[5]) - 1) as u64 & u64::from(double_area_multiplier);
107
108 val <<= Self::BIT_FIELD_LENGTH[6];
109 val |= ((1 << Self::BIT_FIELD_LENGTH[6]) - 1) as u64 & cover as u64;
110
111 Self(val)
112 }
113
114 #[inline]
115 pub fn layer_id(self) -> u32 {
116 extract!(TW, TH, self.0, 2) as u32
117 }
118
119 #[inline]
120 pub fn tile_x(self) -> i16 {
121 extract!(TW, TH, self.0, 1) as i16 - TILE_BIAS
122 }
123
124 #[inline]
125 pub fn tile_y(self) -> i16 {
126 extract!(TW, TH, self.0, 0) as i16 - TILE_BIAS
127 }
128
129 #[inline]
130 pub fn local_x(self) -> u8 {
131 extract!(TW, TH, self.0, 3) as u8
132 }
133
134 #[inline]
135 pub fn local_y(self) -> u8 {
136 extract!(TW, TH, self.0, 4) as u8
137 }
138
139 #[inline]
140 fn double_area_multiplier(self) -> u8 {
141 extract!(TW, TH, self.0, 5) as u8
142 }
143
144 #[inline]
145 pub fn double_area(self) -> i16 {
146 i16::from(self.double_area_multiplier()) * i16::from(self.cover())
147 }
148
149 #[inline]
150 pub fn cover(self) -> i8 {
151 extract!(TW, TH, self.0 as i64, 6) as i8
152 }
153}
154
155impl<const TW: usize, const TH: usize> fmt::Debug for PixelSegment<TW, TH> {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 let unpacked: PixelSegmentUnpacked = (*self).into();
158 f.debug_struct("PixelSegment")
159 .field("layer_id", &unpacked.layer_id)
160 .field("tile_x", &unpacked.tile_x)
161 .field("tile_y", &unpacked.tile_y)
162 .field("local_x", &unpacked.local_x)
163 .field("local_y", &unpacked.local_y)
164 .field("double_area", &unpacked.double_area)
165 .field("cover", &unpacked.cover)
166 .finish()
167 }
168}
169
170impl<const TW: usize, const TH: usize> From<&PixelSegment<TW, TH>> for u64 {
171 fn from(segment: &PixelSegment<TW, TH>) -> Self {
172 segment.0
173 }
174}
175
176#[inline]
177pub fn search_last_by_key<F, K, const TW: usize, const TH: usize>(
178 segments: &[PixelSegment<TW, TH>],
179 key: K,
180 mut f: F,
181) -> Result<usize, usize>
182where
183 F: FnMut(&PixelSegment<TW, TH>) -> K,
184 K: Ord,
185{
186 let mut len = segments.len();
187 if len == 0 {
188 return Err(0);
189 }
190
191 let mut start = 0;
192 while len > 1 {
193 let half = len / 2;
194 let mid = start + half;
195 (start, len) = match f(&segments[mid]).cmp(&key) {
196 Ordering::Greater => (start, half),
197 _ => (mid, len - half),
198 };
199 }
200
201 match f(&segments[start]).cmp(&key) {
202 Ordering::Less => Err(start + 1),
203 Ordering::Equal => Ok(start),
204 Ordering::Greater => Err(start),
205 }
206}
207
208#[derive(Debug)]
209pub struct PixelSegmentUnpacked {
210 pub layer_id: u32,
211 pub tile_x: i16,
212 pub tile_y: i16,
213 pub local_x: u8,
214 pub local_y: u8,
215 pub double_area: i16,
216 pub cover: i8,
217}
218
219impl<const TW: usize, const TH: usize> From<PixelSegment<TW, TH>> for PixelSegmentUnpacked {
220 fn from(value: PixelSegment<TW, TH>) -> Self {
221 PixelSegmentUnpacked {
222 layer_id: value.layer_id(),
223 tile_x: value.tile_x(),
224 tile_y: value.tile_y(),
225 local_x: value.local_x(),
226 local_y: value.local_y(),
227 double_area: value.double_area(),
228 cover: value.cover(),
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 use crate::{LAYER_LIMIT, PIXEL_DOUBLE_WIDTH, TILE_HEIGHT, TILE_WIDTH};
238
239 #[test]
240 fn pixel_segment() {
241 let layer_id = 3;
242 let tile_x = 4;
243 let tile_y = 5;
244 let local_x = 6;
245 let local_y = 7;
246 let double_area_multiplier = 8;
247 let cover = 9;
248
249 let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
250 layer_id,
251 tile_x,
252 tile_y,
253 local_x,
254 local_y,
255 double_area_multiplier,
256 cover,
257 );
258
259 assert_eq!(pixel_segment.layer_id(), layer_id);
260 assert_eq!(pixel_segment.tile_x(), tile_x);
261 assert_eq!(pixel_segment.tile_y(), tile_y);
262 assert_eq!(pixel_segment.local_x(), local_x);
263 assert_eq!(pixel_segment.local_y(), local_y);
264 assert_eq!(
265 pixel_segment.double_area(),
266 i16::from(double_area_multiplier) * i16::from(cover)
267 );
268 assert_eq!(pixel_segment.cover(), cover);
269 }
270
271 #[test]
272 fn pixel_segment_max() {
273 let layer_id = LAYER_LIMIT as u32;
274 let tile_x = (1 << (bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[1] - 1)) - 1;
275 let tile_y = (1 << (bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[0] - 1)) - 1;
276 let local_x = (1 << bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[4]) - 1;
277 let local_y = (1 << bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[3]) - 1;
278 let double_area_multiplier = PIXEL_DOUBLE_WIDTH as u8;
279 let cover = PIXEL_WIDTH as i8;
280
281 let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
282 layer_id,
283 tile_x,
284 tile_y,
285 local_x,
286 local_y,
287 double_area_multiplier,
288 cover,
289 );
290
291 assert_eq!(pixel_segment.layer_id(), layer_id);
292 assert_eq!(pixel_segment.tile_x(), tile_x);
293 assert_eq!(pixel_segment.tile_y(), tile_y);
294 assert_eq!(pixel_segment.local_x(), local_x);
295 assert_eq!(pixel_segment.local_y(), local_y);
296 assert_eq!(
297 pixel_segment.double_area(),
298 i16::from(double_area_multiplier) * i16::from(cover)
299 );
300 assert_eq!(pixel_segment.cover(), cover);
301 }
302
303 #[test]
304 fn pixel_segment_min() {
305 let layer_id = 0;
306 let tile_x = -1;
307 let tile_y = -1;
308 let local_x = 0;
309 let local_y = 0;
310 let double_area_multiplier = 0;
311 let cover = -(PIXEL_WIDTH as i8);
312
313 let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
314 layer_id,
315 tile_x,
316 tile_y,
317 local_x,
318 local_y,
319 double_area_multiplier,
320 cover,
321 );
322
323 assert_eq!(pixel_segment.layer_id(), layer_id);
324 assert_eq!(pixel_segment.tile_x(), -1);
325 assert_eq!(pixel_segment.tile_y(), -1);
326 assert_eq!(pixel_segment.local_x(), local_x);
327 assert_eq!(pixel_segment.local_y(), local_y);
328 assert_eq!(
329 pixel_segment.double_area(),
330 i16::from(double_area_multiplier) * i16::from(cover)
331 );
332 assert_eq!(pixel_segment.cover(), cover);
333 }
334
335 #[test]
336 fn pixel_segment_clipping() {
337 let tile_x = -2;
338 let tile_y = -2;
339
340 let pixel_segment =
341 PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(0, tile_x, tile_y, 0, 0, 0, 0);
342
343 assert_eq!(pixel_segment.tile_x(), -1, "negative tile coord clipped to -1");
344 assert_eq!(pixel_segment.tile_y(), -1, "negative tile coord clipped to -1");
345
346 let tile_x = i16::MIN;
347 let tile_y = i16::MIN;
348
349 let pixel_segment =
350 PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(0, tile_x, tile_y, 0, 0, 0, 0);
351
352 assert_eq!(pixel_segment.tile_x(), -1, "negative tile coord clipped to -1");
353 assert_eq!(pixel_segment.tile_y(), -1, "negative tile coord clipped to -1");
354 }
355
356 #[test]
357 fn search_last_by_key_test() {
358 let size = 50;
359 let segments: Vec<_> = (0..(size * 2))
360 .map(|i| PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(i / 2, 0, 0, 0, 0, 0, 0))
361 .collect();
362 for i in 0..size {
363 assert_eq!(
364 Ok((i * 2 + 1) as usize),
365 search_last_by_key(segments.as_slice(), i, |ps| ps.layer_id())
366 );
367 }
368 }
369}