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
use crate::error::Result;
use crate::graphics::{FilterMode, Texture};
use crate::platform::GraphicsDevice;
#[derive(Copy, Clone, Debug)]
struct Shelf {
current_x: i32,
start_y: i32,
height: i32,
}
pub struct ShelfPacker {
texture: Texture,
shelves: Vec<Shelf>,
next_y: i32,
}
impl ShelfPacker {
const PADDING: i32 = 1;
pub fn new(
device: &mut GraphicsDevice,
texture_width: i32,
texture_height: i32,
) -> Result<ShelfPacker> {
Ok(ShelfPacker {
texture: Texture::with_device_empty(
device,
texture_width,
texture_height,
FilterMode::Nearest,
)?,
shelves: Vec::new(),
next_y: Self::PADDING,
})
}
pub fn texture(&self) -> &Texture {
&self.texture
}
pub fn resize(
&mut self,
device: &mut GraphicsDevice,
texture_width: i32,
texture_height: i32,
) -> Result {
self.texture =
Texture::with_device_empty(device, texture_width, texture_height, FilterMode::Nearest)?;
self.shelves.clear();
self.next_y = 0;
Ok(())
}
pub fn insert(
&mut self,
device: &mut GraphicsDevice,
data: &[u8],
width: i32,
height: i32,
) -> Option<(i32, i32)> {
let space = self.find_space(width, height);
if let Some((x, y)) = space {
device.set_texture_data(&self.texture.data.handle, data, x, y, width, height);
}
space
}
fn find_space(&mut self, source_width: i32, source_height: i32) -> Option<(i32, i32)> {
let texture_width = self.texture.width();
let texture_height = self.texture.height();
self.shelves
.iter_mut()
.find(|shelf| {
shelf.height >= source_height
&& texture_width - shelf.current_x - Self::PADDING >= source_width
})
.map(|shelf| {
let position = (shelf.current_x, shelf.start_y);
shelf.current_x += source_width + Self::PADDING;
position
})
.or_else(|| {
if self.next_y + source_height < texture_height {
let position = (Self::PADDING, self.next_y);
self.shelves.push(Shelf {
current_x: source_width + Self::PADDING * 2,
start_y: self.next_y,
height: source_height,
});
self.next_y += source_height + Self::PADDING;
Some(position)
} else {
None
}
})
}
}