1use crate::error::TileCacheError;
7
8const TILECACHE_MAGIC: u32 = 0x4C494554; const TILECACHE_VERSION: u32 = 1;
13
14#[derive(Debug, Clone)]
16#[cfg_attr(
17 feature = "serialization",
18 derive(serde::Serialize, serde::Deserialize)
19)]
20pub struct TileCacheLayerHeader {
21 pub(crate) magic: u32,
23 pub(crate) version: u32,
25 pub(crate) tx: i32,
27 pub(crate) ty: i32,
29 pub(crate) tlayer: i32,
31 pub(crate) bmin: [f32; 3],
33 pub(crate) bmax: [f32; 3],
35 pub(crate) hmin: u16,
37 pub(crate) hmax: u16,
39 pub(crate) width: u8,
41 pub(crate) height: u8,
43 pub(crate) minx: u8,
45 pub(crate) maxx: u8,
47 pub(crate) miny: u8,
49 pub(crate) maxy: u8,
51}
52
53impl Default for TileCacheLayerHeader {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl TileCacheLayerHeader {
60 pub fn new() -> Self {
62 Self {
63 magic: TILECACHE_MAGIC,
64 version: TILECACHE_VERSION,
65 tx: 0,
66 ty: 0,
67 tlayer: 0,
68 bmin: [0.0; 3],
69 bmax: [0.0; 3],
70 hmin: 0,
71 hmax: 0,
72 width: 0,
73 height: 0,
74 minx: 0,
75 maxx: 0,
76 miny: 0,
77 maxy: 0,
78 }
79 }
80
81 pub fn validate(&self) -> Result<(), TileCacheError> {
83 if self.magic != TILECACHE_MAGIC {
84 return Err(TileCacheError::InvalidParam);
85 }
86 if self.version != TILECACHE_VERSION {
87 return Err(TileCacheError::InvalidParam);
88 }
89 Ok(())
90 }
91
92 pub fn to_bytes(&self) -> Vec<u8> {
94 let mut bytes = Vec::with_capacity(56);
95
96 bytes.extend_from_slice(&self.magic.to_le_bytes());
98 bytes.extend_from_slice(&self.version.to_le_bytes());
99
100 bytes.extend_from_slice(&self.tx.to_le_bytes());
102 bytes.extend_from_slice(&self.ty.to_le_bytes());
103 bytes.extend_from_slice(&self.tlayer.to_le_bytes());
104
105 for i in 0..3 {
107 bytes.extend_from_slice(&self.bmin[i].to_le_bytes());
108 }
109 for i in 0..3 {
110 bytes.extend_from_slice(&self.bmax[i].to_le_bytes());
111 }
112
113 bytes.extend_from_slice(&self.hmin.to_le_bytes());
115 bytes.extend_from_slice(&self.hmax.to_le_bytes());
116 bytes.push(self.width);
117 bytes.push(self.height);
118 bytes.push(self.minx);
119 bytes.push(self.maxx);
120 bytes.push(self.miny);
121 bytes.push(self.maxy);
122
123 bytes
124 }
125
126 pub fn from_bytes(data: &[u8]) -> Result<Self, TileCacheError> {
128 if data.len() < 54 {
129 return Err(TileCacheError::InvalidParam);
130 }
131
132 let mut offset = 0;
133
134 let magic = u32::from_le_bytes([
136 data[offset],
137 data[offset + 1],
138 data[offset + 2],
139 data[offset + 3],
140 ]);
141 offset += 4;
142 let version = u32::from_le_bytes([
143 data[offset],
144 data[offset + 1],
145 data[offset + 2],
146 data[offset + 3],
147 ]);
148 offset += 4;
149
150 let tx = i32::from_le_bytes([
152 data[offset],
153 data[offset + 1],
154 data[offset + 2],
155 data[offset + 3],
156 ]);
157 offset += 4;
158 let ty = i32::from_le_bytes([
159 data[offset],
160 data[offset + 1],
161 data[offset + 2],
162 data[offset + 3],
163 ]);
164 offset += 4;
165 let tlayer = i32::from_le_bytes([
166 data[offset],
167 data[offset + 1],
168 data[offset + 2],
169 data[offset + 3],
170 ]);
171 offset += 4;
172
173 let mut bmin = [0.0f32; 3];
175 for item in &mut bmin {
176 *item = f32::from_le_bytes([
177 data[offset],
178 data[offset + 1],
179 data[offset + 2],
180 data[offset + 3],
181 ]);
182 offset += 4;
183 }
184 let mut bmax = [0.0f32; 3];
185 for item in &mut bmax {
186 *item = f32::from_le_bytes([
187 data[offset],
188 data[offset + 1],
189 data[offset + 2],
190 data[offset + 3],
191 ]);
192 offset += 4;
193 }
194
195 let hmin = u16::from_le_bytes([data[offset], data[offset + 1]]);
197 offset += 2;
198 let hmax = u16::from_le_bytes([data[offset], data[offset + 1]]);
199 offset += 2;
200 let width = data[offset];
201 offset += 1;
202 let height = data[offset];
203 offset += 1;
204 let minx = data[offset];
205 offset += 1;
206 let maxx = data[offset];
207 offset += 1;
208 let miny = data[offset];
209 offset += 1;
210 let maxy = data[offset];
211
212 let header = Self {
213 magic,
214 version,
215 tx,
216 ty,
217 tlayer,
218 bmin,
219 bmax,
220 hmin,
221 hmax,
222 width,
223 height,
224 minx,
225 maxx,
226 miny,
227 maxy,
228 };
229
230 header.validate()?;
231 Ok(header)
232 }
233
234 pub fn magic(&self) -> u32 {
236 self.magic
237 }
238
239 pub fn version(&self) -> u32 {
241 self.version
242 }
243
244 pub fn tx(&self) -> i32 {
246 self.tx
247 }
248
249 pub fn ty(&self) -> i32 {
251 self.ty
252 }
253
254 pub fn tlayer(&self) -> i32 {
256 self.tlayer
257 }
258
259 pub fn bmin(&self) -> [f32; 3] {
261 self.bmin
262 }
263
264 pub fn bmax(&self) -> [f32; 3] {
266 self.bmax
267 }
268
269 pub fn hmin(&self) -> u16 {
271 self.hmin
272 }
273
274 pub fn hmax(&self) -> u16 {
276 self.hmax
277 }
278
279 pub fn width(&self) -> u8 {
281 self.width
282 }
283
284 pub fn height(&self) -> u8 {
286 self.height
287 }
288
289 pub fn minx(&self) -> u8 {
291 self.minx
292 }
293
294 pub fn maxx(&self) -> u8 {
296 self.maxx
297 }
298
299 pub fn miny(&self) -> u8 {
301 self.miny
302 }
303
304 pub fn maxy(&self) -> u8 {
306 self.maxy
307 }
308}
309
310#[derive(Debug, Clone)]
312pub struct TileCacheLayer {
313 pub header: TileCacheLayerHeader,
315 pub regons: Vec<u8>,
317 pub areas: Vec<u8>,
319 pub cons: Vec<u8>,
321}
322
323impl TileCacheLayer {
324 pub fn new(header: TileCacheLayerHeader) -> Self {
326 Self {
327 header,
328 regons: Vec::new(),
329 areas: Vec::new(),
330 cons: Vec::new(),
331 }
332 }
333
334 pub fn to_bytes(&self) -> Vec<u8> {
336 let mut bytes = Vec::new();
337
338 bytes.extend_from_slice(&self.header.to_bytes());
340
341 bytes.extend_from_slice(&(self.regons.len() as u32).to_le_bytes());
343 bytes.extend_from_slice(&(self.areas.len() as u32).to_le_bytes());
344 bytes.extend_from_slice(&(self.cons.len() as u32).to_le_bytes());
345
346 bytes.extend_from_slice(&self.regons);
348 bytes.extend_from_slice(&self.areas);
349 bytes.extend_from_slice(&self.cons);
350
351 bytes
352 }
353
354 pub fn from_bytes(data: &[u8]) -> Result<Self, TileCacheError> {
356 if data.len() < 66 {
357 return Err(TileCacheError::InvalidParam);
359 }
360
361 let header = TileCacheLayerHeader::from_bytes(data)?;
362 let mut offset = 54; let regons_len = u32::from_le_bytes([
366 data[offset],
367 data[offset + 1],
368 data[offset + 2],
369 data[offset + 3],
370 ]) as usize;
371 offset += 4;
372 let areas_len = u32::from_le_bytes([
373 data[offset],
374 data[offset + 1],
375 data[offset + 2],
376 data[offset + 3],
377 ]) as usize;
378 offset += 4;
379 let cons_len = u32::from_le_bytes([
380 data[offset],
381 data[offset + 1],
382 data[offset + 2],
383 data[offset + 3],
384 ]) as usize;
385 offset += 4;
386
387 if offset + regons_len + areas_len + cons_len > data.len() {
389 return Err(TileCacheError::InvalidParam);
390 }
391
392 let regons = data[offset..offset + regons_len].to_vec();
394 offset += regons_len;
395 let areas = data[offset..offset + areas_len].to_vec();
396 offset += areas_len;
397 let cons = data[offset..offset + cons_len].to_vec();
398
399 Ok(Self {
400 header,
401 regons,
402 areas,
403 cons,
404 })
405 }
406}
407
408#[derive(Debug, Clone)]
410#[non_exhaustive]
411pub struct TileCacheBuilderConfig {
412 pub cs: f32,
414 pub ch: f32,
416 pub walkable_height: i32,
418 pub walkable_radius: i32,
420 pub walkable_climb: i32,
422 pub max_edge_len: f32,
424 pub max_simplification_error: f32,
426 pub min_region_area: i32,
428 pub merge_region_area: i32,
430 pub max_verts_per_poly: i32,
432}
433
434impl Default for TileCacheBuilderConfig {
435 fn default() -> Self {
436 Self {
437 cs: 0.3,
438 ch: 0.2,
439 walkable_height: 20,
440 walkable_radius: 6,
441 walkable_climb: 9,
442 max_edge_len: 12.0,
443 max_simplification_error: 1.3,
444 min_region_area: 8,
445 merge_region_area: 20,
446 max_verts_per_poly: 6,
447 }
448 }
449}