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(
23 feature = "tracing",
24 tracing::instrument(level = "debug", skip(writer, bwm))
25)]
26pub fn write_bwm<W: Write>(writer: &mut W, bwm: &Bwm) -> Result<(), BwmBinaryError> {
27 let vertex_count = bwm.vertices.len();
28 let face_count = bwm.faces.len();
29 let aabb_count = bwm.aabb_nodes.len();
30 let adjacency_count = bwm.adjacencies.len();
31 let edge_count = bwm.edges.len();
32 let perimeter_count = bwm.perimeters.len();
33
34 for (index, face) in bwm.faces.iter().enumerate() {
35 for (slot, vertex_index) in face.vertex_indices.iter().enumerate() {
36 let vertex_index = crate::binary::checked_to_usize(*vertex_index, "face_vertex_index")?;
37 if vertex_index >= vertex_count {
38 return Err(BwmBinaryError::InvalidData(format!(
39 "faces[{index}].vertex_indices[{slot}] out of bounds for {vertex_count} vertices"
40 )));
41 }
42 }
43 }
44
45 let vertex_offset = FILE_HEADER_SIZE;
47 let vertex_size = checked_mul(vertex_count, VERTEX_ENTRY_SIZE, "vertex_size")?;
48 let face_indices_offset = checked_add(vertex_offset, vertex_size, "face_indices_offset")?;
49 let face_indices_size = checked_mul(face_count, FACE_INDEX_ENTRY_SIZE, "face_indices_size")?;
50 let materials_offset = checked_add(face_indices_offset, face_indices_size, "materials_offset")?;
51 let materials_size = checked_mul(face_count, MATERIAL_ENTRY_SIZE, "materials_size")?;
52 let normals_offset = checked_add(materials_offset, materials_size, "normals_offset")?;
53 let normals_size = checked_mul(face_count, NORMAL_ENTRY_SIZE, "normals_size")?;
54 let planar_distances_offset =
55 checked_add(normals_offset, normals_size, "planar_distances_offset")?;
56 let distances_size = checked_mul(face_count, DISTANCE_ENTRY_SIZE, "distances_size")?;
57 let aabb_offset = checked_add(planar_distances_offset, distances_size, "aabb_offset")?;
58 let aabb_size = checked_mul(aabb_count, AABB_ENTRY_SIZE, "aabb_size")?;
59 let adjacency_offset = checked_add(aabb_offset, aabb_size, "adjacency_offset")?;
60 let adjacency_size = checked_mul(adjacency_count, ADJACENCY_ENTRY_SIZE, "adjacency_size")?;
61 let edges_offset = checked_add(adjacency_offset, adjacency_size, "edges_offset")?;
62 let edge_size = checked_mul(edge_count, EDGE_ENTRY_SIZE, "edge_size")?;
63 let perimeters_offset = checked_add(edges_offset, edge_size, "perimeters_offset")?;
64
65 writer.write_all(&BWM_MAGIC)?;
67 writer.write_all(&BWM_VERSION_V10)?;
68
69 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(
82 writer,
83 usize_to_u32(face_indices_offset, "face_indices_offset")?,
84 )?; write_u32(writer, usize_to_u32(materials_offset, "materials_offset")?)?; write_u32(writer, usize_to_u32(normals_offset, "normals_offset")?)?; write_u32(
88 writer,
89 usize_to_u32(planar_distances_offset, "planar_distances_offset")?,
90 )?; 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(
100 writer,
101 usize_to_u32(perimeters_offset, "perimeters_offset")?,
102 )?; for vertex in &bwm.vertices {
106 write_vec3(writer, *vertex)?;
107 }
108
109 for face in &bwm.faces {
111 write_u32(writer, face.vertex_indices[0])?;
112 write_u32(writer, face.vertex_indices[1])?;
113 write_u32(writer, face.vertex_indices[2])?;
114 }
115 for face in &bwm.faces {
116 write_u32(writer, face.material_id)?;
117 }
118 for face in &bwm.faces {
119 write_vec3(writer, face.normal)?;
120 }
121 for face in &bwm.faces {
122 write_f32(writer, face.planar_distance)?;
123 }
124
125 for node in &bwm.aabb_nodes {
127 write_vec3(writer, node.bb_min)?;
128 write_vec3(writer, node.bb_max)?;
129 write_u32(writer, node.face_index)?;
130 write_u32(writer, node.unknown)?;
131 write_u32(writer, node.split_axis)?;
132 write_u32(writer, node.left_child)?;
133 write_u32(writer, node.right_child)?;
134 }
135
136 for adjacency in &bwm.adjacencies {
138 write_i32(writer, adjacency.edge_refs[0])?;
139 write_i32(writer, adjacency.edge_refs[1])?;
140 write_i32(writer, adjacency.edge_refs[2])?;
141 }
142 for edge in &bwm.edges {
143 write_i32(writer, edge.edge_index)?;
144 write_i32(writer, edge.transition)?;
145 }
146 for perimeter in &bwm.perimeters {
147 write_u32(writer, *perimeter)?;
148 }
149
150 Ok(())
151}
152
153#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(bwm)))]
160pub fn write_bwm_to_vec(bwm: &Bwm) -> Result<Vec<u8>, BwmBinaryError> {
161 let mut cursor = Cursor::new(Vec::new());
162 write_bwm(&mut cursor, bwm)?;
163 Ok(cursor.into_inner())
164}
165
166fn write_vec3<W: Write>(writer: &mut W, value: BwmVec3) -> Result<(), BwmBinaryError> {
167 write_f32(writer, value.x)?;
168 write_f32(writer, value.y)?;
169 write_f32(writer, value.z)?;
170 Ok(())
171}