Skip to main content

bunny_codec/compressed/
view.rs

1use bunny_geom::FixedAabb3;
2use bunny_mesh::{QuantizedVertex, Triangle16, Triangle32};
3
4use super::error::CompressedMeshError;
5use super::read::{read_triangle, read_vertex, take_record};
6use super::{TRIANGLE16_STRIDE, TRIANGLE32_STRIDE, VERTEX_STRIDE};
7
8/// Triangle index width used by a Bunny compressed mesh payload.
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum CompressedIndexWidth {
11    /// Three little-endian `u16` values per triangle.
12    Width16,
13    /// Three little-endian `u32` values per triangle.
14    Width32,
15}
16
17impl CompressedIndexWidth {
18    pub(super) const fn stride(self) -> usize {
19        match self {
20            Self::Width16 => TRIANGLE16_STRIDE,
21            Self::Width32 => TRIANGLE32_STRIDE,
22        }
23    }
24}
25
26/// Decoded triangle from a Bunny compressed mesh payload.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum CompressedTriangle {
29    /// A 16-bit triangle index record.
30    Width16(Triangle16),
31    /// A 32-bit triangle index record.
32    Width32(Triangle32),
33}
34
35/// A zero-allocation borrowed view over a validated Bunny compressed mesh payload.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub struct CompressedMesh<'a> {
38    bounds: FixedAabb3,
39    vertex_bytes: &'a [u8],
40    triangle_bytes: &'a [u8],
41    vertex_count: usize,
42    triangle_count: usize,
43    index_width: CompressedIndexWidth,
44}
45
46#[derive(Clone, Copy)]
47pub(super) struct CompressedMeshParts<'a> {
48    pub(super) bounds: FixedAabb3,
49    pub(super) vertex_bytes: &'a [u8],
50    pub(super) triangle_bytes: &'a [u8],
51    pub(super) vertex_count: usize,
52    pub(super) triangle_count: usize,
53    pub(super) index_width: CompressedIndexWidth,
54}
55
56impl<'a> CompressedMesh<'a> {
57    pub(super) const fn new(parts: CompressedMeshParts<'a>) -> Self {
58        Self {
59            bounds: parts.bounds,
60            vertex_bytes: parts.vertex_bytes,
61            triangle_bytes: parts.triangle_bytes,
62            vertex_count: parts.vertex_count,
63            triangle_count: parts.triangle_count,
64            index_width: parts.index_width,
65        }
66    }
67
68    /// Returns the decoded Q32.32 quantization bounds.
69    #[must_use]
70    pub const fn bounds(self) -> FixedAabb3 {
71        self.bounds
72    }
73
74    /// Returns the decoded vertex count.
75    #[must_use]
76    pub const fn vertex_count(self) -> usize {
77        self.vertex_count
78    }
79
80    /// Returns the decoded triangle count.
81    #[must_use]
82    pub const fn triangle_count(self) -> usize {
83        self.triangle_count
84    }
85
86    /// Returns the decoded triangle index width.
87    #[must_use]
88    pub const fn index_width(self) -> CompressedIndexWidth {
89        self.index_width
90    }
91
92    /// Returns the borrowed quantized vertex payload bytes.
93    #[must_use]
94    pub const fn vertex_bytes(self) -> &'a [u8] {
95        self.vertex_bytes
96    }
97
98    /// Returns the borrowed triangle index payload bytes.
99    #[must_use]
100    pub const fn triangle_bytes(self) -> &'a [u8] {
101        self.triangle_bytes
102    }
103
104    /// Reads a quantized vertex record.
105    ///
106    /// # Errors
107    /// Returns `CompressedMeshError::IndexOutOfBounds` when `index` is outside
108    /// the decoded vertex range.
109    pub fn vertex(self, index: usize) -> Result<QuantizedVertex, CompressedMeshError> {
110        if index >= self.vertex_count {
111            return Err(CompressedMeshError::IndexOutOfBounds);
112        }
113        read_vertex(take_record(self.vertex_bytes, index, VERTEX_STRIDE)?)
114    }
115
116    /// Reads a triangle record using the width declared by the byte stream.
117    ///
118    /// # Errors
119    /// Returns `CompressedMeshError::IndexOutOfBounds` when `index` is outside
120    /// the decoded triangle range.
121    pub fn triangle(self, index: usize) -> Result<CompressedTriangle, CompressedMeshError> {
122        if index >= self.triangle_count {
123            return Err(CompressedMeshError::IndexOutOfBounds);
124        }
125        let bytes = take_record(self.triangle_bytes, index, self.index_width.stride())?;
126        read_triangle(bytes, self.index_width)
127    }
128}