/* * Copyright (C) Oscar Shrimpton 2020 * * This program 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. * * This program 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 this program. If not, see . */ //! Parses the BSP tree into a usable format use super::Q3BspFile; use crate::coords::CoordSystem; use crate::helpers::{slice_to_i32, slice_to_u32, slice_to_vec3i}; use crate::traits::tree::*; use crate::types::{ParseError, Result}; const NODE_SIZE: usize = 4 + (4 * 2) + (4 * 3) + (4 * 3); const LEAF_SIZE: usize = 4 * 6 + (4 * 3 * 2); pub fn from_data( nodes: &[u8], leaves: &[u8], leaf_faces: &[u8], leaf_brushes: &[u8], n_faces: u32, n_brushes: u32, ) -> Result { if nodes.len() % NODE_SIZE != 0 || leaves.len() % LEAF_SIZE != 0 { return Err(ParseError::Invalid); } compile_node( 0, nodes, leaves, leaf_faces, leaf_brushes, n_faces, n_brushes, ) } /// Internal function. Visits given node and all its children. Used to recursively build tree. fn compile_node( i: i32, nodes: &[u8], leaves: &[u8], leaf_faces: &[u8], leaf_brushes: &[u8], n_faces: u32, n_brushes: u32, ) -> Result { if i < 0 { // Leaf. let i = i.abs() - 1; let raw = &leaves[i as usize * LEAF_SIZE..(i as usize * LEAF_SIZE) + LEAF_SIZE]; let faces_idx = { let start = slice_to_u32(&raw[32..36]) as usize; let n = slice_to_u32(&raw[36..40]) as usize; let mut faces = Vec::with_capacity(n); if n > 0 { if start + n > leaf_faces.len() / 4 { return Err(ParseError::Invalid); } for i in start..start + n { let face_idx = slice_to_u32(&leaf_faces[i * 4..(i + 1) * 4]); if face_idx >= n_faces { return Err(ParseError::Invalid); } faces.push(face_idx); } } faces.into_boxed_slice() }; let brushes_idx = { let start = slice_to_u32(&raw[40..44]) as usize; let n = slice_to_u32(&raw[44..48]) as usize; let mut brushes = Vec::with_capacity(n); if n > 0 { if start + n > leaf_brushes.len() / 4 { return Err(ParseError::Invalid); } for i in start..start + n { let brush_idx = slice_to_u32(&leaf_brushes[i * 4..(i + 1) * 4]); if brush_idx >= n_brushes { return Err(ParseError::Invalid); } brushes.push(brush_idx); } } brushes.into_boxed_slice() }; let leaf = BspLeaf { cluster_id: slice_to_u32(&raw[0..4]), area: slice_to_i32(&raw[4..8]), // 8..20 = min // 20..32 = max faces_idx, brushes_idx, }; Ok(BspNode { plane_idx: 0, min: slice_to_vec3i(&raw[8..20]), max: slice_to_vec3i(&raw[20..32]), value: BspNodeValue::Leaf(leaf), }) } else { // Node. let raw = &nodes[i as usize * NODE_SIZE..(i as usize * NODE_SIZE) + NODE_SIZE]; let plane_idx = slice_to_u32(&raw[0..4]); let child_one = compile_node( slice_to_i32(&raw[4..8]), nodes, leaves, leaf_faces, leaf_brushes, n_faces, n_brushes, )?; let child_two = compile_node( slice_to_i32(&raw[8..12]), nodes, leaves, leaf_faces, leaf_brushes, n_faces, n_brushes, )?; let min = slice_to_vec3i(&raw[12..24]); let max = slice_to_vec3i(&raw[24..36]); Ok(BspNode { plane_idx, value: BspNodeValue::Children(Box::new(child_one), Box::new(child_two)), min, max, }) } } impl HasBspTree for Q3BspFile { fn get_bsp_root(&self) -> &BspNode { &self.tree_root } }