1
0
Fork 0
mirror of https://codeberg.org/icewind/vbsp.git synced 2026-06-03 18:54:05 +02:00

Various fixes

This commit is contained in:
Jef 2019-04-14 19:55:56 +02:00
commit 96b42c80bf
2 changed files with 337 additions and 155 deletions

View file

@ -13,6 +13,7 @@ arrayvec = "0.4"
bitflags = "1.0" bitflags = "1.0"
bv = "0.11" bv = "0.11"
byteorder = "0.5" byteorder = "0.5"
itertools = "0.8"
[features] [features]
bench = [] bench = []

View file

@ -7,9 +7,12 @@ use arrayvec::ArrayString;
use bitflags::bitflags; use bitflags::bitflags;
use bv::BitVec; use bv::BitVec;
use byteorder::{LittleEndian, ReadBytesExt}; use byteorder::{LittleEndian, ReadBytesExt};
use itertools::{GroupBy, Itertools};
use std::{ use std::{
borrow::Cow,
convert::{TryFrom, TryInto},
fmt, fmt,
io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Take}, io::{self, Error, ErrorKind, Read, Seek, SeekFrom, Take},
ops::Deref, ops::Deref,
}; };
@ -39,19 +42,58 @@ macro_rules! elsize {
} }
} }
#[derive(Debug, Clone)]
#[repr(u32)]
pub enum FaceType {
Polygon = 1,
Patch = 2,
Mesh = 3,
Billboard = 4,
}
#[derive(Debug)]
pub struct FaceTypeError;
impl fmt::Display for FaceTypeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Invalid face type ID")
}
}
impl std::error::Error for FaceTypeError {}
impl TryFrom<u32> for FaceType {
type Error = FaceTypeError;
fn try_from(other: u32) -> Result<Self, FaceTypeError> {
const POLYGON: u32 = FaceType::Polygon as u32;
const PATCH: u32 = FaceType::Patch as u32;
const MESH: u32 = FaceType::Mesh as u32;
const BILLBOARD: u32 = FaceType::Billboard as u32;
match other {
POLYGON => Ok(FaceType::Polygon),
PATCH => Ok(FaceType::Patch),
MESH => Ok(FaceType::Mesh),
BILLBOARD => Ok(FaceType::Billboard),
_ => Err(FaceTypeError),
}
}
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct Directories { struct Directories {
entities: DirEntry, entities: DirEntry,
textures: DirEntry, textures: DirEntry,
planes: DirEntry, planes: DirEntry,
nodes: DirEntry, nodes: DirEntry,
leafs: DirEntry, leaves: DirEntry,
leaf_faces: DirEntry, leaf_faces: DirEntry,
leaf_brushes: DirEntry, leaf_brushes: DirEntry,
models: DirEntry, models: DirEntry,
brushes: DirEntry, brushes: DirEntry,
brush_sides: DirEntry, brush_sides: DirEntry,
vertexes: DirEntry, vertices: DirEntry,
mesh_verts: DirEntry, mesh_verts: DirEntry,
effects: DirEntry, effects: DirEntry,
faces: DirEntry, faces: DirEntry,
@ -60,7 +102,7 @@ struct Directories {
visdata: DirEntry, visdata: DirEntry,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Header { pub struct Header {
pub i: u8, pub i: u8,
pub b: u8, pub b: u8,
@ -68,19 +110,20 @@ pub struct Header {
pub p: u8, pub p: u8,
} }
#[derive(Debug, Default)] #[derive(Clone, Debug, Default)]
struct DirEntry { struct DirEntry {
offset: i32, offset: u32,
length: i32, length: u32,
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct LeafFace { pub struct LeafFace {
pub face: i32, pub face: u32,
} }
} }
#[derive(Clone)]
pub struct Entities { pub struct Entities {
entities: String, entities: String,
} }
@ -126,6 +169,7 @@ impl Entities {
} }
} }
#[derive(Clone)]
pub struct Entity<'a> { pub struct Entity<'a> {
buf: &'a str, buf: &'a str,
} }
@ -183,7 +227,7 @@ bitflags! {
const HINT = 0b0000_0000_0001_0000_0000; // Make a primary bsp splitter const HINT = 0b0000_0000_0001_0000_0000; // Make a primary bsp splitter
const SKIP = 0b0000_0000_0010_0000_0000; // Completely ignore, allowing non-closed brushes const SKIP = 0b0000_0000_0010_0000_0000; // Completely ignore, allowing non-closed brushes
const NOLIGHTMAP = 0b0000_0000_0100_0000_0000; // Surface doesn't need a lightmap const NOLIGHTMAP = 0b0000_0000_0100_0000_0000; // Surface doesn't need a lightmap
const POINTLIGHT = 0b0000_0000_1000_0000_0000; // Generate lighting info at vertexes const POINTLIGHT = 0b0000_0000_1000_0000_0000; // Generate lighting info at vertices
const METALSTEPS = 0b0000_0001_0000_0000_0000; // Clanking footsteps const METALSTEPS = 0b0000_0001_0000_0000_0000; // Clanking footsteps
const NOSTEPS = 0b0000_0010_0000_0000_0000; // No footstep sounds const NOSTEPS = 0b0000_0010_0000_0000_0000; // No footstep sounds
const NONSOLID = 0b0000_0100_0000_0000_0000; // Don't collide against curves with this set const NONSOLID = 0b0000_0100_0000_0000_0000; // Don't collide against curves with this set
@ -236,7 +280,7 @@ bitflags! {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Texture { pub struct Texture {
pub name: ArrayString<[u8; 64]>, pub name: ArrayString<[u8; 64]>,
pub flags: SurfFlags, pub flags: SurfFlags,
@ -244,11 +288,11 @@ pub struct Texture {
} }
impl ElementSize for Texture { impl ElementSize for Texture {
const SIZE: usize = std::mem::size_of::<i32>() * 2 + std::mem::size_of::<u8>() * 64; const SIZE: usize = std::mem::size_of::<u32>() * 2 + std::mem::size_of::<u8>() * 64;
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Plane { pub struct Plane {
pub normal: [f32; 3], pub normal: [f32; 3],
pub dist: f32, pub dist: f32,
@ -256,9 +300,9 @@ elsize! {
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Node { pub struct Node {
pub plane: i32, pub plane: u32,
pub children: [i32; 2], pub children: [i32; 2],
pub mins: [i32; 3], pub mins: [i32; 3],
pub maxs: [i32; 3], pub maxs: [i32; 3],
@ -266,107 +310,108 @@ elsize! {
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Leaf { pub struct Leaf {
pub cluster: i32, pub cluster: i32,
pub area: i32, pub area: u32,
pub mins: [i32; 3], pub mins: [i32; 3],
pub maxs: [i32; 3], pub maxs: [i32; 3],
pub leaf_face: i32, pub leaf_face: u32,
pub num_leaf_faces: i32, pub num_leaf_faces: u32,
pub leaf_brush: i32, pub leaf_brush: u32,
pub num_leaf_brushes: i32, pub num_leaf_brushes: u32,
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct LeafBrush { pub struct LeafBrush {
pub brush: i32, pub brush: u32,
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Model { pub struct Model {
pub mins: [f32; 3], pub mins: [f32; 3],
pub maxs: [f32; 3], pub maxs: [f32; 3],
pub face: i32, pub face: u32,
pub num_faces: i32, pub num_faces: u32,
pub brush: i32, pub brush: u32,
pub num_brushes: i32, pub num_brushes: u32,
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Brush { pub struct Brush {
pub brush_side: i32, pub brush_side: u32,
pub num_brush_sides: i32, pub num_brush_sides: u32,
pub texture: i32, pub texture: u32,
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct BrushSide { pub struct BrushSide {
pub plane: i32, pub plane: u32,
pub texture: i32, pub texture: u32,
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Vertex { pub struct Vertex {
pub position: [f32; 3], pub position: [f32; 3],
pub tex_coord1: [f32; 2], pub surface_texcoord: [f32; 2],
pub tex_coord2: [f32; 2], pub lightmap_texcoord: [f32; 2],
pub normal: [f32; 3], pub normal: [f32; 3],
pub color: [u8; 4], pub color: [u8; 4],
} }
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct MeshVert { pub struct MeshVert {
pub offset: i32, pub offset: u32,
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Effect { pub struct Effect {
pub name: ArrayString<[u8; 64]>, pub name: ArrayString<[u8; 64]>,
pub brush: i32, pub brush: u32,
pub unknown: i32, pub unknown: u32,
} }
impl ElementSize for Effect { impl ElementSize for Effect {
const SIZE: usize = std::mem::size_of::<i32>() * 2 + std::mem::size_of::<u8>() * 64; const SIZE: usize = std::mem::size_of::<u32>() * 2 + std::mem::size_of::<u8>() * 64;
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Face { pub struct Face {
pub texture: i32, pub texture: u32,
pub effect: i32, pub effect: u32,
pub face_type: i32, pub face_type: FaceType,
pub vertex: i32, pub vertex: u32,
pub num_vertexes: i32, pub num_vertexes: u32,
pub mesh_vert: i32, pub mesh_vert: u32,
pub num_mesh_verts: i32, pub num_mesh_verts: u32,
pub lm_index: i32, pub lm_index: u32,
pub lm_start: [i32; 2], pub lm_start: [u32; 2],
pub lm_size: [i32; 2], pub lm_size: [u32; 2],
pub lm_origin: [f32; 3], pub lm_origin: [f32; 3],
pub lm_vecs: [[f32; 3]; 2], pub lm_vecs: [[f32; 3]; 2],
pub normal: [f32; 3], pub normal: [f32; 3],
pub size: [i32; 2], pub size: [u32; 2],
} }
} }
const LIGHTMAP_SIZE: usize = 128; const LIGHTMAP_SIZE: usize = 128;
elsize! { elsize! {
#[derive(Clone)]
pub struct Lightmap { pub struct Lightmap {
map: [[[u8; 3]; LIGHTMAP_SIZE]; LIGHTMAP_SIZE], map: [[[u8; 3]; LIGHTMAP_SIZE]; LIGHTMAP_SIZE],
} }
@ -387,7 +432,7 @@ impl fmt::Debug for Lightmap {
} }
elsize! { elsize! {
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Lightvol { pub struct Lightvol {
ambient: [u8; 3], ambient: [u8; 3],
directional: [u8; 3], directional: [u8; 3],
@ -395,10 +440,10 @@ elsize! {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct VisData { pub struct VisData {
pub n_vecs: i32, // Number of vectors. pub n_vecs: u32, // Number of vectors.
pub sz_vecs: i32, // Size of each vector, in bytes. pub sz_vecs: u32, // Size of each vector, in bytes.
pub vecs: BitVec<u8>, // Visibility data. One bit per cluster per vector. pub vecs: BitVec<u8>, // Visibility data. One bit per cluster per vector.
} }
@ -407,7 +452,7 @@ struct BspReader<R> {
} }
impl<R: Read + Seek> BspReader<R> { impl<R: Read + Seek> BspReader<R> {
fn read_entities(&mut self, dir_entry: &DirEntry) -> Result<Entities> { fn read_entities(&mut self, dir_entry: &DirEntry) -> io::Result<Entities> {
let mut entities = Vec::with_capacity(dir_entry.length as usize); let mut entities = Vec::with_capacity(dir_entry.length as usize);
self.inner.seek(SeekFrom::Start(dir_entry.offset as u64))?; self.inner.seek(SeekFrom::Start(dir_entry.offset as u64))?;
self.inner self.inner
@ -419,13 +464,16 @@ impl<R: Read + Seek> BspReader<R> {
Ok(Entities { entities }) Ok(Entities { entities })
} }
fn read_entry<F, T>(&mut self, dir_entry: &DirEntry, mut f: F) -> Result<Vec<T>> fn read_entry<F, T>(&mut self, dir_entry: &DirEntry, mut f: F) -> io::Result<Vec<T>>
where where
F: FnMut(&mut BspReader<Take<&mut R>>) -> Result<T>, F: FnMut(&mut BspReader<Take<&mut R>>) -> io::Result<T>,
T: ElementSize, T: ElementSize,
{ {
if dir_entry.length % T::SIZE as i32 != 0 { if dir_entry.length % T::SIZE as u32 != 0 {
return Err(ErrorKind::InvalidData.into()); return Err(Error::new(
ErrorKind::InvalidData,
format!("Directory entry length isn't a multiple of element size (length: {}, element size: {})", dir_entry.length, T::SIZE),
));
} }
let num_entries = dir_entry.length as usize / T::SIZE; let num_entries = dir_entry.length as usize / T::SIZE;
@ -439,16 +487,12 @@ impl<R: Read + Seek> BspReader<R> {
entries.push(f(&mut reader)?); entries.push(f(&mut reader)?);
} }
if entries.len() != num_entries {
return Err(ErrorKind::InvalidData.into());
}
Ok(entries) Ok(entries)
} }
} }
impl<R: Read> BspReader<R> { impl<R: Read> BspReader<R> {
fn read_header(&mut self) -> Result<Header> { fn read_header(&mut self) -> io::Result<Header> {
let i = self.inner.read_u8()?; let i = self.inner.read_u8()?;
let b = self.inner.read_u8()?; let b = self.inner.read_u8()?;
let s = self.inner.read_u8()?; let s = self.inner.read_u8()?;
@ -456,11 +500,11 @@ impl<R: Read> BspReader<R> {
Ok(Header { i, b, s, p }) Ok(Header { i, b, s, p })
} }
fn read_version(&mut self) -> Result<i32> { fn read_version(&mut self) -> io::Result<u32> {
self.inner.read_i32::<LittleEndian>() self.inner.read_u32::<LittleEndian>()
} }
fn read_directories(&mut self) -> Result<Directories> { fn read_directories(&mut self) -> io::Result<Directories> {
macro_rules! read_dirs { macro_rules! read_dirs {
(@inner $out:expr,) => { (@inner $out:expr,) => {
$out $out
@ -468,8 +512,8 @@ impl<R: Read> BspReader<R> {
(@inner $out:expr, $name:ident $(, $rest:ident)*) => {{ (@inner $out:expr, $name:ident $(, $rest:ident)*) => {{
let mut out = $out; let mut out = $out;
out.$name = { out.$name = {
let offset = self.inner.read_i32::<LittleEndian>()?; let offset = self.inner.read_u32::<LittleEndian>()?;
let length = self.inner.read_i32::<LittleEndian>()?; let length = self.inner.read_u32::<LittleEndian>()?;
DirEntry { DirEntry {
offset, offset,
length, length,
@ -487,13 +531,13 @@ impl<R: Read> BspReader<R> {
textures, textures,
planes, planes,
nodes, nodes,
leafs, leaves,
leaf_faces, leaf_faces,
leaf_brushes, leaf_brushes,
models, models,
brushes, brushes,
brush_sides, brush_sides,
vertexes, vertices,
mesh_verts, mesh_verts,
effects, effects,
faces, faces,
@ -503,12 +547,22 @@ impl<R: Read> BspReader<R> {
)) ))
} }
fn read_texture(&mut self) -> Result<Texture> { fn read_texture(&mut self) -> io::Result<Texture> {
let name = self.read_name()?; let name = self.read_name()?;
let flags = SurfFlags::from_bits(self.inner.read_u32::<LittleEndian>()?) let flags =
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?; SurfFlags::from_bits(self.inner.read_u32::<LittleEndian>()?).ok_or_else(|| {
let contents = ContentFlags::from_bits(self.inner.read_u32::<LittleEndian>()?) Error::new(
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?; ErrorKind::InvalidData,
format!("Invalid surface flag in texture: {}", name),
)
})?;
let contents =
ContentFlags::from_bits(self.inner.read_u32::<LittleEndian>()?).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
format!("Invalid content flag in texture: {}", name),
)
})?;
Ok(Texture { Ok(Texture {
name, name,
flags, flags,
@ -516,7 +570,7 @@ impl<R: Read> BspReader<R> {
}) })
} }
fn read_plane(&mut self) -> Result<Plane> { fn read_plane(&mut self) -> io::Result<Plane> {
let x = self.inner.read_f32::<LittleEndian>()?; let x = self.inner.read_f32::<LittleEndian>()?;
let y = self.inner.read_f32::<LittleEndian>()?; let y = self.inner.read_f32::<LittleEndian>()?;
let z = self.inner.read_f32::<LittleEndian>()?; let z = self.inner.read_f32::<LittleEndian>()?;
@ -528,8 +582,8 @@ impl<R: Read> BspReader<R> {
Ok(plane) Ok(plane)
} }
fn read_node(&mut self) -> Result<Node> { fn read_node(&mut self) -> io::Result<Node> {
let plane = self.inner.read_i32::<LittleEndian>()?; let plane = self.inner.read_u32::<LittleEndian>()?;
let children = [ let children = [
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
@ -553,9 +607,9 @@ impl<R: Read> BspReader<R> {
Ok(node) Ok(node)
} }
fn read_leaf(&mut self) -> Result<Leaf> { fn read_leaf(&mut self) -> io::Result<Leaf> {
let cluster = self.inner.read_i32::<LittleEndian>()?; let cluster = self.inner.read_i32::<LittleEndian>()?;
let area = self.inner.read_i32::<LittleEndian>()?; let area = self.inner.read_u32::<LittleEndian>()?;
let mins = [ let mins = [
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
@ -566,10 +620,10 @@ impl<R: Read> BspReader<R> {
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_i32::<LittleEndian>()?,
]; ];
let leaf_face = self.inner.read_i32::<LittleEndian>()?; let leaf_face = self.inner.read_u32::<LittleEndian>()?;
let num_leaf_faces = self.inner.read_i32::<LittleEndian>()?; let num_leaf_faces = self.inner.read_u32::<LittleEndian>()?;
let leaf_brush = self.inner.read_i32::<LittleEndian>()?; let leaf_brush = self.inner.read_u32::<LittleEndian>()?;
let num_leaf_brushes = self.inner.read_i32::<LittleEndian>()?; let num_leaf_brushes = self.inner.read_u32::<LittleEndian>()?;
let leaf = Leaf { let leaf = Leaf {
cluster, cluster,
area, area,
@ -583,19 +637,19 @@ impl<R: Read> BspReader<R> {
Ok(leaf) Ok(leaf)
} }
fn read_leaf_face(&mut self) -> Result<LeafFace> { fn read_leaf_face(&mut self) -> io::Result<LeafFace> {
let face = self.inner.read_i32::<LittleEndian>()?; let face = self.inner.read_u32::<LittleEndian>()?;
let leaf_face = LeafFace { face }; let leaf_face = LeafFace { face };
Ok(leaf_face) Ok(leaf_face)
} }
fn read_leaf_brush(&mut self) -> Result<LeafBrush> { fn read_leaf_brush(&mut self) -> io::Result<LeafBrush> {
let brush = self.inner.read_i32::<LittleEndian>()?; let brush = self.inner.read_u32::<LittleEndian>()?;
let leaf_brush = LeafBrush { brush }; let leaf_brush = LeafBrush { brush };
Ok(leaf_brush) Ok(leaf_brush)
} }
fn read_model(&mut self) -> Result<Model> { fn read_model(&mut self) -> io::Result<Model> {
let mins = [ let mins = [
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
@ -606,10 +660,10 @@ impl<R: Read> BspReader<R> {
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
]; ];
let face = self.inner.read_i32::<LittleEndian>()?; let face = self.inner.read_u32::<LittleEndian>()?;
let num_faces = self.inner.read_i32::<LittleEndian>()?; let num_faces = self.inner.read_u32::<LittleEndian>()?;
let brush = self.inner.read_i32::<LittleEndian>()?; let brush = self.inner.read_u32::<LittleEndian>()?;
let num_brushes = self.inner.read_i32::<LittleEndian>()?; let num_brushes = self.inner.read_u32::<LittleEndian>()?;
let model = Model { let model = Model {
mins, mins,
maxs, maxs,
@ -621,10 +675,10 @@ impl<R: Read> BspReader<R> {
Ok(model) Ok(model)
} }
fn read_brush(&mut self) -> Result<Brush> { fn read_brush(&mut self) -> io::Result<Brush> {
let brush_side = self.inner.read_i32::<LittleEndian>()?; let brush_side = self.inner.read_u32::<LittleEndian>()?;
let num_brush_sides = self.inner.read_i32::<LittleEndian>()?; let num_brush_sides = self.inner.read_u32::<LittleEndian>()?;
let texture = self.inner.read_i32::<LittleEndian>()?; let texture = self.inner.read_u32::<LittleEndian>()?;
let brush = Brush { let brush = Brush {
brush_side, brush_side,
num_brush_sides, num_brush_sides,
@ -633,24 +687,24 @@ impl<R: Read> BspReader<R> {
Ok(brush) Ok(brush)
} }
fn read_brush_side(&mut self) -> Result<BrushSide> { fn read_brush_side(&mut self) -> io::Result<BrushSide> {
let plane = self.inner.read_i32::<LittleEndian>()?; let plane = self.inner.read_u32::<LittleEndian>()?;
let texture = self.inner.read_i32::<LittleEndian>()?; let texture = self.inner.read_u32::<LittleEndian>()?;
let brush_side = BrushSide { plane, texture }; let brush_side = BrushSide { plane, texture };
Ok(brush_side) Ok(brush_side)
} }
fn read_vertex(&mut self) -> Result<Vertex> { fn read_vertex(&mut self) -> io::Result<Vertex> {
let position = [ let position = [
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
]; ];
let tex_coord1 = [ let surface_texcoord = [
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
]; ];
let tex_coord2 = [ let lightmap_texcoord = [
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
]; ];
@ -667,29 +721,31 @@ impl<R: Read> BspReader<R> {
]; ];
let vertex = Vertex { let vertex = Vertex {
position, position,
tex_coord1, surface_texcoord,
tex_coord2, lightmap_texcoord,
normal, normal,
color, color,
}; };
Ok(vertex) Ok(vertex)
} }
fn read_mesh_vert(&mut self) -> Result<MeshVert> { fn read_mesh_vert(&mut self) -> io::Result<MeshVert> {
let offset = self.inner.read_i32::<LittleEndian>()?; let offset = self.inner.read_u32::<LittleEndian>()?;
let mesh_vert = MeshVert { offset }; let mesh_vert = MeshVert { offset };
Ok(mesh_vert) Ok(mesh_vert)
} }
fn read_name(&mut self) -> Result<ArrayString<[u8; 64]>> { fn read_name(&mut self) -> io::Result<ArrayString<[u8; 64]>> {
use std::str; use std::str;
let mut name_buf = [0u8; 64]; let mut name_buf = [0u8; 64];
self.inner.read_exact(&mut name_buf)?; self.inner.read_exact(&mut name_buf)?;
let zero_pos = name_buf let zero_pos = name_buf.iter().position(|c| *c == 0).ok_or_else(|| {
.iter() Error::new(
.position(|c| *c == 0) ErrorKind::InvalidData,
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?; format!("Name isn't null-terminated"),
)
})?;
let name = &name_buf[..zero_pos]; let name = &name_buf[..zero_pos];
Ok(ArrayString::from( Ok(ArrayString::from(
str::from_utf8(name).map_err(|err| Error::new(ErrorKind::InvalidData, err))?, str::from_utf8(name).map_err(|err| Error::new(ErrorKind::InvalidData, err))?,
@ -697,10 +753,10 @@ impl<R: Read> BspReader<R> {
.expect("Programmer error: it should be impossible for the string to exceed the capacity")) .expect("Programmer error: it should be impossible for the string to exceed the capacity"))
} }
fn read_effect(&mut self) -> Result<Effect> { fn read_effect(&mut self) -> io::Result<Effect> {
let name = self.read_name()?; let name = self.read_name()?;
let brush = self.inner.read_i32::<LittleEndian>()?; let brush = self.inner.read_u32::<LittleEndian>()?;
let unknown = self.inner.read_i32::<LittleEndian>()?; let unknown = self.inner.read_u32::<LittleEndian>()?;
Ok(Effect { Ok(Effect {
name, name,
brush, brush,
@ -708,22 +764,26 @@ impl<R: Read> BspReader<R> {
}) })
} }
fn read_face(&mut self) -> Result<Face> { fn read_face(&mut self) -> io::Result<Face> {
let texture = self.inner.read_i32::<LittleEndian>()?; let texture = self.inner.read_u32::<LittleEndian>()?;
let effect = self.inner.read_i32::<LittleEndian>()?; let effect = self.inner.read_u32::<LittleEndian>()?;
let face_type = self.inner.read_i32::<LittleEndian>()?; let face_type = self
let vertex = self.inner.read_i32::<LittleEndian>()?; .inner
let num_vertexes = self.inner.read_i32::<LittleEndian>()?; .read_u32::<LittleEndian>()?
let mesh_vert = self.inner.read_i32::<LittleEndian>()?; .try_into()
let num_mesh_verts = self.inner.read_i32::<LittleEndian>()?; .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
let lm_index = self.inner.read_i32::<LittleEndian>()?; let vertex = self.inner.read_u32::<LittleEndian>()?;
let num_vertexes = self.inner.read_u32::<LittleEndian>()?;
let mesh_vert = self.inner.read_u32::<LittleEndian>()?;
let num_mesh_verts = self.inner.read_u32::<LittleEndian>()?;
let lm_index = self.inner.read_u32::<LittleEndian>()?;
let lm_start = [ let lm_start = [
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
]; ];
let lm_size = [ let lm_size = [
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
]; ];
let lm_origin = [ let lm_origin = [
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
@ -747,8 +807,8 @@ impl<R: Read> BspReader<R> {
self.inner.read_f32::<LittleEndian>()?, self.inner.read_f32::<LittleEndian>()?,
]; ];
let size = [ let size = [
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
self.inner.read_i32::<LittleEndian>()?, self.inner.read_u32::<LittleEndian>()?,
]; ];
let face = Face { let face = Face {
texture, texture,
@ -769,7 +829,7 @@ impl<R: Read> BspReader<R> {
Ok(face) Ok(face)
} }
fn read_lightmap(&mut self) -> Result<Lightmap> { fn read_lightmap(&mut self) -> io::Result<Lightmap> {
use std::ptr; use std::ptr;
const NUM_BYTES: usize = LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3; const NUM_BYTES: usize = LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3;
@ -793,7 +853,7 @@ impl<R: Read> BspReader<R> {
}) })
} }
fn read_lightvol(&mut self) -> Result<Lightvol> { fn read_lightvol(&mut self) -> io::Result<Lightvol> {
let ambient = [ let ambient = [
self.inner.read_u8()?, self.inner.read_u8()?,
self.inner.read_u8()?, self.inner.read_u8()?,
@ -812,9 +872,9 @@ impl<R: Read> BspReader<R> {
}) })
} }
fn read_visdata(&mut self) -> Result<VisData> { fn read_visdata(&mut self) -> io::Result<VisData> {
let n_vecs = self.inner.read_i32::<LittleEndian>()?; let n_vecs = self.inner.read_u32::<LittleEndian>()?;
let sz_vecs = self.inner.read_i32::<LittleEndian>()?; let sz_vecs = self.inner.read_u32::<LittleEndian>()?;
let vecs_size = n_vecs as usize * sz_vecs as usize; let vecs_size = n_vecs as usize * sz_vecs as usize;
let mut vecs = Vec::with_capacity(vecs_size); let mut vecs = Vec::with_capacity(vecs_size);
self.inner self.inner
@ -822,8 +882,18 @@ impl<R: Read> BspReader<R> {
.take(vecs_size as u64) .take(vecs_size as u64)
.read_to_end(&mut vecs)?; .read_to_end(&mut vecs)?;
if vecs.len() != vecs_size { if vecs.len() < vecs_size {
return Err(Error::from(ErrorKind::InvalidData)); return Err(Error::new(
ErrorKind::InvalidData,
format!("Unexpected EOF while reading VisData"),
));
}
if vecs.len() > vecs_size {
return Err(Error::new(
ErrorKind::InvalidData,
format!("Extra data at end of file"),
));
} }
let vecs = BitVec::from_bits(vecs); let vecs = BitVec::from_bits(vecs);
@ -837,11 +907,18 @@ impl<R: Read> BspReader<R> {
} }
} }
#[derive(Debug)]
pub struct Handle<'a, T> { pub struct Handle<'a, T> {
bsp: &'a Bsp, bsp: &'a Bsp,
data: &'a T, data: &'a T,
} }
impl<T> Clone for Handle<'_, T> {
fn clone(&self) -> Self {
Handle { ..*self }
}
}
impl<'a, T> Handle<'a, T> { impl<'a, T> Handle<'a, T> {
pub fn as_ref(&self) -> &'a T { pub fn as_ref(&self) -> &'a T {
self.data self.data
@ -856,6 +933,81 @@ impl<T> Deref for Handle<'_, T> {
} }
} }
#[derive(Debug, Clone)]
pub struct Leaves {
leaves: Vec<Leaf>,
}
impl Leaves {
pub fn new(mut leaves: Vec<Leaf>) -> Self {
leaves.sort_unstable_by_key(|leaf| leaf.cluster);
Leaves { leaves }
}
pub fn iter(&self) -> impl Iterator<Item = &Leaf> {
self.into_iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Leaf> {
self.into_iter()
}
pub fn into_inner(self) -> Vec<Leaf> {
self.leaves
}
// TODO: There's no syntax for `-> T where &T: IntoIterator<...>` and `GroupBy`
// doesn't implement `IntoIterator` directly, only `&GroupBy`, so we have
// to explicitly specify the type.
pub fn clusters<'this>(
&'this self,
) -> GroupBy<i32, impl Iterator<Item = &'this Leaf>, impl FnMut(&&'this Leaf) -> i32> {
self.leaves.iter().group_by(|leaf: &&Leaf| leaf.cluster)
}
}
impl From<Vec<Leaf>> for Leaves {
fn from(other: Vec<Leaf>) -> Self {
Self::new(other)
}
}
impl Deref for Leaves {
type Target = [Leaf];
fn deref(&self) -> &Self::Target {
&self.leaves
}
}
impl IntoIterator for Leaves {
type IntoIter = <Vec<Leaf> as IntoIterator>::IntoIter;
type Item = Leaf;
fn into_iter(self) -> Self::IntoIter {
self.leaves.into_iter()
}
}
impl<'a> IntoIterator for &'a Leaves {
type IntoIter = <&'a [Leaf] as IntoIterator>::IntoIter;
type Item = &'a Leaf;
fn into_iter(self) -> Self::IntoIter {
(&self.leaves[..]).into_iter()
}
}
impl<'a> IntoIterator for &'a mut Leaves {
type IntoIter = <&'a mut [Leaf] as IntoIterator>::IntoIter;
type Item = &'a mut Leaf;
fn into_iter(self) -> Self::IntoIter {
(&mut self.leaves[..]).into_iter()
}
}
// TODO: Store all the allocated objects inline to improve cache usage // TODO: Store all the allocated objects inline to improve cache usage
#[derive(Debug)] #[derive(Debug)]
pub struct Bsp { pub struct Bsp {
@ -864,13 +1016,13 @@ pub struct Bsp {
pub textures: Vec<Texture>, pub textures: Vec<Texture>,
pub planes: Vec<Plane>, pub planes: Vec<Plane>,
pub nodes: Vec<Node>, pub nodes: Vec<Node>,
pub leafs: Vec<Leaf>, pub leaves: Leaves,
pub leaf_faces: Vec<LeafFace>, pub leaf_faces: Vec<LeafFace>,
pub leaf_brushes: Vec<LeafBrush>, pub leaf_brushes: Vec<LeafBrush>,
pub models: Vec<Model>, pub models: Vec<Model>,
pub brushes: Vec<Brush>, pub brushes: Vec<Brush>,
pub brush_sides: Vec<BrushSide>, pub brush_sides: Vec<BrushSide>,
pub vertexes: Vec<Vertex>, pub vertices: Vec<Vertex>,
pub mesh_verts: Vec<MeshVert>, pub mesh_verts: Vec<MeshVert>,
pub effects: Vec<Effect>, pub effects: Vec<Effect>,
pub faces: Vec<Face>, pub faces: Vec<Face>,
@ -880,7 +1032,7 @@ pub struct Bsp {
} }
impl Bsp { impl Bsp {
pub fn read<R: Read + Seek>(reader: R) -> Result<Self> { pub fn read<R: Read + Seek>(reader: R) -> io::Result<Self> {
const EXPECTED_HEADER: Header = Header { const EXPECTED_HEADER: Header = Header {
i: b'I', i: b'I',
b: b'B', b: b'B',
@ -888,7 +1040,7 @@ impl Bsp {
p: b'P', p: b'P',
}; };
// TODO: Use this to decide on the version to parse it as // TODO: Use this to decide on the version to parse it as
const EXPECTED_VERSION: i32 = 0x2e; const EXPECTED_VERSION: u32 = 0x2e;
let mut reader = BspReader { inner: reader }; let mut reader = BspReader { inner: reader };
let header = reader.read_header()?; let header = reader.read_header()?;
@ -906,13 +1058,15 @@ impl Bsp {
let textures = reader.read_entry(&dir_entries.textures, |r| r.read_texture())?; let textures = reader.read_entry(&dir_entries.textures, |r| r.read_texture())?;
let planes = reader.read_entry(&dir_entries.planes, |r| r.read_plane())?; let planes = reader.read_entry(&dir_entries.planes, |r| r.read_plane())?;
let nodes = reader.read_entry(&dir_entries.nodes, |r| r.read_node())?; let nodes = reader.read_entry(&dir_entries.nodes, |r| r.read_node())?;
let leafs = reader.read_entry(&dir_entries.leafs, |r| r.read_leaf())?; let leaves = reader
.read_entry(&dir_entries.leaves, |r| r.read_leaf())?
.into();
let leaf_faces = reader.read_entry(&dir_entries.leaf_faces, |r| r.read_leaf_face())?; let leaf_faces = reader.read_entry(&dir_entries.leaf_faces, |r| r.read_leaf_face())?;
let leaf_brushes = reader.read_entry(&dir_entries.leaf_brushes, |r| r.read_leaf_brush())?; let leaf_brushes = reader.read_entry(&dir_entries.leaf_brushes, |r| r.read_leaf_brush())?;
let models = reader.read_entry(&dir_entries.models, |r| r.read_model())?; let models = reader.read_entry(&dir_entries.models, |r| r.read_model())?;
let brushes = reader.read_entry(&dir_entries.brushes, |r| r.read_brush())?; let brushes = reader.read_entry(&dir_entries.brushes, |r| r.read_brush())?;
let brush_sides = reader.read_entry(&dir_entries.brush_sides, |r| r.read_brush_side())?; let brush_sides = reader.read_entry(&dir_entries.brush_sides, |r| r.read_brush_side())?;
let vertexes = reader.read_entry(&dir_entries.vertexes, |r| r.read_vertex())?; let vertices = reader.read_entry(&dir_entries.vertices, |r| r.read_vertex())?;
let mesh_verts = reader.read_entry(&dir_entries.mesh_verts, |r| r.read_mesh_vert())?; let mesh_verts = reader.read_entry(&dir_entries.mesh_verts, |r| r.read_mesh_vert())?;
let effects = reader.read_entry(&dir_entries.effects, |r| r.read_effect())?; let effects = reader.read_entry(&dir_entries.effects, |r| r.read_effect())?;
let faces = reader.read_entry(&dir_entries.faces, |r| r.read_face())?; let faces = reader.read_entry(&dir_entries.faces, |r| r.read_face())?;
@ -930,13 +1084,13 @@ impl Bsp {
textures, textures,
planes, planes,
nodes, nodes,
leafs, leaves,
leaf_faces, leaf_faces,
leaf_brushes, leaf_brushes,
models, models,
brushes, brushes,
brush_sides, brush_sides,
vertexes, vertices,
mesh_verts, mesh_verts,
effects, effects,
faces, faces,
@ -948,7 +1102,7 @@ impl Bsp {
} }
pub fn leaf(&self, n: usize) -> Option<Handle<'_, Leaf>> { pub fn leaf(&self, n: usize) -> Option<Handle<'_, Leaf>> {
self.leafs.get(n).map(|leaf| Handle { self.leaves.get(n).map(|leaf| Handle {
bsp: self, bsp: self,
data: leaf, data: leaf,
}) })
@ -1007,10 +1161,37 @@ impl Bsp {
} }
} }
impl Handle<'_, Face> { impl<'a, T> Handle<'a, T> {
pub fn new(bsp: &'a Bsp, data: &'a T) -> Self {
Handle { bsp, data }
}
}
impl<'a> Handle<'a, Face> {
pub fn texture(&self) -> Option<&Texture> { pub fn texture(&self) -> Option<&Texture> {
self.bsp.texture(self.texture as _) self.bsp.texture(self.texture as _)
} }
pub fn vertices(&self) -> impl Iterator<Item = Cow<'a, Vertex>> {
use itertools::Either;
match self.face_type {
FaceType::Polygon | FaceType::Mesh => {
let start = self.mesh_vert as usize;
let end = start + self.num_mesh_verts as usize;
let bsp = self.bsp;
let vertex = self.vertex;
Either::Left(
bsp.mesh_verts[start..end]
.iter()
.map(move |mv| Cow::Borrowed(&bsp.vertices[(mv.offset + vertex) as usize])),
)
}
// TODO
_ => Either::Right(std::iter::empty()),
}
}
} }
impl Handle<'_, Node> { impl Handle<'_, Node> {
@ -1029,7 +1210,7 @@ impl<'a> Handle<'a, Leaf> {
None None
} else { } else {
Some( Some(
bsp.leafs bsp.leaves
.iter() .iter()
.filter(move |leaf| { .filter(move |leaf| {
if leaf.cluster == cluster { if leaf.cluster == cluster {