Bundles carry pre-baked backgrounds (paintings survive filesystem-less boots)
RoomDoc gains baked_visual (quantized indices, exporter-written, skipped when empty); bake() falls back to it when pics/ can't load; --export-bundle folds every room's painting in via World::bake_backgrounds_for_bundle. A six-painting game bundles to 1.5MB. Tests green; alley renders from bundle alone with no pics/ on disk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8f98380261
commit
f706a9ce55
@ -76,7 +76,11 @@ fn main() {
|
|||||||
let mut gs = GameState::new(world);
|
let mut gs = GameState::new(world);
|
||||||
|
|
||||||
if let Some(path) = get("--export-bundle") {
|
if let Some(path) = get("--export-bundle") {
|
||||||
let bundle = gs.world.to_bundle();
|
let mut bundle = gs.world.to_bundle();
|
||||||
|
// Paintings ride inside the bundle as pre-quantized indices, so the
|
||||||
|
// wasm build (no filesystem) keeps its backgrounds.
|
||||||
|
gs.world.bake_backgrounds_for_bundle(&mut bundle.rooms);
|
||||||
|
let bundle = bundle;
|
||||||
// Through Value first, so the output is byte-stable.
|
// Through Value first, so the output is byte-stable.
|
||||||
//
|
//
|
||||||
// A bundle is full of HashMaps — rooms, scripts, sprites, every
|
// A bundle is full of HashMaps — rooms, scripts, sprites, every
|
||||||
|
|||||||
@ -154,6 +154,12 @@ pub struct RoomDoc {
|
|||||||
/// `<name>-ctl.png` companions). Applied before `ops`.
|
/// `<name>-ctl.png` companions). Applied before `ops`.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub background: String,
|
pub background: String,
|
||||||
|
/// The background pre-quantized to visual indices (PIC_W*PIC_H), written
|
||||||
|
/// by the bundle exporter so filesystem-less builds (wasm) keep their
|
||||||
|
/// paintings. Only consulted when the `pics/` file can't be loaded;
|
||||||
|
/// travels with `palette`, which the exporter sets to the quantized one.
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub baked_visual: Vec<u8>,
|
||||||
/// Procedural paint ops (replayed after the background, if any).
|
/// Procedural paint ops (replayed after the background, if any).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ops: Vec<PicOp>,
|
pub ops: Vec<PicOp>,
|
||||||
@ -207,6 +213,7 @@ impl Default for RoomDoc {
|
|||||||
name: String::new(),
|
name: String::new(),
|
||||||
enter_text: String::new(),
|
enter_text: String::new(),
|
||||||
background: String::new(),
|
background: String::new(),
|
||||||
|
baked_visual: Vec::new(),
|
||||||
ops: Vec::new(),
|
ops: Vec::new(),
|
||||||
palette: None,
|
palette: None,
|
||||||
cycles: Vec::new(),
|
cycles: Vec::new(),
|
||||||
@ -395,6 +402,10 @@ impl World {
|
|||||||
let dir = self.base.join("pics");
|
let dir = self.base.join("pics");
|
||||||
if let Some(rgba) = assets::load_rgba_scaled(&dir.join(format!("{}.png", self.doc.background)), PIC_W, PIC_H) {
|
if let Some(rgba) = assets::load_rgba_scaled(&dir.join(format!("{}.png", self.doc.background)), PIC_W, PIC_H) {
|
||||||
assets::bake_background(&rgba, &mut self.palette, &mut self.screens);
|
assets::bake_background(&rgba, &mut self.palette, &mut self.screens);
|
||||||
|
} else if self.doc.baked_visual.len() == PIC_W * PIC_H {
|
||||||
|
// No filesystem (or the art moved): the exporter pre-baked
|
||||||
|
// the painting into the doc. Palette came from doc.palette.
|
||||||
|
self.screens.visual.copy_from_slice(&self.doc.baked_visual);
|
||||||
}
|
}
|
||||||
if let Some(rgba) = assets::load_rgba_scaled(&dir.join(format!("{}-pri.png", self.doc.background)), PIC_W, PIC_H) {
|
if let Some(rgba) = assets::load_rgba_scaled(&dir.join(format!("{}-pri.png", self.doc.background)), PIC_W, PIC_H) {
|
||||||
assets::bake_pri_mask(&rgba, &mut self.screens);
|
assets::bake_pri_mask(&rgba, &mut self.screens);
|
||||||
@ -518,6 +529,25 @@ impl World {
|
|||||||
WorldBundle { manifest: self.manifest.clone(), rooms, scripts, sprites }
|
WorldBundle { manifest: self.manifest.clone(), rooms, scripts, sprites }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fold each room's background painting into its doc (quantized indices
|
||||||
|
/// + palette), so the bundle plays where there is no filesystem. The
|
||||||
|
/// exporter calls this; docs already carrying a bake are left alone.
|
||||||
|
pub fn bake_backgrounds_for_bundle(&self, rooms: &mut BTreeMap<u32, RoomDoc>) {
|
||||||
|
for doc in rooms.values_mut() {
|
||||||
|
if doc.background.is_empty() || doc.baked_visual.len() == PIC_W * PIC_H {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let dir = self.base.join("pics");
|
||||||
|
if let Some(rgba) = assets::load_rgba_scaled(&dir.join(format!("{}.png", doc.background)), PIC_W, PIC_H) {
|
||||||
|
let mut pal = doc.palette.clone().unwrap_or_else(Palette::base);
|
||||||
|
let mut probe = Screens::new();
|
||||||
|
assets::bake_background(&rgba, &mut pal, &mut probe);
|
||||||
|
doc.palette = Some(pal);
|
||||||
|
doc.baked_visual = probe.visual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace the loaded world with a bundle. A bundle that carries
|
/// Replace the loaded world with a bundle. A bundle that carries
|
||||||
/// sprites replaces the art wholesale (the wasm/bootstrap path); one
|
/// sprites replaces the art wholesale (the wasm/bootstrap path); one
|
||||||
/// that doesn't keeps whatever this World already loaded.
|
/// that doesn't keeps whatever this World already loaded.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user