Skip to main content

banished_formats/
picking.rs

1//! Picking geometry: the meshes that select and highlight entities.
2//!
3//! Original: Runtime `0x1801251f0`, `0x18007b6f0`, `0x18007ae20`.
4use crate::{crs, Result};
5
6/// A triangle of a picking mesh.
7#[derive(Debug, Clone)]
8pub struct Triangle {
9    /// The indices of its three vertices.
10    pub vertices: [u16; 3],
11    /// The indices of its three normals.
12    pub normals: [u16; 3],
13}
14
15/// A part of a picking mesh.
16#[derive(Debug, Clone)]
17pub struct SubMesh {
18    /// The name.
19    pub name: String,
20    /// Parent submesh index, used by Runtime AddMesh's bind hierarchy (root is -1).
21    pub node: i32,
22    /// The rotation, a quaternion (x, y, z, w).
23    pub rotation: [f32; 4],
24    /// The translation.
25    pub translation: [f32; 3],
26    /// The lowest corner of its bounds.
27    pub bounds_min: [f32; 3],
28    /// The highest corner of its bounds.
29    pub bounds_max: [f32; 3],
30    /// The vertices.
31    pub vertices: Vec<[f32; 3]>,
32    /// The normals.
33    pub normals: Vec<[f32; 3]>,
34    /// The triangles.
35    pub triangles: Vec<Triangle>,
36    /// The edges: pairs of vertex indices.
37    pub edges: Vec<[u16; 2]>,
38}
39
40/// The simplified mesh the game tests the pointer against, to select an entity.
41#[derive(Debug, Clone)]
42pub struct PickingMesh {
43    /// The source file.
44    pub source: String,
45    /// The name.
46    pub name: String,
47    /// Whether it follows a skeleton (*inferred*).
48    pub skinned: bool,
49    /// The parts.
50    pub meshes: Vec<SubMesh>,
51}
52
53fn shorts<const N: usize>(r: &mut crs::Reader<'_>) -> Result<[u16; N]> {
54    let mut out = [0; N];
55    for n in &mut out {
56        *n = u16::from_le_bytes(r.bytes(2)?.try_into().unwrap());
57    }
58    Ok(out)
59}
60
61/// Read a [`PickingMesh`] from the bytes of its resource.
62pub fn picking_mesh(data: &[u8]) -> Result<PickingMesh> {
63    crs::parse(data, |r, _| {
64        r.block(|r, _| {
65            let source = r.string()?;
66            let name = r.string()?;
67            let skinned = r.bool()?;
68            let mut meshes = Vec::new();
69            for _ in 0..r.count()? {
70                let name = r.string()?;
71                let node = r.i32()?;
72                let rotation = r.f32s()?;
73                let translation = r.f32s()?;
74                let bounds_min = r.f32s()?;
75                let bounds_max = r.f32s()?;
76                let mut vertices = Vec::new();
77                for _ in 0..r.count()? {
78                    vertices.push(r.f32s()?);
79                }
80                let mut normals = Vec::new();
81                for _ in 0..r.count()? {
82                    normals.push(r.f32s()?);
83                }
84                let mut triangles = Vec::new();
85                for _ in 0..r.count()? {
86                    triangles.push(Triangle {
87                        vertices: shorts(r)?,
88                        normals: shorts(r)?,
89                    });
90                }
91                let mut edges = Vec::new();
92                for _ in 0..r.count()? {
93                    edges.push(shorts(r)?);
94                }
95                meshes.push(SubMesh {
96                    name,
97                    node,
98                    rotation,
99                    translation,
100                    bounds_min,
101                    bounds_max,
102                    vertices,
103                    normals,
104                    triangles,
105                    edges,
106                });
107            }
108            Ok(PickingMesh {
109                source,
110                name,
111                skinned,
112                meshes,
113            })
114        })
115    })
116    .map(|(_, v)| v)
117}
118
119/// A `PickingDescription`: the meshes that select an entity, for each model variant and each
120/// construction stage.
121///
122/// Original: `FUN_14012e1d0`.
123#[derive(Debug, Clone)]
124pub struct PickingDescription {
125    /// The meshes, by model variant, then by construction stage.
126    pub meshes: Vec<Vec<Option<String>>>,
127    /// The material.
128    pub material: Option<String>,
129    /// Not identified yet.
130    pub flag_38: bool,
131}
132
133/// Read a [`PickingDescription`] from the bytes of its resource.
134pub fn picking_description(data: &[u8]) -> Result<PickingDescription> {
135    crs::parse(data, |r, _| {
136        r.block(|r, _| {
137            let mut meshes = Vec::new();
138            for _ in 0..r.count()? {
139                let mut stages = Vec::new();
140                for _ in 0..r.count()? {
141                    stages.push(r.external_ref()?);
142                }
143                meshes.push(stages);
144            }
145            Ok(PickingDescription {
146                meshes,
147                material: r.external_ref()?,
148                flag_38: r.bool()?,
149            })
150        })
151    })
152    .map(|(_, v)| v)
153}
154
155/// A `HighlightDescription`: the meshes drawn to highlight an entity, in the order of the model's
156/// variants and stages.
157///
158/// Original: `FUN_14004d330`.
159#[derive(Debug, Clone)]
160pub struct HighlightDescription {
161    /// The meshes, by model variant, then by stage.
162    pub meshes: Vec<Vec<Option<String>>>,
163    /// The material of the mask.
164    pub mask_material: Option<String>,
165    /// The material of the edges.
166    pub edge_material: Option<String>,
167}
168
169/// Read a [`HighlightDescription`] from the bytes of its resource.
170pub fn highlight_description(data: &[u8]) -> Result<HighlightDescription> {
171    crs::parse(data, |r, _| {
172        r.block(|r, _| {
173            let mut meshes = Vec::new();
174            for _ in 0..r.count()? {
175                let mut stages = Vec::new();
176                for _ in 0..r.count()? {
177                    stages.push(r.external_ref()?);
178                }
179                meshes.push(stages);
180            }
181            Ok(HighlightDescription {
182                meshes,
183                mask_material: r.external_ref()?,
184                edge_material: r.external_ref()?,
185            })
186        })
187    })
188    .map(|(_, v)| v)
189}
190
191/// `Graphics::EdgeMesh`: the mask and edge meshes of a highlight. Its ranges have the same six
192/// integers as a GraphicsMesh's.
193///
194/// Original: `Graphics::EdgeMesh::Serialize`, Runtime `0x1800a3120`.
195#[derive(Debug, Clone)]
196pub struct EdgeMesh {
197    /// Five external references; not identified yet.
198    pub references: [Option<String>; 5],
199    /// The draw ranges of the mask.
200    pub ranges: Vec<[i32; 6]>,
201    /// The draw ranges of the edges.
202    pub edge_ranges: Vec<[i32; 6]>,
203    /// Mask indices/vertices (rigid, skinned), then edge indices/vertices (rigid, skinned).
204    pub buffers: [Vec<u8>; 8],
205    /// The lowest corner of its bounds.
206    pub bounds_min: [f32; 3],
207    /// The highest corner of its bounds.
208    pub bounds_max: [f32; 3],
209}
210
211/// Read a [`EdgeMesh`] from the bytes of its resource.
212pub fn edge_mesh(data: &[u8]) -> Result<EdgeMesh> {
213    crs::parse(data, |r, _| {
214        r.block(|r, _| {
215            let mut references = [const { None }; 5];
216            for v in &mut references {
217                *v = r.external_ref()?;
218            }
219            let mut ranges = Vec::new();
220            for _ in 0..r.count()? {
221                ranges.push([r.i32()?, r.i32()?, r.i32()?, r.i32()?, r.i32()?, r.i32()?]);
222            }
223            let mut edge_ranges = Vec::new();
224            for _ in 0..r.count()? {
225                edge_ranges.push([r.i32()?, r.i32()?, r.i32()?, r.i32()?, r.i32()?, r.i32()?]);
226            }
227            let mut buffers = std::array::from_fn(|_| Vec::new());
228            for b in &mut buffers {
229                r.u8()?;
230                let count = r.count()?;
231                *b = r.bytes(count)?.to_vec();
232            }
233            Ok(EdgeMesh {
234                references,
235                ranges,
236                edge_ranges,
237                buffers,
238                bounds_min: r.f32s()?,
239                bounds_max: r.f32s()?,
240            })
241        })
242    })
243    .map(|(_, v)| v)
244}