feat: initialise workspace — Milestone 1 asset explorer
Three-crate Cargo workspace structured per PROJECT.md spec: - crates/sylpheed-formats — Xbox 360 format parsers (no Bevy) - crates/sylpheed-viewer — Bevy 0.15 asset viewer + egui UI - crates/sylpheed-cli — CLI tools (extract/list/sniff/texture) Milestone 1 features: - XISO disc image reading via xdvdfs 0.8 - XPR2 texture container parsing + Morton de-tiling - D3DFORMAT → wgpu TextureFormat mapping (DXT1/3/5, DXN, ARGB) - Custom Bevy AssetLoader for .xpr files - Orbit camera (LMB orbit, RMB pan, scroll zoom) - egui file browser + RE notes panel - CLI: extract / list / sniff / texture info / texture export - GitHub Actions CI (Linux, macOS, Windows, WASM) - Trunk WASM build config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
71
crates/sylpheed-formats/src/mesh.rs
Normal file
71
crates/sylpheed-formats/src/mesh.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
//! Mesh format parsing — TO BE REVERSE ENGINEERED.
|
||||
//!
|
||||
//! Project Sylpheed uses a completely custom engine with unknown mesh formats.
|
||||
//! This module is a scaffold: populate these structs as you discover the
|
||||
//! actual binary layout using a hex editor (010 Editor) and Ghidra.
|
||||
//!
|
||||
//! ## RE Strategy for Meshes
|
||||
//!
|
||||
//! 1. Extract the game files using xdvdfs
|
||||
//! 2. Look for files with extensions like .mdl, .mesh, .geo, .obj, .pak
|
||||
//! 3. Open them in a hex editor — look for:
|
||||
//! - Repeating patterns of 12 bytes (XYZ float vertices)
|
||||
//! - Groups of 3 uint16s (triangle indices)
|
||||
//! - Header magic bytes
|
||||
//! 4. Cross-reference with Ghidra's XEX analysis to find the load functions
|
||||
//!
|
||||
//! ## Useful tools
|
||||
//! - 010 Editor with binary templates
|
||||
//! - Noesis (can preview many console formats)
|
||||
//! - binrw (this project) for writing the parser once the format is known
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MeshError {
|
||||
#[error("Unknown mesh magic: {0:?}")]
|
||||
UnknownMagic([u8; 4]),
|
||||
#[error("Unsupported mesh version: {0}")]
|
||||
UnsupportedVersion(u32),
|
||||
#[error("Parse error: {0}")]
|
||||
Parse(String),
|
||||
}
|
||||
|
||||
/// A decoded 3D mesh ready for Bevy.
|
||||
/// Vertex positions, normals, UVs, and indices.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct GameMesh {
|
||||
/// Interleaved vertex positions [x, y, z, x, y, z, ...]
|
||||
pub positions: Vec<[f32; 3]>,
|
||||
/// Vertex normals [nx, ny, nz, ...]
|
||||
pub normals: Vec<[f32; 3]>,
|
||||
/// UV texture coordinates [u, v, ...]
|
||||
pub uvs: Vec<[f32; 2]>,
|
||||
/// Triangle list indices
|
||||
pub indices: Vec<u32>,
|
||||
/// Name of this mesh (if available in the file)
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl GameMesh {
|
||||
/// Parse a mesh from raw bytes.
|
||||
///
|
||||
/// TODO: implement once the actual file format is identified.
|
||||
/// Currently returns an error until the format is reverse engineered.
|
||||
pub fn from_bytes(_bytes: &[u8]) -> Result<Vec<Self>, MeshError> {
|
||||
// ┌──────────────────────────────────────────────────────────────┐
|
||||
// │ REVERSE ENGINEERING TODO │
|
||||
// │ │
|
||||
// │ Steps to implement this: │
|
||||
// │ 1. Find mesh files in the extraction (look for .mdl etc.) │
|
||||
// │ 2. Identify the file format using identify_format() in vfs │
|
||||
// │ 3. Use 010 Editor to map the binary structure │
|
||||
// │ 4. Add binrw #[derive(BinRead)] structs above │
|
||||
// │ 5. Implement this function to parse and return meshes │
|
||||
// └──────────────────────────────────────────────────────────────┘
|
||||
Err(MeshError::Parse(
|
||||
"Mesh format not yet reverse engineered. \
|
||||
See RE TODO in src/mesh.rs".to_string()
|
||||
))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user