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
46impl<'a> CompressedMesh<'a> {
47    pub(super) const fn new(
48        bounds: FixedAabb3,
49        vertex_bytes: &'a [u8],
50        triangle_bytes: &'a [u8],
51        vertex_count: usize,
52        triangle_count: usize,
53        index_width: CompressedIndexWidth,
54    ) -> Self {
55        Self {
56            bounds,
57            vertex_bytes,
58            triangle_bytes,
59            vertex_count,
60            triangle_count,
61            index_width,
62        }
63    }
64
65    /// Returns the decoded Q32.32 quantization bounds.
66    #[must_use]
67    pub const fn bounds(self) -> FixedAabb3 {
68        self.bounds
69    }
70
71    /// Returns the decoded vertex count.
72    #[must_use]
73    pub const fn vertex_count(self) -> usize {
74        self.vertex_count
75    }
76
77    /// Returns the decoded triangle count.
78    #[must_use]
79    pub const fn triangle_count(self) -> usize {
80        self.triangle_count
81    }
82
83    /// Returns the decoded triangle index width.
84    #[must_use]
85    pub const fn index_width(self) -> CompressedIndexWidth {
86        self.index_width
87    }
88
89    /// Returns the borrowed quantized vertex payload bytes.
90    #[must_use]
91    pub const fn vertex_bytes(self) -> &'a [u8] {
92        self.vertex_bytes
93    }
94
95    /// Returns the borrowed triangle index payload bytes.
96    #[must_use]
97    pub const fn triangle_bytes(self) -> &'a [u8] {
98        self.triangle_bytes
99    }
100
101    /// Reads a quantized vertex record.
102    ///
103    /// # Errors
104    /// Returns `CompressedMeshError::IndexOutOfBounds` when `index` is outside
105    /// the decoded vertex range.
106    pub fn vertex(self, index: usize) -> Result<QuantizedVertex, CompressedMeshError> {
107        if index >= self.vertex_count {
108            return Err(CompressedMeshError::IndexOutOfBounds);
109        }
110        read_vertex(take_record(self.vertex_bytes, index, VERTEX_STRIDE)?)
111    }
112
113    /// Reads a triangle record using the width declared by the byte stream.
114    ///
115    /// # Errors
116    /// Returns `CompressedMeshError::IndexOutOfBounds` when `index` is outside
117    /// the decoded triangle range.
118    pub fn triangle(self, index: usize) -> Result<CompressedTriangle, CompressedMeshError> {
119        if index >= self.triangle_count {
120            return Err(CompressedMeshError::IndexOutOfBounds);
121        }
122        let bytes = take_record(self.triangle_bytes, index, self.index_width.stride())?;
123        read_triangle(bytes, self.index_width)
124    }
125}