1use std::io::{Cursor, Write};
4
5use super::{
6 binary::{write_f32, write_i32, write_u32},
7 checked_add, checked_mul, usize_to_u32, Bwm, BwmBinaryError, BwmVec3, AABB_ENTRY_SIZE,
8 ADJACENCY_ENTRY_SIZE, BWM_MAGIC, BWM_VERSION_V10, DISTANCE_ENTRY_SIZE, EDGE_ENTRY_SIZE,
9 FACE_INDEX_ENTRY_SIZE, FILE_HEADER_SIZE, MATERIAL_ENTRY_SIZE, NORMAL_ENTRY_SIZE,
10 VERTEX_ENTRY_SIZE,
11};
12
13#[cfg_attr(
15 feature = "tracing",
16 tracing::instrument(level = "debug", skip(writer, bwm))
17)]
18pub fn write_bwm<W: Write>(writer: &mut W, bwm: &Bwm) -> Result<(), BwmBinaryError> {
19 let vertex_count = bwm.vertices.len();
20 let face_count = bwm.faces.len();
21 let aabb_count = bwm.aabb_nodes.len();
22 let adjacency_count = bwm.adjacencies.len();
23 let edge_count = bwm.edges.len();
24 let perimeter_count = bwm.perimeters.len();
25
26 for (index, face) in bwm.faces.iter().enumerate() {
27 for (slot, vertex_index) in face.vertex_indices.iter().enumerate() {
28 let vertex_index = crate::binary::checked_to_usize(*vertex_index, "face_vertex_index")?;
29 if vertex_index >= vertex_count {
30 return Err(BwmBinaryError::InvalidData(format!(
31 "faces[{index}].vertex_indices[{slot}] out of bounds for {vertex_count} vertices"
32 )));
33 }
34 }
35 }
36
37 let vertex_offset = FILE_HEADER_SIZE;
39 let vertex_size = checked_mul(vertex_count, VERTEX_ENTRY_SIZE, "vertex_size")?;
40 let face_indices_offset = checked_add(vertex_offset, vertex_size, "face_indices_offset")?;
41 let face_indices_size = checked_mul(face_count, FACE_INDEX_ENTRY_SIZE, "face_indices_size")?;
42 let materials_offset = checked_add(face_indices_offset, face_indices_size, "materials_offset")?;
43 let materials_size = checked_mul(face_count, MATERIAL_ENTRY_SIZE, "materials_size")?;
44 let normals_offset = checked_add(materials_offset, materials_size, "normals_offset")?;
45 let normals_size = checked_mul(face_count, NORMAL_ENTRY_SIZE, "normals_size")?;
46 let planar_distances_offset =
47 checked_add(normals_offset, normals_size, "planar_distances_offset")?;
48 let distances_size = checked_mul(face_count, DISTANCE_ENTRY_SIZE, "distances_size")?;
49 let aabb_offset = checked_add(planar_distances_offset, distances_size, "aabb_offset")?;
50 let aabb_size = checked_mul(aabb_count, AABB_ENTRY_SIZE, "aabb_size")?;
51 let adjacency_offset = checked_add(aabb_offset, aabb_size, "adjacency_offset")?;
52 let adjacency_size = checked_mul(adjacency_count, ADJACENCY_ENTRY_SIZE, "adjacency_size")?;
53 let edges_offset = checked_add(adjacency_offset, adjacency_size, "edges_offset")?;
54 let edge_size = checked_mul(edge_count, EDGE_ENTRY_SIZE, "edge_size")?;
55 let perimeters_offset = checked_add(edges_offset, edge_size, "perimeters_offset")?;
56
57 writer.write_all(&BWM_MAGIC)?;
59 writer.write_all(&BWM_VERSION_V10)?;
60
61 write_u32(writer, bwm.walkmesh_type.raw())?; write_vec3(writer, bwm.relative_hook1)?; write_vec3(writer, bwm.relative_hook2)?; write_vec3(writer, bwm.absolute_hook1)?; write_vec3(writer, bwm.absolute_hook2)?; write_vec3(writer, bwm.position)?; write_u32(writer, usize_to_u32(vertex_count, "vertex_count")?)?; write_u32(writer, usize_to_u32(vertex_offset, "vertex_offset")?)?; write_u32(writer, usize_to_u32(face_count, "face_count")?)?; write_u32(
74 writer,
75 usize_to_u32(face_indices_offset, "face_indices_offset")?,
76 )?; write_u32(writer, usize_to_u32(materials_offset, "materials_offset")?)?; write_u32(writer, usize_to_u32(normals_offset, "normals_offset")?)?; write_u32(
80 writer,
81 usize_to_u32(planar_distances_offset, "planar_distances_offset")?,
82 )?; write_u32(writer, usize_to_u32(aabb_count, "aabb_count")?)?; write_u32(writer, usize_to_u32(aabb_offset, "aabb_offset")?)?; write_u32(writer, bwm.unknown)?; write_u32(writer, usize_to_u32(adjacency_count, "adjacency_count")?)?; write_u32(writer, usize_to_u32(adjacency_offset, "adjacency_offset")?)?; write_u32(writer, usize_to_u32(edge_count, "edge_count")?)?; write_u32(writer, usize_to_u32(edges_offset, "edges_offset")?)?; write_u32(writer, usize_to_u32(perimeter_count, "perimeter_count")?)?; write_u32(
92 writer,
93 usize_to_u32(perimeters_offset, "perimeters_offset")?,
94 )?; for vertex in &bwm.vertices {
98 write_vec3(writer, *vertex)?;
99 }
100
101 for face in &bwm.faces {
103 write_u32(writer, face.vertex_indices[0])?;
104 write_u32(writer, face.vertex_indices[1])?;
105 write_u32(writer, face.vertex_indices[2])?;
106 }
107 for face in &bwm.faces {
108 write_u32(writer, face.material_id)?;
109 }
110 for face in &bwm.faces {
111 write_vec3(writer, face.normal)?;
112 }
113 for face in &bwm.faces {
114 write_f32(writer, face.planar_distance)?;
115 }
116
117 for node in &bwm.aabb_nodes {
119 write_vec3(writer, node.bb_min)?;
120 write_vec3(writer, node.bb_max)?;
121 write_u32(writer, node.face_index)?;
122 write_u32(writer, node.unknown)?;
123 write_u32(writer, node.split_axis)?;
124 write_u32(writer, node.left_child)?;
125 write_u32(writer, node.right_child)?;
126 }
127
128 for adjacency in &bwm.adjacencies {
130 write_i32(writer, adjacency.edge_refs[0])?;
131 write_i32(writer, adjacency.edge_refs[1])?;
132 write_i32(writer, adjacency.edge_refs[2])?;
133 }
134 for edge in &bwm.edges {
135 write_i32(writer, edge.edge_index)?;
136 write_i32(writer, edge.transition)?;
137 }
138 for perimeter in &bwm.perimeters {
139 write_u32(writer, *perimeter)?;
140 }
141
142 Ok(())
143}
144
145#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(bwm)))]
147pub fn write_bwm_to_vec(bwm: &Bwm) -> Result<Vec<u8>, BwmBinaryError> {
148 let mut cursor = Cursor::new(Vec::new());
149 write_bwm(&mut cursor, bwm)?;
150 Ok(cursor.into_inner())
151}
152
153fn write_vec3<W: Write>(writer: &mut W, value: BwmVec3) -> Result<(), BwmBinaryError> {
154 write_f32(writer, value.x)?;
155 write_f32(writer, value.y)?;
156 write_f32(writer, value.z)?;
157 Ok(())
158}