vbsp/data/
leaves.rs

1use std::io::{Read, Seek};
2use std::mem::{align_of, size_of};
3use std::ops::Deref;
4
5use binrw::{BinRead, BinResult, Endian};
6
7use crate::bspfile::LumpType;
8use crate::BspError;
9
10use super::LumpArgs;
11
12#[derive(Debug, Clone)]
13pub struct Leaves {
14    leaves: Vec<Leaf>,
15}
16
17impl Leaves {
18    pub fn new(mut leaves: Vec<Leaf>) -> Self {
19        leaves.sort_unstable_by_key(|leaf| leaf.cluster);
20
21        Leaves { leaves }
22    }
23
24    pub fn iter(&self) -> impl Iterator<Item = &Leaf> {
25        self.into_iter()
26    }
27
28    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Leaf> {
29        self.into_iter()
30    }
31
32    pub fn into_inner(self) -> Vec<Leaf> {
33        self.leaves
34    }
35
36    pub fn clusters(&self) -> impl Iterator<Item = impl Iterator<Item = &Leaf>> {
37        LeafClusters {
38            leaves: &self.leaves,
39            index: 0,
40        }
41    }
42}
43
44impl BinRead for Leaves {
45    type Args<'a> = LumpArgs;
46
47    fn read_options<R: Read + Seek>(
48        reader: &mut R,
49        endian: Endian,
50        args: Self::Args<'_>,
51    ) -> BinResult<Self> {
52        let item_size = match args.version {
53            0 => size_of::<LeafV0>(),
54            1 => size_of::<LeafV1>(),
55            version => {
56                return Err(binrw::Error::Custom {
57                    err: Box::new(BspError::LumpVersion(
58                        crate::error::UnsupportedLumpVersion {
59                            lump_type: "leaves",
60                            version: version as u16,
61                        },
62                    )),
63                    pos: reader.stream_position().unwrap(),
64                })
65            }
66        };
67        if args.length % item_size != 0 {
68            return Err(binrw::Error::Custom {
69                err: Box::new(BspError::InvalidLumpSize {
70                    lump: LumpType::Leaves,
71                    element_size: item_size,
72                    lump_size: args.length,
73                }),
74                pos: reader.stream_position().unwrap(),
75            });
76        }
77        let num_entries = args.length / item_size;
78        let mut entries = Vec::with_capacity(num_entries);
79
80        for _ in 0..num_entries {
81            entries.push(Leaf::read_options(
82                reader,
83                endian,
84                LeafArgs {
85                    version: args.version,
86                },
87            )?);
88        }
89
90        Ok(Self::new(entries))
91    }
92}
93
94struct LeafClusters<'a> {
95    leaves: &'a [Leaf],
96    index: usize,
97}
98
99impl<'a> Iterator for LeafClusters<'a> {
100    type Item = <&'a [Leaf] as IntoIterator>::IntoIter;
101
102    fn next(&mut self) -> Option<Self::Item> {
103        let cluster = self.leaves.get(self.index)?.cluster;
104        let remaining_leaves = self.leaves.get(self.index..)?;
105        let cluster_size = remaining_leaves
106            .iter()
107            .take_while(|leaf| leaf.cluster == cluster)
108            .count();
109        self.index += cluster_size;
110        Some(remaining_leaves[0..cluster_size].iter())
111    }
112}
113
114#[test]
115fn test_leaf_clusters() {
116    let leaves: Leaves = vec![
117        Leaf {
118            contents: 0,
119            cluster: 0,
120            ..Default::default()
121        },
122        Leaf {
123            contents: 1,
124            cluster: 0,
125            ..Default::default()
126        },
127        Leaf {
128            contents: 2,
129            cluster: 1,
130            ..Default::default()
131        },
132        Leaf {
133            contents: 3,
134            cluster: 2,
135            ..Default::default()
136        },
137        Leaf {
138            contents: 4,
139            cluster: 2,
140            ..Default::default()
141        },
142    ]
143    .into();
144
145    let clustered: Vec<Vec<i32>> = leaves
146        .clusters()
147        .map(|cluster| cluster.map(|leaf| leaf.contents).collect())
148        .collect();
149    assert_eq!(vec![vec![0, 1], vec![2], vec![3, 4]], clustered);
150}
151
152impl From<Vec<Leaf>> for Leaves {
153    fn from(other: Vec<Leaf>) -> Self {
154        Self::new(other)
155    }
156}
157
158impl Deref for Leaves {
159    type Target = [Leaf];
160
161    fn deref(&self) -> &Self::Target {
162        &self.leaves
163    }
164}
165
166impl IntoIterator for Leaves {
167    type Item = Leaf;
168    type IntoIter = <Vec<Leaf> as IntoIterator>::IntoIter;
169
170    fn into_iter(self) -> Self::IntoIter {
171        self.leaves.into_iter()
172    }
173}
174
175impl<'a> IntoIterator for &'a Leaves {
176    type Item = &'a Leaf;
177    type IntoIter = <&'a [Leaf] as IntoIterator>::IntoIter;
178
179    fn into_iter(self) -> Self::IntoIter {
180        self.leaves[..].iter()
181    }
182}
183
184impl<'a> IntoIterator for &'a mut Leaves {
185    type Item = &'a mut Leaf;
186    type IntoIter = <&'a mut [Leaf] as IntoIterator>::IntoIter;
187
188    fn into_iter(self) -> Self::IntoIter {
189        self.leaves.iter_mut()
190    }
191}
192
193#[derive(BinRead, Debug, Default, Clone, Copy)]
194pub struct ColorRGBExp32 {
195    pub r: u8,
196    pub g: u8,
197    pub b: u8,
198    pub exponent: i8,
199}
200
201#[derive(BinRead, Debug, Default, Clone, Copy)]
202pub struct CompressedLightCube {
203    pub color: [ColorRGBExp32; 6],
204}
205
206#[derive(Default, Debug, Clone, BinRead)]
207pub struct LeafV0 {
208    pub contents: i32,
209    pub cluster: i16,
210    pub area_and_flags: i16,
211    // first 9 bits is area, last 7 bits is flags
212    pub mins: [i16; 3],
213    pub maxs: [i16; 3],
214    pub first_leaf_face: u16,
215    pub leaf_face_count: u16,
216    pub first_leaf_brush: u16,
217    pub leaf_brush_count: u16,
218    pub leaf_watter_data_id: i16,
219    #[br(align_after = align_of::< LeafV0 > ())]
220    pub cube: CompressedLightCube,
221}
222
223static_assertions::const_assert_eq!(size_of::<LeafV0>(), 56);
224
225impl From<LeafV0> for Leaf {
226    fn from(value: LeafV0) -> Self {
227        Self {
228            contents: value.contents,
229            cluster: value.cluster,
230            area_and_flags: value.area_and_flags,
231            mins: value.mins,
232            maxs: value.maxs,
233            first_leaf_face: value.first_leaf_face,
234            leaf_face_count: value.leaf_face_count,
235            first_leaf_brush: value.first_leaf_brush,
236            leaf_brush_count: value.leaf_brush_count,
237            leaf_watter_data_id: value.leaf_watter_data_id,
238            cube: value.cube,
239        }
240    }
241}
242
243#[derive(Default, Debug, Clone, BinRead)]
244pub struct LeafV1 {
245    pub contents: i32,
246    pub cluster: i16,
247    pub area_and_flags: i16,
248    // first 9 bits is area, last 7 bits is flags
249    pub mins: [i16; 3],
250    pub maxs: [i16; 3],
251    pub first_leaf_face: u16,
252    pub leaf_face_count: u16,
253    pub first_leaf_brush: u16,
254    pub leaf_brush_count: u16,
255    #[br(align_after = align_of::< LeafV1 > ())]
256    pub leaf_watter_data_id: i16,
257}
258
259static_assertions::const_assert_eq!(size_of::<LeafV1>(), 32);
260
261impl From<LeafV1> for Leaf {
262    fn from(value: LeafV1) -> Self {
263        Self {
264            contents: value.contents,
265            cluster: value.cluster,
266            area_and_flags: value.area_and_flags,
267            mins: value.mins,
268            maxs: value.maxs,
269            first_leaf_face: value.first_leaf_face,
270            leaf_face_count: value.leaf_face_count,
271            first_leaf_brush: value.first_leaf_brush,
272            leaf_brush_count: value.leaf_brush_count,
273            leaf_watter_data_id: value.leaf_watter_data_id,
274            cube: Default::default(),
275        }
276    }
277}
278
279#[derive(Default, Debug, Clone)]
280pub struct Leaf {
281    pub contents: i32,
282    pub cluster: i16,
283    pub area_and_flags: i16,
284    // first 9 bits is area, last 7 bits is flags
285    pub mins: [i16; 3],
286    pub maxs: [i16; 3],
287    pub first_leaf_face: u16,
288    pub leaf_face_count: u16,
289    pub first_leaf_brush: u16,
290    pub leaf_brush_count: u16,
291    pub leaf_watter_data_id: i16,
292    pub cube: CompressedLightCube,
293}
294
295static_assertions::const_assert_eq!(size_of::<Leaf>(), 56);
296
297#[test]
298fn test_leaf_bytes() {
299    super::test_read_bytes::<Leaf>();
300}
301
302#[derive(Default, Debug, Clone)]
303pub struct LeafArgs {
304    pub version: u32,
305}
306
307impl BinRead for Leaf {
308    type Args<'a> = LeafArgs;
309
310    fn read_options<R: Read + Seek>(
311        reader: &mut R,
312        endian: Endian,
313        args: Self::Args<'_>,
314    ) -> BinResult<Self> {
315        match args.version {
316            0 => LeafV0::read_options(reader, endian, ()).map(Leaf::from),
317            1 => LeafV1::read_options(reader, endian, ()).map(Leaf::from),
318            version => Err(binrw::Error::Custom {
319                err: Box::new(crate::error::UnsupportedLumpVersion {
320                    lump_type: "leaves",
321                    version: version as u16,
322                }),
323                pos: reader.stream_position().unwrap(),
324            }),
325        }
326    }
327}