srs2dge_core/packer/texture/
map.rs1use crate::prelude::{
2 PositionedRect, Rect, Target, TextureAtlas, TextureAtlasBuilder, TextureAtlasFile,
3 TexturePosition,
4};
5use image::RgbaImage;
6use serde::{Deserialize, Serialize};
7use std::{
8 collections::{BinaryHeap, HashMap},
9 hash::Hash,
10 ops::Deref,
11};
12
13#[derive(Debug, Clone)]
16struct SortBySize<K> {
17 key: K,
18 image: RgbaImage,
19}
20
21impl<K> SortBySize<K> {
22 fn size(&self) -> u64 {
23 let (w, h) = self.image.dimensions();
24 w as u64 * h as u64
25 }
26}
27
28impl<K> PartialEq for SortBySize<K> {
29 fn eq(&self, other: &Self) -> bool {
30 self.size() == other.size()
31 }
32}
33
34impl<K> Eq for SortBySize<K> {}
35
36impl<K> PartialOrd for SortBySize<K> {
37 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
38 self.size().partial_cmp(&other.size())
39 }
40}
41
42impl<K> Ord for SortBySize<K> {
43 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
44 self.size().cmp(&other.size())
45 }
46}
47
48#[derive(Debug, Clone)]
49pub struct TextureAtlasMapBuilder<K> {
50 limit: u16,
52
53 images: BinaryHeap<SortBySize<K>>,
54}
55
56#[derive(Debug)]
57pub struct TextureAtlasMap<K>
58where
59 K: Eq + Hash + Clone,
60{
61 inner: TextureAtlas,
62 map: HashMap<K, TexturePosition>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct TextureAtlasMapFile<K>
67where
68 K: Eq + Hash + Clone,
69{
70 inner: TextureAtlasFile,
71 map: HashMap<K, TexturePosition>,
72}
73
74impl<K> Default for TextureAtlasMapBuilder<K> {
75 fn default() -> Self {
76 Self {
77 images: Default::default(),
78 limit: u16::MAX,
79 }
80 }
81}
82
83impl<K> TextureAtlasMapBuilder<K> {
84 pub fn new() -> Self {
85 Self::default()
86 }
87
88 pub fn with_limit(mut self, limit: u16) -> Self {
90 self.limit = limit;
91 self
92 }
93
94 pub fn with(mut self, key: K, image: RgbaImage) -> Self {
95 self.insert(key, image);
96 self
97 }
98
99 pub fn insert(&mut self, key: K, image: RgbaImage) {
100 self.images.push(SortBySize { key, image });
101 }
102}
103
104impl<K> TextureAtlasMapBuilder<K>
105where
106 K: Eq + Hash + Clone,
107{
108 pub fn build(mut self, target: &Target) -> TextureAtlasMap<K> {
109 let mut builder = TextureAtlasBuilder::new();
110 let mut images = vec![];
111
112 while let Some(SortBySize { key, image }) = self.images.pop() {
113 let (width, height) = image.dimensions();
114
115 let v = builder
116 .push(Rect { width, height })
117 .expect("Texture atlas limit reached");
118 images.push((key, v, image));
119 }
120
121 type Map<K> = Vec<(K, PositionedRect)>;
122 type Iter = Vec<(RgbaImage, PositionedRect)>;
123 let (map, iter): (Map<K>, Iter) = images
124 .into_iter()
125 .map(|(key, pos, img)| ((key, pos), (img, pos)))
126 .unzip();
127
128 let inner = builder.build(target, iter.into_iter());
129 let size = inner.get_dim();
130 let map = map
131 .into_iter()
132 .map(|(key, rect)| (key, TexturePosition::new(size, rect)))
133 .collect();
134
135 TextureAtlasMap { inner, map }
136 }
137}
138
139impl<K> TextureAtlasMap<K>
140where
141 K: Eq + Hash + Clone,
142{
143 pub async fn convert(&self, target: &Target) -> TextureAtlasMapFile<K> {
144 let inner = self.inner.convert(target).await;
145 let map = self.map.clone();
146
147 TextureAtlasMapFile { inner, map }
148 }
149
150 pub fn get(&self, key: &K) -> Option<TexturePosition> {
151 self.map.get(key).copied()
152 }
153}
154
155impl<K> Deref for TextureAtlasMap<K>
156where
157 K: Eq + Hash + Clone,
158{
159 type Target = TextureAtlas;
160
161 fn deref(&self) -> &Self::Target {
162 &self.inner
163 }
164}
165
166impl<K> TextureAtlasMapFile<K>
167where
168 K: Eq + Hash + Clone,
169{
170 pub fn convert(&self, target: &Target) -> TextureAtlasMap<K> {
171 let inner = self.inner.convert(target);
172 let map = self.map.clone();
173
174 TextureAtlasMap { inner, map }
175 }
176}