rmesh/
lib.rs

1use std::io::Cursor;
2
3use binrw::binrw;
4use binrw::prelude::*;
5
6// Re-exports
7pub 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            // Update min values
147            min_x = min_x.min(x);
148            min_y = min_y.min(y);
149            min_z = min_z.min(z);
150
151            // Update max values
152            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        // Initialize vertex normals with zero vectors
164        let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()];
165
166        // Calculate face normals and accumulate them to vertex normals
167        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            // Accumulate face normal to the vertices of the triangle
190            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        // Normalize vertex normals
199        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            // Update min values
225            min_x = min_x.min(x);
226            min_y = min_y.min(y);
227            min_z = min_z.min(z);
228
229            // Update max values
230            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        // Initialize vertex normals with zero vectors
242        let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()];
243
244        // Calculate face normals and accumulate them to vertex normals
245        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            // Accumulate face normal to the vertices of the triangle
268            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        // Normalize vertex normals
277        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    /// Used for aabb calc
292    fn bounding_box(&self) -> Bounds;
293    /// Calculate normals for the vertices based on the triangle faces.
294    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
334/// Reads a .rmesh file.
335pub 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
341/// Writes a .rmesh file.
342pub 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}