aboutsummaryrefslogtreecommitdiff
path: root/stockton-levels/src/q3/faces.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:20 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:20 +0100
commitd076d3a6fd484e298915cd85609ba9706abacc87 (patch)
tree0d74395ff54e56fd54cab35ec0f27254e8306822 /stockton-levels/src/q3/faces.rs
parent5dc6c64394d1e0a09c882b88ecb2b8f04f9e5b22 (diff)
refactor(all): move stockton-bsp to this repo and start using traits
Diffstat (limited to 'stockton-levels/src/q3/faces.rs')
-rw-r--r--stockton-levels/src/q3/faces.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/stockton-levels/src/q3/faces.rs b/stockton-levels/src/q3/faces.rs
new file mode 100644
index 0000000..835dbe8
--- /dev/null
+++ b/stockton-levels/src/q3/faces.rs
@@ -0,0 +1,163 @@
+// 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/>.
+
+use crate::helpers::{slice_to_i32, slice_to_vec2i, slice_to_vec3};
+use crate::types::{Result, ParseError};
+use na::Vector3;
+use crate::traits::faces::*;
+use super::Q3BSPFile;
+
+const FACE_SIZE: usize = (4 * 8) + (4 * 2) + (4 * 2) + (4 * 3) + ((4 * 2) * 3) + (4 * 3) + (4 * 2);
+
+
+pub fn from_data(
+ data: &[u8],
+ n_textures: u32,
+ n_effects: u32,
+ n_vertices: u32,
+ n_meshverts: u32,
+ n_lightmaps: u32,
+) -> Result<Box<[Face]>> {
+ if data.len() % FACE_SIZE != 0 {
+ return Err(ParseError::Invalid);
+ }
+ let length = data.len() / FACE_SIZE;
+
+ let mut faces = Vec::with_capacity(length);
+ for n in 0..length {
+ faces.push(face_from_slice(
+ &data[n * FACE_SIZE..(n + 1) * FACE_SIZE],
+ n_textures as usize,
+ n_effects as usize,
+ n_vertices as usize,
+ n_meshverts as usize,
+ n_lightmaps as usize,
+ )?);
+ }
+
+ Ok(faces.into_boxed_slice())
+}
+
+
+fn face_from_slice(
+ data: &[u8],
+ n_textures: usize,
+ n_effects: usize,
+ n_vertices: usize,
+ n_meshverts: usize,
+ n_lightmaps: usize,
+) -> Result<Face> {
+ if data.len() != FACE_SIZE {
+ panic!("tried to call face.from_slice with invalid slice size");
+ }
+
+ // texture
+ let texture_idx = slice_to_i32(&data[0..4]) as usize;
+ if texture_idx >= n_textures {
+ return Err(ParseError::Invalid);
+ }
+
+ // effects
+ let effect_idx = slice_to_i32(&data[4..8]) as usize;
+ let effect_idx = if effect_idx < 0xffffffff {
+ if effect_idx >= n_effects {
+ return Err(ParseError::Invalid);
+ }
+
+ Some(effect_idx)
+ } else {
+ None
+ };
+
+ // face type
+ // TODO
+ let face_type: FaceType = unsafe { ::std::mem::transmute(slice_to_i32(&data[8..12])) };
+
+ // vertices
+ let vertex_offset = slice_to_i32(&data[12..16]) as usize;
+ let vertex_n = slice_to_i32(&data[16..20]) as usize;
+ if (vertex_offset + vertex_n) > n_vertices {
+ return Err(ParseError::Invalid);
+ }
+
+ let vertices_idx = vertex_offset..vertex_offset + vertex_n;
+
+ // meshverts
+ let meshverts_offset = slice_to_i32(&data[20..24]) as usize;
+ let meshverts_n = slice_to_i32(&data[24..28]) as usize;
+ if (meshverts_offset + meshverts_n) > n_meshverts {
+ return Err(ParseError::Invalid);
+ }
+
+ let meshverts_idx = meshverts_offset..meshverts_offset + meshverts_n;
+
+ // lightmap
+ let lightmap_idx = slice_to_i32(&data[28..32]) as usize;
+ let lightmap_idx = if lightmap_idx < 0xffffffff {
+ if lightmap_idx >= n_lightmaps {
+ return Err(ParseError::Invalid);
+ }
+
+ Some(lightmap_idx)
+ } else {
+ None
+ };
+
+ // map properties
+ let map_start = slice_to_vec2i(&data[32..40]);
+ let map_size = slice_to_vec2i(&data[40..48]);
+ let map_origin = slice_to_vec3(&data[48..60]);
+
+ // map_vecs
+ let mut map_vecs = [Vector3::new(0.0, 0.0, 0.0); 2];
+ for n in 0..2 {
+ let offset = 60 + (n * 3 * 4);
+ map_vecs[n] = slice_to_vec3(&data[offset..offset + 12]);
+ }
+
+ // normal & size
+ let normal = slice_to_vec3(&data[84..96]);
+ let size = slice_to_vec2i(&data[96..104]);
+
+ Ok(Face {
+ face_type,
+ texture_idx,
+ effect_idx,
+ vertices_idx,
+ meshverts_idx,
+ lightmap_idx,
+ map_start,
+ map_size,
+ map_origin,
+ map_vecs,
+ normal,
+ size,
+ })
+}
+
+
+impl<'a> HasFaces<'a> for Q3BSPFile {
+ type FacesIter = std::slice::Iter<'a, Face>;
+
+ fn faces_iter(&'a self) -> Self::FacesIter {
+ self.faces.iter()
+ }
+
+ fn get_face(&'a self, index: u32) -> &'a Face {
+ &self.faces[index as usize]
+ }
+}