mirror of
https://codeberg.org/icewind/vbsp.git
synced 2026-06-03 18:54:05 +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"
|
bitflags = "1.0"
|
||||||
bv = "0.11"
|
bv = "0.11"
|
||||||
byteorder = "0.5"
|
byteorder = "0.5"
|
||||||
|
itertools = "0.8"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
bench = []
|
bench = []
|
||||||
|
|
|
||||||
491
src/lib.rs
491
src/lib.rs
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue