1use std::io::{self, Write};
8
9use flate2::Compression;
10use flate2::write::GzEncoder;
11
12use crate::{
13 EdgeIndices, ExtensionId, QuantizedMeshHeader, QuantizedVertices, TileMetadata, WaterMask,
14};
15
16#[inline]
25pub fn zigzag_encode(value: i32) -> u32 {
26 ((value << 1) ^ (value >> 31)) as u32
27}
28
29#[inline]
31pub fn zigzag_decode(value: u32) -> i32 {
32 ((value >> 1) as i32) ^ (-((value & 1) as i32))
33}
34
35pub fn oct_encode_normal(normal: [f32; 3]) -> [u8; 2] {
39 let [mut x, mut y, z] = normal;
40
41 let inv_l1 = 1.0 / (x.abs() + y.abs() + z.abs());
43 x *= inv_l1;
44 y *= inv_l1;
45
46 if z < 0.0 {
48 let ox = x;
49 x = (1.0 - y.abs()) * if ox >= 0.0 { 1.0 } else { -1.0 };
50 y = (1.0 - ox.abs()) * if y >= 0.0 { 1.0 } else { -1.0 };
51 }
52
53 let encode = |v: f32| -> u8 { ((v * 0.5 + 0.5) * 255.0).clamp(0.0, 255.0) as u8 };
55
56 [encode(x), encode(y)]
57}
58
59#[derive(Debug, Clone, Default)]
61pub struct EncodeOptions {
62 pub include_normals: bool,
64 pub normals: Option<Vec<[f32; 3]>>,
66 pub include_water_mask: bool,
68 pub water_mask: Option<WaterMask>,
70 pub include_metadata: bool,
72 pub metadata: Option<TileMetadata>,
74 pub compression_level: u32,
76}
77
78pub struct QuantizedMeshEncoder {
82 header: QuantizedMeshHeader,
83 vertices: QuantizedVertices,
84 indices: Vec<u32>,
85 edge_indices: EdgeIndices,
86}
87
88impl QuantizedMeshEncoder {
89 pub fn new(
91 header: QuantizedMeshHeader,
92 vertices: QuantizedVertices,
93 indices: Vec<u32>,
94 edge_indices: EdgeIndices,
95 ) -> Self {
96 Self {
97 header,
98 vertices,
99 indices,
100 edge_indices,
101 }
102 }
103
104 pub fn encode(&self) -> Vec<u8> {
106 self.encode_with_options(&EncodeOptions::default())
107 }
108
109 pub fn encode_with_options(&self, options: &EncodeOptions) -> Vec<u8> {
111 let mut output = Vec::new();
112 self.encode_to_with_options(&mut output, options)
113 .expect("Failed to encode to Vec");
114 output
115 }
116
117 pub fn encode_to<W: Write>(&self, writer: W) -> io::Result<()> {
119 self.encode_to_with_options(writer, &EncodeOptions::default())
120 }
121
122 pub fn encode_to_with_options<W: Write>(
124 &self,
125 writer: W,
126 options: &EncodeOptions,
127 ) -> io::Result<()> {
128 if options.compression_level == 0 {
129 self.encode_uncompressed_to(writer, options)
130 } else {
131 let mut encoder = GzEncoder::new(writer, Compression::new(options.compression_level));
132 self.encode_uncompressed_to(&mut encoder, options)?;
133 encoder.finish()?;
134 Ok(())
135 }
136 }
137
138 fn encode_uncompressed_to<W: Write>(
141 &self,
142 mut writer: W,
143 options: &EncodeOptions,
144 ) -> io::Result<()> {
145 let vertex_count = self.vertices.len();
146 let use_32bit = vertex_count > 65535;
147
148 writer.write_all(&self.header.to_bytes())?;
150 writer.write_all(&(vertex_count as u32).to_le_bytes())?;
152
153 write_zigzag_delta_to(&mut writer, &self.vertices.u)?;
155 write_zigzag_delta_to(&mut writer, &self.vertices.v)?;
156 write_zigzag_delta_to(&mut writer, &self.vertices.height)?;
157
158 let current_pos = 88 + 4 + vertex_count * 6;
160 let align = if use_32bit { 4 } else { 2 };
161 let padding = (align - (current_pos % align)) % align;
162 if padding > 0 {
163 let zeros = [0u8; 4];
164 writer.write_all(&zeros[..padding])?;
165 }
166
167 let triangle_count = self.indices.len() / 3;
169 writer.write_all(&(triangle_count as u32).to_le_bytes())?;
170 write_high_water_mark_to(&mut writer, &self.indices, use_32bit)?;
171
172 for edge in [
174 &self.edge_indices.west,
175 &self.edge_indices.south,
176 &self.edge_indices.east,
177 &self.edge_indices.north,
178 ] {
179 writer.write_all(&(edge.len() as u32).to_le_bytes())?;
180 write_indices_to(&mut writer, edge, use_32bit)?;
181 }
182
183 if options.include_normals
185 && let Some(normals) = &options.normals
186 {
187 write_normals_extension_to(&mut writer, normals)?;
188 }
189 if options.include_water_mask {
190 let water_mask = options.water_mask.as_ref().cloned().unwrap_or_default();
191 write_water_mask_extension_to(&mut writer, &water_mask)?;
192 }
193 if options.include_metadata
194 && let Some(metadata) = &options.metadata
195 {
196 write_metadata_extension_to(&mut writer, metadata)?;
197 }
198
199 Ok(())
200 }
201}
202
203const WRITE_BUF: usize = 4096;
210
211fn write_zigzag_delta_to<W: Write>(writer: &mut W, values: &[u16]) -> io::Result<()> {
212 let mut buf = [0u8; WRITE_BUF];
213 let mut len = 0;
214 let mut prev = 0i32;
215 for &value in values {
216 let current = value as i32;
217 let delta = current - prev;
218 let bytes = (zigzag_encode(delta) as u16).to_le_bytes();
219 buf[len] = bytes[0];
220 buf[len + 1] = bytes[1];
221 len += 2;
222 prev = current;
223 if len + 2 > WRITE_BUF {
224 writer.write_all(&buf[..len])?;
225 len = 0;
226 }
227 }
228 if len > 0 {
229 writer.write_all(&buf[..len])?;
230 }
231 Ok(())
232}
233
234fn write_high_water_mark_to<W: Write>(
235 writer: &mut W,
236 indices: &[u32],
237 use_32bit: bool,
238) -> io::Result<()> {
239 let mut buf = [0u8; WRITE_BUF];
240 let mut len = 0;
241 let mut highest = 0u32;
242 let stride = if use_32bit { 4 } else { 2 };
243 for &index in indices {
244 let code = if index == highest {
245 highest += 1;
246 0
247 } else {
248 highest - index
249 };
250 if use_32bit {
251 buf[len..len + 4].copy_from_slice(&code.to_le_bytes());
252 } else {
253 buf[len..len + 2].copy_from_slice(&(code as u16).to_le_bytes());
254 }
255 len += stride;
256 if len + stride > WRITE_BUF {
257 writer.write_all(&buf[..len])?;
258 len = 0;
259 }
260 }
261 if len > 0 {
262 writer.write_all(&buf[..len])?;
263 }
264 Ok(())
265}
266
267fn write_indices_to<W: Write>(writer: &mut W, indices: &[u32], use_32bit: bool) -> io::Result<()> {
268 let mut buf = [0u8; WRITE_BUF];
269 let mut len = 0;
270 let stride = if use_32bit { 4 } else { 2 };
271 for &idx in indices {
272 if use_32bit {
273 buf[len..len + 4].copy_from_slice(&idx.to_le_bytes());
274 } else {
275 buf[len..len + 2].copy_from_slice(&(idx as u16).to_le_bytes());
276 }
277 len += stride;
278 if len + stride > WRITE_BUF {
279 writer.write_all(&buf[..len])?;
280 len = 0;
281 }
282 }
283 if len > 0 {
284 writer.write_all(&buf[..len])?;
285 }
286 Ok(())
287}
288
289fn write_normals_extension_to<W: Write>(writer: &mut W, normals: &[[f32; 3]]) -> io::Result<()> {
290 writer.write_all(&[ExtensionId::OctEncodedVertexNormals as u8])?;
291 writer.write_all(&((normals.len() * 2) as u32).to_le_bytes())?;
292 let mut buf = [0u8; WRITE_BUF];
293 let mut len = 0;
294 for &normal in normals {
295 let encoded = oct_encode_normal(normal);
296 buf[len] = encoded[0];
297 buf[len + 1] = encoded[1];
298 len += 2;
299 if len + 2 > WRITE_BUF {
300 writer.write_all(&buf[..len])?;
301 len = 0;
302 }
303 }
304 if len > 0 {
305 writer.write_all(&buf[..len])?;
306 }
307 Ok(())
308}
309
310fn write_water_mask_extension_to<W: Write>(
311 writer: &mut W,
312 water_mask: &WaterMask,
313) -> io::Result<()> {
314 writer.write_all(&[ExtensionId::WaterMask as u8])?;
315 match water_mask {
316 WaterMask::Uniform(value) => {
317 writer.write_all(&1u32.to_le_bytes())?;
318 writer.write_all(&[*value])?;
319 }
320 WaterMask::Grid(grid) => {
321 writer.write_all(&(256 * 256u32).to_le_bytes())?;
322 writer.write_all(grid.as_ref())?;
323 }
324 }
325 Ok(())
326}
327
328fn write_metadata_extension_to<W: Write>(
329 writer: &mut W,
330 metadata: &TileMetadata,
331) -> io::Result<()> {
332 let json = serde_json::to_string(metadata)
333 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
334 let json_bytes = json.as_bytes();
335 writer.write_all(&[ExtensionId::Metadata as u8])?;
336 let extension_length = 4 + json_bytes.len() as u32;
337 writer.write_all(&extension_length.to_le_bytes())?;
338 writer.write_all(&(json_bytes.len() as u32).to_le_bytes())?;
339 writer.write_all(json_bytes)?;
340 Ok(())
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346
347 #[test]
348 fn test_zigzag_encode() {
349 assert_eq!(zigzag_encode(0), 0);
350 assert_eq!(zigzag_encode(-1), 1);
351 assert_eq!(zigzag_encode(1), 2);
352 assert_eq!(zigzag_encode(-2), 3);
353 assert_eq!(zigzag_encode(2), 4);
354 }
355
356 #[test]
357 fn test_zigzag_roundtrip() {
358 for i in -1000..1000 {
359 assert_eq!(zigzag_decode(zigzag_encode(i)), i);
360 }
361 }
362
363 #[test]
364 fn test_oct_encode_normal() {
365 let up = [0.0f32, 0.0, 1.0];
366 let encoded = oct_encode_normal(up);
367 assert!((encoded[0] as i32 - 127).abs() < 2);
368 assert!((encoded[1] as i32 - 127).abs() < 2);
369
370 let down = [0.0f32, 0.0, -1.0];
371 let encoded = oct_encode_normal(down);
372 assert!(encoded[0] == 0 || encoded[0] == 255);
373 }
374
375 #[test]
376 fn test_encoder_basic() {
377 let header = QuantizedMeshHeader::default();
378 let vertices = QuantizedVertices {
379 u: vec![0, 32767, 0, 32767],
380 v: vec![0, 0, 32767, 32767],
381 height: vec![0, 0, 0, 0],
382 };
383 let indices = vec![0, 1, 2, 1, 3, 2];
384 let edge_indices = EdgeIndices::from_vertices(&vertices);
385
386 let encoder = QuantizedMeshEncoder::new(header, vertices, indices, edge_indices);
387 let data = encoder.encode_with_options(&EncodeOptions {
388 compression_level: 0,
389 ..Default::default()
390 });
391
392 assert!(data.len() > 88);
393 let parsed_header = QuantizedMeshHeader::from_bytes(&data).unwrap();
394 assert_eq!(parsed_header.min_height, 0.0);
395 }
396
397 #[test]
398 fn test_encoder_with_compression() {
399 let header = QuantizedMeshHeader::default();
400 let vertices = QuantizedVertices {
401 u: vec![0, 32767, 0, 32767],
402 v: vec![0, 0, 32767, 32767],
403 height: vec![0, 0, 0, 0],
404 };
405 let indices = vec![0, 1, 2, 1, 3, 2];
406 let edge_indices = EdgeIndices::from_vertices(&vertices);
407
408 let encoder = QuantizedMeshEncoder::new(header, vertices, indices, edge_indices);
409
410 let compressed = encoder.encode_with_options(&EncodeOptions {
411 compression_level: 6,
412 ..Default::default()
413 });
414
415 assert_eq!(&compressed[0..2], &[0x1f, 0x8b]);
416 }
417
418 #[test]
419 fn test_encoder_with_extensions() {
420 let header = QuantizedMeshHeader::default();
421 let vertices = QuantizedVertices {
422 u: vec![0, 32767, 0, 32767],
423 v: vec![0, 0, 32767, 32767],
424 height: vec![0, 0, 0, 0],
425 };
426 let indices = vec![0, 1, 2, 1, 3, 2];
427 let edge_indices = EdgeIndices::from_vertices(&vertices);
428
429 let encoder = QuantizedMeshEncoder::new(header, vertices, indices, edge_indices);
430
431 let normals = vec![[0.0, 0.0, 1.0]; 4];
432
433 let data = encoder.encode_with_options(&EncodeOptions {
434 compression_level: 0,
435 include_normals: true,
436 normals: Some(normals),
437 include_water_mask: true,
438 water_mask: Some(WaterMask::Uniform(0)),
439 ..Default::default()
440 });
441
442 let without_ext = encoder.encode_with_options(&EncodeOptions {
443 compression_level: 0,
444 ..Default::default()
445 });
446
447 assert!(data.len() > without_ext.len());
448 }
449
450 #[test]
451 fn test_encode_to_writer_matches_encode_with_options() {
452 let header = QuantizedMeshHeader::default();
453 let vertices = QuantizedVertices {
454 u: vec![0, 32767, 0, 32767],
455 v: vec![0, 0, 32767, 32767],
456 height: vec![0, 0, 0, 0],
457 };
458 let indices = vec![0, 1, 2, 1, 3, 2];
459 let edge_indices = EdgeIndices::from_vertices(&vertices);
460
461 let encoder = QuantizedMeshEncoder::new(header, vertices, indices, edge_indices);
462
463 let data_vec = encoder.encode_with_options(&EncodeOptions {
464 compression_level: 0,
465 ..Default::default()
466 });
467
468 let mut data_writer = Vec::new();
469 encoder
470 .encode_to_with_options(
471 &mut data_writer,
472 &EncodeOptions {
473 compression_level: 0,
474 ..Default::default()
475 },
476 )
477 .expect("Failed to encode to writer");
478
479 assert_eq!(data_vec, data_writer);
480 }
481
482 #[test]
483 fn test_encode_to_writer_compressed() {
484 let header = QuantizedMeshHeader::default();
485 let vertices = QuantizedVertices {
486 u: vec![0, 32767, 0, 32767],
487 v: vec![0, 0, 32767, 32767],
488 height: vec![0, 0, 0, 0],
489 };
490 let indices = vec![0, 1, 2, 1, 3, 2];
491 let edge_indices = EdgeIndices::from_vertices(&vertices);
492
493 let encoder = QuantizedMeshEncoder::new(header, vertices, indices, edge_indices);
494
495 let mut data_writer = Vec::new();
496 encoder
497 .encode_to_with_options(
498 &mut data_writer,
499 &EncodeOptions {
500 compression_level: 6,
501 ..Default::default()
502 },
503 )
504 .expect("Failed to encode to writer");
505
506 assert_eq!(&data_writer[0..2], &[0x1f, 0x8b]);
507 }
508}