oxygengine_composite_renderer/
sprite_sheet_asset_protocol.rs

1use crate::math::Rect;
2use core::{
3    assets::{
4        asset::{Asset, AssetId},
5        protocol::{AssetLoadResult, AssetProtocol, AssetVariant, Meta},
6    },
7    Ignite, Scalar,
8};
9use serde::{Deserialize, Serialize};
10use std::{any::Any, collections::HashMap, str::from_utf8};
11
12#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
13pub struct SpriteSheetInfo {
14    pub meta: SpriteSheetInfoMeta,
15    #[serde(default)]
16    pub frames: HashMap<String, SpriteSheetInfoFrame>,
17}
18
19#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
20pub struct SpriteSheetInfoMeta {
21    pub image: String,
22    #[serde(default)]
23    pub size: SpriteSheetInfoMetaSize,
24    #[serde(default)]
25    pub scale: String,
26}
27
28impl SpriteSheetInfoMeta {
29    pub fn image_name(&self) -> String {
30        let parts = self.image.split("://").collect::<Vec<_>>();
31        if parts.len() > 1 {
32            parts[1].to_owned()
33        } else {
34            self.image.clone()
35        }
36    }
37}
38
39#[derive(Ignite, Debug, Default, Clone, Copy, Serialize, Deserialize)]
40pub struct SpriteSheetInfoMetaSize {
41    #[serde(default)]
42    pub w: Scalar,
43    #[serde(default)]
44    pub h: Scalar,
45}
46
47#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
48pub struct SpriteSheetInfoFrame {
49    #[serde(default)]
50    pub frame: Rect,
51    #[serde(default)]
52    pub rotated: bool,
53    #[serde(default)]
54    pub trimmed: bool,
55    #[serde(alias = "spriteSourceSize")]
56    #[serde(default)]
57    pub sprite_source_size: Rect,
58    #[serde(alias = "sourceSize")]
59    #[serde(default)]
60    pub source_size: SpriteSheetInfoMetaSize,
61}
62
63pub struct SpriteSheetAsset {
64    info: SpriteSheetInfo,
65    image_asset: AssetId,
66}
67
68impl SpriteSheetAsset {
69    pub fn info(&self) -> &SpriteSheetInfo {
70        &self.info
71    }
72
73    pub fn image_asset(&self) -> AssetId {
74        self.image_asset
75    }
76}
77
78pub struct SpriteSheetAssetProtocol;
79
80impl AssetProtocol for SpriteSheetAssetProtocol {
81    fn name(&self) -> &str {
82        "atlas"
83    }
84
85    fn on_load(&mut self, data: Vec<u8>) -> AssetLoadResult {
86        let data = from_utf8(&data).unwrap();
87        let info: SpriteSheetInfo = serde_json::from_str(data).unwrap();
88        let image = info.meta.image.clone();
89        AssetLoadResult::Yield(Some(Box::new(info)), vec![("image".to_owned(), image)])
90    }
91
92    fn on_resume(&mut self, payload: Meta, list: &[(&str, &Asset)]) -> AssetLoadResult {
93        let info = *(payload.unwrap() as Box<dyn Any + Send>)
94            .downcast::<SpriteSheetInfo>()
95            .unwrap();
96        let image_asset = list
97            .get(0)
98            .expect("Could not obtain sprite sheet image asset")
99            .1
100            .id();
101        AssetLoadResult::Data(Box::new(SpriteSheetAsset { info, image_asset }))
102    }
103
104    fn on_unload(&mut self, asset: &Asset) -> Option<Vec<AssetVariant>> {
105        asset
106            .get::<SpriteSheetAsset>()
107            .map(|asset| vec![AssetVariant::Id(asset.image_asset)])
108    }
109}