diff options
Diffstat (limited to 'stockton-levels/src/q3/brushes.rs')
-rw-r--r-- | stockton-levels/src/q3/brushes.rs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/stockton-levels/src/q3/brushes.rs b/stockton-levels/src/q3/brushes.rs new file mode 100644 index 0000000..48462a2 --- /dev/null +++ b/stockton-levels/src/q3/brushes.rs @@ -0,0 +1,117 @@ +// Copyright (C) 2019 Oscar Shrimpton +// +// This file is part of stockton-bsp. +// +// stockton-bsp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// stockton-bsp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with stockton-bsp. If not, see <http://www.gnu.org/licenses/>. + +//! Parses the brushes & brushsides lumps from a bsp file + +/// The size of one brush record. +const BRUSH_SIZE: usize = 4 * 3; + +/// The size of one brushsize record +const SIDE_SIZE: usize = 4 * 2; + +use crate::helpers::slice_to_i32; +use crate::types::{ParseError, Result}; +use crate::traits::brushes::*; +use super::Q3BSPFile; + +/// Parse the brushes & brushsides lump from a bsp file. +pub fn from_data( + brushes_data: &[u8], + sides_data: &[u8], + n_textures: u32, + n_planes: u32 +) -> Result<Box<[Brush]>> { + if brushes_data.len() % BRUSH_SIZE != 0 || sides_data.len() % SIDE_SIZE != 0 { + return Err(ParseError::Invalid); + } + let length = brushes_data.len() / BRUSH_SIZE; + + let mut brushes = Vec::with_capacity(length as usize); + for n in 0..length { + let offset = n * BRUSH_SIZE; + let brush = &brushes_data[offset..offset + BRUSH_SIZE]; + + let texture_idx = slice_to_i32(&brush[8..12]) as usize; + if texture_idx >= n_textures as usize { + return Err(ParseError::Invalid); + } + + brushes.push(Brush { + sides: get_sides( + sides_data, + slice_to_i32(&brush[0..4]), + slice_to_i32(&brush[4..8]), + n_textures as usize, + n_planes as usize + )?, + texture_idx + }); + } + + Ok(brushes.into_boxed_slice()) +} + +/// Internal function to get the relevant brushsides for a brush from the data in the brush lump. +fn get_sides( + sides_data: &[u8], + start: i32, + length: i32, + n_textures: usize, + n_planes: usize, +) -> Result<Box<[BrushSide]>> { + let mut sides = Vec::with_capacity(length as usize); + + if length > 0 { + for n in start..start + length { + let offset = n as usize * SIDE_SIZE; + let brush = &sides_data[offset..offset + SIDE_SIZE]; + + let plane_idx = slice_to_i32(&brush[0..4]) as usize; + if plane_idx / 2 >= n_planes { + return Err(ParseError::Invalid); + } + + let is_opposing = plane_idx % 2 != 0; + + let texture_idx = slice_to_i32(&brush[4..8]) as usize; + if texture_idx >= n_textures { + return Err(ParseError::Invalid); + } + + sides.push(BrushSide { + plane_idx, + texture_idx, + is_opposing + }); + } + } + + Ok(sides.into_boxed_slice()) +} + + +impl<'a> HasBrushes<'a> for Q3BSPFile { + type BrushesIter = std::slice::Iter<'a, Brush>; + + fn brushes_iter(&'a self) -> Self::BrushesIter { + self.brushes.iter() + } + + fn get_brush(&'a self, index: u32) -> &'a Brush { + &self.brushes[index as usize] + } +} |