hud: slice animated GUI sprites to first frame in atlas packing (fixes #9948)

Co-Authored-By: Antigravity <[email protected]>
This commit is contained in:
AxxioandAntigravity committed 2026-11-05 20:54:48 +01:00
1 parent 5b4823c198
commit cfccbb8f40
1 file changed
+45 -1
+45 -1
View File
@@ -1232,7 +1232,8 @@ impl HudAtlas {
.ok();
let animation = animation_of(mcmeta.as_deref());
// An animated strip keeps its first frame.
let frames = name.starts_with("block/") || name.starts_with("item/");
let frames =
animation.is_some() || name.starts_with("block/") || name.starts_with("item/");
let (w, h, pixels) = if frames {
first_frame(image, animation.as_ref())
} else {
@@ -3495,6 +3496,49 @@ mod tests {
let banner = atlas.sprites["custom/banner"];
assert_eq!(banner.texels((atlas.width, atlas.height)), (16, 32));
}
#[test]
fn an_animated_gui_sprite_packs_its_first_frame_and_animates() {
let root =
std::env::temp_dir().join(format!("horizon-atlas-gui-anim-{}", std::process::id()));
let sprites = root.join("assets/minecraft/textures/gui/sprites/icon");
fs::create_dir_all(&sprites).unwrap();
// A GUI sprite like icon/music_notes: 4 frames stacked vertically (16x64),
// with animation metadata, and a still 16x32 texture beside it.
write_strip(
&sprites.join("music_notes.png"),
16,
64,
&[
[10, 20, 30, 255],
[40, 50, 60, 255],
[70, 80, 90, 255],
[100, 110, 120, 255],
],
Some(r#"{"animation": {"frametime": 2}}"#),
);
write_strip(
&sprites.join("static_badge.png"),
16,
32,
&[[9, 9, 9, 255]],
None,
);
let atlas = HudAtlas::build(&root).unwrap();
let _ = fs::remove_dir_all(&root);
let rect = atlas.sprites["gui/sprites/icon/music_notes"];
// One frame, not the whole 16x64 strip squeezed into a slot.
assert_eq!(rect.texels((atlas.width, atlas.height)), (16, 16));
assert_eq!(texel_at(&atlas, rect, 0, 15), [10, 20, 30, 255]);
let (_, animation) = atlas
.sprite_animations
.iter()
.find(|(r, _)| r.u0 == rect.u0 && r.v0 == rect.v0)
.expect("the gui sprite animates");
assert_eq!(animation.frame_count(), 4);
// A still texture there stays whole.
let static_badge = atlas.sprites["gui/sprites/icon/static_badge"];
assert_eq!(static_badge.texels((atlas.width, atlas.height)), (16, 32));
}
/// A resource root with one plain item texture and these CIT files (relative path, contents).
fn cit_root(name: &str, files: &[(&str, &str)]) -> PathBuf {
let root =