viewer: preview reassembled UI screens in the PAK browser
When an opened GP_*.pak RATC entry is a .rat build, compose the screen (ui_layout::compose_build) and show it atop the RATC detail, labelled 'UI screen', with the sprite children below. Reuses the existing pak-open + T8aD-decode path — no new browser/threading. Entry summaries mark UI builds. cargo check -p sylpheed-viewer: clean.
This commit is contained in:
@@ -160,8 +160,9 @@ pub enum PakContent {
|
||||
T8ad(ImageRgba),
|
||||
/// An LSTA sprite list — inline T8aD frames.
|
||||
Lsta(Vec<ImageRgba>),
|
||||
/// A RATC bundle — its listed children (T8aD children carry a decoded image).
|
||||
Ratc(Vec<RatcEntry>),
|
||||
/// A RATC bundle — its listed children (T8aD children carry a decoded
|
||||
/// image), plus the reassembled UI screen when the bundle is a `.rat` build.
|
||||
Ratc(Vec<RatcEntry>, Option<ImageRgba>),
|
||||
/// Plain-text / XML payload, with its encoding label.
|
||||
Text { text: String, encoding: String },
|
||||
}
|
||||
@@ -192,6 +193,13 @@ impl ImageRgba {
|
||||
rgba: img.rgba,
|
||||
}
|
||||
}
|
||||
fn from_composed(s: sylpheed_formats::ui_layout::ComposedScreen) -> Self {
|
||||
Self {
|
||||
width: s.width,
|
||||
height: s.height,
|
||||
rgba: s.rgba,
|
||||
}
|
||||
}
|
||||
fn pixels(&self) -> usize {
|
||||
(self.width as usize) * (self.height as usize)
|
||||
}
|
||||
@@ -1469,7 +1477,10 @@ fn classify_content(payload: &[u8]) -> PakContent {
|
||||
})
|
||||
.collect();
|
||||
if !entries.is_empty() {
|
||||
return PakContent::Ratc(entries);
|
||||
// If this bundle is a `.rat` UI build, reassemble the screen.
|
||||
let ui_screen = sylpheed_formats::ui_layout::compose_build(payload, false)
|
||||
.map(ImageRgba::from_composed);
|
||||
return PakContent::Ratc(entries, ui_screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,7 +672,9 @@ fn draw_pak_browser(ui: &mut egui::Ui, pak: &mut PakView) {
|
||||
PakContent::Png(img) => draw_png_detail(ui, row, img, img_tex),
|
||||
PakContent::T8ad(img) => draw_t8ad_detail(ui, row, img, img_tex),
|
||||
PakContent::Lsta(frames) => draw_lsta_detail(ui, row, frames, img_tex),
|
||||
PakContent::Ratc(children) => draw_ratc_detail(ui, row, children, img_tex),
|
||||
PakContent::Ratc(children, ui_screen) => {
|
||||
draw_ratc_detail(ui, row, children, ui_screen.as_ref(), img_tex)
|
||||
}
|
||||
PakContent::Text { text, encoding } => {
|
||||
draw_text_detail(ui, row, text, encoding)
|
||||
}
|
||||
@@ -699,7 +701,10 @@ fn row_kind(row: &crate::iso_loader::PakRow) -> String {
|
||||
PakContent::Png(img) => format!("PNG {}×{}", img.width, img.height),
|
||||
PakContent::T8ad(img) => format!("T8aD {}×{}", img.width, img.height),
|
||||
PakContent::Lsta(f) => format!("LSTA · {} sprite(s)", f.len()),
|
||||
PakContent::Ratc(c) => format!("RATC · {} item(s)", c.len()),
|
||||
PakContent::Ratc(c, screen) => {
|
||||
let s = if screen.is_some() { " · UI screen" } else { "" };
|
||||
format!("RATC · {} item(s){s}", c.len())
|
||||
}
|
||||
PakContent::Text { .. } => "text".into(),
|
||||
PakContent::None => row.identity.clone(),
|
||||
}
|
||||
@@ -939,21 +944,47 @@ fn draw_ratc_detail(
|
||||
ui: &mut egui::Ui,
|
||||
row: &crate::iso_loader::PakRow,
|
||||
children: &[crate::iso_loader::RatcEntry],
|
||||
ui_screen: Option<&ImageRgba>,
|
||||
img_tex: &mut ImgCache,
|
||||
) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.heading("RATC bundle");
|
||||
ui.separator();
|
||||
ui.label(format!("{} item(s)", children.len()));
|
||||
if ui_screen.is_some() {
|
||||
ui.separator();
|
||||
ui.strong("🖼 UI screen");
|
||||
}
|
||||
ui.separator();
|
||||
ui.weak("colours unverified");
|
||||
});
|
||||
ui.separator();
|
||||
|
||||
let refs: Vec<&ImageRgba> = children.iter().filter_map(|c| c.image.as_ref()).collect();
|
||||
// Cache the reassembled screen (if any) as texture 0, then child thumbnails.
|
||||
let mut refs: Vec<&ImageRgba> = Vec::new();
|
||||
if let Some(s) = ui_screen {
|
||||
refs.push(s);
|
||||
}
|
||||
let child_base = refs.len();
|
||||
refs.extend(children.iter().filter_map(|c| c.image.as_ref()));
|
||||
ensure_textures(ui, row.hash, &refs, img_tex);
|
||||
|
||||
let mut img_i = 0;
|
||||
// The reassembled screen, scaled to fit the panel width.
|
||||
if ui_screen.is_some() {
|
||||
if let Some(tex) = img_tex.as_ref().and_then(|(_, t)| t.first()) {
|
||||
ui.label("Reassembled from this screen's .rat layout records:");
|
||||
let sz = tex.size_vec2();
|
||||
let scale = (ui.available_width() / sz.x.max(1.0)).min(1.0);
|
||||
ui.add(egui::Image::new(egui::load::SizedTexture::new(
|
||||
tex.id(),
|
||||
[sz.x * scale, sz.y * scale],
|
||||
)));
|
||||
ui.weak("Frame/glow decorations (no .rat) and the live 3D background are omitted.");
|
||||
ui.separator();
|
||||
}
|
||||
}
|
||||
|
||||
let mut img_i = child_base;
|
||||
for c in children {
|
||||
ui.horizontal(|ui| {
|
||||
if c.image.is_some() {
|
||||
|
||||
Reference in New Issue
Block a user