// 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 . //! 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> { 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> { 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 HasBrushes for Q3BSPFile { type BrushesIter<'a> = std::slice::Iter<'a, Brush>; fn brushes_iter<'a>(&'a self) -> Self::BrushesIter<'a> { self.brushes.iter() } fn get_brush<'a>(&'a self, index: u32) -> &'a Brush { &self.brushes[index as usize] } }