Skip to main content

fastpack_core/imaging/
alias.rs

1use rustc_hash::FxHashMap;
2
3use crate::types::sprite::Sprite;
4
5/// Detect duplicate sprites by pixel content and mark them as aliases.
6///
7/// Sprites are grouped by `(width, height, content_hash)`. Within each group,
8/// pixel bytes are compared exactly to confirm identity (handles hash collisions).
9/// The first sprite encountered in each unique-pixel group becomes the canonical
10/// entry; all others have `alias_of` set to that canonical sprite's id.
11///
12/// Returns `(unique, aliases)` where `unique` is suitable to pass to the packer
13/// and `aliases` contains the stripped duplicates (each with `alias_of` set).
14pub fn detect_aliases(sprites: Vec<Sprite>) -> (Vec<Sprite>, Vec<Sprite>) {
15    // key → indices into `unique` that have this (w, h, hash).
16    let mut buckets: FxHashMap<(u32, u32, u64), Vec<usize>> = FxHashMap::default();
17    let mut unique: Vec<Sprite> = Vec::new();
18    let mut aliases: Vec<Sprite> = Vec::new();
19
20    for mut sprite in sprites {
21        let w = sprite.image.width();
22        let h = sprite.image.height();
23        let key = (w, h, sprite.content_hash);
24
25        let canon_id = buckets.get(&key).and_then(|indices| {
26            indices.iter().find_map(|&i| {
27                if pixels_equal(&sprite.image, &unique[i].image) {
28                    Some(unique[i].id.clone())
29                } else {
30                    None
31                }
32            })
33        });
34
35        if let Some(id) = canon_id {
36            sprite.alias_of = Some(id);
37            aliases.push(sprite);
38        } else {
39            let idx = unique.len();
40            buckets.entry(key).or_default().push(idx);
41            unique.push(sprite);
42        }
43    }
44
45    (unique, aliases)
46}
47
48fn pixels_equal(a: &image::DynamicImage, b: &image::DynamicImage) -> bool {
49    match (a.as_rgba8(), b.as_rgba8()) {
50        (Some(ra), Some(rb)) => ra.as_raw() == rb.as_raw(),
51        _ => false,
52    }
53}