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

displacement triangulation

This commit is contained in:
Robin Appelman 2022-02-20 19:12:16 +01:00
commit a0e505d907
3 changed files with 219 additions and 42 deletions

View file

@ -6,11 +6,90 @@ use binrw::{BinRead, BinResult, ReadOptions};
use bitflags::bitflags; use bitflags::bitflags;
use bv::BitVec; use bv::BitVec;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
use std::io::{Read, Seek}; use std::io::{Read, Seek};
use std::mem::{align_of, size_of}; use std::mem::{align_of, size_of};
use std::ops::{Add, Index}; use std::ops::Index;
use std::ops::{Add, Mul, Sub};
#[derive(Debug, Clone, Copy, BinRead)]
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vector {
pub fn iter(&self) -> impl Iterator<Item = f32> {
[self.x, self.y, self.z].into_iter()
}
pub fn length_squared(&self) -> f32 {
self.x.powf(2.0) + self.y.powf(2.0) + self.z.powf(2.0)
}
}
impl Add<Vector> for Vector {
type Output = Vector;
fn add(self, rhs: Vector) -> Self::Output {
Vector {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl Sub<Vector> for Vector {
type Output = Vector;
fn sub(self, rhs: Vector) -> Self::Output {
Vector {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
impl Mul<f32> for Vector {
type Output = Vector;
fn mul(self, rhs: f32) -> Self::Output {
Vector {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
impl PartialEq for Vector {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl PartialOrd for Vector {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.length_squared().partial_cmp(&other.length_squared())
}
}
impl From<Vector> for [f32; 3] {
fn from(vector: Vector) -> Self {
[vector.x, vector.y, vector.z]
}
}
impl From<&Vector> for [f32; 3] {
fn from(vector: &Vector) -> Self {
[vector.x, vector.y, vector.z]
}
}
#[cfg(test)] #[cfg(test)]
fn test_read_bytes<T: BinRead>() fn test_read_bytes<T: BinRead>()
@ -231,43 +310,6 @@ impl<const LEN: usize> BinRead for FixedString<LEN> {
} }
} }
#[derive(Debug, Clone, Copy, BinRead)]
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vector {
pub fn iter(&self) -> impl Iterator<Item = f32> {
[self.x, self.y, self.z].into_iter()
}
}
impl Add<Vector> for Vector {
type Output = Vector;
fn add(self, rhs: Vector) -> Self::Output {
Vector {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl From<Vector> for [f32; 3] {
fn from(vector: Vector) -> Self {
[vector.x, vector.y, vector.z]
}
}
impl From<&Vector> for [f32; 3] {
fn from(vector: &Vector) -> Self {
[vector.x, vector.y, vector.z]
}
}
#[derive(Debug, Clone, BinRead)] #[derive(Debug, Clone, BinRead)]
pub struct TextureInfo { pub struct TextureInfo {
pub texture_scale: [f32; 4], pub texture_scale: [f32; 4],
@ -427,6 +469,7 @@ pub struct Edge {
pub end_index: u16, pub end_index: u16,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum EdgeDirection { pub enum EdgeDirection {
FirstToLast, FirstToLast,
LastToFirst, LastToFirst,
@ -537,6 +580,16 @@ pub struct DisplacementInfo {
pub allowed_vertices: [u32; 10], 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] #[test]
fn test_displacement_bytes() { fn test_displacement_bytes() {
test_read_bytes::<DisplacementInfo>(); test_read_bytes::<DisplacementInfo>();
@ -642,3 +695,32 @@ static_assertions::const_assert_eq!(size_of::<DisplacementCornerNeighbour>(), 10
fn test_corner_neighbour_bytes() { fn test_corner_neighbour_bytes() {
test_read_bytes::<DisplacementCornerNeighbour>(); 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,6 @@
use crate::data::*; use crate::data::*;
use crate::Bsp; use crate::Bsp;
use arrayvec::ArrayVec;
use std::ops::Deref; use std::ops::Deref;
/// A handle represents a data structure in the bsp file and the bsp file containing it. /// A handle represents a data structure in the bsp file and the bsp file containing it.
@ -97,6 +98,10 @@ impl<'a> Handle<'a, Face> {
}) })
} }
pub fn edge_direction(&self) -> EdgeDirection {
self.bsp.surface_edges[self.first_edge as usize].direction()
}
/// Check if the face is flagged as visible /// Check if the face is flagged as visible
pub fn is_visible(&self) -> bool { pub fn is_visible(&self) -> bool {
self.texture() self.texture()
@ -131,6 +136,10 @@ impl<'a> Handle<'a, Face> {
points points
}) })
} }
pub fn displacement(&self) -> Option<Handle<'a, DisplacementInfo>> {
self.bsp.displacement(self.displacement_info as usize)
}
} }
impl Handle<'_, Node> { impl Handle<'_, Node> {
@ -196,6 +205,70 @@ impl<'a> Handle<'a, DisplacementInfo> {
.copied() .copied()
.filter_map(|id| self.bsp.displacement(id as usize)) .filter_map(|id| self.bsp.displacement(id as usize))
} }
pub fn displacement_vertices(&self) -> impl Iterator<Item = Handle<'a, DisplacementVertex>> {
(self.displacement_vertex_start..(self.displacement_vertex_start + self.vertex_count()))
.flat_map(|i| self.bsp.displacement_vertex(i as usize))
}
pub fn face(&self) -> Option<Handle<'a, Face>> {
self.bsp.face(self.map_face as usize)
}
pub fn displaced_vertices(&self) -> Option<impl Iterator<Item = Vector> + 'a> {
let face = self.face()?;
let steps = 2usize.pow(self.power as u32) + 1;
let mut corner_positions: ArrayVec<_, 4> = face.vertices().map(|v| v.position).collect();
let start_index = corner_positions
.iter()
.copied()
.map(|point| point - self.start_position)
.enumerate()
.min_by(|(_a, a_pos), (_b, b_pos)| (a_pos).partial_cmp(b_pos).unwrap())
.map(|(i, _pos)| i)
.unwrap();
corner_positions.rotate_left(start_index);
let start_corner = corner_positions[0];
let x_dir = corner_positions[3] - corner_positions[0];
let y_dir = corner_positions[1] - corner_positions[0];
Some(
self.displacement_vertices()
.enumerate()
.map(move |(i, displacement)| {
let x = (i % steps) as f32 / (steps - 1) as f32;
let y = (i / steps) as f32 / (steps - 1) as f32;
let base_pos = start_corner + (x_dir * x) + (y_dir * y);
base_pos + displacement.displacement()
}),
)
}
pub fn triangulated_displaced_vertices(&self) -> Option<impl Iterator<Item = Vector> + 'a> {
let vertices: Vec<_> = self.displaced_vertices()?.collect();
let steps = 2usize.pow(self.power as u32);
let index = move |x: usize, y: usize| y * (steps + 1) + x;
Some(
(0..steps)
.flat_map(move |x| (0..steps).map(move |y| (x, y)))
.flat_map(move |(x, y)| {
[
vertices[index(x, y)],
vertices[index(x + 1, y)],
vertices[index(x, y + 1)],
vertices[index(x, y + 1)],
vertices[index(x + 1, y + 1)],
vertices[index(x + 1, y)],
]
}),
)
}
} }
impl<'a> Handle<'a, DisplacementSubNeighbour> { impl<'a> Handle<'a, DisplacementSubNeighbour> {

View file

@ -8,7 +8,7 @@ use crate::bspfile::LumpType;
pub use crate::data::TextureFlags; pub use crate::data::TextureFlags;
pub use crate::data::Vector; pub use crate::data::Vector;
use crate::data::*; use crate::data::*;
use crate::handle::Handle; pub use crate::handle::Handle;
use binrw::io::Cursor; use binrw::io::Cursor;
use binrw::BinRead; use binrw::BinRead;
use bspfile::BspFile; use bspfile::BspFile;
@ -172,6 +172,8 @@ pub struct Bsp {
pub original_faces: Vec<Face>, pub original_faces: Vec<Face>,
pub vis_data: VisData, pub vis_data: VisData,
pub displacements: Vec<DisplacementInfo>, pub displacements: Vec<DisplacementInfo>,
pub displacement_vertices: Vec<DisplacementVertex>,
pub displacement_triangles: Vec<DisplacementTriangle>,
} }
impl Bsp { impl Bsp {
@ -229,6 +231,12 @@ impl Bsp {
let displacements = bsp_file let displacements = bsp_file
.lump_reader(LumpType::DisplacementInfo)? .lump_reader(LumpType::DisplacementInfo)?
.read_vec(|r| r.read())?; .read_vec(|r| r.read())?;
let displacement_vertices = bsp_file
.lump_reader(LumpType::DisplacementVertices)?
.read_vec(|r| r.read())?;
let displacement_triangles = bsp_file
.lump_reader(LumpType::DisplacementTris)?
.read_vec(|r| r.read())?;
Ok({ Ok({
Bsp { Bsp {
@ -251,6 +259,8 @@ impl Bsp {
original_faces, original_faces,
vis_data, vis_data,
displacements, displacements,
displacement_vertices,
displacement_triangles,
} }
}) })
} }
@ -277,6 +287,18 @@ impl Bsp {
.map(|displacement| Handle::new(self, displacement)) .map(|displacement| Handle::new(self, displacement))
} }
pub fn displacement_vertex(&self, n: usize) -> Option<Handle<'_, DisplacementVertex>> {
self.displacement_vertices
.get(n)
.map(|vert| Handle::new(self, vert))
}
pub fn displacement_triangle(&self, n: usize) -> Option<Handle<'_, DisplacementTriangle>> {
self.displacement_triangles
.get(n)
.map(|tri| Handle::new(self, tri))
}
/// Get the root node of the bsp /// Get the root node of the bsp
pub fn root_node(&self) -> Option<Handle<'_, Node>> { pub fn root_node(&self) -> Option<Handle<'_, Node>> {
self.node(0) self.node(0)