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:
MechaCat02
2026-03-25 21:04:07 +01:00
commit f8127e73b0
23 changed files with 8107 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
//! # sylpheed-viewer
//!
//! Bevy-based asset viewer for Project Sylpheed: Arc of Deception.
//!
//! This crate serves as both:
//! - A **native binary** (via `main.rs`) — full desktop viewer
//! - A **WASM library** (this file) — browser viewer at `index.html`
//!
//! ## Architecture
//! - `sylpheed_formats` handles all binary parsing — no Bevy dependency
//! - This crate is the thin Bevy integration layer on top
//! - `asset_loader` bridges the two: wraps parsers as `AssetLoader` impls
//!
//! ## WASM notes
//! On the web, local file access is unavailable. Assets must be
//! pre-extracted and served over HTTP. XISO reading is native-only.
use bevy::prelude::*;
use bevy_egui::EguiPlugin;
pub mod asset_loader;
pub mod camera;
pub mod ui;
// ── Application state ────────────────────────────────────────────────────────
/// Global viewer state, shared across all UI and rendering systems.
#[derive(Resource)]
pub struct ViewerState {
/// Which type of asset is currently being browsed / previewed.
pub current_mode: ViewMode,
/// Whether to render meshes in wireframe mode (toggle with F2).
pub wireframe: bool,
}
impl Default for ViewerState {
fn default() -> Self {
Self {
current_mode: ViewMode::Textures,
wireframe: false,
}
}
}
/// The active view / asset type being inspected.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ViewMode {
/// XPR2 texture preview (Milestone 1).
#[default]
Textures,
/// 3D mesh viewer (Milestone 2+).
Mesh,
/// Audio waveform / playback (Milestone 2+).
Audio,
}
// ── App builder ──────────────────────────────────────────────────────────────
/// Build and run the viewer application.
///
/// Called from `main.rs` on native and from `wasm_bindgen` init on the web.
pub fn run() {
let mut app = App::new();
app.add_plugins(
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Project Sylpheed: Arc of Deception — Asset Viewer".into(),
resolution: (1280.0, 720.0).into(),
..default()
}),
..default()
}),
);
app.add_plugins(EguiPlugin);
app.add_plugins(asset_loader::SylpheedAssetPlugin);
app.add_plugins(camera::OrbitCameraPlugin);
app.add_plugins(ui::ViewerUiPlugin);
app.init_resource::<ViewerState>();
// Minimal 3D scene: a directional light so meshes are visible
app.add_systems(Startup, setup_scene);
app.run();
}
fn setup_scene(mut commands: Commands) {
commands.spawn(DirectionalLight {
illuminance: 10_000.0,
shadows_enabled: true,
..default()
});
}