mirror of
https://codeberg.org/icewind/vbsp.git
synced 2026-06-03 10:44:07 +02:00
Various fixes
This commit is contained in:
parent
26b7dcd69b
commit
96b42c80bf
2 changed files with 337 additions and 155 deletions
|
|
@ -13,6 +13,7 @@ arrayvec = "0.4"
|
|||
bitflags = "1.0"
|
||||
bv = "0.11"
|
||||
byteorder = "0.5"
|
||||
itertools = "0.8"
|
||||
|
||||
[features]
|
||||
bench = []
|
||||
|
|
|
|||
491
src/lib.rs
491
src/lib.rs
|
|
@ -7,9 +7,12 @@ use arrayvec::ArrayString;
|
|||
use bitflags::bitflags;
|
||||
use bv::BitVec;
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use itertools::{GroupBy, Itertools};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt,
|
||||
io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Take},
|
||||
io::{self, Error, ErrorKind, Read, Seek, SeekFrom, Take},
|
||||
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)]
|
||||
struct Directories {
|
||||
entities: DirEntry,
|
||||
textures: DirEntry,
|
||||
planes: DirEntry,
|
||||
nodes: DirEntry,
|
||||
leafs: DirEntry,
|
||||
leaves: DirEntry,
|
||||
leaf_faces: DirEntry,
|
||||
leaf_brushes: DirEntry,
|
||||
models: DirEntry,
|
||||
brushes: DirEntry,
|
||||
brush_sides: DirEntry,
|
||||
vertexes: DirEntry,
|
||||
vertices: DirEntry,
|
||||
mesh_verts: DirEntry,
|
||||
effects: DirEntry,
|
||||
faces: DirEntry,
|
||||
|
|
@ -60,7 +102,7 @@ struct Directories {
|
|||
visdata: DirEntry,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Header {
|
||||
pub i: u8,
|
||||
pub b: u8,
|
||||
|
|
@ -68,19 +110,20 @@ pub struct Header {
|
|||
pub p: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct DirEntry {
|
||||
offset: i32,
|
||||
length: i32,
|
||||
offset: u32,
|
||||
length: u32,
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LeafFace {
|
||||
pub face: i32,
|
||||
pub face: u32,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Entities {
|
||||
entities: String,
|
||||
}
|
||||
|
|
@ -126,6 +169,7 @@ impl Entities {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Entity<'a> {
|
||||
buf: &'a str,
|
||||
}
|
||||
|
|
@ -183,7 +227,7 @@ bitflags! {
|
|||
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 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 NOSTEPS = 0b0000_0010_0000_0000_0000; // No footstep sounds
|
||||
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 name: ArrayString<[u8; 64]>,
|
||||
pub flags: SurfFlags,
|
||||
|
|
@ -244,11 +288,11 @@ pub struct 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! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Plane {
|
||||
pub normal: [f32; 3],
|
||||
pub dist: f32,
|
||||
|
|
@ -256,9 +300,9 @@ elsize! {
|
|||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Node {
|
||||
pub plane: i32,
|
||||
pub plane: u32,
|
||||
pub children: [i32; 2],
|
||||
pub mins: [i32; 3],
|
||||
pub maxs: [i32; 3],
|
||||
|
|
@ -266,107 +310,108 @@ elsize! {
|
|||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Leaf {
|
||||
pub cluster: i32,
|
||||
pub area: i32,
|
||||
pub area: u32,
|
||||
pub mins: [i32; 3],
|
||||
pub maxs: [i32; 3],
|
||||
pub leaf_face: i32,
|
||||
pub num_leaf_faces: i32,
|
||||
pub leaf_brush: i32,
|
||||
pub num_leaf_brushes: i32,
|
||||
pub leaf_face: u32,
|
||||
pub num_leaf_faces: u32,
|
||||
pub leaf_brush: u32,
|
||||
pub num_leaf_brushes: u32,
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LeafBrush {
|
||||
pub brush: i32,
|
||||
pub brush: u32,
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Model {
|
||||
pub mins: [f32; 3],
|
||||
pub maxs: [f32; 3],
|
||||
pub face: i32,
|
||||
pub num_faces: i32,
|
||||
pub brush: i32,
|
||||
pub num_brushes: i32,
|
||||
pub face: u32,
|
||||
pub num_faces: u32,
|
||||
pub brush: u32,
|
||||
pub num_brushes: u32,
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Brush {
|
||||
pub brush_side: i32,
|
||||
pub num_brush_sides: i32,
|
||||
pub texture: i32,
|
||||
pub brush_side: u32,
|
||||
pub num_brush_sides: u32,
|
||||
pub texture: u32,
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BrushSide {
|
||||
pub plane: i32,
|
||||
pub texture: i32,
|
||||
pub plane: u32,
|
||||
pub texture: u32,
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Vertex {
|
||||
pub position: [f32; 3],
|
||||
pub tex_coord1: [f32; 2],
|
||||
pub tex_coord2: [f32; 2],
|
||||
pub surface_texcoord: [f32; 2],
|
||||
pub lightmap_texcoord: [f32; 2],
|
||||
pub normal: [f32; 3],
|
||||
pub color: [u8; 4],
|
||||
}
|
||||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshVert {
|
||||
pub offset: i32,
|
||||
pub offset: u32,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Effect {
|
||||
pub name: ArrayString<[u8; 64]>,
|
||||
pub brush: i32,
|
||||
pub unknown: i32,
|
||||
pub brush: u32,
|
||||
pub unknown: u32,
|
||||
}
|
||||
|
||||
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! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Face {
|
||||
pub texture: i32,
|
||||
pub effect: i32,
|
||||
pub face_type: i32,
|
||||
pub vertex: i32,
|
||||
pub num_vertexes: i32,
|
||||
pub mesh_vert: i32,
|
||||
pub num_mesh_verts: i32,
|
||||
pub lm_index: i32,
|
||||
pub lm_start: [i32; 2],
|
||||
pub lm_size: [i32; 2],
|
||||
pub texture: u32,
|
||||
pub effect: u32,
|
||||
pub face_type: FaceType,
|
||||
pub vertex: u32,
|
||||
pub num_vertexes: u32,
|
||||
pub mesh_vert: u32,
|
||||
pub num_mesh_verts: u32,
|
||||
pub lm_index: u32,
|
||||
pub lm_start: [u32; 2],
|
||||
pub lm_size: [u32; 2],
|
||||
pub lm_origin: [f32; 3],
|
||||
pub lm_vecs: [[f32; 3]; 2],
|
||||
pub normal: [f32; 3],
|
||||
pub size: [i32; 2],
|
||||
pub size: [u32; 2],
|
||||
}
|
||||
}
|
||||
|
||||
const LIGHTMAP_SIZE: usize = 128;
|
||||
|
||||
elsize! {
|
||||
#[derive(Clone)]
|
||||
pub struct Lightmap {
|
||||
map: [[[u8; 3]; LIGHTMAP_SIZE]; LIGHTMAP_SIZE],
|
||||
}
|
||||
|
|
@ -387,7 +432,7 @@ impl fmt::Debug for Lightmap {
|
|||
}
|
||||
|
||||
elsize! {
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lightvol {
|
||||
ambient: [u8; 3],
|
||||
directional: [u8; 3],
|
||||
|
|
@ -395,10 +440,10 @@ elsize! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VisData {
|
||||
pub n_vecs: i32, // Number of vectors.
|
||||
pub sz_vecs: i32, // Size of each vector, in bytes.
|
||||
pub n_vecs: u32, // Number of vectors.
|
||||
pub sz_vecs: u32, // Size of each vector, in bytes.
|
||||
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> {
|
||||
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);
|
||||
self.inner.seek(SeekFrom::Start(dir_entry.offset as u64))?;
|
||||
self.inner
|
||||
|
|
@ -419,13 +464,16 @@ impl<R: Read + Seek> BspReader<R> {
|
|||
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
|
||||
F: FnMut(&mut BspReader<Take<&mut R>>) -> Result<T>,
|
||||
F: FnMut(&mut BspReader<Take<&mut R>>) -> io::Result<T>,
|
||||
T: ElementSize,
|
||||
{
|
||||
if dir_entry.length % T::SIZE as i32 != 0 {
|
||||
return Err(ErrorKind::InvalidData.into());
|
||||
if dir_entry.length % T::SIZE as u32 != 0 {
|
||||
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;
|
||||
|
|
@ -439,16 +487,12 @@ impl<R: Read + Seek> BspReader<R> {
|
|||
entries.push(f(&mut reader)?);
|
||||
}
|
||||
|
||||
if entries.len() != num_entries {
|
||||
return Err(ErrorKind::InvalidData.into());
|
||||
}
|
||||
|
||||
Ok(entries)
|
||||
}
|
||||
}
|
||||
|
||||
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 b = 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 })
|
||||
}
|
||||
|
||||
fn read_version(&mut self) -> Result<i32> {
|
||||
self.inner.read_i32::<LittleEndian>()
|
||||
fn read_version(&mut self) -> io::Result<u32> {
|
||||
self.inner.read_u32::<LittleEndian>()
|
||||
}
|
||||
|
||||
fn read_directories(&mut self) -> Result<Directories> {
|
||||
fn read_directories(&mut self) -> io::Result<Directories> {
|
||||
macro_rules! read_dirs {
|
||||
(@inner $out:expr,) => {
|
||||
$out
|
||||
|
|
@ -468,8 +512,8 @@ impl<R: Read> BspReader<R> {
|
|||
(@inner $out:expr, $name:ident $(, $rest:ident)*) => {{
|
||||
let mut out = $out;
|
||||
out.$name = {
|
||||
let offset = self.inner.read_i32::<LittleEndian>()?;
|
||||
let length = self.inner.read_i32::<LittleEndian>()?;
|
||||
let offset = self.inner.read_u32::<LittleEndian>()?;
|
||||
let length = self.inner.read_u32::<LittleEndian>()?;
|
||||
DirEntry {
|
||||
offset,
|
||||
length,
|
||||
|
|
@ -487,13 +531,13 @@ impl<R: Read> BspReader<R> {
|
|||
textures,
|
||||
planes,
|
||||
nodes,
|
||||
leafs,
|
||||
leaves,
|
||||
leaf_faces,
|
||||
leaf_brushes,
|
||||
models,
|
||||
brushes,
|
||||
brush_sides,
|
||||
vertexes,
|
||||
vertices,
|
||||
mesh_verts,
|
||||
effects,
|
||||
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 flags = SurfFlags::from_bits(self.inner.read_u32::<LittleEndian>()?)
|
||||
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
|
||||
let contents = ContentFlags::from_bits(self.inner.read_u32::<LittleEndian>()?)
|
||||
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
|
||||
let flags =
|
||||
SurfFlags::from_bits(self.inner.read_u32::<LittleEndian>()?).ok_or_else(|| {
|
||||
Error::new(
|
||||
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 {
|
||||
name,
|
||||
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 y = self.inner.read_f32::<LittleEndian>()?;
|
||||
let z = self.inner.read_f32::<LittleEndian>()?;
|
||||
|
|
@ -528,8 +582,8 @@ impl<R: Read> BspReader<R> {
|
|||
Ok(plane)
|
||||
}
|
||||
|
||||
fn read_node(&mut self) -> Result<Node> {
|
||||
let plane = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_node(&mut self) -> io::Result<Node> {
|
||||
let plane = self.inner.read_u32::<LittleEndian>()?;
|
||||
let children = [
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
|
|
@ -553,9 +607,9 @@ impl<R: Read> BspReader<R> {
|
|||
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 area = self.inner.read_i32::<LittleEndian>()?;
|
||||
let area = self.inner.read_u32::<LittleEndian>()?;
|
||||
let mins = [
|
||||
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>()?,
|
||||
];
|
||||
let leaf_face = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_leaf_faces = self.inner.read_i32::<LittleEndian>()?;
|
||||
let leaf_brush = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_leaf_brushes = self.inner.read_i32::<LittleEndian>()?;
|
||||
let leaf_face = self.inner.read_u32::<LittleEndian>()?;
|
||||
let num_leaf_faces = self.inner.read_u32::<LittleEndian>()?;
|
||||
let leaf_brush = self.inner.read_u32::<LittleEndian>()?;
|
||||
let num_leaf_brushes = self.inner.read_u32::<LittleEndian>()?;
|
||||
let leaf = Leaf {
|
||||
cluster,
|
||||
area,
|
||||
|
|
@ -583,19 +637,19 @@ impl<R: Read> BspReader<R> {
|
|||
Ok(leaf)
|
||||
}
|
||||
|
||||
fn read_leaf_face(&mut self) -> Result<LeafFace> {
|
||||
let face = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_leaf_face(&mut self) -> io::Result<LeafFace> {
|
||||
let face = self.inner.read_u32::<LittleEndian>()?;
|
||||
let leaf_face = LeafFace { face };
|
||||
Ok(leaf_face)
|
||||
}
|
||||
|
||||
fn read_leaf_brush(&mut self) -> Result<LeafBrush> {
|
||||
let brush = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_leaf_brush(&mut self) -> io::Result<LeafBrush> {
|
||||
let brush = self.inner.read_u32::<LittleEndian>()?;
|
||||
let leaf_brush = LeafBrush { brush };
|
||||
Ok(leaf_brush)
|
||||
}
|
||||
|
||||
fn read_model(&mut self) -> Result<Model> {
|
||||
fn read_model(&mut self) -> io::Result<Model> {
|
||||
let mins = [
|
||||
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>()?,
|
||||
];
|
||||
let face = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_faces = self.inner.read_i32::<LittleEndian>()?;
|
||||
let brush = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_brushes = self.inner.read_i32::<LittleEndian>()?;
|
||||
let face = self.inner.read_u32::<LittleEndian>()?;
|
||||
let num_faces = self.inner.read_u32::<LittleEndian>()?;
|
||||
let brush = self.inner.read_u32::<LittleEndian>()?;
|
||||
let num_brushes = self.inner.read_u32::<LittleEndian>()?;
|
||||
let model = Model {
|
||||
mins,
|
||||
maxs,
|
||||
|
|
@ -621,10 +675,10 @@ impl<R: Read> BspReader<R> {
|
|||
Ok(model)
|
||||
}
|
||||
|
||||
fn read_brush(&mut self) -> Result<Brush> {
|
||||
let brush_side = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_brush_sides = self.inner.read_i32::<LittleEndian>()?;
|
||||
let texture = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_brush(&mut self) -> io::Result<Brush> {
|
||||
let brush_side = self.inner.read_u32::<LittleEndian>()?;
|
||||
let num_brush_sides = self.inner.read_u32::<LittleEndian>()?;
|
||||
let texture = self.inner.read_u32::<LittleEndian>()?;
|
||||
let brush = Brush {
|
||||
brush_side,
|
||||
num_brush_sides,
|
||||
|
|
@ -633,24 +687,24 @@ impl<R: Read> BspReader<R> {
|
|||
Ok(brush)
|
||||
}
|
||||
|
||||
fn read_brush_side(&mut self) -> Result<BrushSide> {
|
||||
let plane = self.inner.read_i32::<LittleEndian>()?;
|
||||
let texture = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_brush_side(&mut self) -> io::Result<BrushSide> {
|
||||
let plane = self.inner.read_u32::<LittleEndian>()?;
|
||||
let texture = self.inner.read_u32::<LittleEndian>()?;
|
||||
let brush_side = BrushSide { plane, texture };
|
||||
Ok(brush_side)
|
||||
}
|
||||
|
||||
fn read_vertex(&mut self) -> Result<Vertex> {
|
||||
fn read_vertex(&mut self) -> io::Result<Vertex> {
|
||||
let position = [
|
||||
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>()?,
|
||||
];
|
||||
let tex_coord2 = [
|
||||
let lightmap_texcoord = [
|
||||
self.inner.read_f32::<LittleEndian>()?,
|
||||
self.inner.read_f32::<LittleEndian>()?,
|
||||
];
|
||||
|
|
@ -667,29 +721,31 @@ impl<R: Read> BspReader<R> {
|
|||
];
|
||||
let vertex = Vertex {
|
||||
position,
|
||||
tex_coord1,
|
||||
tex_coord2,
|
||||
surface_texcoord,
|
||||
lightmap_texcoord,
|
||||
normal,
|
||||
color,
|
||||
};
|
||||
Ok(vertex)
|
||||
}
|
||||
|
||||
fn read_mesh_vert(&mut self) -> Result<MeshVert> {
|
||||
let offset = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_mesh_vert(&mut self) -> io::Result<MeshVert> {
|
||||
let offset = self.inner.read_u32::<LittleEndian>()?;
|
||||
let mesh_vert = MeshVert { offset };
|
||||
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;
|
||||
|
||||
let mut name_buf = [0u8; 64];
|
||||
self.inner.read_exact(&mut name_buf)?;
|
||||
let zero_pos = name_buf
|
||||
.iter()
|
||||
.position(|c| *c == 0)
|
||||
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
|
||||
let zero_pos = name_buf.iter().position(|c| *c == 0).ok_or_else(|| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!("Name isn't null-terminated"),
|
||||
)
|
||||
})?;
|
||||
let name = &name_buf[..zero_pos];
|
||||
Ok(ArrayString::from(
|
||||
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"))
|
||||
}
|
||||
|
||||
fn read_effect(&mut self) -> Result<Effect> {
|
||||
fn read_effect(&mut self) -> io::Result<Effect> {
|
||||
let name = self.read_name()?;
|
||||
let brush = self.inner.read_i32::<LittleEndian>()?;
|
||||
let unknown = self.inner.read_i32::<LittleEndian>()?;
|
||||
let brush = self.inner.read_u32::<LittleEndian>()?;
|
||||
let unknown = self.inner.read_u32::<LittleEndian>()?;
|
||||
Ok(Effect {
|
||||
name,
|
||||
brush,
|
||||
|
|
@ -708,22 +764,26 @@ impl<R: Read> BspReader<R> {
|
|||
})
|
||||
}
|
||||
|
||||
fn read_face(&mut self) -> Result<Face> {
|
||||
let texture = self.inner.read_i32::<LittleEndian>()?;
|
||||
let effect = self.inner.read_i32::<LittleEndian>()?;
|
||||
let face_type = self.inner.read_i32::<LittleEndian>()?;
|
||||
let vertex = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_vertexes = self.inner.read_i32::<LittleEndian>()?;
|
||||
let mesh_vert = self.inner.read_i32::<LittleEndian>()?;
|
||||
let num_mesh_verts = self.inner.read_i32::<LittleEndian>()?;
|
||||
let lm_index = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_face(&mut self) -> io::Result<Face> {
|
||||
let texture = self.inner.read_u32::<LittleEndian>()?;
|
||||
let effect = self.inner.read_u32::<LittleEndian>()?;
|
||||
let face_type = self
|
||||
.inner
|
||||
.read_u32::<LittleEndian>()?
|
||||
.try_into()
|
||||
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
|
||||
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 = [
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
];
|
||||
let lm_size = [
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
];
|
||||
let lm_origin = [
|
||||
self.inner.read_f32::<LittleEndian>()?,
|
||||
|
|
@ -747,8 +807,8 @@ impl<R: Read> BspReader<R> {
|
|||
self.inner.read_f32::<LittleEndian>()?,
|
||||
];
|
||||
let size = [
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_i32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
self.inner.read_u32::<LittleEndian>()?,
|
||||
];
|
||||
let face = Face {
|
||||
texture,
|
||||
|
|
@ -769,7 +829,7 @@ impl<R: Read> BspReader<R> {
|
|||
Ok(face)
|
||||
}
|
||||
|
||||
fn read_lightmap(&mut self) -> Result<Lightmap> {
|
||||
fn read_lightmap(&mut self) -> io::Result<Lightmap> {
|
||||
use std::ptr;
|
||||
|
||||
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 = [
|
||||
self.inner.read_u8()?,
|
||||
self.inner.read_u8()?,
|
||||
|
|
@ -812,9 +872,9 @@ impl<R: Read> BspReader<R> {
|
|||
})
|
||||
}
|
||||
|
||||
fn read_visdata(&mut self) -> Result<VisData> {
|
||||
let n_vecs = self.inner.read_i32::<LittleEndian>()?;
|
||||
let sz_vecs = self.inner.read_i32::<LittleEndian>()?;
|
||||
fn read_visdata(&mut self) -> io::Result<VisData> {
|
||||
let n_vecs = self.inner.read_u32::<LittleEndian>()?;
|
||||
let sz_vecs = self.inner.read_u32::<LittleEndian>()?;
|
||||
let vecs_size = n_vecs as usize * sz_vecs as usize;
|
||||
let mut vecs = Vec::with_capacity(vecs_size);
|
||||
self.inner
|
||||
|
|
@ -822,8 +882,18 @@ impl<R: Read> BspReader<R> {
|
|||
.take(vecs_size as u64)
|
||||
.read_to_end(&mut vecs)?;
|
||||
|
||||
if vecs.len() != vecs_size {
|
||||
return Err(Error::from(ErrorKind::InvalidData));
|
||||
if vecs.len() < vecs_size {
|
||||
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);
|
||||
|
|
@ -837,11 +907,18 @@ impl<R: Read> BspReader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Handle<'a, T> {
|
||||
bsp: &'a Bsp,
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
impl<T> Clone for Handle<'_, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Handle { ..*self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Handle<'a, T> {
|
||||
pub fn as_ref(&self) -> &'a T {
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub struct Bsp {
|
||||
|
|
@ -864,13 +1016,13 @@ pub struct Bsp {
|
|||
pub textures: Vec<Texture>,
|
||||
pub planes: Vec<Plane>,
|
||||
pub nodes: Vec<Node>,
|
||||
pub leafs: Vec<Leaf>,
|
||||
pub leaves: Leaves,
|
||||
pub leaf_faces: Vec<LeafFace>,
|
||||
pub leaf_brushes: Vec<LeafBrush>,
|
||||
pub models: Vec<Model>,
|
||||
pub brushes: Vec<Brush>,
|
||||
pub brush_sides: Vec<BrushSide>,
|
||||
pub vertexes: Vec<Vertex>,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub mesh_verts: Vec<MeshVert>,
|
||||
pub effects: Vec<Effect>,
|
||||
pub faces: Vec<Face>,
|
||||
|
|
@ -880,7 +1032,7 @@ pub struct 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 {
|
||||
i: b'I',
|
||||
b: b'B',
|
||||
|
|
@ -888,7 +1040,7 @@ impl Bsp {
|
|||
p: b'P',
|
||||
};
|
||||
// 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 header = reader.read_header()?;
|
||||
|
|
@ -906,13 +1058,15 @@ impl Bsp {
|
|||
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 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_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 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 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 effects = reader.read_entry(&dir_entries.effects, |r| r.read_effect())?;
|
||||
let faces = reader.read_entry(&dir_entries.faces, |r| r.read_face())?;
|
||||
|
|
@ -930,13 +1084,13 @@ impl Bsp {
|
|||
textures,
|
||||
planes,
|
||||
nodes,
|
||||
leafs,
|
||||
leaves,
|
||||
leaf_faces,
|
||||
leaf_brushes,
|
||||
models,
|
||||
brushes,
|
||||
brush_sides,
|
||||
vertexes,
|
||||
vertices,
|
||||
mesh_verts,
|
||||
effects,
|
||||
faces,
|
||||
|
|
@ -948,7 +1102,7 @@ impl Bsp {
|
|||
}
|
||||
|
||||
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,
|
||||
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> {
|
||||
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> {
|
||||
|
|
@ -1029,7 +1210,7 @@ impl<'a> Handle<'a, Leaf> {
|
|||
None
|
||||
} else {
|
||||
Some(
|
||||
bsp.leafs
|
||||
bsp.leaves
|
||||
.iter()
|
||||
.filter(move |leaf| {
|
||||
if leaf.cluster == cluster {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue