aboutsummaryrefslogtreecommitdiff
path: root/stockton-levels
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:23 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:23 +0100
commit439219e74090c7158f8dbc33fed4107a5eb7c003 (patch)
tree7ba62254b2d888578ff6c1c8de4f0f35c01c75dd /stockton-levels
parent04f17923d38171f07f72603a54237f20ca3572dd (diff)
refactor(levels): no longer q3 specific
Diffstat (limited to 'stockton-levels')
-rw-r--r--stockton-levels/Cargo.toml6
-rw-r--r--stockton-levels/src/coords.rs41
-rw-r--r--stockton-levels/src/features.rs7
-rw-r--r--stockton-levels/src/helpers.rs54
-rw-r--r--stockton-levels/src/lib.rs11
-rw-r--r--stockton-levels/src/parts/entities.rs36
-rw-r--r--stockton-levels/src/parts/faces.rs43
-rw-r--r--stockton-levels/src/parts/mod.rs17
-rw-r--r--stockton-levels/src/parts/textures.rs48
-rw-r--r--stockton-levels/src/parts/vertices.rs156
-rw-r--r--stockton-levels/src/parts/visdata.rs8
-rw-r--r--stockton-levels/src/prelude.rs3
-rw-r--r--stockton-levels/src/q3/brushes.rs100
-rw-r--r--stockton-levels/src/q3/effects.rs48
-rw-r--r--stockton-levels/src/q3/entities.rs95
-rw-r--r--stockton-levels/src/q3/faces.rs148
-rw-r--r--stockton-levels/src/q3/file.rs147
-rw-r--r--stockton-levels/src/q3/header.rs68
-rw-r--r--stockton-levels/src/q3/light_maps.rs43
-rw-r--r--stockton-levels/src/q3/light_vols.rs39
-rw-r--r--stockton-levels/src/q3/mod.rs18
-rw-r--r--stockton-levels/src/q3/models.rs65
-rw-r--r--stockton-levels/src/q3/planes.rs40
-rw-r--r--stockton-levels/src/q3/textures.rs137
-rw-r--r--stockton-levels/src/q3/tree.rs151
-rw-r--r--stockton-levels/src/q3/vertices.rs72
-rw-r--r--stockton-levels/src/q3/visdata.rs53
-rw-r--r--stockton-levels/src/traits/brushes.rs27
-rw-r--r--stockton-levels/src/traits/effects.rs19
-rw-r--r--stockton-levels/src/traits/entities.rs14
-rw-r--r--stockton-levels/src/traits/faces.rs42
-rw-r--r--stockton-levels/src/traits/light_maps.rs45
-rw-r--r--stockton-levels/src/traits/light_vols.rs15
-rw-r--r--stockton-levels/src/traits/mod.rs27
-rw-r--r--stockton-levels/src/traits/models.rs20
-rw-r--r--stockton-levels/src/traits/planes.rs27
-rw-r--r--stockton-levels/src/traits/textures.rs147
-rw-r--r--stockton-levels/src/traits/tree.rs35
-rw-r--r--stockton-levels/src/traits/vertices.rs52
-rw-r--r--stockton-levels/src/traits/visdata.rs27
-rw-r--r--stockton-levels/src/types.rs19
41 files changed, 319 insertions, 1851 deletions
diff --git a/stockton-levels/Cargo.toml b/stockton-levels/Cargo.toml
index 2cae877..526b21c 100644
--- a/stockton-levels/Cargo.toml
+++ b/stockton-levels/Cargo.toml
@@ -2,13 +2,11 @@
name = "stockton-levels"
version = "0.1.0"
authors = ["Oscar <oscar.shrimpton.personal@gmail.com>"]
-description = "Library for parsing different types of .bsp files."
+description = "Traits relating to levels renderable by stockton."
repository = "https://github.com/tcmal/stockton"
homepage = "https://github.com/tcmal/stockton"
edition = "2018"
[dependencies]
nalgebra = "^0.20"
-bitflags = "^1.2"
-thiserror = "1.0.25"
-bitvec = "0.17"
+serde = { version = "1.0", features = ["derive"] } \ No newline at end of file
diff --git a/stockton-levels/src/coords.rs b/stockton-levels/src/coords.rs
deleted file mode 100644
index 1b1fa55..0000000
--- a/stockton-levels/src/coords.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 <http://www.gnu.org/licenses/>.
-//! Marker traits for different co-ordinate systems, and functions to swizzle between them
-
-use na::base::Scalar;
-use na::Vector3;
-use std::ops::Neg;
-
-pub trait CoordSystem {}
-
-/// X points East, Y points South, Z points downwards
-pub struct Q3System;
-impl CoordSystem for Q3System {}
-
-/// X points east, Y points downwards, Z points inwards
-pub struct VulkanSystem;
-impl CoordSystem for VulkanSystem {}
-
-pub struct Swizzler;
-
-pub trait SwizzleFromTo<F: CoordSystem, T: CoordSystem> {
- fn swizzle<U: Scalar + Copy + Neg<Output = U>>(vec: &mut Vector3<U>);
-}
-
-impl SwizzleFromTo<Q3System, VulkanSystem> for Swizzler {
- fn swizzle<U: Scalar + Copy + Neg<Output = U>>(vec: &mut Vector3<U>) {
- let temp = vec.y;
- vec.y = vec.z;
- vec.z = -temp;
- }
-}
diff --git a/stockton-levels/src/features.rs b/stockton-levels/src/features.rs
index 9b05772..f748bd0 100644
--- a/stockton-levels/src/features.rs
+++ b/stockton-levels/src/features.rs
@@ -12,8 +12,7 @@
// with this program. If not, see <http://www.gnu.org/licenses/>.
//! Marker traits for different feature sets
-use crate::coords::CoordSystem;
-use crate::traits::*;
+use crate::parts::*;
-pub trait MinBspFeatures<S: CoordSystem>: HasBspTree<S> + Send + Sync {}
-impl<T, S: CoordSystem> MinBspFeatures<S> for T where T: HasBspTree<S> + Send + Sync {}
+pub trait MinRenderFeatures: HasFaces + HasTextures + Send + Sync {}
+impl<T> MinRenderFeatures for T where T: HasFaces + HasTextures + Send + Sync {}
diff --git a/stockton-levels/src/helpers.rs b/stockton-levels/src/helpers.rs
deleted file mode 100644
index 0fe3e96..0000000
--- a/stockton-levels/src/helpers.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-//! Helper functions for parsing
-
-use na::{Vector2, Vector3};
-use std::convert::TryInto;
-
-/// Turn a slice into a le i32, the int datatype in a bsp file.
-/// # Panics
-/// If slice is not 4 bytes long
-pub fn slice_to_i32(slice: &[u8]) -> i32 {
- i32::from_le_bytes(slice.try_into().unwrap())
-}
-
-/// Turn a slice into a le u32, used for some bitflags.
-/// # Panics
-/// If slice is not 4 bytes long.
-pub fn slice_to_u32(slice: &[u8]) -> u32 {
- u32::from_le_bytes(slice.try_into().unwrap())
-}
-
-/// Turn a slice into a le f32, the float datatype in a bsp file.
-/// # Panics
-/// If slice is not 4 bytes long
-pub fn slice_to_f32(slice: &[u8]) -> f32 {
- f32::from_bits(u32::from_le_bytes(slice.try_into().unwrap()))
-}
-
-/// Turn a slice of floats into a 3D vector
-/// # Panics
-/// If slice isn't 12 bytes long.
-pub fn slice_to_vec3(slice: &[u8]) -> Vector3<f32> {
- Vector3::new(
- slice_to_f32(&slice[0..4]),
- slice_to_f32(&slice[4..8]),
- slice_to_f32(&slice[8..12]),
- )
-}
-
-/// Turn a slice of i32s into a 3D vector
-/// # Panics
-/// If slice isn't 12 bytes long.
-pub fn slice_to_vec3i(slice: &[u8]) -> Vector3<i32> {
- Vector3::new(
- slice_to_i32(&slice[0..4]),
- slice_to_i32(&slice[4..8]),
- slice_to_i32(&slice[8..12]),
- )
-}
-
-/// Turn a slice of u32s into a 2D vector
-/// # Panics
-/// If slice isn't 8 bytes long.
-pub fn slice_to_vec2ui(slice: &[u8]) -> Vector2<u32> {
- Vector2::new(slice_to_u32(&slice[0..4]), slice_to_u32(&slice[4..8]))
-}
diff --git a/stockton-levels/src/lib.rs b/stockton-levels/src/lib.rs
index a71d8e2..49609c2 100644
--- a/stockton-levels/src/lib.rs
+++ b/stockton-levels/src/lib.rs
@@ -10,18 +10,11 @@
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
-//! Parses common features from many BSP file formats.
-#![allow(incomplete_features)]
-#![feature(generic_associated_types)]
+//! Interfaces & Data structures stockton expects when rendering a level.
extern crate nalgebra as na;
-#[macro_use]
-extern crate bitflags;
-pub mod coords;
pub mod features;
-mod helpers;
+pub mod parts;
pub mod prelude;
-pub mod q3;
-pub mod traits;
pub mod types;
diff --git a/stockton-levels/src/parts/entities.rs b/stockton-levels/src/parts/entities.rs
new file mode 100644
index 0000000..7a5ac74
--- /dev/null
+++ b/stockton-levels/src/parts/entities.rs
@@ -0,0 +1,36 @@
+use std::iter::Iterator;
+
+pub type EntityRef = u32;
+
+/// A game entity
+pub trait IsEntity<C: HasEntities + ?Sized> {
+ fn get_attr(&self, container: &C) -> Option<&str>;
+}
+
+pub trait HasEntities {
+ type Entity: IsEntity<Self>;
+
+ fn get_entity(&self, idx: EntityRef) -> Option<&Self::Entity>;
+ fn iter_entities(&self) -> Entities<Self> {
+ Entities {
+ next: 0,
+ container: self,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Entities<'a, T: HasEntities + ?Sized> {
+ next: EntityRef,
+ container: &'a T,
+}
+
+impl<'a, T: HasEntities> Iterator for Entities<'a, T> {
+ type Item = &'a T::Entity;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let res = self.container.get_entity(self.next);
+ self.next += 1;
+ res
+ }
+}
diff --git a/stockton-levels/src/parts/faces.rs b/stockton-levels/src/parts/faces.rs
new file mode 100644
index 0000000..0168cd8
--- /dev/null
+++ b/stockton-levels/src/parts/faces.rs
@@ -0,0 +1,43 @@
+use super::{textures::TextureRef, vertices::Vertex};
+use serde::{Deserialize, Serialize};
+
+pub type FaceRef = u32;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Geometry {
+ Vertices(Vertex, Vertex, Vertex),
+}
+
+pub trait IsFace<C: HasFaces + ?Sized> {
+ fn index(&self, container: &C) -> FaceRef;
+ fn geometry(&self, container: &C) -> Geometry;
+ fn texture_idx(&self, container: &C) -> TextureRef;
+}
+
+pub trait HasFaces {
+ type Face: IsFace<Self>;
+
+ fn get_face(&self, index: FaceRef) -> Option<&Self::Face>;
+ fn iter_faces(&self) -> Faces<Self> {
+ Faces {
+ next: 0,
+ container: self,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Faces<'a, T: HasFaces + ?Sized> {
+ next: FaceRef,
+ container: &'a T,
+}
+
+impl<'a, T: HasFaces> Iterator for Faces<'a, T> {
+ type Item = &'a T::Face;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let res = self.container.get_face(self.next);
+ self.next += 1;
+ res
+ }
+}
diff --git a/stockton-levels/src/parts/mod.rs b/stockton-levels/src/parts/mod.rs
new file mode 100644
index 0000000..05697f0
--- /dev/null
+++ b/stockton-levels/src/parts/mod.rs
@@ -0,0 +1,17 @@
+mod entities;
+mod faces;
+mod textures;
+mod vertices;
+mod visdata;
+
+pub mod data {
+ pub use super::entities::{Entities, EntityRef};
+ pub use super::faces::{FaceRef, Faces, Geometry};
+ pub use super::textures::{TextureRef, Textures};
+ pub use super::vertices::{Vertex, VertexRef};
+}
+
+pub use entities::{HasEntities, IsEntity};
+pub use faces::{HasFaces, IsFace};
+pub use textures::{HasTextures, IsTexture};
+pub use visdata::HasVisData;
diff --git a/stockton-levels/src/parts/textures.rs b/stockton-levels/src/parts/textures.rs
new file mode 100644
index 0000000..8e6cb9a
--- /dev/null
+++ b/stockton-levels/src/parts/textures.rs
@@ -0,0 +1,48 @@
+// 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 <http://www.gnu.org/licenses/>.
+
+use std::iter::Iterator;
+
+pub type TextureRef = u32;
+
+pub trait IsTexture {
+ fn name(&self) -> &str;
+}
+
+pub trait HasTextures {
+ type Texture: IsTexture;
+
+ fn get_texture(&self, idx: TextureRef) -> Option<&Self::Texture>;
+ fn iter_textures(&self) -> Textures<Self> {
+ Textures {
+ next: 0,
+ container: self,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Textures<'a, T: HasTextures + ?Sized> {
+ next: TextureRef,
+ container: &'a T,
+}
+
+impl<'a, T: HasTextures> Iterator for Textures<'a, T> {
+ type Item = &'a T::Texture;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let res = self.container.get_texture(self.next);
+ self.next += 1;
+ res
+ }
+}
diff --git a/stockton-levels/src/parts/vertices.rs b/stockton-levels/src/parts/vertices.rs
new file mode 100644
index 0000000..0b7dfd6
--- /dev/null
+++ b/stockton-levels/src/parts/vertices.rs
@@ -0,0 +1,156 @@
+use crate::types::Rgba;
+use na::{Vector2, Vector3};
+use serde::de;
+use serde::de::{Deserializer, MapAccess, SeqAccess, Visitor};
+use serde::ser::{Serialize, SerializeStruct, Serializer};
+use serde::Deserialize;
+use std::fmt;
+
+pub type VertexRef = u32;
+
+/// A vertex, used to describe a face.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct Vertex {
+ pub position: Vector3<f32>,
+ pub tex: Vector2<f32>,
+ pub color: Rgba,
+}
+
+impl Serialize for Vertex {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ let mut state = serializer.serialize_struct("Vertex", 5)?;
+ state.serialize_field("pos_x", &self.position.x)?;
+ state.serialize_field("pos_y", &self.position.y)?;
+ state.serialize_field("pos_z", &self.position.z)?;
+ state.serialize_field("tex_u", &self.tex.x)?;
+ state.serialize_field("tex_v", &self.tex.y)?;
+ state.serialize_field("color", &self.color)?;
+
+ state.end()
+ }
+}
+
+impl<'de> Deserialize<'de> for Vertex {
+ fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+ #[derive(Deserialize)]
+ #[serde(field_identifier, rename_all = "snake_case")]
+ enum Field {
+ PosX,
+ PosY,
+ PosZ,
+ TexU,
+ TexV,
+ Color,
+ }
+ const FIELDS: &'static [&'static str] =
+ &["pos_x", "pos_y", "pos_z", "tex_x", "tex_y", "color"];
+
+ struct VertexVisitor;
+
+ impl<'de> Visitor<'de> for VertexVisitor {
+ type Value = Vertex;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("struct Vertex")
+ }
+
+ fn visit_seq<V>(self, mut seq: V) -> Result<Vertex, V::Error>
+ where
+ V: SeqAccess<'de>,
+ {
+ let pos_x = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(0, &self))?;
+ let pos_y = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(1, &self))?;
+ let pos_z = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(2, &self))?;
+ let tex_u = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(3, &self))?;
+ let tex_v = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(4, &self))?;
+ let color = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(5, &self))?;
+ Ok(Vertex {
+ position: Vector3::new(pos_x, pos_y, pos_z),
+ tex: Vector2::new(tex_u, tex_v),
+ color,
+ })
+ }
+
+ fn visit_map<V>(self, mut map: V) -> Result<Vertex, V::Error>
+ where
+ V: MapAccess<'de>,
+ {
+ let mut pos_x = None;
+ let mut pos_y = None;
+ let mut pos_z = None;
+ let mut tex_u = None;
+ let mut tex_v = None;
+ let mut color = None;
+ while let Some(key) = map.next_key()? {
+ match key {
+ Field::PosX => {
+ if pos_x.is_some() {
+ return Err(de::Error::duplicate_field("pos_x"));
+ }
+ pos_x = Some(map.next_value()?);
+ }
+ Field::PosY => {
+ if pos_y.is_some() {
+ return Err(de::Error::duplicate_field("pos_y"));
+ }
+ pos_y = Some(map.next_value()?);
+ }
+ Field::PosZ => {
+ if pos_z.is_some() {
+ return Err(de::Error::duplicate_field("pos_z"));
+ }
+ pos_z = Some(map.next_value()?);
+ }
+ Field::TexU => {
+ if tex_u.is_some() {
+ return Err(de::Error::duplicate_field("tex_u"));
+ }
+ tex_u = Some(map.next_value()?);
+ }
+ Field::TexV => {
+ if tex_v.is_some() {
+ return Err(de::Error::duplicate_field("tex_v"));
+ }
+ tex_v = Some(map.next_value()?);
+ }
+ Field::Color => {
+ if color.is_some() {
+ return Err(de::Error::duplicate_field("color"));
+ }
+ color = Some(map.next_value()?);
+ }
+ }
+ }
+ let position = Vector3::new(
+ pos_x.ok_or_else(|| de::Error::missing_field("pos_x"))?,
+ pos_y.ok_or_else(|| de::Error::missing_field("pos_y"))?,
+ pos_z.ok_or_else(|| de::Error::missing_field("pos_z"))?,
+ );
+ let tex = Vector2::new(
+ tex_u.ok_or_else(|| de::Error::missing_field("tex_u"))?,
+ tex_v.ok_or_else(|| de::Error::missing_field("tex_v"))?,
+ );
+ let color = color.ok_or_else(|| de::Error::missing_field("nanos"))?;
+ Ok(Vertex {
+ position,
+ tex,
+ color,
+ })
+ }
+ }
+
+ deserializer.deserialize_struct("Vertex", FIELDS, VertexVisitor)
+ }
+}
diff --git a/stockton-levels/src/parts/visdata.rs b/stockton-levels/src/parts/visdata.rs
new file mode 100644
index 0000000..f311bf7
--- /dev/null
+++ b/stockton-levels/src/parts/visdata.rs
@@ -0,0 +1,8 @@
+use super::faces::FaceRef;
+use na::Vector3;
+use std::iter::Iterator;
+
+pub trait HasVisData {
+ type Faces: Iterator<Item = FaceRef>;
+ fn get_visible(pos: Vector3<f32>, rot: Vector3<f32>) -> Self::Faces;
+}
diff --git a/stockton-levels/src/prelude.rs b/stockton-levels/src/prelude.rs
index 2d09252..0da890b 100644
--- a/stockton-levels/src/prelude.rs
+++ b/stockton-levels/src/prelude.rs
@@ -12,6 +12,5 @@
// with this program. If not, see <http://www.gnu.org/licenses/>.
//! Common traits, etc.
-pub use crate::coords::*;
pub use crate::features::*;
-pub use crate::traits::*;
+pub use crate::parts::*;
diff --git a/stockton-levels/src/q3/brushes.rs b/stockton-levels/src/q3/brushes.rs
deleted file mode 100644
index 9cb0d8e..0000000
--- a/stockton-levels/src/q3/brushes.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-//! 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 super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::slice_to_i32;
-use crate::traits::brushes::*;
-use crate::types::{ParseError, Result};
-
-/// 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<T: CoordSystem> HasBrushes<T> for Q3BspFile<T> {
- type BrushesIter<'a> = std::slice::Iter<'a, Brush>;
-
- fn brushes_iter(&self) -> Self::BrushesIter<'_> {
- self.brushes.iter()
- }
-
- fn get_brush(&self, index: u32) -> &Brush {
- &self.brushes[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/effects.rs b/stockton-levels/src/q3/effects.rs
deleted file mode 100644
index 369ed80..0000000
--- a/stockton-levels/src/q3/effects.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use std::str;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::slice_to_u32;
-use crate::traits::effects::*;
-use crate::types::{ParseError, Result};
-
-/// The size of one effect definition
-const EFFECT_SIZE: usize = 64 + 4 + 4;
-
-pub fn from_data(data: &[u8], n_brushes: u32) -> Result<Box<[Effect]>> {
- if data.len() % EFFECT_SIZE != 0 {
- return Err(ParseError::Invalid);
- }
- let length = data.len() / EFFECT_SIZE;
-
- let mut effects = Vec::with_capacity(length);
- for n in 0..length {
- let raw = &data[n * EFFECT_SIZE..(n + 1) * EFFECT_SIZE];
-
- let brush_idx = slice_to_u32(&raw[64..68]);
- if brush_idx >= n_brushes {
- return Err(ParseError::Invalid);
- }
-
- effects.push(Effect {
- name: str::from_utf8(&raw[..64])
- .map_err(|_| ParseError::Invalid)?
- .to_owned(),
- brush_idx,
- });
- }
-
- Ok(effects.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasEffects<T> for Q3BspFile<T> {
- type EffectsIter<'a> = std::slice::Iter<'a, Effect>;
-
- fn effects_iter(&self) -> Self::EffectsIter<'_> {
- self.effects.iter()
- }
-
- fn get_effect(&self, index: u32) -> &Effect {
- &self.effects[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/entities.rs b/stockton-levels/src/q3/entities.rs
deleted file mode 100644
index d36eb37..0000000
--- a/stockton-levels/src/q3/entities.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use std::collections::HashMap;
-use std::str;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::traits::entities::*;
-use crate::types::{ParseError, Result};
-
-const QUOTE: u8 = b'"';
-const END_BRACKET: u8 = b'}';
-const START_BRACKET: u8 = b'{';
-
-/// Internal enum to parse through the entities string.
-#[derive(PartialEq, Eq)]
-enum ParseState {
- InKey,
- InValue,
- AfterKey,
- InsideEntity,
- OutsideEntity,
-}
-
-/// Parse the given data as an Entities lump
-pub fn from_data(data: &[u8]) -> Result<Box<[Entity]>> {
- use self::ParseState::*;
-
- let string = str::from_utf8(data).unwrap();
-
- let mut attrs = HashMap::new();
- let mut entities = Vec::new();
-
- let mut state = ParseState::OutsideEntity;
-
- let mut key_start = 0;
- let mut key_end = 0;
- let mut val_start = 0;
- let mut val_end;
-
- for (i, chr) in string.bytes().enumerate() {
- match chr {
- QUOTE => match state {
- InsideEntity => {
- state = ParseState::InKey;
- key_start = i + 1;
- }
- InKey => {
- state = ParseState::AfterKey;
- key_end = i;
- }
- AfterKey => {
- state = ParseState::InValue;
- val_start = i + 1;
- }
- InValue => {
- state = ParseState::InsideEntity;
- val_end = i;
-
- attrs.insert(
- string[key_start..key_end].to_owned(),
- string[val_start..val_end].to_owned(),
- );
- }
- _ => {
- return Err(ParseError::Invalid);
- }
- },
- END_BRACKET => {
- if state != InsideEntity {
- return Err(ParseError::Invalid);
- }
-
- state = OutsideEntity;
-
- entities.push(Entity { attributes: attrs });
- attrs = HashMap::new();
- }
- START_BRACKET => {
- if state != OutsideEntity {
- return Err(ParseError::Invalid);
- }
- state = InsideEntity;
- }
- _ => {}
- }
- }
- Ok(entities.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasEntities for Q3BspFile<T> {
- type EntitiesIter<'a> = std::slice::Iter<'a, Entity>;
-
- fn entities_iter(&self) -> Self::EntitiesIter<'_> {
- self.entities.iter()
- }
-}
diff --git a/stockton-levels/src/q3/faces.rs b/stockton-levels/src/q3/faces.rs
deleted file mode 100644
index 95467bb..0000000
--- a/stockton-levels/src/q3/faces.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::{slice_to_i32, slice_to_u32, slice_to_vec2ui, slice_to_vec3};
-use crate::traits::faces::*;
-use crate::types::{ParseError, Result};
-use na::Vector3;
-
-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,
- n_effects,
- n_vertices,
- n_meshverts,
- n_lightmaps,
- )?);
- }
-
- Ok(faces.into_boxed_slice())
-}
-
-fn face_from_slice(
- data: &[u8],
- n_textures: u32,
- n_effects: u32,
- n_vertices: u32,
- n_meshverts: u32,
- n_lightmaps: u32,
-) -> Result<Face> {
- if data.len() != FACE_SIZE {
- panic!("tried to call face.from_slice with invalid slice size");
- }
-
- // texture
- let texture_idx = slice_to_u32(&data[0..4]);
- if texture_idx >= n_textures {
- return Err(ParseError::Invalid);
- }
-
- // effects
- let effect_idx = slice_to_u32(&data[4..8]);
- 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_u32(&data[8..12])) };
-
- // vertices
- let vertex_offset = slice_to_u32(&data[12..16]);
- let vertex_n = slice_to_u32(&data[16..20]);
- 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_u32(&data[20..24]);
- let meshverts_n = slice_to_u32(&data[24..28]);
- 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]);
- let lightmap_idx = if lightmap_idx > 0 {
- if lightmap_idx as u32 >= n_lightmaps {
- return Err(ParseError::Invalid);
- }
-
- Some(lightmap_idx as u32)
- } else {
- None
- };
-
- // map properties
- let map_start = slice_to_vec2ui(&data[32..40]);
- let map_size = slice_to_vec2ui(&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, map_vec) in map_vecs.iter_mut().enumerate() {
- let offset = 60 + (n * 3 * 4);
- *map_vec = slice_to_vec3(&data[offset..offset + 12]);
- }
-
- // normal & size
- let normal = slice_to_vec3(&data[84..96]);
- let size = slice_to_vec2ui(&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<T: CoordSystem> HasFaces<T> for Q3BspFile<T> {
- type FacesIter<'a> = std::slice::Iter<'a, Face>;
-
- fn faces_iter(&self) -> Self::FacesIter<'_> {
- self.faces.iter()
- }
-
- fn faces_len(&self) -> u32 {
- self.faces.len() as u32
- }
-
- fn get_face(&self, index: u32) -> &Face {
- &self.faces[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/file.rs b/stockton-levels/src/q3/file.rs
deleted file mode 100644
index f577fb0..0000000
--- a/stockton-levels/src/q3/file.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-//! A complete BSP file
-
-// Trait implementations are stored in their own files.
-
-use bitvec::prelude::*;
-use std::marker::PhantomData;
-
-use self::header::Header;
-use crate::coords::*;
-use crate::types::Result;
-
-use super::*;
-use crate::traits::brushes::Brush;
-use crate::traits::effects::Effect;
-use crate::traits::entities::Entity;
-use crate::traits::faces::Face;
-use crate::traits::light_maps::LightMap;
-use crate::traits::light_vols::LightVol;
-use crate::traits::models::Model;
-use crate::traits::planes::Plane;
-use crate::traits::textures::Texture;
-use crate::traits::tree::BspNode;
-use crate::traits::vertices::{MeshVert, Vertex};
-
-/// A parsed Quake 3 BSP File.
-pub struct Q3BspFile<T: CoordSystem> {
- pub(crate) visdata: Box<[BitBox<Local, u8>]>,
- pub(crate) textures: Box<[Texture]>,
- pub(crate) entities: Box<[Entity]>,
- pub(crate) planes: Box<[Plane]>,
- pub(crate) vertices: Box<[Vertex]>,
- pub(crate) meshverts: Box<[MeshVert]>,
- pub(crate) light_maps: Box<[LightMap]>,
- pub(crate) light_vols: Box<[LightVol]>,
- pub(crate) brushes: Box<[Brush]>,
- pub(crate) effects: Box<[Effect]>,
- pub(crate) faces: Box<[Face]>,
- pub(crate) models: Box<[Model]>,
- pub(crate) tree_root: BspNode,
- _phantom: PhantomData<T>,
-}
-
-impl Q3BspFile<Q3System> {
- /// Parse `data` as a quake 3 bsp file.
- pub fn parse_file(data: &[u8]) -> Result<Q3BspFile<Q3System>> {
- let header = Header::from(data)?;
-
- let entities = entities::from_data(header.get_lump(&data, 0))?;
- let textures = textures::from_data(header.get_lump(&data, 1))?;
- let planes = planes::from_data(header.get_lump(&data, 2))?;
- let vertices = vertices::verts_from_data(header.get_lump(&data, 10))?;
- let meshverts = vertices::meshverts_from_data(header.get_lump(&data, 11))?;
- let light_maps = light_maps::from_data(header.get_lump(&data, 14))?;
- let light_vols = light_vols::from_data(header.get_lump(&data, 15))?;
- let visdata = visdata::from_data(header.get_lump(&data, 16))?;
- let brushes = brushes::from_data(
- header.get_lump(&data, 8),
- header.get_lump(&data, 9),
- textures.len() as u32,
- planes.len() as u32,
- )?;
- let effects = effects::from_data(header.get_lump(&data, 12), brushes.len() as u32)?;
- let faces = faces::from_data(
- header.get_lump(&data, 13),
- textures.len() as u32,
- effects.len() as u32,
- vertices.len() as u32,
- meshverts.len() as u32,
- light_maps.len() as u32,
- )?;
-
- let tree_root = tree::from_data(
- header.get_lump(&data, 3),
- header.get_lump(&data, 4),
- header.get_lump(&data, 5),
- header.get_lump(&data, 6),
- faces.len() as u32,
- brushes.len() as u32,
- )?;
-
- let models = models::from_data(
- header.get_lump(&data, 7),
- faces.len() as u32,
- brushes.len() as u32,
- )?;
-
- Ok(Q3BspFile {
- visdata,
- textures,
- entities,
- planes,
- vertices,
- meshverts,
- light_maps,
- light_vols,
- brushes,
- effects,
- faces,
- tree_root,
- models,
- _phantom: PhantomData,
- })
- }
-}
-
-impl<T: CoordSystem> Q3BspFile<T> {
- pub fn swizzle_to<D: CoordSystem>(mut self) -> Q3BspFile<D>
- where
- Swizzler: SwizzleFromTo<T, D>,
- {
- for vertex in self.vertices.iter_mut() {
- Swizzler::swizzle(&mut vertex.normal);
- Swizzler::swizzle(&mut vertex.position);
- }
-
- for model in self.models.iter_mut() {
- Swizzler::swizzle(&mut model.mins);
- Swizzler::swizzle(&mut model.maxs);
- }
-
- for face in self.faces.iter_mut() {
- Swizzler::swizzle(&mut face.normal);
- }
-
- for plane in self.planes.iter_mut() {
- Swizzler::swizzle(&mut plane.normal);
- }
-
- // TODO: Possibly don't need to move?
- Q3BspFile {
- visdata: self.visdata,
- textures: self.textures,
- entities: self.entities,
- planes: self.planes,
- vertices: self.vertices,
- meshverts: self.meshverts,
- light_maps: self.light_maps,
- light_vols: self.light_vols,
- brushes: self.brushes,
- effects: self.effects,
- faces: self.faces,
- tree_root: self.tree_root,
- models: self.models,
- _phantom: PhantomData,
- }
- }
-}
diff --git a/stockton-levels/src/q3/header.rs b/stockton-levels/src/q3/header.rs
deleted file mode 100644
index 45478e0..0000000
--- a/stockton-levels/src/q3/header.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use crate::types::{ParseError, Result};
-use std::convert::TryInto;
-
-const MAGIC_HEADER: &[u8] = &[0x49, 0x42, 0x53, 0x50];
-const HEADER_LEN: usize = 4 + 4 + (17 * 4 * 2);
-
-/// The header found at the start of a (Q3) bsp file
-#[derive(Clone, Copy, Debug)]
-pub struct Header {
- pub version: u32,
- pub dir_entries: [DirEntry; 17],
-}
-
-/// A directory entry, pointing to a lump in the file
-#[derive(Clone, Copy, Debug)]
-pub struct DirEntry {
- /// Offset from beginning of file to start of lump
- pub offset: u32,
-
- /// Length of lump, multiple of 4.
- pub length: u32,
-}
-
-impl Header {
- /// Deserialise from buffer.
- /// # Format
- /// string[4] magic Magic number. Always "IBSP".
- /// int version Version number. 0x2e for the BSP files distributed with Quake 3.
- /// direntry[17] direntries Lump directory, seventeen entries.
- pub fn from(v: &[u8]) -> Result<Header> {
- if v.len() < HEADER_LEN {
- return Err(ParseError::Invalid);
- }
- let magic = &v[0..4];
-
- if magic != MAGIC_HEADER {
- return Err(ParseError::Invalid);
- }
-
- let version: &[u8; 4] = v[4..8].try_into().unwrap();
-
- let entries: &[u8] = &v[8..144];
- let mut dir_entries: [DirEntry; 17] = [DirEntry {
- offset: 0,
- length: 0,
- }; 17];
-
- for n in 0..17 {
- let base = &entries[(n * 8)..(n * 8) + 8];
- dir_entries[n] = DirEntry {
- offset: u32::from_le_bytes(base[0..4].try_into().unwrap()),
- length: u32::from_le_bytes(base[4..8].try_into().unwrap()),
- }
- }
-
- Ok(Header {
- version: u32::from_le_bytes(*version),
- dir_entries,
- })
- }
-
- /// Get the lump at given index from the buffer, with offset & length based on this directory.
- pub fn get_lump<'l>(&self, buf: &'l [u8], index: usize) -> &'l [u8] {
- let entry = self.dir_entries[index];
-
- &buf[entry.offset as usize..entry.offset as usize + entry.length as usize]
- }
-}
diff --git a/stockton-levels/src/q3/light_maps.rs b/stockton-levels/src/q3/light_maps.rs
deleted file mode 100644
index 377fea5..0000000
--- a/stockton-levels/src/q3/light_maps.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::traits::light_maps::*;
-use crate::types::{ParseError, Result, Rgb};
-
-/// The size of one LightMap
-const LIGHTMAP_SIZE: usize = 128 * 128 * 3;
-
-/// Parse the LightMap data from a bsp file.
-pub fn from_data(data: &[u8]) -> Result<Box<[LightMap]>> {
- if data.len() % LIGHTMAP_SIZE != 0 {
- return Err(ParseError::Invalid);
- }
- let length = data.len() / LIGHTMAP_SIZE;
-
- let mut maps = Vec::with_capacity(length as usize);
- for n in 0..length {
- let raw = &data[n * LIGHTMAP_SIZE..(n + 1) * LIGHTMAP_SIZE];
- let mut map: [[Rgb; 128]; 128] = [[Rgb::white(); 128]; 128];
-
- for (x, outer) in map.iter_mut().enumerate() {
- for (y, inner) in outer.iter_mut().enumerate() {
- let offset = (x * 128 * 3) + (y * 3);
- *inner = Rgb::from_slice(&raw[offset..offset + 3]);
- }
- }
- maps.push(LightMap { map })
- }
-
- Ok(maps.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasLightMaps for Q3BspFile<T> {
- type LightMapsIter<'a> = std::slice::Iter<'a, LightMap>;
-
- fn lightmaps_iter(&self) -> Self::LightMapsIter<'_> {
- self.light_maps.iter()
- }
-
- fn get_lightmap(&self, index: u32) -> &LightMap {
- &self.light_maps[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/light_vols.rs b/stockton-levels/src/q3/light_vols.rs
deleted file mode 100644
index 46f2557..0000000
--- a/stockton-levels/src/q3/light_vols.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use std::convert::TryInto;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::traits::light_vols::*;
-use crate::types::{ParseError, Result, Rgb};
-
-const VOL_LENGTH: usize = (3 * 2) + 2;
-
-pub fn from_data(data: &[u8]) -> Result<Box<[LightVol]>> {
- if data.len() % VOL_LENGTH != 0 {
- return Err(ParseError::Invalid);
- }
- let length = data.len() / VOL_LENGTH;
-
- let mut vols = Vec::with_capacity(length);
- for n in 0..length {
- let data = &data[n * VOL_LENGTH..(n + 1) * VOL_LENGTH];
- vols.push(LightVol {
- ambient: Rgb::from_slice(&data[0..3]),
- directional: Rgb::from_slice(&data[3..6]),
- dir: data[6..8].try_into().unwrap(),
- });
- }
-
- Ok(vols.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasLightVols for Q3BspFile<T> {
- type LightVolsIter<'a> = std::slice::Iter<'a, LightVol>;
-
- fn lightvols_iter(&self) -> Self::LightVolsIter<'_> {
- self.light_vols.iter()
- }
-
- fn get_lightvol(&self, index: u32) -> &LightVol {
- &self.light_vols[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/mod.rs b/stockton-levels/src/q3/mod.rs
deleted file mode 100644
index 44d5159..0000000
--- a/stockton-levels/src/q3/mod.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Parsing data from Q3 and similar BSPs
-
-mod brushes;
-mod effects;
-mod entities;
-mod faces;
-pub mod file;
-mod header;
-mod light_maps;
-mod light_vols;
-mod models;
-mod planes;
-mod textures;
-mod tree;
-mod vertices;
-mod visdata;
-
-pub use self::file::Q3BspFile;
diff --git a/stockton-levels/src/q3/models.rs b/stockton-levels/src/q3/models.rs
deleted file mode 100644
index a3de54a..0000000
--- a/stockton-levels/src/q3/models.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::{slice_to_u32, slice_to_vec3};
-use crate::traits::models::*;
-use crate::types::{ParseError, Result};
-
-const MODEL_SIZE: usize = (4 * 3 * 2) + (4 * 4);
-
-pub fn from_data(data: &[u8], n_faces: u32, n_brushes: u32) -> Result<Box<[Model]>> {
- if data.len() % MODEL_SIZE != 0 {
- return Err(ParseError::Invalid);
- }
- let n_models = data.len() / MODEL_SIZE;
-
- let mut models = Vec::with_capacity(n_models);
- for n in 0..n_models {
- let raw = &data[n * MODEL_SIZE..(n + 1) * MODEL_SIZE];
-
- let mins = slice_to_vec3(&raw[0..12]);
- let maxs = slice_to_vec3(&raw[12..24]);
-
- let faces_idx = {
- let start = slice_to_u32(&raw[24..28]);
- let n = slice_to_u32(&raw[28..32]);
-
- if start + n > n_faces {
- return Err(ParseError::Invalid);
- }
-
- start..start + n
- };
-
- let brushes_idx = {
- let start = slice_to_u32(&raw[32..36]);
- let n = slice_to_u32(&raw[36..40]);
-
- if start + n > n_brushes {
- return Err(ParseError::Invalid);
- }
-
- start..start + n
- };
-
- models.push(Model {
- mins,
- maxs,
- faces_idx,
- brushes_idx,
- })
- }
-
- Ok(models.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasModels<T> for Q3BspFile<T> {
- type ModelsIter<'a> = std::slice::Iter<'a, Model>;
-
- fn models_iter(&self) -> Self::ModelsIter<'_> {
- self.models.iter()
- }
-
- fn get_model(&self, index: u32) -> &Model {
- &self.models[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/planes.rs b/stockton-levels/src/q3/planes.rs
deleted file mode 100644
index b4d3217..0000000
--- a/stockton-levels/src/q3/planes.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-const PLANE_SIZE: usize = (4 * 3) + 4;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::{slice_to_f32, slice_to_vec3};
-use crate::traits::planes::*;
-use crate::types::{ParseError, Result};
-
-/// Parse a lump of planes.
-/// A lump is (data length / plane size) planes long
-pub fn from_data(data: &[u8]) -> Result<Box<[Plane]>> {
- let length = data.len() / PLANE_SIZE;
- if data.is_empty() || data.len() % PLANE_SIZE != 0 || length % 2 != 0 {
- return Err(ParseError::Invalid);
- }
-
- let mut planes = Vec::with_capacity(length / 2);
- for n in 0..length {
- let offset = n * PLANE_SIZE;
- let plane = &data[offset..offset + PLANE_SIZE];
- planes.push(Plane {
- normal: slice_to_vec3(&plane[0..12]),
- dist: slice_to_f32(&plane[12..16]),
- });
- }
-
- Ok(planes.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasPlanes<T> for Q3BspFile<T> {
- type PlanesIter<'a> = std::slice::Iter<'a, Plane>;
-
- fn planes_iter(&self) -> Self::PlanesIter<'_> {
- self.planes.iter()
- }
-
- fn get_plane(&self, idx: u32) -> &Plane {
- &self.planes[idx as usize]
- }
-}
diff --git a/stockton-levels/src/q3/textures.rs b/stockton-levels/src/q3/textures.rs
deleted file mode 100644
index 98c2fe4..0000000
--- a/stockton-levels/src/q3/textures.rs
+++ /dev/null
@@ -1,137 +0,0 @@
-use std::str;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::slice_to_u32;
-use crate::traits::textures::*;
-use crate::types::{ParseError, Result};
-
-const TEXTURE_LUMP_SIZE: usize = 64 + 4 + 4;
-
-/// Try to parse the given buffer as an entities lump.
-/// # Format
-/// Each entity is:
-/// string[64] name Texture name.
-/// int flags Surface flags.
-/// int contents Content flags.
-/// Length of entities is total lump size / TEXTURE_LUMP_SIZE (64 + 4 + 4)
-pub fn from_data(lump: &[u8]) -> Result<Box<[Texture]>> {
- if lump.is_empty() || lump.len() % TEXTURE_LUMP_SIZE != 0 {
- return Err(ParseError::Invalid);
- }
- let length = lump.len() / TEXTURE_LUMP_SIZE;
-
- let mut textures = Vec::with_capacity(length);
- for n in 0..length {
- let offset = n * TEXTURE_LUMP_SIZE;
- textures.push(Texture {
- name: str::from_utf8(&lump[offset..offset + 64])
- .map_err(|_| ParseError::Invalid)?
- .trim_matches('\0')
- .to_owned(),
- surface: SurfaceFlags::from_bits_truncate(slice_to_u32(
- &lump[offset + 64..offset + 68],
- )),
- contents: ContentsFlags::from_bits_truncate(slice_to_u32(
- &lump[offset + 68..offset + 72],
- )),
- });
- }
-
- Ok(textures.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasTextures for Q3BspFile<T> {
- type TexturesIter<'a> = std::slice::Iter<'a, Texture>;
-
- fn textures_iter(&self) -> Self::TexturesIter<'_> {
- self.textures.iter()
- }
-
- fn get_texture(&self, idx: u32) -> Option<&Texture> {
- if idx >= self.textures.len() as u32 {
- None
- } else {
- Some(&self.textures[idx as usize])
- }
- }
-}
-
-#[test]
-fn textures_single_texture() {
- let buf: &[u8] = &[
- b'T', b'E', b'S', b'T', b' ', b'T', b'E', b'X', b'T', b'U', b'R', b'E', 0x00, 0x00, 0x00,
- 0x00, // name (padded to 64 bytes)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x43, 0x00, 0x04, 0x00, // surface flags
- 0x09, 0x00, 0x00, 0x00, // contents flags
- ];
-
- let lump = from_data(buf).unwrap();
-
- assert_eq!(lump.len(), 1);
-
- assert_eq!(lump[0].name, "TEST TEXTURE");
- assert_eq!(
- lump[0].surface,
- SurfaceFlags::NO_DAMAGE | SurfaceFlags::SLICK | SurfaceFlags::FLESH | SurfaceFlags::DUST
- );
- assert_eq!(lump[0].contents, ContentsFlags::SOLID | ContentsFlags::LAVA);
-}
-
-#[test]
-fn textures_multiple_textures() {
- let buf: &[u8] = &[
- b'T', b'E', b'S', b'T', b' ', b'T', b'E', b'X', b'T', b'U', b'R', b'E', b'1', 0x00, 0x00,
- 0x00, // name (padded to 64 bytes)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x43, 0x00, 0x04, 0x00, // surface flags
- 0x09, 0x00, 0x00, 0x00, // contents flags
- b'T', b'E', b'S', b'T', b' ', b'T', b'E', b'X', b'T', b'U', b'R', b'E', b'2', 0x00, 0x00,
- 0x00, // name (padded to 64 bytes)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x2c, 0x10, 0x00, 0x00, // surface flags
- 0x01, 0x00, 0x00, 0x00, // contents flags
- b'T', b'E', b'S', b'T', b' ', b'T', b'E', b'X', b'T', b'U', b'R', b'E', b'3', 0x00, 0x00,
- 0x00, // name (padded to 64 bytes)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, // surface flags
- 0x41, 0x00, 0x00, 0x00, // contents flags
- ];
-
- let lump = from_data(buf).unwrap();
-
- assert_eq!(lump.len(), 3);
-
- assert_eq!(lump[0].name, "TEST TEXTURE1");
- assert_eq!(lump[1].name, "TEST TEXTURE2");
- assert_eq!(lump[2].name, "TEST TEXTURE3");
-
- assert_eq!(
- lump[0].surface,
- SurfaceFlags::NO_DAMAGE | SurfaceFlags::SLICK | SurfaceFlags::FLESH | SurfaceFlags::DUST
- );
- assert_eq!(
- lump[1].surface,
- SurfaceFlags::METAL_STEPS
- | SurfaceFlags::NO_MARKS
- | SurfaceFlags::LADDER
- | SurfaceFlags::SKY
- );
- assert_eq!(
- lump[2].surface,
- SurfaceFlags::POINT_LIGHT | SurfaceFlags::SKIP
- );
-
- assert_eq!(lump[0].contents, ContentsFlags::SOLID | ContentsFlags::LAVA);
- assert_eq!(lump[1].contents, ContentsFlags::SOLID);
- assert_eq!(lump[2].contents, ContentsFlags::SOLID | ContentsFlags::FOG);
-}
diff --git a/stockton-levels/src/q3/tree.rs b/stockton-levels/src/q3/tree.rs
deleted file mode 100644
index 05f1531..0000000
--- a/stockton-levels/src/q3/tree.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-//! 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<BspNode> {
- 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<BspNode> {
- 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<T: CoordSystem> HasBspTree<T> for Q3BspFile<T> {
- fn get_bsp_root(&self) -> &BspNode {
- &self.tree_root
- }
-}
diff --git a/stockton-levels/src/q3/vertices.rs b/stockton-levels/src/q3/vertices.rs
deleted file mode 100644
index 77ff667..0000000
--- a/stockton-levels/src/q3/vertices.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use std::convert::TryInto;
-
-use super::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::{slice_to_u32, slice_to_vec3};
-use crate::traits::vertices::*;
-use crate::types::{ParseError, Result, Rgba};
-
-/// The size of one vertex
-const VERTEX_SIZE: usize = (4 * 3) + (2 * 2 * 4) + (4 * 3) + 4;
-
-/// Parse a Vertices data from the data in a BSP file.
-pub fn verts_from_data(data: &[u8]) -> Result<Box<[Vertex]>> {
- if data.len() % VERTEX_SIZE != 0 {
- return Err(ParseError::Invalid);
- }
- let length = data.len() / VERTEX_SIZE;
-
- let mut vertices = Vec::with_capacity(length as usize);
- for n in 0..length {
- let offset = n * VERTEX_SIZE;
- let vertex = &data[offset..offset + VERTEX_SIZE];
-
- vertices.push(Vertex {
- position: slice_to_vec3(&vertex[0..12]),
- tex: TexCoord::from_bytes(&vertex[12..28].try_into().unwrap()),
- normal: slice_to_vec3(&vertex[28..40]),
- color: Rgba::from_slice(&vertex[40..44]),
- })
- }
-
- Ok(vertices.into_boxed_slice())
-}
-
-/// Parse the given data as a list of MeshVerts.
-pub fn meshverts_from_data(data: &[u8]) -> Result<Box<[MeshVert]>> {
- if data.len() % 4 != 0 {
- return Err(ParseError::Invalid);
- }
- let length = data.len() / 4;
-
- let mut meshverts = Vec::with_capacity(length as usize);
- for n in 0..length {
- meshverts.push(slice_to_u32(&data[n * 4..(n + 1) * 4]))
- }
-
- Ok(meshverts.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasVertices<T> for Q3BspFile<T> {
- type VerticesIter<'a> = std::slice::Iter<'a, Vertex>;
-
- fn vertices_iter(&self) -> Self::VerticesIter<'_> {
- self.vertices.iter()
- }
-
- fn get_vertex(&self, index: u32) -> &Vertex {
- &self.vertices[index as usize]
- }
-}
-
-impl<T: CoordSystem> HasMeshVerts<T> for Q3BspFile<T> {
- type MeshVertsIter<'a> = std::slice::Iter<'a, MeshVert>;
-
- fn meshverts_iter(&self) -> Self::MeshVertsIter<'_> {
- self.meshverts.iter()
- }
-
- fn get_meshvert<'a>(&self, index: u32) -> MeshVert {
- self.meshverts[index as usize]
- }
-}
diff --git a/stockton-levels/src/q3/visdata.rs b/stockton-levels/src/q3/visdata.rs
deleted file mode 100644
index d3cc532..0000000
--- a/stockton-levels/src/q3/visdata.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-//! Parses visdata from Q3 BSPs.
-
-use bitvec::prelude::*;
-use std::vec::IntoIter;
-
-use super::file::Q3BspFile;
-use crate::coords::CoordSystem;
-use crate::helpers::slice_to_i32;
-use crate::traits::visdata::*;
-use crate::types::{ParseError, Result};
-
-/// Stores cluster-to-cluster visibility information.
-pub fn from_data(data: &[u8]) -> Result<Box<[BitBox<Local, u8>]>> {
- if data.len() < 8 {
- return Err(ParseError::Invalid);
- }
-
- let n_vecs = slice_to_i32(&data[0..4]) as usize;
- let size_vecs = slice_to_i32(&data[4..8]) as usize;
-
- if data.len() - 8 != (n_vecs * size_vecs) {
- return Err(ParseError::Invalid);
- }
-
- let mut vecs = Vec::with_capacity(n_vecs);
- for n in 0..n_vecs {
- let offset = 8 + (n * size_vecs);
- let slice = &data[offset..offset + size_vecs];
- vecs.push(BitBox::from_slice(slice));
- }
-
- Ok(vecs.into_boxed_slice())
-}
-
-impl<T: CoordSystem> HasVisData for Q3BspFile<T> {
- type VisibleIterator = IntoIter<ClusterId>;
-
- fn all_visible_from(&self, from: ClusterId) -> Self::VisibleIterator {
- let mut visible = vec![];
-
- for (idx, val) in self.visdata[from as usize].iter().enumerate() {
- if *val {
- visible.push(idx as u32);
- }
- }
-
- visible.into_iter()
- }
-
- fn cluster_visible_from(&self, from: ClusterId, dest: ClusterId) -> bool {
- self.visdata[from as usize][dest as usize]
- }
-}
diff --git a/stockton-levels/src/traits/brushes.rs b/stockton-levels/src/traits/brushes.rs
deleted file mode 100644
index 911d068..0000000
--- a/stockton-levels/src/traits/brushes.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//! Parses the brushes & brushsides lumps from a bsp file
-
-use super::HasPlanes;
-use crate::coords::CoordSystem;
-
-/// One brush record. Used for collision detection.
-/// "Each brush describes a convex volume as defined by its surrounding surfaces."
-#[derive(Debug, Clone, PartialEq)]
-pub struct Brush {
- pub sides: Box<[BrushSide]>,
- pub texture_idx: usize,
-}
-
-/// Bounding surface for brush.
-#[derive(Debug, Clone, PartialEq)]
-pub struct BrushSide {
- pub plane_idx: usize,
- pub texture_idx: usize,
- pub is_opposing: bool,
-}
-
-pub trait HasBrushes<S: CoordSystem>: HasPlanes<S> {
- type BrushesIter<'a>: Iterator<Item = &'a Brush>;
-
- fn brushes_iter(&self) -> Self::BrushesIter<'_>;
- fn get_brush(&self, index: u32) -> &Brush;
-}
diff --git a/stockton-levels/src/traits/effects.rs b/stockton-levels/src/traits/effects.rs
deleted file mode 100644
index 75e696e..0000000
--- a/stockton-levels/src/traits/effects.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use super::HasBrushes;
-use crate::coords::CoordSystem;
-
-/// One effect definition
-#[derive(Debug, Clone, PartialEq)]
-pub struct Effect {
- /// The name of the effect - always 64 characters long
- pub name: String,
-
- /// The brush used for this effect
- pub brush_idx: u32, // todo: unknown: i32
-}
-
-pub trait HasEffects<S: CoordSystem>: HasBrushes<S> {
- type EffectsIter<'a>: Iterator<Item = &'a Effect>;
-
- fn effects_iter(&self) -> Self::EffectsIter<'_>;
- fn get_effect(&self, index: u32) -> &Effect;
-}
diff --git a/stockton-levels/src/traits/entities.rs b/stockton-levels/src/traits/entities.rs
deleted file mode 100644
index 330ef35..0000000
--- a/stockton-levels/src/traits/entities.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use std::collections::HashMap;
-use std::iter::Iterator;
-
-#[derive(Debug, Clone, PartialEq)]
-/// A game entity
-pub struct Entity {
- pub attributes: HashMap<String, String>,
-}
-
-pub trait HasEntities {
- type EntitiesIter<'a>: Iterator<Item = &'a Entity>;
-
- fn entities_iter(&self) -> Self::EntitiesIter<'_>;
-}
diff --git a/stockton-levels/src/traits/faces.rs b/stockton-levels/src/traits/faces.rs
deleted file mode 100644
index 00addc4..0000000
--- a/stockton-levels/src/traits/faces.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use na::{Vector2, Vector3};
-use std::ops::Range;
-
-use super::{HasEffects, HasLightMaps, HasMeshVerts, HasTextures};
-use crate::coords::CoordSystem;
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-#[repr(i32)]
-pub enum FaceType {
- Polygon = 1,
- Patch = 2,
- Mesh = 3,
- Billboard = 4,
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Face {
- pub face_type: FaceType,
- pub texture_idx: u32,
- pub effect_idx: Option<u32>,
- pub lightmap_idx: Option<u32>,
- pub vertices_idx: Range<u32>,
- pub meshverts_idx: Range<u32>,
-
- pub map_start: Vector2<u32>,
- pub map_size: Vector2<u32>,
- pub map_origin: Vector3<f32>,
- pub map_vecs: [Vector3<f32>; 2],
-
- pub normal: Vector3<f32>,
- pub size: Vector2<u32>,
-}
-
-pub trait HasFaces<S: CoordSystem>:
- HasTextures + HasEffects<S> + HasLightMaps + HasMeshVerts<S>
-{
- type FacesIter<'a>: Iterator<Item = &'a Face>;
-
- fn faces_iter(&self) -> Self::FacesIter<'_>;
- fn faces_len(&self) -> u32;
- fn get_face(&self, index: u32) -> &Face;
-}
diff --git a/stockton-levels/src/traits/light_maps.rs b/stockton-levels/src/traits/light_maps.rs
deleted file mode 100644
index 0ee468a..0000000
--- a/stockton-levels/src/traits/light_maps.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use std::fmt;
-
-use crate::types::Rgb;
-
-/// Stores light map textures that help make surface lighting more realistic
-#[derive(Clone)]
-pub struct LightMap {
- pub map: [[Rgb; 128]; 128],
-}
-
-impl PartialEq for LightMap {
- fn eq(&self, other: &LightMap) -> bool {
- for x in 0..128 {
- for y in 0..128 {
- if self.map[x][y] != other.map[x][y] {
- return false;
- }
- }
- }
- true
- }
-}
-
-impl fmt::Debug for LightMap {
- // rust can't derive debug for 3d arrays so done manually
- // \_( )_/
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "LightMap {{ map: [")?;
- for c in self.map.iter() {
- write!(f, "[")?;
- for x in c.iter() {
- write!(f, "{:?}, ", x)?;
- }
- write!(f, "], ")?;
- }
- write!(f, "}}")
- }
-}
-
-pub trait HasLightMaps {
- type LightMapsIter<'a>: Iterator<Item = &'a LightMap>;
-
- fn lightmaps_iter(&self) -> Self::LightMapsIter<'_>;
- fn get_lightmap(&self, index: u32) -> &LightMap;
-}
diff --git a/stockton-levels/src/traits/light_vols.rs b/stockton-levels/src/traits/light_vols.rs
deleted file mode 100644
index 2014fad..0000000
--- a/stockton-levels/src/traits/light_vols.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use crate::types::Rgb;
-
-#[derive(Debug, Clone, Copy)]
-pub struct LightVol {
- pub ambient: Rgb,
- pub directional: Rgb,
- pub dir: [u8; 2],
-}
-
-pub trait HasLightVols {
- type LightVolsIter<'a>: Iterator<Item = &'a LightVol>;
-
- fn lightvols_iter(&self) -> Self::LightVolsIter<'_>;
- fn get_lightvol(&self, index: u32) -> &LightVol;
-}
diff --git a/stockton-levels/src/traits/mod.rs b/stockton-levels/src/traits/mod.rs
deleted file mode 100644
index 84fa7eb..0000000
--- a/stockton-levels/src/traits/mod.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//! Traits for parts of files that can exist
-
-pub mod brushes;
-pub mod effects;
-pub mod entities;
-pub mod faces;
-pub mod light_maps;
-pub mod light_vols;
-pub mod models;
-pub mod planes;
-pub mod textures;
-pub mod tree;
-pub mod vertices;
-pub mod visdata;
-
-pub use self::brushes::HasBrushes;
-pub use self::effects::HasEffects;
-pub use self::entities::HasEntities;
-pub use self::faces::HasFaces;
-pub use self::light_maps::HasLightMaps;
-pub use self::light_vols::HasLightVols;
-pub use self::models::HasModels;
-pub use self::planes::HasPlanes;
-pub use self::textures::HasTextures;
-pub use self::tree::HasBspTree;
-pub use self::vertices::{HasMeshVerts, HasVertices};
-pub use self::visdata::HasVisData;
diff --git a/stockton-levels/src/traits/models.rs b/stockton-levels/src/traits/models.rs
deleted file mode 100644
index 58b5f74..0000000
--- a/stockton-levels/src/traits/models.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use na::Vector3;
-use std::ops::Range;
-
-use super::{HasBrushes, HasFaces};
-use crate::coords::CoordSystem;
-
-#[derive(Debug, Clone)]
-pub struct Model {
- pub mins: Vector3<f32>,
- pub maxs: Vector3<f32>,
- pub faces_idx: Range<u32>,
- pub brushes_idx: Range<u32>,
-}
-
-pub trait HasModels<S: CoordSystem>: HasFaces<S> + HasBrushes<S> {
- type ModelsIter<'a>: Iterator<Item = &'a Model>;
-
- fn models_iter(&self) -> Self::ModelsIter<'_>;
- fn get_model(&self, index: u32) -> &Model;
-}
diff --git a/stockton-levels/src/traits/planes.rs b/stockton-levels/src/traits/planes.rs
deleted file mode 100644
index ed48c63..0000000
--- a/stockton-levels/src/traits/planes.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use crate::coords::CoordSystem;
-use na::Vector3;
-use std::iter::Iterator;
-
-/// The planes lump from a BSP file.
-/// Found at lump index 2 in a q3 bsp.
-#[derive(Debug, Clone)]
-pub struct PlanesLump {
- pub planes: Box<[Plane]>,
-}
-
-/// Generic plane, referenced by nodes & brushsizes
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Plane {
- /// Plane normal
- pub normal: Vector3<f32>,
-
- /// Distance from origin to plane along normal
- pub dist: f32,
-}
-
-pub trait HasPlanes<S: CoordSystem> {
- type PlanesIter<'a>: Iterator<Item = &'a Plane>;
-
- fn planes_iter(&self) -> Self::PlanesIter<'_>;
- fn get_plane(&self, idx: u32) -> &Plane;
-}
diff --git a/stockton-levels/src/traits/textures.rs b/stockton-levels/src/traits/textures.rs
deleted file mode 100644
index 75764b6..0000000
--- a/stockton-levels/src/traits/textures.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-// 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 <http://www.gnu.org/licenses/>.
-
-use std::iter::Iterator;
-
-#[derive(Debug, Clone, PartialEq)]
-/// A texture from a BSP File.
-pub struct Texture {
- pub name: String,
- pub surface: SurfaceFlags,
- pub contents: ContentsFlags,
-}
-
-bitflags!(
- /// Extracted from the Q3 arena engine code.
- /// https://github.com/id-Software/Quake-III-Arena/blob/master/code/game/surfaceflags.h
- pub struct SurfaceFlags: u32 {
- /// never give falling damage
- const NO_DAMAGE = 0x1;
-
- /// affects game physics
- const SLICK = 0x2;
-
- /// lighting from environment map
- const SKY = 0x4;
-
- /// don't make missile explosions
- const NO_IMPACT = 0x10;
-
- /// function as a ladder
- const LADDER = 0x8;
-
- /// don't leave missile marks
- const NO_MARKS = 0x20;
-
- /// make flesh sounds and effects
- const FLESH = 0x40;
-
- /// don't generate a drawsurface at all
- const NODRAW = 0x80;
-
- /// make a primary bsp splitter
- const HINT = 0x01_00;
-
- /// completely ignore, allowing non-closed brushes
- const SKIP = 0x02_00;
-
- /// surface doesn't need a lightmap
- const NO_LIGHT_MAP = 0x04_00;
-
- /// generate lighting info at vertexes
- const POINT_LIGHT = 0x08_00;
-
- /// clanking footsteps
- const METAL_STEPS = 0x10_00;
-
- /// no footstep sounds
- const NO_STEPS = 0x20_00;
-
- /// don't collide against curves with this set
- const NON_SOLID = 0x40_00;
-
- /// act as a light filter during q3map -light
- const LIGHT_FILTER = 0x80_00;
-
- /// do per-pixel light shadow casting in q3map
- const ALPHA_SHADOW = 0x01_00_00;
-
- /// don't dlight even if solid (solid lava, skies)
- const NO_DLIGHT = 0x02_00_00;
-
- /// leave a dust trail when walking on this surface
- const DUST = 0x04_00_00;
- }
-);
-
-bitflags!(
- /// Extracted from the Q3 arena engine code. Less documented than `SurfaceFlags`.
- /// https://github.com/id-Software/Quake-III-Arena/blob/master/code/game/surfaceflags.h
- pub struct ContentsFlags: u32 {
- // an eye is never valid in a solid
- const SOLID = 0x1;
- const LAVA = 0x8;
- const SLIME = 0x10;
- const WATER = 0x20;
- const FOG = 0x40;
-
- const NOT_TEAM1 = 0x00_80;
- const NOT_TEAM2 = 0x01_00;
- const NOT_BOT_CLIP = 0x02_00;
-
- const AREA_PORTAL = 0x80_00;
-
- /// bot specific contents type
- const PLAYER_CLIP = 0x01_00_00;
-
- /// bot specific contents type
- const MONSTER_CLIP = 0x02_00_00;
-
- const TELEPORTER = 0x04_00_00;
- const JUMP_PAD = 0x08_00_00;
- const CLUSTER_PORTAL = 0x10_00_00;
- const DO_NOT_ENTER = 0x20_00_00;
- const BOT_CLIP = 0x40_00_00;
- const MOVER = 0x80_00_00;
-
- // removed before bsping an entity
- const ORIGIN = 0x01_00_00_00;
-
- // should never be on a brush, only in game
- const BODY = 0x02_00_00_00;
-
- /// brush not used for the bsp
- const DETAIL = 0x08_00_00_00;
-
- /// brush not used for the bsp
- const CORPSE = 0x04_00_00_00;
-
- /// brushes used for the bsp
- const STRUCTURAL = 0x10_00_00_00;
-
- /// don't consume surface fragments inside
- const TRANSLUCENT = 0x20_00_00_00;
-
- const TRIGGER = 0x40_00_00_00;
-
- /// don't leave bodies or items (death fog, lava)
- const NODROP = 0x80_00_00_00;
- }
-);
-
-pub trait HasTextures {
- type TexturesIter<'a>: Iterator<Item = &'a Texture>;
-
- fn textures_iter(&self) -> Self::TexturesIter<'_>;
- fn get_texture(&self, idx: u32) -> Option<&Texture>;
-}
diff --git a/stockton-levels/src/traits/tree.rs b/stockton-levels/src/traits/tree.rs
deleted file mode 100644
index f22be2c..0000000
--- a/stockton-levels/src/traits/tree.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-//! Parses the BSP tree into a usable format
-
-use super::{HasBrushes, HasFaces, HasVisData};
-use crate::coords::CoordSystem;
-use na::Vector3;
-
-/// A node in a BSP tree.
-/// Either has two children *or* a leaf entry.
-#[derive(Debug, Clone)]
-pub struct BspNode {
- pub plane_idx: u32,
- pub min: Vector3<i32>,
- pub max: Vector3<i32>,
- pub value: BspNodeValue,
-}
-
-#[derive(Debug, Clone)]
-pub enum BspNodeValue {
- Leaf(BspLeaf),
- Children(Box<BspNode>, Box<BspNode>),
-}
-
-/// A leaf in a BSP tree.
-/// Will be under a `BSPNode`, min and max values are stored there.
-#[derive(Debug, Clone)]
-pub struct BspLeaf {
- pub cluster_id: u32,
- pub area: i32,
- pub faces_idx: Box<[u32]>,
- pub brushes_idx: Box<[u32]>,
-}
-
-pub trait HasBspTree<S: CoordSystem>: HasFaces<S> + HasBrushes<S> + HasVisData {
- fn get_bsp_root(&self) -> &BspNode;
-}
diff --git a/stockton-levels/src/traits/vertices.rs b/stockton-levels/src/traits/vertices.rs
deleted file mode 100644
index 11cd681..0000000
--- a/stockton-levels/src/traits/vertices.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use crate::coords::CoordSystem;
-use crate::helpers::slice_to_f32;
-use crate::types::Rgba;
-use na::Vector3;
-
-/// A vertex, used to describe a face.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Vertex {
- pub position: Vector3<f32>,
- pub tex: TexCoord,
- pub normal: Vector3<f32>,
- pub color: Rgba,
-}
-
-/// Represents a TexCoord. 0 = surface, 1= lightmap.
-/// This could also be written as [[f32; 2]; 2]
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct TexCoord {
- pub u: [f32; 2],
- pub v: [f32; 2],
-}
-
-impl TexCoord {
- /// Internal function. Converts a slice to a TexCoord.
- pub fn from_bytes(bytes: &[u8; 16]) -> TexCoord {
- TexCoord {
- u: [slice_to_f32(&bytes[0..4]), slice_to_f32(&bytes[8..12])],
- v: [slice_to_f32(&bytes[4..8]), slice_to_f32(&bytes[12..16])],
- }
- }
-}
-
-/// A vertex offset, used to describe generalised triangle meshes
-pub type MeshVert = u32;
-
-pub trait HasVertices<S: CoordSystem> {
- type VerticesIter<'a>: Iterator<Item = &'a Vertex>;
-
- fn vertices_iter(&self) -> Self::VerticesIter<'_>;
- fn get_vertex(&self, index: u32) -> &Vertex;
-}
-
-pub trait HasMeshVerts<S: CoordSystem>: HasVertices<S> {
- type MeshVertsIter<'a>: Iterator<Item = &'a MeshVert>;
-
- fn meshverts_iter(&self) -> Self::MeshVertsIter<'_>;
- fn get_meshvert(&self, index: u32) -> MeshVert;
-
- fn resolve_meshvert(&self, index: u32, base: u32) -> &Vertex {
- self.get_vertex(self.get_meshvert(index) + base)
- }
-}
diff --git a/stockton-levels/src/traits/visdata.rs b/stockton-levels/src/traits/visdata.rs
deleted file mode 100644
index 7cd4d20..0000000
--- a/stockton-levels/src/traits/visdata.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 <http://www.gnu.org/licenses/>.
-
-use std::iter::Iterator;
-
-pub type ClusterId = u32;
-
-pub trait HasVisData {
- /// The iterator returned from all_visible_from
- type VisibleIterator: Iterator<Item = ClusterId>;
-
- /// Returns an iterator of all clusters visible from the given Cluster ID
- fn all_visible_from(&self, from: ClusterId) -> Self::VisibleIterator;
-
- /// Returns true if `dest` is visible from `from`.
- fn cluster_visible_from(&self, from: ClusterId, dest: ClusterId) -> bool;
-}
diff --git a/stockton-levels/src/types.rs b/stockton-levels/src/types.rs
index dd42a5e..dad824c 100644
--- a/stockton-levels/src/types.rs
+++ b/stockton-levels/src/types.rs
@@ -1,10 +1,10 @@
//! Various types used in parsed BSP files.
+use serde::{Deserialize, Serialize};
use std::convert::TryInto;
-use thiserror::Error;
/// RGBA Colour (0-255)
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Rgba {
pub r: u8,
pub g: u8,
@@ -32,7 +32,7 @@ impl Rgba {
}
/// RGB Colour (0-255)
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Rgb {
pub r: u8,
pub g: u8,
@@ -65,16 +65,3 @@ impl Rgb {
Rgb::from_bytes(slice.try_into().unwrap())
}
}
-
-#[derive(Error, Debug)]
-/// An error encountered while parsing.
-pub enum ParseError {
- #[error("Unsupported format")]
- Unsupported,
-
- #[error("Invalid file")]
- Invalid,
-}
-
-/// Standard result type.
-pub type Result<T> = std::result::Result<T, ParseError>;