1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use std::collections::{BTreeMap, HashMap};
use serde::{Serialize, Serializer};

use texture_packer;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Screen {
    pub x: f32,
    pub y: f32,
    pub w: f32,
    pub h: f32,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Frame {
    pub x: u32,
    pub y: u32,
    pub w: u32,
    pub h: u32,
    pub screen: Screen,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Spritesheet {
    #[serde(serialize_with = "ordered_map")]
    pub frames: HashMap<String, Frame>,
}

fn ordered_map<S>(value: &HashMap<String, Frame>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
    let ordered: BTreeMap<_, _> = value.iter().collect();
    ordered.serialize(serializer)
}

pub fn to_atlas(
    frames: &HashMap<String, texture_packer::Frame>,
    image_width: u32,
    image_height: u32,
) -> Spritesheet {
    let frames_map = frames
        .iter()
        .map(|(name, frame)| (
                name.clone(),
                Frame {
                    x: frame.frame.x,
                    y: frame.frame.y,
                    w: frame.frame.w,
                    h: frame.frame.h,
                    screen: Screen {
                        x: 1. / (image_width as f32 / frame.frame.x as f32),
                        y: 1. / (image_height as f32 / frame.frame.y as f32),
                        w: 1. / (image_width as f32 / frame.frame.w as f32),
                        h: 1. / (image_height as f32 / frame.frame.h as f32),
                    }
                }
            )
        )
        .collect();

    return Spritesheet { frames: frames_map };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn should_convert_to_atlas() {
        let mut converted_frames: HashMap<String, texture_packer::Frame> = HashMap::new();
        converted_frames.insert(
            "test1".to_string(),
            texture_packer::Frame {
                key: "test1".to_string(),
                frame: texture_packer::Rect{ x: 0, y: 0, w: 10, h: 50},
                source: texture_packer::Rect{ x: 0, y: 0, w: 10, h: 50},
                rotated: false,
                trimmed: false,
            }
        );
        let atlas = to_atlas(&converted_frames, 100, 100);

        let mut created_frames: HashMap<String, Frame> = HashMap::new();
        created_frames.insert(
            "test1".to_string(),
            Frame {
                x: 0, y: 0, w: 10, h: 50, screen: Screen { x: 0., y: 0., w: 0.1, h: 0.5 }
            }
        );
        created_frames.insert(
            "test2".to_string(),
            Frame {
                x: 1, y: 1, w: 1, h: 1, screen: Screen { x: 0., y: 0., w: 0., h: 0. }
            }
        );

        let converted = atlas.frames.get("test1").unwrap();
        let created = created_frames.get("test1").unwrap();

        assert_eq!(converted.x, created.x);
        assert_eq!(converted.y, created.y);
        assert_eq!(converted.w, created.w);
        assert_eq!(converted.h, created.h);
        assert_eq!(converted.screen.x, created.screen.x);
        assert_eq!(converted.screen.y, created.screen.y);
        assert_eq!(converted.screen.w, created.screen.w);
        assert_eq!(converted.screen.h, created.screen.h);
    }
}