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 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 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 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}