1use std::io::Cursor;
2
3use binrw::binrw;
4use binrw::prelude::*;
5
6pub use crate::entities::*;
8pub use crate::error::RMeshError;
9pub use crate::strings::*;
10
11mod entities;
12mod error;
13mod strings;
14
15pub const ROOM_SCALE: f32 = 8. / 2048.;
16
17pub fn header_tag(trigger_box_count: usize) -> Result<FixedLengthString, RMeshError> {
18 if trigger_box_count > 0 {
19 Ok("RoomMesh.HasTriggerBox".into())
20 } else {
21 Ok("RoomMesh".into())
22 }
23}
24
25#[binrw]
26#[derive(Debug, Default)]
27pub struct Header {
28 #[bw(try_calc(header_tag(trigger_boxes.len())))]
29 pub kind: FixedLengthString,
30
31 #[bw(try_calc(u32::try_from(meshes.len())))]
32 mesh_count: u32,
33
34 #[br(count = mesh_count)]
35 pub meshes: Vec<ComplexMesh>,
36
37 #[bw(try_calc(u32::try_from(colliders.len())))]
38 #[br(temp)]
39 collider_count: u32,
40
41 #[br(count = collider_count)]
42 pub colliders: Vec<SimpleMesh>,
43
44 #[bw(try_calc(u32::try_from(trigger_boxes.len())))]
45 #[br(temp, if(kind.values == b"RoomMesh.HasTriggerBox"))]
46 trigger_boxes_count: u32,
47
48 #[br(count = trigger_boxes_count, if(kind.values == b"RoomMesh.HasTriggerBox"))]
49 pub trigger_boxes: Vec<TriggerBox>,
50
51 #[bw(try_calc(u32::try_from(entities.len())))]
52 #[br(temp)]
53 entity_count: u32,
54
55 #[br(count = entity_count)]
56 pub entities: Vec<EntityData>,
57}
58
59#[binrw]
60#[derive(Debug, Default)]
61pub struct ComplexMesh {
62 pub textures: [Texture; 2],
63
64 #[bw(try_calc(u32::try_from(vertices.len())))]
65 #[br(temp)]
66 vertex_count: u32,
67
68 #[br(count = vertex_count)]
69 pub vertices: Vec<Vertex>,
70
71 #[bw(try_calc(u32::try_from(triangles.len())))]
72 #[br(temp)]
73 triangle_count: u32,
74
75 #[br(count = triangle_count)]
76 pub triangles: Vec<[u32; 3]>,
77}
78
79#[binrw]
80#[derive(Debug, Default)]
81pub struct Texture {
82 pub blend_type: TextureBlendType,
83
84 #[br(if(blend_type != TextureBlendType::None))]
85 pub path: Option<FixedLengthString>,
86}
87
88#[binrw]
89#[brw(repr(u8))]
90#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
91pub enum TextureBlendType {
92 #[default]
93 None,
94 Visible,
95 Lightmap,
96 Transparent,
97}
98
99#[binrw]
100#[derive(Debug, Default)]
101pub struct Vertex {
102 pub position: [f32; 3],
103 pub tex_coords: [[f32; 2]; 2],
104 pub color: [u8; 3],
105}
106
107#[binrw]
108#[derive(Debug)]
109pub struct SimpleMesh {
110 pub vertex_count: u32,
111
112 #[br(count = vertex_count)]
113 pub vertices: Vec<[f32; 3]>,
114
115 pub triangle_count: u32,
116
117 #[br(count = triangle_count)]
118 pub triangles: Vec<[u32; 3]>,
119}
120
121#[binrw]
122#[derive(Debug)]
123pub struct TriggerBox {
124 #[bw(try_calc(u32::try_from(meshes.len())))]
125 #[br(temp)]
126 pub mesh_count: u32,
127
128 #[br(count = mesh_count)]
129 pub meshes: Vec<SimpleMesh>,
130
131 pub name: FixedLengthString,
132}
133
134impl ExtMesh for SimpleMesh {
135 fn bounding_box(&self) -> Bounds {
136 let mut min_x = f32::INFINITY;
137 let mut min_y = f32::INFINITY;
138 let mut min_z = f32::INFINITY;
139 let mut max_x = f32::NEG_INFINITY;
140 let mut max_y = f32::NEG_INFINITY;
141 let mut max_z = f32::NEG_INFINITY;
142
143 for vertex in &self.vertices {
144 let [x, y, z] = *vertex;
145
146 min_x = min_x.min(x);
148 min_y = min_y.min(y);
149 min_z = min_z.min(z);
150
151 max_x = max_x.max(x);
153 max_y = max_y.max(y);
154 max_z = max_z.max(z);
155 }
156
157 let min_point = [min_x, min_y, min_z];
158 let max_point = [max_x, max_y, max_z];
159 Bounds::new(min_point, max_point)
160 }
161
162 fn calculate_normals(&self) -> Vec<[f32; 3]> {
163 let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()];
165
166 for triangle in &self.triangles {
168 let vertex0 = self.vertices[triangle[0] as usize];
169 let vertex1 = self.vertices[triangle[1] as usize];
170 let vertex2 = self.vertices[triangle[2] as usize];
171
172 let edge1 = [
173 vertex1[0] - vertex0[0],
174 vertex1[1] - vertex0[1],
175 vertex1[2] - vertex0[2],
176 ];
177 let edge2 = [
178 vertex2[0] - vertex0[0],
179 vertex2[1] - vertex0[1],
180 vertex2[2] - vertex0[2],
181 ];
182
183 let normal = [
184 edge1[1] * edge2[2] - edge1[2] * edge2[1],
185 edge1[2] * edge2[0] - edge1[0] * edge2[2],
186 edge1[0] * edge2[1] - edge1[1] * edge2[0],
187 ];
188
189 for i in 0..3 {
191 let vertex_index = triangle[i] as usize;
192 vertex_normals[vertex_index][0] += normal[0];
193 vertex_normals[vertex_index][1] += normal[1];
194 vertex_normals[vertex_index][2] += normal[2];
195 }
196 }
197
198 for normal in &mut vertex_normals {
200 let length = (normal[0].powi(2) + normal[1].powi(2) + normal[2].powi(2)).sqrt();
201 if length != 0.0 {
202 normal[0] /= length;
203 normal[1] /= length;
204 normal[2] /= length;
205 }
206 }
207
208 vertex_normals
209 }
210}
211
212impl ExtMesh for ComplexMesh {
213 fn bounding_box(&self) -> Bounds {
214 let mut min_x = f32::INFINITY;
215 let mut min_y = f32::INFINITY;
216 let mut min_z = f32::INFINITY;
217 let mut max_x = f32::NEG_INFINITY;
218 let mut max_y = f32::NEG_INFINITY;
219 let mut max_z = f32::NEG_INFINITY;
220
221 for vertex in &self.vertices {
222 let [x, y, z] = vertex.position;
223
224 min_x = min_x.min(x);
226 min_y = min_y.min(y);
227 min_z = min_z.min(z);
228
229 max_x = max_x.max(x);
231 max_y = max_y.max(y);
232 max_z = max_z.max(z);
233 }
234
235 let min_point = [min_x, min_y, min_z];
236 let max_point = [max_x, max_y, max_z];
237 Bounds::new(min_point, max_point)
238 }
239
240 fn calculate_normals(&self) -> Vec<[f32; 3]> {
241 let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()];
243
244 for triangle in &self.triangles {
246 let vertex0 = self.vertices[triangle[0] as usize].position;
247 let vertex1 = self.vertices[triangle[1] as usize].position;
248 let vertex2 = self.vertices[triangle[2] as usize].position;
249
250 let edge1 = [
251 vertex1[0] - vertex0[0],
252 vertex1[1] - vertex0[1],
253 vertex1[2] - vertex0[2],
254 ];
255 let edge2 = [
256 vertex2[0] - vertex0[0],
257 vertex2[1] - vertex0[1],
258 vertex2[2] - vertex0[2],
259 ];
260
261 let normal = [
262 edge1[1] * edge2[2] - edge1[2] * edge2[1],
263 edge1[2] * edge2[0] - edge1[0] * edge2[2],
264 edge1[0] * edge2[1] - edge1[1] * edge2[0],
265 ];
266
267 for i in 0..3 {
269 let vertex_index = triangle[i] as usize;
270 vertex_normals[vertex_index][0] += normal[0];
271 vertex_normals[vertex_index][1] += normal[1];
272 vertex_normals[vertex_index][2] += normal[2];
273 }
274 }
275
276 for normal in &mut vertex_normals {
278 let length = (normal[0].powi(2) + normal[1].powi(2) + normal[2].powi(2)).sqrt();
279 if length != 0.0 {
280 normal[0] /= length;
281 normal[1] /= length;
282 normal[2] /= length;
283 }
284 }
285
286 vertex_normals
287 }
288}
289
290pub trait ExtMesh {
291 fn bounding_box(&self) -> Bounds;
293 fn calculate_normals(&self) -> Vec<[f32; 3]>;
295}
296
297pub struct Bounds {
298 pub min: [f32; 3],
299 pub max: [f32; 3],
300}
301
302impl Bounds {
303 pub fn new(min: [f32; 3], max: [f32; 3]) -> Self {
304 Self { min, max }
305 }
306}
307
308#[binrw]
309#[derive(Debug)]
310pub struct EntityData {
311 entity_name_size: u32,
312 pub entity_type: Option<EntityType>,
313}
314
315#[binrw]
316#[derive(Debug)]
317pub enum EntityType {
318 #[br(magic = b"screen")]
319 Screen(EntityScreen),
320 #[br(magic = b"waypoint")]
321 WayPoint(EntityWaypoint),
322 #[br(magic = b"light")]
323 Light(EntityLight),
324 #[br(magic = b"spotlight")]
325 SpotLight(EntitySpotlight),
326 #[br(magic = b"soundemitter")]
327 SoundEmitter(EntitySoundEmitter),
328 #[br(magic = b"playerstart")]
329 PlayerStart(EntityPlayerStart),
330 #[br(magic = b"model")]
331 Model(EntityModel),
332}
333
334pub fn read_rmesh(bytes: &[u8]) -> Result<Header, RMeshError> {
336 let mut cursor = Cursor::new(bytes);
337 let header: Header = cursor.read_le()?;
338 Ok(header)
339}
340
341pub fn write_rmesh(header: &Header) -> Result<Vec<u8>, RMeshError> {
343 let mut bytes = Vec::new();
344 let mut cursor = Cursor::new(&mut bytes);
345
346 cursor.write_le(header)?;
347
348 Ok(bytes)
349}