use crate::{
BspParseError,
data::{util::UBspValue, visdata::VisDataRef},
};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use glam::{U16Vec3, Vec3};
use qbsp_macros::{BspValue, BspVariableValue};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use bitflags::bitflags;
use crate::{
BspResult,
data::util::NoField,
reader::{BspByteReader, BspParseContext, BspValue, BspVariableValue},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum BspNodeRef<T = u32> {
Node(T),
Leaf(T),
}
impl BspValue for BspNodeRef<u32> {
fn bsp_parse(reader: &mut BspByteReader) -> BspResult<Self> {
Ok(BspNodeRef::from_i32(i32::bsp_parse(reader)?))
}
fn bsp_struct_size(ctx: &BspParseContext) -> usize {
i32::bsp_struct_size(ctx)
}
}
impl BspValue for BspNodeRef<u16> {
fn bsp_parse(reader: &mut BspByteReader) -> BspResult<Self> {
Ok(BspNodeRef::from_i16(i16::bsp_parse(reader)?))
}
fn bsp_struct_size(ctx: &BspParseContext) -> usize {
i16::bsp_struct_size(ctx)
}
}
#[derive(BspVariableValue, Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[bsp29(BspNodeRef<u16>)]
#[bsp2(BspNodeRef<u32>)]
#[bsp30(BspNodeRef<u16>)]
#[bsp38(BspNodeRef<u32>)]
#[qbism(BspNodeRef<u32>)]
pub struct BspNodeSubRef(BspNodeRef);
impl From<BspNodeRef<u16>> for BspNodeRef<u32> {
fn from(value: BspNodeRef<u16>) -> Self {
match value {
BspNodeRef::Node(val) => BspNodeRef::Node(val.into()),
BspNodeRef::Leaf(val) => BspNodeRef::Leaf(val.into()),
}
}
}
impl<T> BspNodeRef<T>
where
T: Copy,
{
pub fn node(&self) -> Option<T> {
match *self {
Self::Node(i) => Some(i),
Self::Leaf(_) => None,
}
}
pub fn leaf(&self) -> Option<T> {
match *self {
Self::Leaf(i) => Some(i),
Self::Node(_) => None,
}
}
}
impl From<i32> for BspNodeRef {
fn from(value: i32) -> Self {
Self::from_i32(value)
}
}
impl From<i16> for BspNodeRef<u16> {
fn from(value: i16) -> Self {
Self::from_i16(value as _)
}
}
impl BspNodeRef<u32> {
pub const fn from_i32(value: i32) -> Self {
if value.is_negative() {
Self::Leaf(!value as u32)
} else {
Self::Node(value as u32)
}
}
}
impl BspNodeRef<u16> {
pub const fn from_i16(value: i16) -> Self {
if value.is_negative() {
Self::Leaf(!value as u16)
} else {
Self::Node(value as u16)
}
}
}
#[derive(BspValue, Debug, Clone, Copy, Default, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(i32)]
pub enum Bsp29LeafContents {
#[default]
Empty = -1,
Solid = -2,
Water = -3,
Slime = -4,
Lava = -5,
Sky = -6,
Clip = -8,
Current0 = -9,
Current90 = -10,
Current180 = -11,
Current270 = -12,
CurrentUp = -13,
CurrentDown = -14,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ShortBsp29LeafContents(pub Bsp29LeafContents);
impl BspValue for ShortBsp29LeafContents {
fn bsp_parse(reader: &mut BspByteReader) -> BspResult<Self> {
let value = reader.read::<i16>()? as i32;
Bsp29LeafContents::bsp_parse(&mut BspByteReader::new(&value.to_le_bytes(), reader.ctx)).map(Self)
}
fn bsp_struct_size(_ctx: &BspParseContext) -> usize {
size_of::<i16>()
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(transparent)]
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
pub struct BspLeafContentFlags: u32 {
const SOLID = 0b0000_0000_0000_0000_0000_0000_0000_0001;
const WINDOW = 0b0000_0000_0000_0000_0000_0000_0000_0010;
const AUX = 0b0000_0000_0000_0000_0000_0000_0000_0100;
const LAVA = 0b0000_0000_0000_0000_0000_0000_0000_1000;
const SLIME = 0b0000_0000_0000_0000_0000_0000_0001_0000;
const WATER = 0b0000_0000_0000_0000_0000_0000_0010_0000;
const MIST = 0b0000_0000_0000_0000_0000_0000_0100_0000;
const AREA_PORTAL = 0b0000_0000_0000_0000_1000_0000_0000_0000;
const PLAYER_CLIP = 0b0000_0000_0000_0001_0000_0000_0000_0000;
const MONSTER_CLIP = 0b0000_0000_0000_0010_0000_0000_0000_0000;
const CURRENT_0 = 0b0000_0000_0000_0100_0000_0000_0000_0000;
const CURRENT_90 = 0b0000_0000_0000_1000_0000_0000_0000_0000;
const CURRENT_180 = 0b0000_0000_0001_0000_0000_0000_0000_0000;
const CURRENT_270 = 0b0000_0000_0010_0000_0000_0000_0000_0000;
const CURRENT_UP = 0b0000_0000_0100_0000_0000_0000_0000_0000;
const CURRENT_DOWN = 0b0000_0000_1000_0000_0000_0000_0000_0000;
const ORIGIN = 0b0000_0001_0000_0000_0000_0000_0000_0000;
const MONSTER = 0b0000_0010_0000_0000_0000_0000_0000_0000;
const DEAD_MONSTER = 0b0000_0100_0000_0000_0000_0000_0000_0000;
const DETAIL = 0b0000_1000_0000_0000_0000_0000_0000_0000;
const TRANSLUCENT = 0b0001_0000_0000_0000_0000_0000_0000_0000;
const LADDER = 0b0010_0000_0000_0000_0000_0000_0000_0000;
const UNUSED1 = 0b0100_0000_0000_0000_0000_0000_0000_0000;
const UNUSED2 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
}
}
impl BspValue for BspLeafContentFlags {
fn bsp_parse(reader: &mut BspByteReader) -> BspResult<Self> {
u32::bsp_parse(reader).map(Self::from_bits_truncate)
}
fn bsp_struct_size(ctx: &BspParseContext) -> usize {
u32::bsp_struct_size(ctx)
}
}
impl From<Bsp29LeafContents> for BspLeafContentFlags {
fn from(value: Bsp29LeafContents) -> Self {
match value {
Bsp29LeafContents::Empty => Self::empty(),
Bsp29LeafContents::Solid => BspLeafContentFlags::SOLID,
Bsp29LeafContents::Water => BspLeafContentFlags::WATER,
Bsp29LeafContents::Slime => BspLeafContentFlags::SLIME,
Bsp29LeafContents::Lava => BspLeafContentFlags::LAVA,
Bsp29LeafContents::Sky => BspLeafContentFlags::SOLID,
Bsp29LeafContents::Clip => BspLeafContentFlags::SOLID,
Bsp29LeafContents::Current0 => BspLeafContentFlags::CURRENT_0,
Bsp29LeafContents::Current90 => BspLeafContentFlags::CURRENT_90,
Bsp29LeafContents::Current180 => BspLeafContentFlags::CURRENT_180,
Bsp29LeafContents::Current270 => BspLeafContentFlags::CURRENT_270,
Bsp29LeafContents::CurrentUp => BspLeafContentFlags::CURRENT_UP,
Bsp29LeafContents::CurrentDown => BspLeafContentFlags::CURRENT_DOWN,
}
}
}
impl From<ShortBsp29LeafContents> for BspLeafContentFlags {
fn from(value: ShortBsp29LeafContents) -> Self {
value.0.into()
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BoundingBox {
pub min: Vec3,
pub max: Vec3,
}
impl From<FloatBoundingBox> for BoundingBox {
fn from(value: FloatBoundingBox) -> Self {
Self {
min: value.min,
max: value.max,
}
}
}
impl From<ShortBoundingBox> for BoundingBox {
fn from(value: ShortBoundingBox) -> Self {
Self {
min: value.min.as_vec3(),
max: value.max.as_vec3(),
}
}
}
impl BspVariableValue for BoundingBox {
type Bsp29 = ShortBoundingBox;
type Bsp2 = FloatBoundingBox;
type Bsp30 = ShortBoundingBox;
type Bsp38 = ShortBoundingBox;
type Qbism = FloatBoundingBox;
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FloatBoundingBox {
pub min: Vec3,
pub max: Vec3,
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ShortBoundingBox {
pub min: U16Vec3,
pub max: U16Vec3,
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspNode {
pub plane_idx: u32,
pub front: BspNodeSubRef,
pub back: BspNodeSubRef,
pub bound: BoundingBox,
pub face_idx: UBspValue,
pub face_num: UBspValue,
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspClipNode {
pub plane_idx: u32,
pub front: BspNodeSubRef,
pub back: BspNodeSubRef,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspAreaIdx(pub Option<u32>);
impl BspVariableValue for BspAreaIdx {
type Bsp29 = NoField;
type Bsp2 = NoField;
type Bsp30 = NoField;
type Bsp38 = u16;
type Qbism = u32;
}
impl From<u16> for BspAreaIdx {
fn from(value: u16) -> Self {
Self(Some(value as u32))
}
}
impl From<u32> for BspAreaIdx {
fn from(value: u32) -> Self {
Self(Some(value))
}
}
impl From<NoField> for BspAreaIdx {
fn from(_: NoField) -> Self {
Self(None)
}
}
#[derive(BspVariableValue, Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[bsp29(Bsp29LeafContents)]
#[bsp2(Bsp29LeafContents)]
#[bsp30(BspLeafContentFlags)]
#[bsp38(BspLeafContentFlags)]
#[qbism(BspLeafContentFlags)]
pub struct BspLeafContents(pub BspLeafContentFlags);
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspLeaf {
pub contents: BspLeafContents,
pub visdata: VisDataRef,
pub area: BspAreaIdx,
pub bound: BoundingBox,
pub face_idx: UBspValue,
pub face_num: UBspValue,
pub ambience: Option<BspAmbience>,
pub leaf_brushes: Option<BspLeafBrushes>,
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspLeafBrushes {
pub idx: UBspValue,
pub num: UBspValue,
}
impl BspVariableValue for Option<BspLeafBrushes> {
type Bsp29 = NoField;
type Bsp2 = NoField;
type Bsp30 = NoField;
type Bsp38 = BspLeafBrushes;
type Qbism = BspLeafBrushes;
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspAmbience {
pub water: u8,
pub sky: u8,
pub slime: u8,
pub lava: u8,
}
impl BspVariableValue for Option<BspAmbience> {
type Bsp29 = BspAmbience;
type Bsp2 = BspAmbience;
type Bsp30 = BspAmbience;
type Bsp38 = NoField;
type Qbism = NoField;
}
#[derive(BspValue, Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BspPlane {
pub normal: Vec3,
pub dist: f32,
pub ty: BspPlaneType,
}
impl BspPlane {
pub fn point_side(&self, point: Vec3) -> f32 {
let plane_axis = self.ty as usize;
if plane_axis < 3 {
point[plane_axis] - self.dist
} else {
(self.normal.as_dvec3().dot(point.as_dvec3()) - self.dist as f64) as f32
}
}
}
#[derive(BspValue, Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u32)]
pub enum BspPlaneType {
AxialX = 0,
AxialY = 1,
AxialZ = 2,
AroundX = 3,
AroundY = 4,
AroundZ = 5,
}