1use crate::{BBox, Map, ValueContainer};
2use theframework::prelude::*;
3
4#[derive(Serialize, Deserialize, Clone, Debug)]
5pub struct Linedef {
6 pub id: u32,
7
8 pub creator_id: Uuid,
10
11 pub name: String,
12 pub start_vertex: u32,
13 pub end_vertex: u32,
14
15 #[serde(default)]
17 pub sector_ids: Vec<u32>,
18
19 pub properties: ValueContainer,
20}
21
22impl Linedef {
23 pub fn new(id: u32, start_vertex: u32, end_vertex: u32) -> Self {
24 let properties = ValueContainer::default();
25 Self {
26 id,
27 creator_id: Uuid::new_v4(),
28 name: String::new(),
29 start_vertex,
30 end_vertex,
31 sector_ids: Vec::new(),
32
33 properties,
34 }
35 }
36
37 pub fn signed_distance(&self, map: &Map, point: Vec2<f32>) -> Option<f32> {
40 let v0 = map.get_vertex(self.start_vertex)?;
41 let v1 = map.get_vertex(self.end_vertex)?;
42
43 let edge = v1 - v0;
44 let to_point = point - v0;
45
46 let t = to_point.dot(edge) / edge.dot(edge);
47 let t_clamped = t.clamp(0.0, 1.0);
48 let closest = v0 + edge * t_clamped;
49
50 let dist = (point - closest).magnitude();
51
52 let normal = Vec2::new(-edge.y, edge.x).normalized();
54 let side = (point - closest).dot(normal);
55
56 Some(if side < 0.0 { -dist } else { dist })
57 }
58
59 pub fn length(&self, map: &Map) -> Option<f32> {
61 let start = map.get_vertex(self.start_vertex)?;
62 let end = map.get_vertex(self.end_vertex)?;
63
64 Some((end - start).magnitude())
65 }
66
67 pub fn bounding_box(&self, map: &Map) -> BBox {
69 let start = map
70 .get_vertex(self.start_vertex)
71 .unwrap_or(Vec2::broadcast(0.0));
72 let end = map
73 .get_vertex(self.end_vertex)
74 .unwrap_or(Vec2::broadcast(0.0));
75
76 let min = Vec2::new(start.x.min(end.x), start.y.min(end.y));
77 let max = Vec2::new(start.x.max(end.x), start.y.max(end.y));
78
79 BBox::new(min, max)
80 }
81
82 pub fn y_span_world(&self, map: &Map) -> Option<(f32, f32)> {
84 let a = map.get_vertex_3d(self.start_vertex)?;
85 let b = map.get_vertex_3d(self.end_vertex)?;
86 let min_y = a.y.min(b.y);
87 let max_y = a.y.max(b.y);
88 Some((min_y, max_y))
89 }
90
91 pub fn intersects_vertical_slice(&self, map: &Map, slice_y: f32, thickness: f32) -> bool {
93 if thickness <= 0.0 {
94 return false;
95 }
96 if let Some((min_y, max_y)) = self.y_span_world(map) {
97 let half = thickness * 0.5;
98 let y0 = slice_y - half;
99 let y1 = slice_y + half;
100 max_y >= y0 && min_y <= y1
101 } else {
102 false
103 }
104 }
105}
106
107impl PartialEq for Linedef {
108 fn eq(&self, other: &Self) -> bool {
109 (self.start_vertex == other.start_vertex && self.end_vertex == other.end_vertex)
110 || (self.start_vertex == other.end_vertex && self.end_vertex == other.start_vertex)
111 }
112}
113impl Eq for Linedef {}
114
115#[derive(Clone)]
117pub struct CompiledLinedef {
118 pub start: Vec2<f32>,
119 pub end: Vec2<f32>,
120
121 pub wall_width: f32,
122 pub wall_height: f32,
123}
124
125impl CompiledLinedef {
126 pub fn new(start: Vec2<f32>, end: Vec2<f32>, wall_width: f32, wall_height: f32) -> Self {
127 Self {
128 start,
129 end,
130 wall_width,
131 wall_height,
132 }
133 }
134}