1use crate::model::{Atlas, Meta, Rect};
2use serde::Serialize;
3use serde_json::{Value, json};
4
5#[derive(Debug, Clone)]
6pub(crate) struct ExportManifest {
7 pub(crate) pages: Vec<ExportPage>,
8 pub(crate) meta: Meta,
9}
10
11#[derive(Debug, Clone)]
12pub(crate) struct ExportPage {
13 pub(crate) id: usize,
14 pub(crate) width: u32,
15 pub(crate) height: u32,
16 pub(crate) image: String,
17 pub(crate) frames: Vec<ExportFrame>,
18}
19
20#[derive(Debug, Clone)]
21pub(crate) struct ExportFrame {
22 pub(crate) key: String,
23 pub(crate) frame: Rect,
24 pub(crate) rotated: bool,
25 pub(crate) trimmed: bool,
26 pub(crate) sprite_source_size: Rect,
27 pub(crate) source_size: (u32, u32),
28 pub(crate) pivot: (f32, f32),
29 pub(crate) page: usize,
30 pub(crate) page_size: (u32, u32),
31}
32
33impl ExportManifest {
34 pub(crate) fn from_atlas<K: ToString + Clone>(atlas: &Atlas<K>) -> Self {
35 let default_page_names: Vec<String> = atlas
36 .pages
37 .iter()
38 .map(|page| format!("page_{}.png", page.id))
39 .collect();
40 Self::from_atlas_with_page_names(atlas, &default_page_names)
41 }
42
43 pub(crate) fn from_atlas_with_page_names<K: ToString + Clone>(
44 atlas: &Atlas<K>,
45 page_names: &[String],
46 ) -> Self {
47 let pages = atlas
48 .pages
49 .iter()
50 .enumerate()
51 .map(|(idx, page)| {
52 let image = page_names
53 .get(idx)
54 .cloned()
55 .unwrap_or_else(|| format!("page_{}.png", page.id));
56 let frames = page
57 .frames
58 .iter()
59 .map(|frame| ExportFrame {
60 key: frame.key.to_string(),
61 frame: frame.frame,
62 rotated: frame.rotated,
63 trimmed: frame.trimmed,
64 sprite_source_size: frame.source,
65 source_size: frame.source_size,
66 pivot: (0.5, 0.5),
67 page: page.id,
68 page_size: (page.width, page.height),
69 })
70 .collect();
71 ExportPage {
72 id: page.id,
73 width: page.width,
74 height: page.height,
75 image,
76 frames,
77 }
78 })
79 .collect();
80
81 Self {
82 pages,
83 meta: atlas.meta.clone(),
84 }
85 }
86}
87
88impl ExportFrame {
89 pub(crate) fn frame_value(&self) -> Value {
90 rect_value(&self.frame)
91 }
92
93 pub(crate) fn sprite_source_size_value(&self) -> Value {
94 rect_value(&self.sprite_source_size)
95 }
96
97 pub(crate) fn source_size_value(&self) -> Value {
98 size_value(self.source_size)
99 }
100
101 pub(crate) fn pivot_value(&self) -> Value {
102 json!({"x": self.pivot.0, "y": self.pivot.1})
103 }
104
105 pub(crate) fn page_size_value(&self) -> Value {
106 size_value(self.page_size)
107 }
108}
109
110pub(crate) fn rect_value(rect: &Rect) -> Value {
111 json!({"x": rect.x, "y": rect.y, "w": rect.w, "h": rect.h})
112}
113
114pub(crate) fn size_value(size: (u32, u32)) -> Value {
115 json!({"w": size.0, "h": size.1})
116}
117
118#[derive(Debug, Clone, Serialize)]
119pub struct TemplateContext {
120 pub pages: Vec<TemplatePage>,
121 pub meta: Value,
122}
123
124#[derive(Debug, Clone, Serialize)]
125pub struct TemplatePage {
126 pub image: String,
127 pub size: Value,
128 pub sprites: Vec<TemplateSprite>,
129}
130
131#[derive(Debug, Clone, Serialize)]
132pub struct TemplateSprite {
133 pub name: String,
134 pub frame: Value,
135 pub rotated: bool,
136 pub trimmed: bool,
137 pub sprite_source_size: Value,
138 pub source_size: Value,
139 pub pivot: Value,
140}
141
142pub fn to_template_context<K: ToString + Clone>(
143 atlas: &Atlas<K>,
144 page_names: &[String],
145) -> TemplateContext {
146 let manifest = ExportManifest::from_atlas_with_page_names(atlas, page_names);
147 let pages = manifest
148 .pages
149 .iter()
150 .map(|page| TemplatePage {
151 image: page.image.clone(),
152 size: size_value((page.width, page.height)),
153 sprites: page
154 .frames
155 .iter()
156 .map(|frame| TemplateSprite {
157 name: frame.key.clone(),
158 frame: frame.frame_value(),
159 rotated: frame.rotated,
160 trimmed: frame.trimmed,
161 sprite_source_size: frame.sprite_source_size_value(),
162 source_size: frame.source_size_value(),
163 pivot: frame.pivot_value(),
164 })
165 .collect(),
166 })
167 .collect();
168 let meta = json!({
169 "app": manifest.meta.app,
170 "version": manifest.meta.version,
171 "format": manifest.meta.format,
172 "scale": manifest.meta.scale,
173 });
174 TemplateContext { pages, meta }
175}