From 972b05fbd2be04e8938e302e1084b9ebc03f5b3e Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 4 Mar 2023 18:36:39 -0800 Subject: [PATCH] Add support for viewing WMDL and SMDL files --- lib/src/format/cmdl.rs | 23 ++++++++++++++++++++--- retrotool-gui/src/loaders.rs | 2 +- retrotool-gui/src/tabs/project.rs | 6 +++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/src/format/cmdl.rs b/lib/src/format/cmdl.rs index 966ded3..da16396 100644 --- a/lib/src/format/cmdl.rs +++ b/lib/src/format/cmdl.rs @@ -14,9 +14,15 @@ use crate::{ // Cooked model pub const K_FORM_CMDL: FourCC = FourCC(*b"CMDL"); +pub const K_FORM_SMDL: FourCC = FourCC(*b"SMDL"); +pub const K_FORM_WMDL: FourCC = FourCC(*b"WMDL"); // Model header pub const K_CHUNK_HEAD: FourCC = FourCC(*b"HEAD"); +// World header +pub const K_CHUNK_WDHD: FourCC = FourCC(*b"WDHD"); +// Skinned header +pub const K_CHUNK_SKHD: FourCC = FourCC(*b"SKHD"); // Material data pub const K_CHUNK_MTRL: FourCC = FourCC(*b"MTRL"); // Mesh data @@ -776,9 +782,18 @@ pub struct ModelData { impl ModelData { pub fn slice(data: &[u8], meta: &[u8], e: Endian) -> Result { let (cmdl_desc, mut cmdl_data, _) = FormDescriptor::slice(data, Endian::Little)?; - ensure!(cmdl_desc.id == K_FORM_CMDL); - ensure!(cmdl_desc.version_a == 114); - ensure!(cmdl_desc.version_b == 125); + ensure!(cmdl_desc.id == K_FORM_CMDL || cmdl_desc.id == K_FORM_SMDL || cmdl_desc.id == K_FORM_WMDL); + if cmdl_desc.id == K_FORM_CMDL { + ensure!(cmdl_desc.version_a == 114); + ensure!(cmdl_desc.version_b == 125); + } else if cmdl_desc.id == K_FORM_SMDL { + ensure!(cmdl_desc.version_a == 127); + ensure!(cmdl_desc.version_b == 133); + } else if cmdl_desc.id == K_FORM_WMDL { + ensure!(cmdl_desc.version_a == 118); + ensure!(cmdl_desc.version_b == 124); + } + let meta: SModelMetaData = Cursor::new(meta).read_type(e)?; let vtx_buffers = decompress_gpu_buffers(data, &meta.read_info, &meta.vtx_buffer_info)?; @@ -792,6 +807,8 @@ impl ModelData { while !cmdl_data.is_empty() { let (chunk_desc, chunk_data, remain) = ChunkDescriptor::slice(cmdl_data, e)?; match chunk_desc.id { + K_CHUNK_WDHD => head = Some(Cursor::new(chunk_data).read_type(e)?), + K_CHUNK_SKHD => head = Some(Cursor::new(chunk_data).read_type(e)?), K_CHUNK_HEAD => head = Some(Cursor::new(chunk_data).read_type(e)?), K_CHUNK_MTRL => mtrl = Some(Cursor::new(chunk_data).read_type(e)?), K_CHUNK_MESH => mesh = Some(Cursor::new(chunk_data).read_type(e)?), diff --git a/retrotool-gui/src/loaders.rs b/retrotool-gui/src/loaders.rs index 406113e..fb99788 100644 --- a/retrotool-gui/src/loaders.rs +++ b/retrotool-gui/src/loaders.rs @@ -297,7 +297,7 @@ impl AssetLoader for ModelAssetLoader { }) } - fn extensions(&self) -> &[&str] { &["cmdl"] } + fn extensions(&self) -> &[&str] { &["cmdl", "smdl", "wmdl"] } } #[derive(Debug, Clone, bevy::reflect::TypeUuid)] diff --git a/retrotool-gui/src/tabs/project.rs b/retrotool-gui/src/tabs/project.rs index 24fe95b..89a6580 100644 --- a/retrotool-gui/src/tabs/project.rs +++ b/retrotool-gui/src/tabs/project.rs @@ -3,7 +3,7 @@ use bevy::{ prelude::*, }; use egui::{text::LayoutJob, Color32, TextFormat, Widget}; -use retrolib::format::{cmdl::K_FORM_CMDL, txtr::K_FORM_TXTR, FourCC}; +use retrolib::format::{cmdl::{K_FORM_CMDL, K_FORM_SMDL, K_FORM_WMDL}, txtr::K_FORM_TXTR, FourCC}; use crate::{ icon, @@ -41,7 +41,7 @@ impl SystemTab for ProjectTab { "{} {} {}", match entry.kind { K_FORM_TXTR => icon::TEXTURE, - K_FORM_CMDL => icon::FILE_3D, + K_FORM_CMDL | K_FORM_SMDL | K_FORM_WMDL => icon::FILE_3D, K_FORM_FMV0 => icon::FILE_MOVIE, K_FORM_ROOM => icon::SCENE_DATA, _ => icon::FILE, @@ -77,7 +77,7 @@ impl SystemTab for ProjectTab { loaded_texture: None, })); } - K_FORM_CMDL => { + K_FORM_CMDL | K_FORM_SMDL | K_FORM_WMDL => { let handle = server .load::(format!("{}.{}", entry.id, entry.kind)); state.open_tab = Some(TabType::Model(ModelTab {