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

split off displacement stuff

This commit is contained in:
Robin Appelman 2022-02-20 22:10:22 +01:00
commit 5e918a397b
2 changed files with 178 additions and 171 deletions

175
src/data/displacement.rs Normal file
View file

@ -0,0 +1,175 @@
use super::vector::Vector;
use binrw::{BinRead, BinResult, ReadOptions};
use bitflags::bitflags;
use num_enum::TryFromPrimitive;
use std::fmt::Debug;
use std::io::{Read, Seek};
use std::mem::{align_of, size_of};
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementInfo {
pub start_position: Vector,
pub displacement_vertex_start: i32,
pub displacement_triangle_tag_start: i32,
pub power: i32,
pub minimum_tesselation: i32,
pub smoothing_angle: f32,
pub contents: i32,
pub map_face: u16,
#[br(align_before = 4)]
pub lightmap_alpha_start: i32,
pub lightmap_sample_position_start: i32,
pub edge_neighbours: [DisplacementNeighbour; 4],
pub corner_neighbours: [DisplacementCornerNeighbour; 4],
pub allowed_vertices: [u32; 10],
}
impl DisplacementInfo {
pub fn vertex_count(&self) -> i32 {
(2i32.pow(self.power as u32) + 1).pow(2)
}
pub fn triangle_count(&self) -> i32 {
2 * 2i32.pow(self.power as u32).pow(2)
}
}
#[test]
fn test_displacement_bytes() {
super::test_read_bytes::<DisplacementInfo>();
}
static_assertions::const_assert_eq!(size_of::<DisplacementInfo>(), 176);
#[derive(Debug, Clone)]
pub struct DisplacementNeighbour {
pub sub_neighbours: [Option<DisplacementSubNeighbour>; 2],
}
impl BinRead for DisplacementNeighbour {
type Args = ();
fn read_options<R: Read + Seek>(
reader: &mut R,
options: &ReadOptions,
args: Self::Args,
) -> BinResult<Self> {
let raws = <[RawDisplacementSubNeighbour; 2]>::read_options(reader, options, args)?;
Ok(DisplacementNeighbour {
sub_neighbours: raws.map(|raw| raw.try_into().ok()),
})
}
}
static_assertions::const_assert_eq!(size_of::<DisplacementNeighbour>(), 12);
#[derive(Debug, Clone, BinRead)]
#[br(assert(neighbour_index == u16::MAX || (neighbour_orientation < 4 && span < 4 && neighbour_span < 4), "valid neighbour index with invalid enum fields"))]
struct RawDisplacementSubNeighbour {
neighbour_index: u16,
neighbour_orientation: u8,
span: u8,
#[br(align_after = align_of::< DisplacementSubNeighbour > ())]
neighbour_span: u8,
}
#[test]
fn test_sub_neighbour_bytes() {
test_read_bytes::<RawDisplacementSubNeighbour>();
}
#[derive(Debug, Clone)]
pub struct DisplacementSubNeighbour {
pub neighbour_index: u16,
/// Orientation of the neighbour relative to us
pub neighbour_orientation: NeighbourOrientation,
/// How the neighbour fits into us
pub span: NeighbourSpan,
/// How we fit into our neighbour
pub neighbour_span: NeighbourSpan,
}
impl TryFrom<RawDisplacementSubNeighbour> for DisplacementSubNeighbour {
type Error = ();
fn try_from(value: RawDisplacementSubNeighbour) -> Result<Self, Self::Error> {
match value.neighbour_index {
u16::MAX => Err(()),
neighbour_index => Ok(DisplacementSubNeighbour {
neighbour_index,
// note that we already checked if these enums are valid in the assert of the RawDisplacementSubNeighbour reader
neighbour_orientation: NeighbourOrientation::try_from(value.neighbour_orientation)
.unwrap(),
span: NeighbourSpan::try_from(value.span).unwrap(),
neighbour_span: NeighbourSpan::try_from(value.neighbour_span).unwrap(),
}),
}
}
}
static_assertions::const_assert_eq!(size_of::<DisplacementSubNeighbour>(), 6);
#[derive(Debug, Clone, TryFromPrimitive)]
#[repr(u8)]
pub enum NeighbourSpan {
CornerToCorner,
CornerToMidPoint,
MidPointToCorner,
}
#[derive(Debug, Clone, TryFromPrimitive)]
#[repr(u8)]
pub enum NeighbourOrientation {
Ccw0,
Ccw90,
Ccw180,
Ccw270,
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementCornerNeighbour {
pub neighbours: [u16; 4],
#[br(align_after = align_of::< DisplacementCornerNeighbour > ())]
pub neighbour_count: u8,
}
static_assertions::const_assert_eq!(size_of::<DisplacementCornerNeighbour>(), 10);
#[test]
fn test_corner_neighbour_bytes() {
test_read_bytes::<DisplacementCornerNeighbour>();
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementVertex {
pub vector: Vector,
pub distance: f32,
pub alpha: f32,
}
impl DisplacementVertex {
pub fn displacement(&self) -> Vector {
self.vector * self.distance
}
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementTriangle {
pub tags: DisplacementTriangleFlags,
}
bitflags! {
#[derive(BinRead)]
pub struct DisplacementTriangleFlags: u8 {
const SURFACE = 0x01;
const WALKABLE = 0x02;
const BULDABLE = 0x04;
const SURFACE_PROP1 = 0x08;
const SURFACE_PROP2 = 0x10;
}
}

View file

@ -1,5 +1,8 @@
mod displacement;
mod vector;
pub use self::displacement::*;
pub use self::vector::*;
use crate::bspfile::LumpType;
use crate::StringError;
use arrayvec::ArrayString;
@ -7,13 +10,10 @@ use binrw::io::SeekFrom;
use binrw::{BinRead, BinResult, ReadOptions};
use bitflags::bitflags;
use bv::BitVec;
use num_enum::TryFromPrimitive;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::io::{Read, Seek};
use std::mem::{align_of, size_of};
use std::ops::Index;
pub use vector::Vector;
#[cfg(test)]
fn test_read_bytes<T: BinRead>()
@ -480,171 +480,3 @@ impl VisData {
visible_clusters
}
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementInfo {
pub start_position: Vector,
pub displacement_vertex_start: i32,
pub displacement_triangle_tag_start: i32,
pub power: i32,
pub minimum_tesselation: i32,
pub smoothing_angle: f32,
pub contents: i32,
pub map_face: u16,
#[br(align_before = 4)]
pub lightmap_alpha_start: i32,
pub lightmap_sample_position_start: i32,
pub edge_neighbours: [DisplacementNeighbour; 4],
pub corner_neighbours: [DisplacementCornerNeighbour; 4],
pub allowed_vertices: [u32; 10],
}
impl DisplacementInfo {
pub fn vertex_count(&self) -> i32 {
(2i32.pow(self.power as u32) + 1).pow(2)
}
pub fn triangle_count(&self) -> i32 {
2 * 2i32.pow(self.power as u32).pow(2)
}
}
#[test]
fn test_displacement_bytes() {
test_read_bytes::<DisplacementInfo>();
}
static_assertions::const_assert_eq!(size_of::<DisplacementInfo>(), 176);
#[derive(Debug, Clone)]
pub struct DisplacementNeighbour {
pub sub_neighbours: [Option<DisplacementSubNeighbour>; 2],
}
impl BinRead for DisplacementNeighbour {
type Args = ();
fn read_options<R: Read + Seek>(
reader: &mut R,
options: &ReadOptions,
args: Self::Args,
) -> BinResult<Self> {
let raws = <[RawDisplacementSubNeighbour; 2]>::read_options(reader, options, args)?;
Ok(DisplacementNeighbour {
sub_neighbours: raws.map(|raw| raw.try_into().ok()),
})
}
}
static_assertions::const_assert_eq!(size_of::<DisplacementNeighbour>(), 12);
#[derive(Debug, Clone, BinRead)]
#[br(assert(neighbour_index == u16::MAX || (neighbour_orientation < 4 && span < 4 && neighbour_span < 4), "valid neighbour index with invalid enum fields"))]
struct RawDisplacementSubNeighbour {
neighbour_index: u16,
neighbour_orientation: u8,
span: u8,
#[br(align_after = align_of::< DisplacementSubNeighbour > ())]
neighbour_span: u8,
}
#[test]
fn test_sub_neighbour_bytes() {
test_read_bytes::<RawDisplacementSubNeighbour>();
}
#[derive(Debug, Clone)]
pub struct DisplacementSubNeighbour {
pub neighbour_index: u16,
/// Orientation of the neighbour relative to us
pub neighbour_orientation: NeighbourOrientation,
/// How the neighbour fits into us
pub span: NeighbourSpan,
/// How we fit into our neighbour
pub neighbour_span: NeighbourSpan,
}
impl TryFrom<RawDisplacementSubNeighbour> for DisplacementSubNeighbour {
type Error = ();
fn try_from(value: RawDisplacementSubNeighbour) -> Result<Self, Self::Error> {
match value.neighbour_index {
u16::MAX => Err(()),
neighbour_index => Ok(DisplacementSubNeighbour {
neighbour_index,
// note that we already checked if these enums are valid in the assert of the RawDisplacementSubNeighbour reader
neighbour_orientation: NeighbourOrientation::try_from(value.neighbour_orientation)
.unwrap(),
span: NeighbourSpan::try_from(value.span).unwrap(),
neighbour_span: NeighbourSpan::try_from(value.neighbour_span).unwrap(),
}),
}
}
}
static_assertions::const_assert_eq!(size_of::<DisplacementSubNeighbour>(), 6);
#[derive(Debug, Clone, TryFromPrimitive)]
#[repr(u8)]
pub enum NeighbourSpan {
CornerToCorner,
CornerToMidPoint,
MidPointToCorner,
}
#[derive(Debug, Clone, TryFromPrimitive)]
#[repr(u8)]
pub enum NeighbourOrientation {
Ccw0,
Ccw90,
Ccw180,
Ccw270,
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementCornerNeighbour {
pub neighbours: [u16; 4],
#[br(align_after = align_of::< DisplacementCornerNeighbour > ())]
pub neighbour_count: u8,
}
static_assertions::const_assert_eq!(size_of::<DisplacementCornerNeighbour>(), 10);
#[test]
fn test_corner_neighbour_bytes() {
test_read_bytes::<DisplacementCornerNeighbour>();
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementVertex {
pub vector: Vector,
pub distance: f32,
pub alpha: f32,
}
impl DisplacementVertex {
pub fn displacement(&self) -> Vector {
self.vector * self.distance
}
}
#[derive(Debug, Clone, BinRead)]
pub struct DisplacementTriangle {
pub tags: DisplacementTriangleFlags,
}
bitflags! {
#[derive(BinRead)]
pub struct DisplacementTriangleFlags: u8 {
const SURFACE = 0x01;
const WALKABLE = 0x02;
const BULDABLE = 0x04;
const SURFACE_PROP1 = 0x08;
const SURFACE_PROP2 = 0x10;
}
}