1use std::collections::HashMap;
13use std::io::{Cursor, Write};
14
15use crate::binary::{write_f32, write_i32, write_u16, write_u32};
16
17use super::controllers::MdlController;
18use super::types::MdlNodeData;
19use super::{
20 aabb_offsets, anim_mesh_offsets, dangly_offsets, header_offsets, light_offsets, mesh_offsets,
21 node_offsets, saber_offsets, skin_offsets, Mdl, MdlError, MdlNode, AABB_EXTRA_SIZE,
22 ANIM_MESH_EXTRA_SIZE, DANGLY_EXTRA_SIZE, LIGHT_EXTRA_SIZE, MDL_WRAPPER_SIZE, MESH_EXTRA_SIZE,
23 NODE_HEADER_SIZE, SABER_EXTRA_SIZE, SKIN_EXTRA_SIZE,
24};
25
26struct MeshRef<'a> {
28 mesh: &'a super::MdlMesh,
30 skin: Option<&'a super::MdlSkin>,
32 is_skin: bool,
34}
35
36#[cfg_attr(
45 feature = "tracing",
46 tracing::instrument(level = "debug", skip(writer, mdl))
47)]
48pub fn write_mdl<W: Write>(writer: &mut W, mdl: &Mdl) -> Result<(), MdlError> {
49 let bytes = write_mdl_to_vec(mdl)?;
50 crate::trace_debug!(bytes_len = bytes.len(), "wrote mdl to writer");
51 writer.write_all(&bytes)?;
52 Ok(())
53}
54
55#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(mdl)))]
62pub fn write_mdl_to_vec(mdl: &Mdl) -> Result<Vec<u8>, MdlError> {
63 let writer = MdlWriter::new();
64 let (bytes, _) = writer.write(mdl)?;
65 crate::trace_debug!(bytes_len = bytes.len(), "serialized mdl to vec");
66 Ok(bytes)
67}
68
69#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(mdl)))]
82pub fn write_mdl_with_mdx_to_vec(mdl: &Mdl) -> Result<super::MdlWriteResult, MdlError> {
83 let writer = MdlWriter::new_with_mdx();
84 let (mdl_bytes, mdx_bytes) = writer.write(mdl)?;
85 crate::trace_debug!(
86 mdl_bytes_len = mdl_bytes.len(),
87 mdx_bytes_len = mdx_bytes.len(),
88 "serialized mdl+mdx to vec"
89 );
90 Ok(super::MdlWriteResult {
91 mdl_bytes,
92 mdx_bytes,
93 })
94}
95
96fn count_u32(len: usize, field: &'static str) -> Result<u32, MdlError> {
98 u32::try_from(len).map_err(|_| MdlError::ValueOverflow(field))
99}
100
101fn count_u16(len: usize, field: &'static str) -> Result<u16, MdlError> {
103 u16::try_from(len).map_err(|_| MdlError::ValueOverflow(field))
104}
105
106struct DeferredMdxEntry {
110 mesh_header_pos: u64,
112 skin_header_pos: Option<u64>,
114 is_skin: bool,
116 dfs_index: usize,
118}
119
120struct MdlWriter {
121 buffer: Cursor<Vec<u8>>,
122 mdx_buffer: Cursor<Vec<u8>>,
123 write_mdx: bool,
124 names: Vec<String>,
125 name_map: HashMap<String, u16>,
126 name_string_offsets: Vec<u32>,
128 mdx_pre_align_pos: u64,
131 deferred_mdx: Vec<DeferredMdxEntry>,
133 node_offset_map: HashMap<String, u32>,
136}
137
138impl MdlWriter {
139 fn new() -> Self {
140 MdlWriter {
141 buffer: Cursor::new(Vec::new()),
142 mdx_buffer: Cursor::new(Vec::new()),
143 write_mdx: false,
144 names: Vec::new(),
145 name_map: HashMap::new(),
146 name_string_offsets: Vec::new(),
147 mdx_pre_align_pos: 0,
148 deferred_mdx: Vec::new(),
149 node_offset_map: HashMap::new(),
150 }
151 }
152
153 fn new_with_mdx() -> Self {
154 MdlWriter {
155 buffer: Cursor::new(Vec::new()),
156 mdx_buffer: Cursor::new(Vec::new()),
157 write_mdx: true,
158 names: Vec::new(),
159 name_map: HashMap::new(),
160 name_string_offsets: Vec::new(),
161 mdx_pre_align_pos: 0,
162 deferred_mdx: Vec::new(),
163 node_offset_map: HashMap::new(),
164 }
165 }
166
167 fn content_position(&self) -> Result<u32, MdlError> {
170 let pos = self.buffer.position();
171 let content = pos
172 .checked_sub(MDL_WRAPPER_SIZE)
173 .ok_or(MdlError::ValueOverflow("content_position underflow"))?;
174 u32::try_from(content).map_err(|_| MdlError::ValueOverflow("content_position"))
175 }
176
177 fn mdx_position(&self) -> Result<u32, MdlError> {
179 u32::try_from(self.mdx_buffer.position())
180 .map_err(|_| MdlError::ValueOverflow("mdx_position"))
181 }
182
183 fn seek_to(&mut self, base: u64, offset: usize) {
185 self.buffer
186 .set_position(base + u64::try_from(offset).expect("offset fits in u64"));
187 }
188
189 fn write(mut self, mdl: &Mdl) -> Result<(Vec<u8>, Vec<u8>), MdlError> {
190 self.collect_names(&mdl.root_node);
192 for anim in &mdl.animations {
193 self.collect_anim_names(&anim.root_node);
194 }
195
196 #[allow(clippy::as_conversions)]
198 const WRAPPER_BYTES: usize = MDL_WRAPPER_SIZE as usize;
199 #[allow(clippy::as_conversions)]
201 const _: () = assert!(MDL_WRAPPER_SIZE == WRAPPER_BYTES as u64);
202 self.buffer.write_all(&[0u8; WRAPPER_BYTES])?;
203
204 let header_start = self.buffer.position();
206 self.buffer.write_all(&[0u8; 196])?;
207
208 let name_offsets_ptr = self.content_position()?;
210 let name_count = count_u32(self.names.len(), "name_count")?;
211
212 let name_offsets_start = self.buffer.position();
214 for _ in 0..name_count {
215 write_u32(&mut self.buffer, 0)?;
216 }
217
218 self.name_string_offsets = Vec::with_capacity(self.names.len());
220 let mut current_offset_pos = name_offsets_start;
221 for name in &self.names {
222 let str_start = self.content_position()?;
223 self.name_string_offsets.push(str_start);
224
225 let save_pos = self.buffer.position();
227 self.buffer.set_position(current_offset_pos);
228 write_u32(&mut self.buffer, str_start)?;
229 self.buffer.set_position(save_pos);
230 current_offset_pos += 4;
231
232 self.buffer.write_all(name.as_bytes())?;
234 self.buffer.write_all(&[0u8])?;
235 }
236
237 let root_node_offset = self.write_node(&mdl.root_node, None)?;
239
240 if self.write_mdx && !self.deferred_mdx.is_empty() {
244 self.write_deferred_mdx(&mdl.root_node)?;
245 }
246
247 let (anim_arr_ptr, anim_arr_count) = self.write_animations(&mdl.animations)?;
249
250 self.seek_to(header_start, header_offsets::FN_PTR1);
254 write_u32(&mut self.buffer, mdl.geometry_fn_ptr1)?;
255
256 self.seek_to(header_start, header_offsets::FN_PTR2);
257 write_u32(&mut self.buffer, mdl.geometry_fn_ptr2)?;
258
259 self.seek_to(header_start, header_offsets::MODEL_NAME);
261 let model_name = mdl.root_node.name.as_bytes();
262 let model_name_len = model_name.len().min(header_offsets::MODEL_NAME_SIZE - 1);
263 self.buffer.write_all(&model_name[..model_name_len])?;
264 self.buffer.write_all(&[0])?;
265
266 self.seek_to(header_start, header_offsets::ROOT_NODE_PTR);
267 write_u32(&mut self.buffer, root_node_offset)?;
268
269 self.seek_to(header_start, header_offsets::NODE_COUNT);
270 write_u32(&mut self.buffer, mdl.node_count)?;
271
272 self.seek_to(header_start, header_offsets::MODEL_TYPE);
277 self.buffer.write_all(&[mdl.model_type])?;
278
279 self.seek_to(header_start, header_offsets::CLASSIFICATION);
281 self.buffer.write_all(&[mdl.classification])?;
282
283 self.seek_to(header_start, header_offsets::SUBCLASSIFICATION);
284 self.buffer.write_all(&[mdl.subclassification])?;
285
286 self.seek_to(header_start, header_offsets::AFFECTED_BY_FOG);
289 self.buffer.write_all(&[mdl.affected_by_fog])?;
290
291 self.seek_to(header_start, header_offsets::ANIMATION_ARR_PTR);
295 write_u32(&mut self.buffer, anim_arr_ptr)?;
296 write_u32(&mut self.buffer, anim_arr_count)?;
297 write_u32(&mut self.buffer, anim_arr_count)?; self.seek_to(header_start, header_offsets::BOUNDING_BOX_MIN);
303 for &val in &mdl.bounding_box {
304 write_f32(&mut self.buffer, val)?;
305 }
306
307 self.seek_to(header_start, header_offsets::RADIUS);
309 write_f32(&mut self.buffer, mdl.radius)?;
310
311 self.seek_to(header_start, header_offsets::ANIMATION_SCALE);
313 write_f32(&mut self.buffer, mdl.animation_scale)?;
314
315 self.seek_to(header_start, header_offsets::SUPERMODEL_NAME);
317 let name_bytes = mdl.supermodel_name.as_bytes();
318 let write_len = name_bytes
319 .len()
320 .min(header_offsets::SUPERMODEL_NAME_SIZE - 1);
321 self.buffer.write_all(&name_bytes[..write_len])?;
322 self.buffer.write_all(&[0])?;
323
324 let anim_root_offset = mdl
328 .anim_root_node
329 .as_ref()
330 .and_then(|name| self.node_offset_map.get(name).copied())
331 .unwrap_or(root_node_offset);
332 self.seek_to(header_start, header_offsets::OFF_ANIM_ROOT);
333 write_u32(&mut self.buffer, anim_root_offset)?;
334
335 self.seek_to(header_start, header_offsets::NAME_OFFSETS_PTR);
339 write_u32(&mut self.buffer, name_offsets_ptr)?;
340
341 self.seek_to(header_start, header_offsets::NAME_COUNT);
342 write_u32(&mut self.buffer, name_count)?;
343
344 let mut mdl_bytes = self.buffer.into_inner();
345 let mut mdx_bytes = self.mdx_buffer.into_inner();
346
347 let trim_to =
353 usize::try_from(self.mdx_pre_align_pos).expect("mdx_pre_align_pos fits in usize");
354 if trim_to > 0 && trim_to < mdx_bytes.len() {
355 mdx_bytes.truncate(trim_to);
356 }
357
358 let mdl_content_size = mdl_bytes
361 .len()
362 .checked_sub(WRAPPER_BYTES)
363 .ok_or_else(|| MdlError::InvalidData("serialized MDL shorter than wrapper".into()))?;
364 let mdl_content_size_u32 = u32::try_from(mdl_content_size)
365 .map_err(|_| MdlError::ValueOverflow("mdl_content_size"))?;
366 let mdx_size_u32 =
367 u32::try_from(mdx_bytes.len()).map_err(|_| MdlError::ValueOverflow("mdx_file_size"))?;
368 mdl_bytes[0..4].copy_from_slice(&0u32.to_le_bytes());
369 mdl_bytes[4..8].copy_from_slice(&mdl_content_size_u32.to_le_bytes());
370 mdl_bytes[8..12].copy_from_slice(&mdx_size_u32.to_le_bytes());
371
372 let mdx_size_offset = WRAPPER_BYTES + header_offsets::MDX_SIZE;
374 mdl_bytes[mdx_size_offset..mdx_size_offset + 4]
375 .copy_from_slice(&mdx_size_u32.to_le_bytes());
376
377 Ok((mdl_bytes, mdx_bytes))
378 }
379
380 fn write_deferred_mdx(&mut self, root: &MdlNode) -> Result<(), MdlError> {
389 let mut mesh_refs: Vec<MeshRef<'_>> = Vec::new();
391 Self::collect_mesh_refs(root, &mut mesh_refs);
392
393 debug_assert_eq!(mesh_refs.len(), self.deferred_mdx.len());
395
396 let entries: Vec<DeferredMdxEntry> = std::mem::take(&mut self.deferred_mdx);
400 let (non_skin, skin): (Vec<usize>, Vec<usize>) =
401 (0..entries.len()).partition(|&i| !entries[i].is_skin);
402 let ordered: Vec<usize> = non_skin.into_iter().chain(skin).collect();
403
404 for idx in &ordered {
405 let entry = &entries[*idx];
406 let mesh_ref = &mesh_refs[entry.dfs_index];
407
408 let mdx_offset = self.mdx_position()?;
411
412 let stride = self.write_mesh_mdx_data(
413 mesh_ref.mesh,
414 mesh_ref.skin,
415 entry.mesh_header_pos,
416 entry.skin_header_pos,
417 )?;
418 self.write_mdx_terminator(stride, mesh_ref.is_skin)?;
419
420 let save = self.buffer.position();
425 self.seek_to(entry.mesh_header_pos, mesh_offsets::MDX_DATA_OFFSET);
426 write_u32(&mut self.buffer, mdx_offset)?;
427 self.buffer.set_position(save);
428 }
429
430 Ok(())
431 }
432
433 fn collect_mesh_refs<'a>(node: &'a MdlNode, out: &mut Vec<MeshRef<'a>>) {
439 if !node.is_saber() {
440 if let Some(mesh) = node.node_data.mesh() {
441 let skin = if let MdlNodeData::Skin(s) = &node.node_data {
442 Some(s)
443 } else {
444 None
445 };
446 out.push(MeshRef {
447 mesh,
448 skin,
449 is_skin: node.is_skin(),
450 });
451 }
452 }
453 for child in &node.children {
454 Self::collect_mesh_refs(child, out);
455 }
456 }
457
458 fn collect_names(&mut self, node: &MdlNode) {
459 if !self.name_map.contains_key(&node.name) {
460 let index = count_u16(self.names.len(), "name_index")
461 .expect("name table must not exceed u16::MAX entries during collect_names");
462 self.name_map.insert(node.name.clone(), index);
466 self.names.push(node.name.clone());
467 }
468 for child in &node.children {
469 self.collect_names(child);
470 }
471 }
472
473 fn collect_anim_names(&mut self, node: &super::MdlAnimNode) {
474 if !self.name_map.contains_key(&node.name) {
475 let index = count_u16(self.names.len(), "name_index")
476 .expect("name table must not exceed u16::MAX entries during collect_anim_names");
477 self.name_map.insert(node.name.clone(), index);
478 self.names.push(node.name.clone());
479 }
480 for child in &node.children {
481 self.collect_anim_names(child);
482 }
483 }
484
485 fn write_animations(
492 &mut self,
493 animations: &[super::MdlAnimation],
494 ) -> Result<(u32, u32), MdlError> {
495 if animations.is_empty() {
496 return Ok((0, 0));
497 }
498
499 let arr_ptr = self.content_position()?;
501 let arr_count = count_u32(animations.len(), "animation_count")?;
502
503 let arr_start = self.buffer.position();
505 for _ in 0..arr_count {
506 write_u32(&mut self.buffer, 0)?;
507 }
508
509 let mut anim_offsets = Vec::with_capacity(animations.len());
510 for anim in animations {
511 let offset = self.write_animation(anim)?;
512 anim_offsets.push(offset);
513 }
514
515 let save_pos = self.buffer.position();
517 self.buffer.set_position(arr_start);
518 for &offset in &anim_offsets {
519 write_u32(&mut self.buffer, offset)?;
520 }
521 self.buffer.set_position(save_pos);
522
523 Ok((arr_ptr, arr_count))
524 }
525
526 fn write_animation(&mut self, anim: &super::MdlAnimation) -> Result<u32, MdlError> {
529 let anim_offset = self.content_position()?;
530
531 let header_pos = self.buffer.position();
533 self.buffer
534 .write_all(&[0u8; super::ANIMATION_HEADER_SIZE])?;
535
536 let events_ptr = if anim.events.is_empty() {
538 0u32
539 } else {
540 let ptr = self.content_position()?;
541 for event in &anim.events {
542 write_f32(&mut self.buffer, event.time)?;
543 self.write_fixed_string(&event.name, 32)?;
544 }
545 ptr
546 };
547 let event_count = count_u32(anim.events.len(), "event_count")?;
548
549 let root_node_offset = self.write_anim_node(&anim.root_node, anim_offset, None)?;
551
552 let total_nodes = super::count_anim_nodes(&anim.root_node);
554
555 let save_pos = self.buffer.position();
557 self.buffer.set_position(header_pos);
558
559 write_u32(&mut self.buffer, anim.fn_ptr1)?;
561 write_u32(&mut self.buffer, anim.fn_ptr2)?;
562
563 self.write_fixed_string(&anim.name, super::anim_header_offsets::NAME_SIZE)?;
565
566 write_u32(&mut self.buffer, root_node_offset)?;
568
569 write_u32(&mut self.buffer, total_nodes)?;
571
572 self.buffer.write_all(&[0u8; 12])?;
574 self.buffer.write_all(&[0u8; 12])?;
576 write_u32(&mut self.buffer, 0)?;
578
579 self.buffer.write_all(&[5, 0, 0, 0])?;
581
582 write_f32(&mut self.buffer, anim.length)?;
584
585 write_f32(&mut self.buffer, anim.transition_time)?;
587
588 self.write_fixed_string(&anim.anim_root, super::anim_header_offsets::ANIM_ROOT_SIZE)?;
590
591 write_u32(&mut self.buffer, events_ptr)?;
593 write_u32(&mut self.buffer, event_count)?;
594 write_u32(&mut self.buffer, event_count)?;
595
596 write_u32(&mut self.buffer, 0)?;
598
599 self.buffer.set_position(save_pos);
600 Ok(anim_offset)
601 }
602
603 fn write_anim_node(
606 &mut self,
607 node: &super::MdlAnimNode,
608 anim_header_offset: u32,
609 parent_node_offset: Option<u32>,
610 ) -> Result<u32, MdlError> {
611 let node_offset = self.content_position()?;
612
613 let header_pos = self.buffer.position();
615 self.buffer.write_all(&[0u8; NODE_HEADER_SIZE])?;
616
617 let child_arr_ptr = if node.children.is_empty() {
619 0u32
620 } else {
621 let ptr = self.content_position()?;
622 let children_start = self.buffer.position();
624 for _ in 0..node.children.len() {
625 write_u32(&mut self.buffer, 0)?;
626 }
627
628 let mut child_offsets = Vec::with_capacity(node.children.len());
630 for child in &node.children {
631 let child_off =
632 self.write_anim_node(child, anim_header_offset, Some(node_offset))?;
633 child_offsets.push(child_off);
634 }
635
636 let save = self.buffer.position();
638 self.buffer.set_position(children_start);
639 for &off in &child_offsets {
640 write_u32(&mut self.buffer, off)?;
641 }
642 self.buffer.set_position(save);
643
644 ptr
645 };
646 let child_count = count_u32(node.children.len(), "anim_child_count")?;
647
648 let (ctrl_key_ptr, ctrl_key_count, ctrl_data_ptr, ctrl_data_count) =
650 self.write_controllers(&node.controllers, &node.orphan_controller_data)?;
651
652 let save_pos = self.buffer.position();
654 self.buffer.set_position(header_pos);
655
656 write_u16(
658 &mut self.buffer,
659 u16::try_from(super::node_flags::HEADER)
660 .map_err(|_| MdlError::ValueOverflow("anim_node_flags"))?,
661 )?;
662
663 write_u16(&mut self.buffer, node.node_number)?;
665
666 let name_index = *self.name_map.get(&node.name).unwrap_or(&0);
668 write_u16(&mut self.buffer, name_index)?;
669
670 self.buffer.write_all(&[0u8; 2])?;
672
673 write_u32(&mut self.buffer, anim_header_offset)?;
675
676 write_u32(&mut self.buffer, parent_node_offset.unwrap_or(0))?;
678
679 write_f32(&mut self.buffer, 0.0)?;
681 write_f32(&mut self.buffer, 0.0)?;
682 write_f32(&mut self.buffer, 0.0)?;
683
684 write_f32(&mut self.buffer, 1.0)?;
686 write_f32(&mut self.buffer, 0.0)?;
687 write_f32(&mut self.buffer, 0.0)?;
688 write_f32(&mut self.buffer, 0.0)?;
689
690 write_u32(&mut self.buffer, child_arr_ptr)?;
692 write_u32(&mut self.buffer, child_count)?;
693 write_u32(&mut self.buffer, child_count)?;
694
695 write_u32(&mut self.buffer, ctrl_key_ptr)?;
697 write_u32(&mut self.buffer, ctrl_key_count)?;
698 write_u32(&mut self.buffer, ctrl_key_count)?;
699
700 write_u32(&mut self.buffer, ctrl_data_ptr)?;
702 write_u32(&mut self.buffer, ctrl_data_count)?;
703 write_u32(&mut self.buffer, ctrl_data_count)?;
704
705 self.buffer.set_position(save_pos);
706 Ok(node_offset)
707 }
708
709 fn write_node(
714 &mut self,
715 node: &MdlNode,
716 parent_node_offset: Option<u32>,
717 ) -> Result<u32, MdlError> {
718 let node_start_offset = self.content_position()?;
720
721 self.node_offset_map
723 .insert(node.name.clone(), node_start_offset);
724
725 let header_pos = self.buffer.position();
727 self.buffer.write_all(&[0u8; NODE_HEADER_SIZE])?;
728
729 let light_header_pos = match &node.node_data {
733 MdlNodeData::Light(light) => Some(self.write_light_header(light)?),
734 _ => None,
735 };
736 match &node.node_data {
737 MdlNodeData::Light(_) => {} MdlNodeData::Emitter(emitter) => {
739 self.write_emitter_header(emitter)?;
740 }
741 MdlNodeData::Camera(_) => {
742 }
744 MdlNodeData::Reference(reference) => {
745 self.write_reference_header(reference)?;
746 }
747 _ => {}
748 }
749
750 let mesh_header_pos = if let Some(mesh) = node.node_data.mesh() {
754 Some(self.write_mesh_header(mesh)?)
755 } else {
756 None
757 };
758
759 let skin_header_pos = if let MdlNodeData::Skin(skin) = &node.node_data {
761 Some(self.write_skin_header(skin)?)
762 } else {
763 None
764 };
765 let anim_header_pos = if let MdlNodeData::AnimMesh(anim) = &node.node_data {
766 Some(self.write_anim_mesh_header(anim)?)
767 } else {
768 None
769 };
770 let dangly_header_pos = if let MdlNodeData::Dangly(dangly) = &node.node_data {
771 Some(self.write_dangly_header(dangly)?)
772 } else {
773 None
774 };
775 let aabb_header_pos = if let MdlNodeData::Aabb(_) = &node.node_data {
776 Some(self.write_aabb_header()?)
777 } else {
778 None
779 };
780 let saber_header_pos = if let MdlNodeData::Saber(saber) = &node.node_data {
781 Some(self.write_saber_header(saber)?)
782 } else {
783 None
784 };
785
786 if let (MdlNodeData::Light(light), Some(lhp)) = (&node.node_data, light_header_pos) {
790 self.write_light_arrays(light, lhp)?;
791 }
792 if let (MdlNodeData::Skin(skin), Some(shp)) = (&node.node_data, skin_header_pos) {
797 self.write_skin_arrays(skin, shp)?;
798 }
799 if let (MdlNodeData::Saber(saber), Some(shp)) = (&node.node_data, saber_header_pos) {
800 self.write_saber_arrays(saber, shp)?;
801 }
802 if let (MdlNodeData::Dangly(dangly), Some(dhp)) = (&node.node_data, dangly_header_pos) {
803 self.write_dangly_arrays(dangly, dhp)?;
804 self.write_dangly_pre_mesh_payload(dangly, dhp)?;
805 }
806 if let (MdlNodeData::Aabb(aabb), Some(ahp)) = (&node.node_data, aabb_header_pos) {
807 self.write_aabb_arrays(aabb, ahp)?;
808 }
809 let embedded_pos_ptr =
810 if let (Some(mesh), Some(mhp)) = (node.node_data.mesh(), mesh_header_pos) {
811 self.write_mesh_arrays(mesh, mhp)?
812 } else {
813 None
814 };
815 if let (MdlNodeData::AnimMesh(anim), Some(ahp)) = (&node.node_data, anim_header_pos) {
816 self.write_anim_mesh_arrays(anim, ahp)?;
817 }
818 if let (Some(mesh), Some(mhp)) = (node.node_data.mesh(), mesh_header_pos) {
826 self.write_mesh_content_positions(mesh, mhp, embedded_pos_ptr)?;
827 }
828
829 if self.write_mdx && !node.is_saber() {
838 if let Some(mhp) = mesh_header_pos {
839 if node.node_data.mesh().is_some() {
840 let dfs_index = self.deferred_mdx.len();
841 self.deferred_mdx.push(DeferredMdxEntry {
842 mesh_header_pos: mhp,
843 skin_header_pos,
844 is_skin: node.is_skin(),
845 dfs_index,
846 });
847 }
848 }
849 }
850
851 let child_count = count_u32(node.children.len(), "child_count")?;
854 let mut child_array_ptr = 0;
855
856 if child_count > 0 {
857 let array_start = self.buffer.position();
859 child_array_ptr = self.content_position()?;
860 let child_arr_bytes =
861 usize::try_from(child_count).expect("child_count fits in usize") * 4;
862 self.buffer.write_all(&vec![0u8; child_arr_bytes])?;
863
864 for (i, child) in node.children.iter().enumerate() {
866 let child_offset = self.write_node(child, Some(node_start_offset))?;
867
868 let save = self.buffer.position();
870 self.seek_to(array_start, i * 4);
872 write_u32(&mut self.buffer, child_offset)?;
873 self.buffer.set_position(save);
874 }
875 }
876
877 let (key_ptr, key_count, data_ptr, data_count) =
879 self.write_controllers(&node.controllers, &node.orphan_controller_data)?;
880
881 let save_end = self.buffer.position();
883 self.buffer.set_position(header_pos);
884
885 write_u16(
886 &mut self.buffer,
887 u16::try_from(node.node_data.flags())
888 .map_err(|_| MdlError::ValueOverflow("node_flags"))?,
889 )?; self.buffer.write_all(&node.header_padding_02)?; let node_id = *self.name_map.get(&node.name).unwrap_or(&0);
893 write_u16(&mut self.buffer, node_id)?; self.buffer.write_all(&node.header_padding_06)?; write_u32(&mut self.buffer, 0)?; write_u32(&mut self.buffer, parent_node_offset.unwrap_or(0))?; self.seek_to(header_pos, node_offsets::POS_X);
907 write_f32(&mut self.buffer, node.position[0])?;
908 write_f32(&mut self.buffer, node.position[1])?;
909 write_f32(&mut self.buffer, node.position[2])?;
910
911 self.seek_to(header_pos, node_offsets::ORIENTATION_W);
913 write_f32(&mut self.buffer, node.rotation[0])?; write_f32(&mut self.buffer, node.rotation[1])?; write_f32(&mut self.buffer, node.rotation[2])?; write_f32(&mut self.buffer, node.rotation[3])?; self.seek_to(header_pos, node_offsets::CHILD_ARRAY_PTR);
920 let child_ptr_field = if child_count > 0 {
921 child_array_ptr
922 } else if key_count > 0 {
923 key_ptr
926 } else {
927 0
928 };
929 write_u32(&mut self.buffer, child_ptr_field)?;
930 write_u32(&mut self.buffer, child_count)?; write_u32(&mut self.buffer, child_count)?; self.seek_to(header_pos, node_offsets::CONTROLLER_KEY_PTR);
934 write_u32(&mut self.buffer, key_ptr)?;
935 write_u32(&mut self.buffer, key_count)?; write_u32(&mut self.buffer, key_count)?; self.seek_to(header_pos, node_offsets::CONTROLLER_DATA_PTR);
939 write_u32(&mut self.buffer, data_ptr)?;
940 write_u32(&mut self.buffer, data_count)?; write_u32(&mut self.buffer, data_count)?; self.buffer.set_position(save_end);
944 Ok(node_start_offset)
945 }
946
947 fn write_f32_at(
949 &mut self,
950 header_pos: u64,
951 field_offset: usize,
952 val: f32,
953 ) -> Result<(), MdlError> {
954 let save = self.buffer.position();
955 self.seek_to(header_pos, field_offset);
956 write_f32(&mut self.buffer, val)?;
957 self.buffer.set_position(save);
958 Ok(())
959 }
960
961 fn write_u32_at(
963 &mut self,
964 header_pos: u64,
965 field_offset: usize,
966 val: u32,
967 ) -> Result<(), MdlError> {
968 let save = self.buffer.position();
969 self.seek_to(header_pos, field_offset);
970 write_u32(&mut self.buffer, val)?;
971 self.buffer.set_position(save);
972 Ok(())
973 }
974
975 fn write_i32_at(
977 &mut self,
978 header_pos: u64,
979 field_offset: usize,
980 val: i32,
981 ) -> Result<(), MdlError> {
982 let save = self.buffer.position();
983 self.seek_to(header_pos, field_offset);
984 write_i32(&mut self.buffer, val)?;
985 self.buffer.set_position(save);
986 Ok(())
987 }
988
989 fn write_u16_at(
991 &mut self,
992 header_pos: u64,
993 field_offset: usize,
994 val: u16,
995 ) -> Result<(), MdlError> {
996 let save = self.buffer.position();
997 self.seek_to(header_pos, field_offset);
998 write_u16(&mut self.buffer, val)?;
999 self.buffer.set_position(save);
1000 Ok(())
1001 }
1002
1003 fn write_u8_at(
1005 &mut self,
1006 header_pos: u64,
1007 field_offset: usize,
1008 val: u8,
1009 ) -> Result<(), MdlError> {
1010 let save = self.buffer.position();
1011 self.seek_to(header_pos, field_offset);
1012 self.buffer.write_all(&[val])?;
1013 self.buffer.set_position(save);
1014 Ok(())
1015 }
1016
1017 fn write_vec3_at(
1019 &mut self,
1020 header_pos: u64,
1021 field_offset: usize,
1022 v: &[f32; 3],
1023 ) -> Result<(), MdlError> {
1024 let save = self.buffer.position();
1025 self.seek_to(header_pos, field_offset);
1026 write_f32(&mut self.buffer, v[0])?;
1027 write_f32(&mut self.buffer, v[1])?;
1028 write_f32(&mut self.buffer, v[2])?;
1029 self.buffer.set_position(save);
1030 Ok(())
1031 }
1032
1033 fn write_string_at(
1036 &mut self,
1037 header_pos: u64,
1038 field_offset: usize,
1039 s: &str,
1040 max_len: usize,
1041 ) -> Result<(), MdlError> {
1042 let save = self.buffer.position();
1043 self.seek_to(header_pos, field_offset);
1044 crate::binary::write_fixed_c_string(&mut self.buffer, s, max_len)?;
1045 self.buffer.set_position(save);
1046 Ok(())
1047 }
1048
1049 fn write_mesh_header(&mut self, mesh: &super::MdlMesh) -> Result<u64, MdlError> {
1054 let header_pos = self.buffer.position();
1055 self.buffer.write_all(&[0u8; MESH_EXTRA_SIZE])?;
1057
1058 self.write_u32_at(
1060 header_pos,
1061 mesh_offsets::FN_PTR_GEN_VERTICES,
1062 mesh.fn_ptr_gen_vertices,
1063 )?;
1064 self.write_u32_at(
1065 header_pos,
1066 mesh_offsets::FN_PTR_REMOVE_TEMP_ARRAY,
1067 mesh.fn_ptr_remove_temp_array,
1068 )?;
1069
1070 self.write_vec3_at(header_pos, mesh_offsets::BOUNDING_MIN, &mesh.bounding_min)?;
1072 self.write_vec3_at(header_pos, mesh_offsets::BOUNDING_MAX, &mesh.bounding_max)?;
1073 self.write_f32_at(
1074 header_pos,
1075 mesh_offsets::BSPHERE_RADIUS,
1076 mesh.bsphere_radius,
1077 )?;
1078 self.write_vec3_at(
1079 header_pos,
1080 mesh_offsets::BSPHERE_CENTER,
1081 &mesh.bsphere_center,
1082 )?;
1083
1084 self.write_vec3_at(header_pos, mesh_offsets::DIFFUSE_COLOR, &mesh.diffuse_color)?;
1086 self.write_vec3_at(header_pos, mesh_offsets::AMBIENT_COLOR, &mesh.ambient_color)?;
1087
1088 self.write_i32_at(
1090 header_pos,
1091 mesh_offsets::TRANSPARENCY_HINT,
1092 mesh.transparency_hint,
1093 )?;
1094
1095 self.write_string_at(
1097 header_pos,
1098 mesh_offsets::TEXTURE_0,
1099 &mesh.texture_0,
1100 mesh_offsets::TEXTURE_NAME_SIZE,
1101 )?;
1102 self.write_string_at(
1103 header_pos,
1104 mesh_offsets::TEXTURE_1,
1105 &mesh.texture_1,
1106 mesh_offsets::TEXTURE_NAME_SIZE,
1107 )?;
1108
1109 {
1111 let save = self.buffer.position();
1112 self.seek_to(header_pos, mesh_offsets::SHARED_INDEX_OFFSET);
1113 write_i32(&mut self.buffer, mesh.shared_index_offset)?;
1114 write_i32(&mut self.buffer, mesh.shared_index_pool)?;
1115 write_i32(&mut self.buffer, mesh.shared_index_size)?;
1116 write_u32(&mut self.buffer, mesh.indices_per_face)?;
1117 self.buffer.set_position(save);
1118 }
1119
1120 self.write_i32_at(header_pos, mesh_offsets::ANIMATE_UV, mesh.animate_uv)?;
1122 self.write_f32_at(
1123 header_pos,
1124 mesh_offsets::UV_DIRECTION_X,
1125 mesh.uv_direction_x,
1126 )?;
1127 self.write_f32_at(
1128 header_pos,
1129 mesh_offsets::UV_DIRECTION_Y,
1130 mesh.uv_direction_y,
1131 )?;
1132 self.write_f32_at(header_pos, mesh_offsets::UV_JITTER, mesh.uv_jitter)?;
1133 self.write_f32_at(
1134 header_pos,
1135 mesh_offsets::UV_JITTER_SPEED,
1136 mesh.uv_jitter_speed,
1137 )?;
1138
1139 self.write_u16_at(header_pos, mesh_offsets::VERTEX_COUNT, mesh.vertex_count)?;
1141 self.write_u16_at(
1142 header_pos,
1143 mesh_offsets::TEXTURE_CHANNEL_COUNT,
1144 mesh.texture_channel_count,
1145 )?;
1146
1147 self.write_u8_at(
1149 header_pos,
1150 mesh_offsets::LIGHT_MAPPED,
1151 u8::from(mesh.light_mapped),
1152 )?;
1153 self.write_u8_at(
1154 header_pos,
1155 mesh_offsets::ROTATE_TEXTURE,
1156 u8::from(mesh.rotate_texture),
1157 )?;
1158 self.write_u8_at(
1159 header_pos,
1160 mesh_offsets::IS_BACKGROUND_GEOMETRY,
1161 u8::from(mesh.is_background_geometry),
1162 )?;
1163 self.write_u8_at(header_pos, mesh_offsets::SHADOW, u8::from(mesh.shadow))?;
1164 self.write_u8_at(header_pos, mesh_offsets::BEAMING, u8::from(mesh.beaming))?;
1165 self.write_u8_at(header_pos, mesh_offsets::RENDER, u8::from(mesh.render))?;
1166
1167 self.write_f32_at(
1169 header_pos,
1170 mesh_offsets::TOTAL_SURFACE_AREA,
1171 mesh.total_surface_area,
1172 )?;
1173
1174 {
1180 let save = self.buffer.position();
1181 self.seek_to(header_pos, mesh_offsets::MDX_POSITION_OFFSET);
1184 for _ in 0..8 {
1185 write_u32(&mut self.buffer, 0xFFFF_FFFF)?;
1186 }
1187 for _ in 0..3 {
1189 write_u32(&mut self.buffer, 0xFFFF_FFFF)?;
1190 }
1191 self.buffer.set_position(save);
1192 }
1193
1194 Ok(header_pos)
1195 }
1196
1197 fn write_mesh_arrays(
1204 &mut self,
1205 mesh: &super::MdlMesh,
1206 mesh_header_pos: u64,
1207 ) -> Result<Option<u32>, MdlError> {
1208 let face_count = count_u32(mesh.faces.len(), "face_count")?;
1209 let mut face_offset = 0u32;
1210
1211 if face_count > 0 {
1212 face_offset = self.content_position()?;
1213 for face in &mesh.faces {
1214 write_f32(&mut self.buffer, face.plane_normal[0])?;
1215 write_f32(&mut self.buffer, face.plane_normal[1])?;
1216 write_f32(&mut self.buffer, face.plane_normal[2])?;
1217 write_f32(&mut self.buffer, face.plane_distance)?;
1218 write_u32(&mut self.buffer, face.surface_id)?;
1219 write_u16(&mut self.buffer, face.adjacent[0])?;
1220 write_u16(&mut self.buffer, face.adjacent[1])?;
1221 write_u16(&mut self.buffer, face.adjacent[2])?;
1222 write_u16(&mut self.buffer, face.vertex_indices[0])?;
1223 write_u16(&mut self.buffer, face.vertex_indices[1])?;
1224 write_u16(&mut self.buffer, face.vertex_indices[2])?;
1225 }
1226 }
1227
1228 let save_end = self.buffer.position();
1230 self.seek_to(mesh_header_pos, mesh_offsets::FACE_ARRAY_OFFSET);
1231 write_u32(&mut self.buffer, face_offset)?;
1232 write_u32(&mut self.buffer, face_count)?;
1233 write_u32(&mut self.buffer, face_count)?; self.buffer.set_position(save_end);
1235
1236 self.backpatch_cexolist(
1259 mesh_header_pos,
1260 mesh_offsets::LEFT_OVER_FACES_ARRAY_PTR,
1261 0,
1262 0,
1263 0,
1264 )?;
1265
1266 let vertex_count = usize::from(mesh.vertex_count);
1268 let can_embed_positions = mesh.has_embedded_positions
1269 && !mesh.positions.is_empty()
1270 && mesh.positions.len() >= vertex_count;
1271
1272 let mut vertex_indices_count_data_ptr = 0u32;
1273
1274 if can_embed_positions {
1276 let ptr = self.content_position()?;
1277 vertex_indices_count_data_ptr = ptr;
1278 write_u32(&mut self.buffer, face_count * 3)?;
1279 for pos in mesh.positions.iter().take(vertex_count) {
1280 write_f32(&mut self.buffer, pos[0])?;
1281 write_f32(&mut self.buffer, pos[1])?;
1282 write_f32(&mut self.buffer, pos[2])?;
1283 }
1284 self.backpatch_cexolist(
1285 mesh_header_pos,
1286 mesh_offsets::VERTEX_INDICES_COUNT_ARRAY_PTR,
1287 ptr,
1288 1,
1289 1,
1290 )?;
1291 } else if face_count > 0 {
1292 let ptr = self.content_position()?;
1293 vertex_indices_count_data_ptr = ptr;
1294 write_u32(&mut self.buffer, face_count * 3)?;
1295 self.backpatch_cexolist(
1296 mesh_header_pos,
1297 mesh_offsets::VERTEX_INDICES_COUNT_ARRAY_PTR,
1298 ptr,
1299 1,
1300 1,
1301 )?;
1302 } else {
1303 self.backpatch_cexolist(
1304 mesh_header_pos,
1305 mesh_offsets::VERTEX_INDICES_COUNT_ARRAY_PTR,
1306 0,
1307 0,
1308 0,
1309 )?;
1310 }
1311
1312 if face_count > 0 {
1314 let ptr = self.content_position()?;
1315 write_u32(&mut self.buffer, 0)?; self.backpatch_cexolist(
1317 mesh_header_pos,
1318 mesh_offsets::MDX_OFFSETS_ARRAY_PTR,
1319 ptr,
1320 1,
1321 1,
1322 )?;
1323 } else {
1324 self.backpatch_cexolist(
1325 mesh_header_pos,
1326 mesh_offsets::MDX_OFFSETS_ARRAY_PTR,
1327 0,
1328 0,
1329 0,
1330 )?;
1331 }
1332
1333 if mesh.inverted_counter > 0 || face_count > 0 {
1335 let ptr = self.content_position()?;
1336 write_u32(&mut self.buffer, mesh.inverted_counter)?;
1337 self.backpatch_cexolist(
1338 mesh_header_pos,
1339 mesh_offsets::INDEX_BUFFER_POOLS_ARRAY_PTR,
1340 ptr,
1341 1,
1342 1,
1343 )?;
1344 } else {
1345 self.backpatch_cexolist(
1346 mesh_header_pos,
1347 mesh_offsets::INDEX_BUFFER_POOLS_ARRAY_PTR,
1348 0,
1349 0,
1350 0,
1351 )?;
1352 }
1353
1354 if face_count > 0 {
1357 let packed_ptr = self.content_position()?;
1358 for face in &mesh.faces {
1359 write_u16(&mut self.buffer, face.vertex_indices[0])?;
1360 write_u16(&mut self.buffer, face.vertex_indices[1])?;
1361 write_u16(&mut self.buffer, face.vertex_indices[2])?;
1362 }
1363 self.backpatch_mdx_offsets_data(mesh_header_pos, packed_ptr)?;
1364 }
1365
1366 let embedded_pos_ptr = if can_embed_positions && vertex_indices_count_data_ptr > 0 {
1370 Some(vertex_indices_count_data_ptr.saturating_add(4))
1371 } else {
1372 None
1373 };
1374
1375 Ok(embedded_pos_ptr)
1376 }
1377
1378 fn backpatch_cexolist(
1380 &mut self,
1381 mesh_header_pos: u64,
1382 ptr_field: usize,
1383 ptr: u32,
1384 count: u32,
1385 alloc: u32,
1386 ) -> Result<(), MdlError> {
1387 let save = self.buffer.position();
1388 self.seek_to(mesh_header_pos, ptr_field);
1389 write_u32(&mut self.buffer, ptr)?;
1390 write_u32(&mut self.buffer, count)?;
1391 write_u32(&mut self.buffer, alloc)?;
1392 self.buffer.set_position(save);
1393 Ok(())
1394 }
1395
1396 fn backpatch_mdx_offsets_data(
1402 &mut self,
1403 mesh_header_pos: u64,
1404 packed_ptr: u32,
1405 ) -> Result<(), MdlError> {
1406 let save = self.buffer.position();
1408 self.seek_to(mesh_header_pos, mesh_offsets::MDX_OFFSETS_ARRAY_PTR);
1409 let mut ptr_bytes = [0u8; 4];
1410 std::io::Read::read_exact(&mut self.buffer, &mut ptr_bytes)?;
1411 let data_ptr = u32::from_le_bytes(ptr_bytes);
1412 if data_ptr > 0 {
1413 self.buffer
1415 .set_position(u64::from(data_ptr) + MDL_WRAPPER_SIZE);
1416 write_u32(&mut self.buffer, packed_ptr)?;
1417 }
1418 self.buffer.set_position(save);
1419 Ok(())
1420 }
1421
1422 fn write_mesh_content_positions(
1432 &mut self,
1433 mesh: &super::MdlMesh,
1434 mesh_header_pos: u64,
1435 embedded_pos_ptr: Option<u32>,
1436 ) -> Result<(), MdlError> {
1437 if let Some(pos_ptr) = embedded_pos_ptr {
1438 let save = self.buffer.position();
1439 self.seek_to(mesh_header_pos, mesh_offsets::VERT_ARRAY_OFFSET);
1440 write_u32(&mut self.buffer, pos_ptr)?;
1441 self.buffer.set_position(save);
1442 return Ok(());
1443 }
1444
1445 if mesh.positions.is_empty() {
1446 return Ok(());
1447 }
1448
1449 let pos_start = self.content_position()?; for pos in &mesh.positions {
1453 write_f32(&mut self.buffer, pos[0])?;
1454 write_f32(&mut self.buffer, pos[1])?;
1455 write_f32(&mut self.buffer, pos[2])?;
1456 }
1457
1458 let save = self.buffer.position();
1460 self.seek_to(mesh_header_pos, mesh_offsets::VERT_ARRAY_OFFSET);
1461 write_u32(&mut self.buffer, pos_start)?;
1462 self.buffer.set_position(save);
1463
1464 Ok(())
1465 }
1466
1467 fn write_mesh_mdx_data(
1476 &mut self,
1477 mesh: &super::MdlMesh,
1478 skin: Option<&super::MdlSkin>,
1479 mesh_header_pos: u64,
1480 skin_header_pos: Option<u64>,
1481 ) -> Result<u32, MdlError> {
1482 #[derive(Clone, Copy)]
1483 struct MdxLayout {
1484 stride: u32,
1485 flags: u32,
1486 pos_off: i32,
1487 norm_off: i32,
1488 color_off: i32,
1489 uv1_off: i32,
1490 uv2_off: i32,
1491 uv3_off: i32,
1492 uv4_off: i32,
1493 tangent_off: i32,
1494 bone_weights_off: i32,
1495 bone_indices_off: i32,
1496 }
1497
1498 let vertex_count = usize::from(mesh.vertex_count);
1499 if vertex_count == 0 {
1500 return Ok(0);
1501 }
1502
1503 let mut effective_vertex_count = vertex_count;
1514 macro_rules! clamp_attr {
1515 ($arr:expr, $name:expr) => {
1516 if !$arr.is_empty() {
1517 if effective_vertex_count == vertex_count {
1518 effective_vertex_count = $arr.len();
1520 } else if $arr.len() != effective_vertex_count {
1521 return Err(MdlError::InvalidData(format!(
1522 "mesh {}: {} has {} elements but {} has {}",
1523 $name,
1524 stringify!($arr),
1525 $arr.len(),
1526 "other attribute",
1527 effective_vertex_count
1528 )));
1529 }
1530 }
1531 };
1532 }
1533 clamp_attr!(mesh.positions, "positions");
1534 clamp_attr!(mesh.normals, "normals");
1535 clamp_attr!(mesh.vertex_colors, "vertex_colors");
1536 clamp_attr!(mesh.uv1, "uv1");
1537 clamp_attr!(mesh.uv2, "uv2");
1538 clamp_attr!(mesh.uv3, "uv3");
1539 clamp_attr!(mesh.uv4, "uv4");
1540 clamp_attr!(mesh.tangent_space, "tangent_space");
1541 if let Some(s) = skin {
1542 clamp_attr!(s.bone_weights, "bone_weights");
1543 clamp_attr!(s.bone_indices, "bone_indices");
1544 }
1545
1546 let has_pos = !mesh.positions.is_empty();
1548 let has_norm = !mesh.normals.is_empty();
1549 let has_color = !mesh.vertex_colors.is_empty();
1550 let has_uv1 = !mesh.uv1.is_empty();
1551 let has_uv2 = !mesh.uv2.is_empty();
1552 let has_uv3 = !mesh.uv3.is_empty();
1553 let has_uv4 = !mesh.uv4.is_empty();
1554 let has_tangent = !mesh.tangent_space.is_empty();
1555 let has_bone_weights = skin.is_some_and(|s| !s.bone_weights.is_empty());
1556 let has_bone_indices = skin.is_some_and(|s| !s.bone_indices.is_empty());
1557
1558 let mut current_byte = 0u32;
1561
1562 let pos_off: i32 = if has_pos {
1563 let o = i32::try_from(current_byte)
1564 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1565 current_byte += 12;
1566 o
1567 } else {
1568 -1
1569 };
1570 let norm_off: i32 = if has_norm {
1571 let o = i32::try_from(current_byte)
1572 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1573 current_byte += 12;
1574 o
1575 } else {
1576 -1
1577 };
1578 let color_off: i32 = if has_color {
1579 let o = i32::try_from(current_byte)
1580 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1581 current_byte += 4;
1582 o
1583 } else {
1584 -1
1585 };
1586 let uv1_off: i32 = if has_uv1 {
1587 let o = i32::try_from(current_byte)
1588 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1589 current_byte += 8;
1590 o
1591 } else {
1592 -1
1593 };
1594 let uv2_off: i32 = if has_uv2 {
1595 let o = i32::try_from(current_byte)
1596 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1597 current_byte += 8;
1598 o
1599 } else {
1600 -1
1601 };
1602 let uv3_off: i32 = if has_uv3 {
1603 let o = i32::try_from(current_byte)
1604 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1605 current_byte += 8;
1606 o
1607 } else {
1608 -1
1609 };
1610 let uv4_off: i32 = if has_uv4 {
1611 let o = i32::try_from(current_byte)
1612 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1613 current_byte += 8;
1614 o
1615 } else {
1616 -1
1617 };
1618 let tangent_off: i32 = if has_tangent {
1619 let o = i32::try_from(current_byte)
1620 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1621 current_byte += 36;
1622 o
1623 } else {
1624 -1
1625 };
1626 let bone_weights_off: i32 = if has_bone_weights {
1627 let o = i32::try_from(current_byte)
1628 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1629 current_byte += 16;
1630 o
1631 } else {
1632 -1
1633 };
1634 let bone_indices_off: i32 = if has_bone_indices {
1635 let o = i32::try_from(current_byte)
1636 .map_err(|_| MdlError::ValueOverflow("mdx_attribute_offset"))?;
1637 current_byte += 16;
1638 o
1639 } else {
1640 -1
1641 };
1642
1643 let canonical_stride = current_byte;
1644
1645 let mut canonical_flags = 0u32;
1648 if has_pos {
1649 canonical_flags |= 0x01;
1650 }
1651 if has_norm {
1652 canonical_flags |= 0x20;
1653 }
1654 if has_uv1 {
1655 canonical_flags |= 0x02;
1656 }
1657 if has_uv2 {
1658 canonical_flags |= 0x04;
1659 }
1660 if has_uv3 {
1661 canonical_flags |= 0x08;
1662 }
1663 if has_uv4 {
1664 canonical_flags |= 0x10;
1665 }
1666 if has_tangent {
1667 canonical_flags |= 0x80;
1668 }
1669
1670 let layout = MdxLayout {
1671 stride: canonical_stride,
1672 flags: canonical_flags,
1673 pos_off,
1674 norm_off,
1675 color_off,
1676 uv1_off,
1677 uv2_off,
1678 uv3_off,
1679 uv4_off,
1680 tangent_off,
1681 bone_weights_off,
1682 bone_indices_off,
1683 };
1684
1685 if layout.stride == 0 {
1686 return Ok(0); }
1688
1689 for i in 0..effective_vertex_count {
1691 if has_pos {
1692 let p = &mesh.positions[i];
1693 write_f32(&mut self.mdx_buffer, p[0])?;
1694 write_f32(&mut self.mdx_buffer, p[1])?;
1695 write_f32(&mut self.mdx_buffer, p[2])?;
1696 }
1697 if has_norm {
1698 let n = &mesh.normals[i];
1699 write_f32(&mut self.mdx_buffer, n[0])?;
1700 write_f32(&mut self.mdx_buffer, n[1])?;
1701 write_f32(&mut self.mdx_buffer, n[2])?;
1702 }
1703 if has_color {
1704 let c = &mesh.vertex_colors[i];
1705 self.mdx_buffer.write_all(c)?;
1706 }
1707 if has_uv1 {
1708 let u = &mesh.uv1[i];
1709 write_f32(&mut self.mdx_buffer, u[0])?;
1710 write_f32(&mut self.mdx_buffer, u[1])?;
1711 }
1712 if has_uv2 {
1713 let u = &mesh.uv2[i];
1714 write_f32(&mut self.mdx_buffer, u[0])?;
1715 write_f32(&mut self.mdx_buffer, u[1])?;
1716 }
1717 if has_uv3 {
1718 let u = &mesh.uv3[i];
1719 write_f32(&mut self.mdx_buffer, u[0])?;
1720 write_f32(&mut self.mdx_buffer, u[1])?;
1721 }
1722 if has_uv4 {
1723 let u = &mesh.uv4[i];
1724 write_f32(&mut self.mdx_buffer, u[0])?;
1725 write_f32(&mut self.mdx_buffer, u[1])?;
1726 }
1727 if has_tangent {
1728 let t = &mesh.tangent_space[i];
1729 for row in t {
1730 write_f32(&mut self.mdx_buffer, row[0])?;
1731 write_f32(&mut self.mdx_buffer, row[1])?;
1732 write_f32(&mut self.mdx_buffer, row[2])?;
1733 }
1734 }
1735 if has_bone_weights {
1736 let bw = &skin
1738 .expect("has_bone_weights implies skin is Some")
1739 .bone_weights[i];
1740 write_f32(&mut self.mdx_buffer, bw[0])?;
1741 write_f32(&mut self.mdx_buffer, bw[1])?;
1742 write_f32(&mut self.mdx_buffer, bw[2])?;
1743 write_f32(&mut self.mdx_buffer, bw[3])?;
1744 }
1745 if has_bone_indices {
1746 let bi = &skin
1748 .expect("has_bone_indices implies skin is Some")
1749 .bone_indices[i];
1750 write_f32(&mut self.mdx_buffer, bi[0])?;
1751 write_f32(&mut self.mdx_buffer, bi[1])?;
1752 write_f32(&mut self.mdx_buffer, bi[2])?;
1753 write_f32(&mut self.mdx_buffer, bi[3])?;
1754 }
1755 }
1756
1757 let save = self.buffer.position();
1759
1760 self.seek_to(mesh_header_pos, mesh_offsets::VERTEX_STRUCT_SIZE);
1762 write_u32(&mut self.buffer, layout.stride)?;
1763
1764 self.seek_to(mesh_header_pos, mesh_offsets::MDX_VERTEX_FLAGS);
1766 write_u32(&mut self.buffer, layout.flags)?;
1767
1768 self.seek_to(mesh_header_pos, mesh_offsets::MDX_POSITION_OFFSET);
1770 write_i32(&mut self.buffer, layout.pos_off)?;
1771 write_i32(&mut self.buffer, layout.norm_off)?;
1772 write_i32(&mut self.buffer, layout.color_off)?;
1773 write_i32(&mut self.buffer, layout.uv1_off)?;
1774 write_i32(&mut self.buffer, layout.uv2_off)?;
1775 write_i32(&mut self.buffer, layout.uv3_off)?;
1776 write_i32(&mut self.buffer, layout.uv4_off)?;
1777 write_i32(&mut self.buffer, layout.tangent_off)?;
1778
1779 if let Some(shp) = skin_header_pos {
1787 self.write_i32_at(
1788 shp,
1789 skin_offsets::MDX_BONE_WEIGHTS_OFFSET,
1790 layout.bone_weights_off,
1791 )?;
1792 self.write_i32_at(
1793 shp,
1794 skin_offsets::MDX_BONE_INDICES_OFFSET,
1795 layout.bone_indices_off,
1796 )?;
1797 }
1798
1799 self.buffer.set_position(save);
1800 Ok(layout.stride)
1801 }
1802
1803 fn write_mdx_terminator(&mut self, stride: u32, is_skin: bool) -> Result<(), MdlError> {
1812 if stride == 0 {
1813 return Ok(());
1814 }
1815
1816 let stride = usize::try_from(stride).expect("u32 stride fits in usize");
1817 let sentinel: f32 = if is_skin { 1_000_000.0 } else { 10_000_000.0 };
1818
1819 write_f32(&mut self.mdx_buffer, sentinel)?;
1821 write_f32(&mut self.mdx_buffer, sentinel)?;
1822 write_f32(&mut self.mdx_buffer, sentinel)?;
1823
1824 let remaining = stride.saturating_sub(12);
1826 if remaining > 0 {
1827 let zeros = vec![0u8; remaining];
1828 self.mdx_buffer.write_all(&zeros)?;
1829 }
1830
1831 self.mdx_pre_align_pos = self.mdx_buffer.position();
1834
1835 let pos =
1837 usize::try_from(self.mdx_buffer.position()).expect("mdx buffer position fits in usize");
1838 let aligned = (pos + 15) & !15;
1839 let pad = aligned - pos;
1840 if pad > 0 {
1841 let zeros = vec![0u8; pad];
1842 self.mdx_buffer.write_all(&zeros)?;
1843 }
1844
1845 Ok(())
1846 }
1847
1848 fn write_skin_header(&mut self, skin: &super::MdlSkin) -> Result<u64, MdlError> {
1854 let header_pos = self.buffer.position();
1855 self.buffer.write_all(&[0u8; SKIN_EXTRA_SIZE])?;
1856
1857 let save = self.buffer.position();
1858
1859 self.write_i32_at(
1861 header_pos,
1862 skin_offsets::MDX_BONE_WEIGHTS_OFFSET,
1863 skin.mdx_bone_weights_offset,
1864 )?;
1865 self.write_i32_at(
1866 header_pos,
1867 skin_offsets::MDX_BONE_INDICES_OFFSET,
1868 skin.mdx_bone_indices_offset,
1869 )?;
1870
1871 self.seek_to(header_pos, skin_offsets::BONE_NODE_NUMBERS);
1873 for &n in &skin.bone_node_numbers {
1874 write_u16(&mut self.buffer, n)?;
1875 }
1876
1877 self.buffer.set_position(save);
1881 Ok(header_pos)
1882 }
1883
1884 fn write_skin_arrays(
1886 &mut self,
1887 skin: &super::MdlSkin,
1888 skin_header_pos: u64,
1889 ) -> Result<(), MdlError> {
1890 let bonemap_count = count_u32(skin.bonemap.len(), "bonemap_count")?;
1892 let mut bonemap_ptr = 0u32;
1893 if bonemap_count > 0 {
1894 bonemap_ptr = self.content_position()?;
1895 for &idx in &skin.bonemap {
1896 write_u32(&mut self.buffer, idx)?;
1897 }
1898 }
1899
1900 let qbone_count = count_u32(skin.qbone_ref_inv.len(), "qbone_count")?;
1902 let mut qbone_ptr = 0u32;
1903 if qbone_count > 0 {
1904 qbone_ptr = self.content_position()?;
1905 for q in &skin.qbone_ref_inv {
1906 write_f32(&mut self.buffer, q[0])?;
1907 write_f32(&mut self.buffer, q[1])?;
1908 write_f32(&mut self.buffer, q[2])?;
1909 write_f32(&mut self.buffer, q[3])?;
1910 }
1911 }
1912
1913 let tbone_count = count_u32(skin.tbone_ref_inv.len(), "tbone_count")?;
1915 let mut tbone_ptr = 0u32;
1916 if tbone_count > 0 {
1917 tbone_ptr = self.content_position()?;
1918 for t in &skin.tbone_ref_inv {
1919 write_f32(&mut self.buffer, t[0])?;
1920 write_f32(&mut self.buffer, t[1])?;
1921 write_f32(&mut self.buffer, t[2])?;
1922 }
1923 }
1924
1925 let bone_idx_count = count_u32(skin.bone_constant_indices.len(), "bone_idx_count")?;
1927 let mut bone_idx_ptr = 0u32;
1928 if bone_idx_count > 0 {
1929 bone_idx_ptr = self.content_position()?;
1930 for &idx in &skin.bone_constant_indices {
1931 write_i32(&mut self.buffer, idx)?;
1932 }
1933 }
1934
1935 let save_end = self.buffer.position();
1937
1938 self.seek_to(skin_header_pos, skin_offsets::BONEMAP_PTR);
1942 write_u32(&mut self.buffer, bonemap_ptr)?;
1943 write_u32(&mut self.buffer, bonemap_count)?;
1944
1945 self.seek_to(skin_header_pos, skin_offsets::QBONE_REF_INV_PTR);
1947 write_u32(&mut self.buffer, qbone_ptr)?;
1948 write_u32(&mut self.buffer, qbone_count)?;
1949 write_u32(&mut self.buffer, qbone_count)?; self.seek_to(skin_header_pos, skin_offsets::TBONE_REF_INV_PTR);
1953 write_u32(&mut self.buffer, tbone_ptr)?;
1954 write_u32(&mut self.buffer, tbone_count)?;
1955 write_u32(&mut self.buffer, tbone_count)?; self.seek_to(skin_header_pos, skin_offsets::BONE_CONSTANT_INDICES_PTR);
1959 write_u32(&mut self.buffer, bone_idx_ptr)?;
1960 write_u32(&mut self.buffer, bone_idx_count)?;
1961 write_u32(&mut self.buffer, bone_idx_count)?; self.buffer.set_position(save_end);
1964 Ok(())
1965 }
1966
1967 fn write_anim_mesh_header(&mut self, anim: &super::MdlAnimMesh) -> Result<u64, MdlError> {
1972 let header_pos = self.buffer.position();
1973
1974 self.buffer.write_all(&[0u8; ANIM_MESH_EXTRA_SIZE])?;
1976 let save = self.buffer.position();
1977
1978 self.write_f32_at(
1980 header_pos,
1981 anim_mesh_offsets::SAMPLE_PERIOD,
1982 anim.sample_period,
1983 )?;
1984 self.write_u32_at(header_pos, anim_mesh_offsets::DATA_PTR_1, anim.data_ptr_1)?;
1989 self.write_u32_at(
1990 header_pos,
1991 anim_mesh_offsets::DATA_COUNT_1,
1992 anim.data_count_1,
1993 )?;
1994 self.write_u32_at(header_pos, anim_mesh_offsets::PADDING_24, anim.padding_24)?;
1995 self.write_u32_at(
1996 header_pos,
1997 anim_mesh_offsets::ANIM_VERTICES_PTR,
1998 anim.anim_vertices_ptr,
1999 )?;
2000 self.write_u32_at(
2001 header_pos,
2002 anim_mesh_offsets::ANIM_TEX_VERTICES_PTR,
2003 anim.anim_tex_vertices_ptr,
2004 )?;
2005 self.write_u32_at(
2006 header_pos,
2007 anim_mesh_offsets::ANIM_VERTICES_COUNT,
2008 anim.anim_vertices_count,
2009 )?;
2010 self.write_u32_at(
2011 header_pos,
2012 anim_mesh_offsets::ANIM_TEX_VERTICES_COUNT,
2013 anim.anim_tex_vertices_count,
2014 )?;
2015
2016 self.buffer.set_position(save);
2017 Ok(header_pos)
2018 }
2019
2020 fn write_anim_mesh_arrays(
2022 &mut self,
2023 anim: &super::MdlAnimMesh,
2024 anim_header_pos: u64,
2025 ) -> Result<(), MdlError> {
2026 let anim_verts_count = count_u32(anim.anim_verts.len(), "anim_verts_count")?;
2028 let mut anim_verts_ptr = 0u32;
2029 if anim_verts_count > 0 {
2030 anim_verts_ptr = self.content_position()?;
2031 for v in &anim.anim_verts {
2032 write_f32(&mut self.buffer, v[0])?;
2033 write_f32(&mut self.buffer, v[1])?;
2034 write_f32(&mut self.buffer, v[2])?;
2035 }
2036 }
2037
2038 let anim_t_verts_count = count_u32(anim.anim_t_verts.len(), "anim_t_verts_count")?;
2040 let mut anim_t_verts_ptr = 0u32;
2041 if anim_t_verts_count > 0 {
2042 anim_t_verts_ptr = self.content_position()?;
2043 for v in &anim.anim_t_verts {
2044 write_f32(&mut self.buffer, v[0])?;
2045 write_f32(&mut self.buffer, v[1])?;
2046 write_f32(&mut self.buffer, v[2])?;
2047 }
2048 }
2049
2050 let save_end = self.buffer.position();
2052
2053 self.seek_to(anim_header_pos, anim_mesh_offsets::ANIM_VERTS_PTR);
2055 write_u32(&mut self.buffer, anim_verts_ptr)?;
2056 write_u32(&mut self.buffer, anim_verts_count)?;
2057 write_u32(&mut self.buffer, anim_verts_count)?; self.seek_to(anim_header_pos, anim_mesh_offsets::ANIM_T_VERTS_PTR);
2061 write_u32(&mut self.buffer, anim_t_verts_ptr)?;
2062 write_u32(&mut self.buffer, anim_t_verts_count)?;
2063 write_u32(&mut self.buffer, anim_t_verts_count)?; self.buffer.set_position(save_end);
2066 Ok(())
2067 }
2068
2069 fn write_controllers(
2070 &mut self,
2071 controllers: &[MdlController],
2072 orphan_data: &[f32],
2073 ) -> Result<(u32, u32, u32, u32), MdlError> {
2074 if controllers.is_empty() && orphan_data.is_empty() {
2075 return Ok((0, 0, 0, 0));
2076 }
2077
2078 if controllers.is_empty() {
2081 let data_ptr = self.content_position()?;
2082 for &val in orphan_data {
2083 write_f32(&mut self.buffer, val)?;
2084 }
2085 return Ok((
2086 0,
2087 0,
2088 data_ptr,
2089 count_u32(orphan_data.len(), "orphan_data_count")?,
2090 ));
2091 }
2092
2093 let key_ptr = self.content_position()?;
2094 let key_count = count_u32(controllers.len(), "controller_count")?;
2095
2096 let headers_start = self.buffer.position();
2098 self.buffer.write_all(&vec![
2099 0u8;
2100 usize::try_from(key_count)
2101 .expect("key_count fits in usize")
2102 * 16
2103 ])?;
2104
2105 let mut master_float_data = Vec::new();
2107 let mut controller_indices = Vec::new(); for c in controllers {
2110 let time_idx = master_float_data.len();
2111 for key in &c.keys {
2112 master_float_data.push(key.time);
2113 }
2114
2115 let data_idx = master_float_data.len();
2116 for key in &c.keys {
2117 master_float_data.extend_from_slice(&key.values);
2118 }
2119
2120 controller_indices.push((time_idx, data_idx));
2121 }
2122
2123 let data_start_pos = headers_start + u64::from(key_count) * 16;
2125 self.buffer.set_position(data_start_pos);
2126
2127 let real_data_ptr = u32::try_from(
2128 data_start_pos
2129 .checked_sub(MDL_WRAPPER_SIZE)
2130 .ok_or(MdlError::ValueOverflow("ctrl_data_position underflow"))?,
2131 )
2132 .map_err(|_| MdlError::ValueOverflow("ctrl_data_position"))?;
2133
2134 for val in &master_float_data {
2135 write_f32(&mut self.buffer, *val)?;
2136 }
2137 let real_data_count = count_u32(master_float_data.len(), "controller_data_count")?;
2138
2139 let final_end = self.buffer.position();
2141 self.buffer.set_position(headers_start);
2142
2143 for (i, c) in controllers.iter().enumerate() {
2144 let row_count = count_u16(c.keys.len(), "key_row_count")?;
2145 let (t_idx, d_idx) = controller_indices[i];
2146
2147 write_u32(&mut self.buffer, c.controller_type.raw())?; self.buffer.write_all(&c.key_unknown_04)?;
2151 write_u16(&mut self.buffer, row_count)?;
2152
2153 write_u16(
2155 &mut self.buffer,
2156 u16::try_from(t_idx).map_err(|_| MdlError::ValueOverflow("time_index"))?,
2157 )?;
2158 write_u16(
2159 &mut self.buffer,
2160 u16::try_from(d_idx).map_err(|_| MdlError::ValueOverflow("data_index"))?,
2161 )?;
2162
2163 self.buffer.write_all(&[c.raw_column_count])?;
2168 self.buffer.write_all(&c.key_unknown_0d)?;
2169 }
2170
2171 self.buffer.set_position(final_end);
2172
2173 Ok((key_ptr, key_count, real_data_ptr, real_data_count))
2174 }
2175
2176 fn write_light_header(&mut self, light: &super::MdlLight) -> Result<u64, MdlError> {
2182 let header_pos = self.buffer.position();
2183
2184 self.buffer.write_all(&[0u8; LIGHT_EXTRA_SIZE])?;
2186
2187 self.write_f32_at(header_pos, light_offsets::FLARE_RADIUS, light.flare_radius)?;
2189
2190 let sp_off = light_offsets::TEXTURE_SAFE_PTRS_PTR;
2192 self.write_u32_at(header_pos, sp_off, light.texture_safe_ptrs[0])?;
2193 self.write_u32_at(header_pos, sp_off + 4, light.texture_safe_ptrs[1])?;
2194 self.write_u32_at(header_pos, sp_off + 8, light.texture_safe_ptrs[2])?;
2195
2196 self.write_i32_at(header_pos, light_offsets::PRIORITY, light.priority)?;
2200 self.write_i32_at(
2201 header_pos,
2202 light_offsets::NUM_DYNAMIC_TYPES,
2203 light.num_dynamic_types,
2204 )?;
2205 self.write_i32_at(
2206 header_pos,
2207 light_offsets::AFFECTDYNAMIC,
2208 light.affectdynamic,
2209 )?;
2210 self.write_i32_at(header_pos, light_offsets::SHADOW, light.shadow)?;
2211 self.write_i32_at(header_pos, light_offsets::AMBIENTONLY, light.ambientonly)?;
2212 self.write_i32_at(
2213 header_pos,
2214 light_offsets::GENERATEFLARE,
2215 light.generateflare,
2216 )?;
2217 self.write_i32_at(header_pos, light_offsets::FADING_LIGHT, light.fading_light)?;
2218
2219 Ok(header_pos)
2220 }
2221
2222 fn write_light_arrays(
2233 &mut self,
2234 light: &super::MdlLight,
2235 header_pos: u64,
2236 ) -> Result<(), MdlError> {
2237 let write_cexo_header = |writer: &mut Self,
2239 ptr_offset: usize,
2240 data_ptr: u32,
2241 count: u32|
2242 -> Result<(), MdlError> {
2243 writer.write_u32_at(header_pos, ptr_offset, data_ptr)?;
2244 writer.write_u32_at(header_pos, ptr_offset + 4, count)?;
2245 writer.write_u32_at(header_pos, ptr_offset + 8, count)?;
2247 Ok(())
2248 };
2249
2250 let count = count_u32(light.flare_sizes.len(), "flare_sizes_count")?;
2252 if count > 0 {
2253 let data_ptr = self.content_position()?; for &size in &light.flare_sizes {
2255 write_f32(&mut self.buffer, size)?;
2256 }
2257 write_cexo_header(self, light_offsets::FLARE_SIZES_PTR, data_ptr, count)?;
2258 }
2259
2260 let count = count_u32(light.flare_positions.len(), "flare_positions_count")?;
2262 if count > 0 {
2263 let data_ptr = self.content_position()?; for &pos in &light.flare_positions {
2265 write_f32(&mut self.buffer, pos)?;
2266 }
2267 write_cexo_header(self, light_offsets::FLARE_POSITIONS_PTR, data_ptr, count)?;
2268 }
2269
2270 let count = count_u32(light.flare_color_shifts.len(), "flare_color_shifts_count")?;
2272 if count > 0 {
2273 let data_ptr = self.content_position()?; for shift in &light.flare_color_shifts {
2275 write_f32(&mut self.buffer, shift[0])?;
2276 write_f32(&mut self.buffer, shift[1])?;
2277 write_f32(&mut self.buffer, shift[2])?;
2278 }
2279 write_cexo_header(self, light_offsets::FLARE_COLOR_SHIFTS_PTR, data_ptr, count)?;
2280 }
2281
2282 let count = count_u32(light.flare_texture_names.len(), "flare_tex_names_count")?;
2285 if count > 0 {
2286 let ptr_array_pos = self.buffer.position();
2288 let ptr_array_content_rel = self.content_position()?;
2289 for _ in 0..count {
2291 write_u32(&mut self.buffer, 0)?;
2292 }
2293
2294 for (i, name) in light.flare_texture_names.iter().enumerate() {
2296 let str_ptr = self.content_position()?; self.buffer.write_all(name.as_bytes())?;
2299 self.buffer.write_all(&[0])?; let save = self.buffer.position();
2303 self.seek_to(ptr_array_pos, i * 4);
2304 write_u32(&mut self.buffer, str_ptr)?;
2305 self.buffer.set_position(save);
2306 }
2307
2308 write_cexo_header(
2309 self,
2310 light_offsets::FLARE_TEX_NAMES_PTR,
2311 ptr_array_content_rel,
2312 count,
2313 )?;
2314 }
2315
2316 Ok(())
2317 }
2318
2319 fn write_reference_header(&mut self, reference: &super::MdlReference) -> Result<(), MdlError> {
2321 self.write_fixed_string(&reference.ref_model, 32)?;
2323 write_i32(&mut self.buffer, reference.reattachable)?;
2325 Ok(())
2326 }
2327
2328 fn write_emitter_header(&mut self, emitter: &super::MdlEmitter) -> Result<(), MdlError> {
2330 write_f32(&mut self.buffer, emitter.deadspace)?;
2332 write_f32(&mut self.buffer, emitter.blast_radius)?;
2333 write_f32(&mut self.buffer, emitter.blast_length)?;
2334 write_i32(&mut self.buffer, emitter.num_branches)?;
2335 write_i32(&mut self.buffer, emitter.control_pt_smoothing)?;
2336 write_i32(&mut self.buffer, emitter.x_grid)?;
2337 write_i32(&mut self.buffer, emitter.y_grid)?;
2338 write_i32(&mut self.buffer, emitter.spawn_type)?;
2339
2340 self.write_fixed_string(&emitter.update, 32)?; self.write_fixed_string(&emitter.render, 32)?; self.write_fixed_string(&emitter.blend, 32)?; self.write_fixed_string(&emitter.texture, 32)?; self.write_fixed_string(&emitter.chunk_name, 16)?; write_i32(&mut self.buffer, emitter.two_sided_tex)?;
2349 write_i32(&mut self.buffer, emitter.loop_emitter)?;
2350 write_u16(&mut self.buffer, emitter.render_order)?;
2351 self.buffer
2352 .write_all(&[if emitter.frame_blending { 1 } else { 0 }])?;
2353
2354 self.write_fixed_string(&emitter.depth_texture_name, 16)?;
2356
2357 self.buffer.write_all(&emitter.reserved)?;
2359
2360 Ok(())
2361 }
2362
2363 fn write_dangly_header(&mut self, dangly: &super::MdlDangly) -> Result<u64, MdlError> {
2368 let header_pos = self.buffer.position();
2369
2370 self.buffer.write_all(&[0u8; DANGLY_EXTRA_SIZE])?;
2374
2375 let save = self.buffer.position();
2376 self.seek_to(header_pos, dangly_offsets::DISPLACEMENT);
2377 write_f32(&mut self.buffer, dangly.displacement)?;
2378 write_f32(&mut self.buffer, dangly.tightness)?;
2379 write_f32(&mut self.buffer, dangly.period)?;
2380 self.buffer.set_position(save);
2381
2382 Ok(header_pos)
2383 }
2384
2385 fn write_dangly_pre_mesh_payload(
2390 &mut self,
2391 dangly: &super::MdlDangly,
2392 dangly_header_pos: u64,
2393 ) -> Result<(), MdlError> {
2394 let ptr = if !dangly.dangly_vertices.is_empty() {
2395 let p = self.content_position()?;
2396 for v in &dangly.dangly_vertices {
2397 write_f32(&mut self.buffer, v[0])?;
2398 write_f32(&mut self.buffer, v[1])?;
2399 write_f32(&mut self.buffer, v[2])?;
2400 }
2401 p
2402 } else {
2403 0
2404 };
2405
2406 self.write_u32_at(dangly_header_pos, dangly_offsets::DATA_PTR, ptr)?;
2407 Ok(())
2408 }
2409
2410 fn write_dangly_arrays(
2412 &mut self,
2413 dangly: &super::MdlDangly,
2414 dangly_header_pos: u64,
2415 ) -> Result<(), MdlError> {
2416 let constraints_count = count_u32(dangly.constraints.len(), "constraints_count")?;
2417 let mut constraints_ptr = 0u32;
2418
2419 if constraints_count > 0 {
2420 constraints_ptr = self.content_position()?;
2421 for &val in &dangly.constraints {
2422 write_f32(&mut self.buffer, val)?;
2423 }
2424 }
2425
2426 let save_end = self.buffer.position();
2428 self.seek_to(dangly_header_pos, dangly_offsets::CONSTRAINTS_PTR);
2429 write_u32(&mut self.buffer, constraints_ptr)?;
2430 write_u32(&mut self.buffer, constraints_count)?;
2431 write_u32(&mut self.buffer, constraints_count)?; self.buffer.set_position(save_end);
2433
2434 Ok(())
2435 }
2436
2437 fn write_aabb_header(&mut self) -> Result<u64, MdlError> {
2442 let header_pos = self.buffer.position();
2443 self.buffer.write_all(&[0u8; AABB_EXTRA_SIZE])?;
2444 Ok(header_pos)
2445 }
2446
2447 fn write_aabb_arrays(
2449 &mut self,
2450 aabb: &super::MdlAabb,
2451 aabb_header_pos: u64,
2452 ) -> Result<(), MdlError> {
2453 let ptr = if let Some(tree) = &aabb.aabb_tree {
2454 self.write_aabb_tree(tree)?
2455 } else {
2456 0
2457 };
2458
2459 let save = self.buffer.position();
2460 self.seek_to(aabb_header_pos, aabb_offsets::TREE_PTR);
2461 write_u32(&mut self.buffer, ptr)?;
2462 self.buffer.set_position(save);
2463 Ok(())
2464 }
2465
2466 fn write_aabb_tree(&mut self, node: &super::AabbNode) -> Result<u32, MdlError> {
2471 let node_ptr = self.content_position()?; for &v in &node.box_min {
2475 write_f32(&mut self.buffer, v)?;
2476 }
2477 for &v in &node.box_max {
2478 write_f32(&mut self.buffer, v)?;
2479 }
2480
2481 let right_ph = self.buffer.position();
2483 write_u32(&mut self.buffer, 0)?;
2484 let left_ph = self.buffer.position();
2485 write_u32(&mut self.buffer, 0)?;
2486
2487 write_i32(&mut self.buffer, node.face_index)?;
2489 write_u32(&mut self.buffer, node.split_direction_flags)?;
2490
2491 if let Some(left) = &node.left {
2493 let left_ptr = self.write_aabb_tree(left)?;
2494 let save = self.buffer.position();
2495 self.buffer.set_position(left_ph);
2496 write_u32(&mut self.buffer, left_ptr)?;
2497 self.buffer.set_position(save);
2498 }
2499
2500 if let Some(right) = &node.right {
2502 let right_ptr = self.write_aabb_tree(right)?;
2503 let save = self.buffer.position();
2504 self.buffer.set_position(right_ph);
2505 write_u32(&mut self.buffer, right_ptr)?;
2506 self.buffer.set_position(save);
2507 }
2508
2509 Ok(node_ptr)
2510 }
2511
2512 fn write_saber_header(&mut self, saber: &super::MdlSaber) -> Result<u64, MdlError> {
2517 let header_pos = self.buffer.position();
2518
2519 self.buffer.write_all(&[0u8; SABER_EXTRA_SIZE])?;
2521 let save = self.buffer.position();
2522
2523 self.write_u32_at(header_pos, saber_offsets::GL_POOL_VERT, saber.gl_pool_vert)?;
2525 self.write_u32_at(
2526 header_pos,
2527 saber_offsets::GL_POOL_INDEX,
2528 saber.gl_pool_index,
2529 )?;
2530
2531 self.buffer.set_position(save);
2532 Ok(header_pos)
2533 }
2534
2535 fn write_saber_arrays(
2537 &mut self,
2538 saber: &super::MdlSaber,
2539 saber_header_pos: u64,
2540 ) -> Result<(), MdlError> {
2541 let verts_ptr = if !saber.saber_verts.is_empty() {
2543 let p = self.content_position()?;
2544 for v in &saber.saber_verts {
2545 write_f32(&mut self.buffer, v[0])?;
2546 write_f32(&mut self.buffer, v[1])?;
2547 write_f32(&mut self.buffer, v[2])?;
2548 }
2549 p
2550 } else {
2551 0
2552 };
2553
2554 let uvs_ptr = if !saber.saber_uvs.is_empty() {
2556 let p = self.content_position()?;
2557 for v in &saber.saber_uvs {
2558 write_f32(&mut self.buffer, v[0])?;
2559 write_f32(&mut self.buffer, v[1])?;
2560 }
2561 p
2562 } else {
2563 0
2564 };
2565
2566 let normals_ptr = if !saber.saber_normals.is_empty() {
2568 let p = self.content_position()?;
2569 for v in &saber.saber_normals {
2570 write_f32(&mut self.buffer, v[0])?;
2571 write_f32(&mut self.buffer, v[1])?;
2572 write_f32(&mut self.buffer, v[2])?;
2573 }
2574 p
2575 } else {
2576 0
2577 };
2578
2579 self.write_u32_at(saber_header_pos, saber_offsets::VERTS_PTR, verts_ptr)?;
2581 self.write_u32_at(saber_header_pos, saber_offsets::UVS_PTR, uvs_ptr)?;
2582 self.write_u32_at(saber_header_pos, saber_offsets::NORMALS_PTR, normals_ptr)?;
2583
2584 Ok(())
2585 }
2586
2587 fn write_fixed_string(&mut self, s: &str, field_size: usize) -> Result<(), MdlError> {
2589 crate::binary::write_fixed_c_string(&mut self.buffer, s, field_size)?;
2590 Ok(())
2591 }
2592}