refactor: sprite_mipmap_limit lives in sprites.rs

sprites.rs called back into gfx for this one function, one of the edges that
keep the client lib's modules in a single cycle. The function and its test
move to sprites.rs; gfx calls it there. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Ludovic MarieandClaude Opus 5.5 committed 2026-10-27 09:18:56 +01:00
1 parent 1284f97df6
commit 42c653be00
3 files changed
+21 -16

No files matched your search

+1 -13
View File
@@ -3197,7 +3197,7 @@ impl Renderer {
/// The Mipmap Levels option: block textures sample at most `levels`
/// reduced copies (0: none).
pub fn set_mipmap_levels(&mut self, levels: u32) {
let levels = sprite_mipmap_limit(
let levels = crate::sprites::sprite_mipmap_limit(
levels,
self.sprite_textures[0].width(),
self.sprite_minimum_size,
@@ -5479,11 +5479,6 @@ mod tests {
}
}
pub(crate) fn sprite_mipmap_limit(requested: u32, size: u32, minimum: u32, available: u32) -> u32 {
// Only the atlas native minimum determines how many resampling-only mips to skip.
let upscale = (size / minimum.max(1)).max(1).ilog2();
requested.saturating_add(upscale).min(available - 1)
}
#[cfg(test)]
mod sprite_upload_tests {
use super::*;
@@ -5544,13 +5539,6 @@ mod sprite_upload_tests {
}
}
#[test]
fn mipmap_option_keeps_real_16px_reductions() {
for levels in 0..=4 {
assert_eq!(sprite_mipmap_limit(levels, 32, 16, 6), levels + 1);
assert_eq!(sprite_mipmap_limit(levels, 16, 16, 5), levels);
}
}
#[test]
fn prepared_texture_uploads_preserve_layer_order_and_settings() {
let size = 4;
let layers = 5;
+17 -2
View File
@@ -342,10 +342,25 @@ pub(crate) fn test_frames(layer: u32, frames: Vec<Vec<u8>>, metadata: &str) -> S
}
}
/// How many reduced copies a sprite atlas keeps: the Mipmap Levels option plus the
/// resampling-only levels an upscaled pack needs, within what the atlas holds.
pub(crate) fn sprite_mipmap_limit(requested: u32, size: u32, minimum: u32, available: u32) -> u32 {
// Only the atlas native minimum determines how many resampling-only mips to skip.
let upscale = (size / minimum.max(1)).max(1).ilog2();
requested.saturating_add(upscale).min(available - 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mipmap_option_keeps_real_16px_reductions() {
for levels in 0..=4 {
assert_eq!(sprite_mipmap_limit(levels, 32, 16, 6), levels + 1);
assert_eq!(sprite_mipmap_limit(levels, 16, 16, 5), levels);
}
}
#[test]
fn identical_still_textures_share_a_layer() {
let root =
std::env::temp_dir().join(format!("horizon-sprite-share-{}", std::process::id()));
@@ -398,7 +413,7 @@ mod tests {
assert_eq!((sprites.size, sprites.minimum_size), (32, 32));
for level in 0..=4 {
assert_eq!(
crate::gfx::sprite_mipmap_limit(level, sprites.size, sprites.minimum_size, 6),
sprite_mipmap_limit(level, sprites.size, sprites.minimum_size, 6),
level
);
}
@@ -408,7 +423,7 @@ mod tests {
sprites.finish();
assert_eq!((sprites.size, sprites.minimum_size), (32, 16));
assert_eq!(
crate::gfx::sprite_mipmap_limit(0, sprites.size, sprites.minimum_size, 6),
sprite_mipmap_limit(0, sprites.size, sprites.minimum_size, 6),
1
);
}
+3 -1
View File
@@ -52,7 +52,9 @@ def main():
baseline = subprocess.check_output(['git', 'show', '89b58991bbc02eb79b6965fc4ca56357fe2297d9:crates/horizon-client/src/gfx.rs'], cwd=ROOT, text=True)
code += '\n' + function(baseline, 'animate_sprites').replace('fn animate_sprites(', 'fn reference_animate_sprites(', 1)
if args.test:
code += '\n' + function(source, 'sprite_mipmap_limit')
# sprites.rs holds it since the gfx -> sprites cut; older refs kept it in gfx.rs.
code += '\n' + (function(source, 'sprite_mipmap_limit') if 'fn sprite_mipmap_limit' in source
else 'use sprites::sprite_mipmap_limit;')
code += '\n' + source[source.index('#[cfg(test)]\nmod sprite_upload_tests'):]
modules = '\n'.join(f'#[path = {json.dumps(str(ROOT / "crates/horizon-client/src" / (name + ".rs")))}] mod {name};'
for name in ('mipmap', 'sprites', 'fast_hash'))