1use crate::background::{ScatterContext, check_rect, scatter};
3use crate::scene::Budget;
4use crate::*;
5use std::collections::{HashMap, HashSet};
6use std::sync::Arc;
7
8pub struct BackgroundBuilder<'a> {
9 doc: &'a Document,
10 background: Background,
11 limits: Limits,
12 budget: Budget,
13 sprites: HashMap<String, Arc<Sprite>>,
14 operations: HashSet<String>,
15}
16impl Background {
17 pub fn builder<'a>(
18 doc: &'a Document,
19 name: &str,
20 size: (u32, u32),
21 seed: u64,
22 limits: &Limits,
23 ) -> Result<BackgroundBuilder<'a>> {
24 check_name(name)?;
25 check_size(size, limits)?;
26 let mut budget = Budget::new(limits);
27 budget.pixels(doc.scene_storage())?;
28 budget.commands(doc.scene_commands())?;
29 Ok(BackgroundBuilder {
30 doc,
31 background: Background {
32 commands: 0,
33 name: name.into(),
34 width: size.0,
35 height: size.1,
36 seed,
37 layers: Vec::new(),
38 },
39 limits: limits.clone(),
40 budget,
41 sprites: HashMap::new(),
42 operations: HashSet::new(),
43 })
44 }
45}
46pub(crate) fn check_name(name: &str) -> Result<()> {
47 if name.is_empty()
48 || !name
49 .chars()
50 .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-'))
51 {
52 return Err(Error::invalid(
53 "Scene name must contain ASCII letters, digits, underscores or hyphens",
54 ));
55 }
56 Ok(())
57}
58fn check_size(size: (u32, u32), limits: &Limits) -> Result<()> {
59 if size.0 == 0 || size.1 == 0 {
60 return Err(Error::invalid("Scene size must be positive"));
61 }
62 limits.check_image(size.0, size.1)
63}
64impl BackgroundBuilder<'_> {
65 pub fn layer(
66 &mut self,
67 name: &str,
68 size: (u32, u32),
69 options: LayerOptions,
70 ) -> Result<&mut Self> {
71 check_name(name)?;
72 check_size(size, &self.limits)?;
73 if size.0 > i32::MAX as u32 || size.1 > i32::MAX as u32 {
74 return Err(Error::limit("Layer coordinates exceed signed range"));
75 }
76 if self.background.layers.len() >= self.limits.max_layers {
77 return Err(Error::limit("Too many background layers"));
78 }
79 if self.background.layers.iter().any(|l| l.name == name) {
80 return Err(Error::new(
81 ErrorCode::DuplicateName,
82 "Duplicate background layer",
83 ));
84 }
85 if let Some(clip) = options.clip {
86 check_rect(clip, size)?;
87 }
88 self.budget.commands(1)?;
89 self.background.commands += 1;
90 self.operations.clear();
91 self.background.layers.push(BackgroundLayer {
92 name: name.into(),
93 width: size.0,
94 height: size.1,
95 options,
96 items: Vec::new(),
97 position: Position::new(1, 1),
98 });
99 Ok(self)
100 }
101 fn resolve(&mut self, source: &SourceRef) -> Result<(SourceRef, Option<Arc<Sprite>>)> {
102 match source {
103 SourceRef::Sprite(name) => {
104 let canonical = crate::text::scene_chain_name(name, &self.limits)?;
105 if let Some(s) = self.sprites.get(&canonical) {
106 return Ok((SourceRef::Sprite(canonical), Some(s.clone())));
107 }
108 let (name, sprite) =
109 crate::text::scene_chain(name, self.doc, &self.limits, &mut self.budget)?;
110 let sprite = Arc::new(sprite);
111 self.sprites.insert(name.clone(), sprite.clone());
112 Ok((SourceRef::Sprite(name), Some(sprite)))
113 }
114 _ => Ok((source.clone(), None)),
115 }
116 }
117 pub fn place(&mut self, source: SourceRef, options: PlacementOptions) -> Result<&mut Self> {
118 if self.background.layers.is_empty() {
119 return Err(Error::invalid("Add a layer before placing sources"));
120 }
121 self.budget.commands(1)?;
122 self.background.commands += 1;
123 let (source, sprite) = self.resolve(&source)?;
124 let placement = BackgroundPlacement {
125 source,
126 sprite,
127 options,
128 position: Position::new(1, 1),
129 };
130 placement.crop(placement.view(self.doc)?.size()?)?;
131 self.budget.pixels(1)?;
132 self.background
133 .layers
134 .last_mut()
135 .unwrap()
136 .items
137 .push(placement);
138 Ok(self)
139 }
140 pub fn scatter(
141 &mut self,
142 name: &str,
143 options: &ScatterOptions,
144 variants: &[WeightedVariant],
145 ) -> Result<&mut Self> {
146 check_name(name)?;
147 if !self.operations.insert(name.into()) {
148 return Err(Error::new(
149 ErrorCode::DuplicateName,
150 "Duplicate layer operation",
151 ));
152 }
153 self.budget.commands(
154 variants
155 .len()
156 .checked_add(1)
157 .ok_or_else(|| Error::limit("Scene command overflow"))?,
158 )?;
159 self.background.commands += 1 + variants.len();
160 let mut resolved = Vec::new();
161 for variant in variants {
162 let (source, sprite) = self.resolve(&variant.source)?;
163 resolved.push((
164 WeightedVariant {
165 source,
166 weight: variant.weight,
167 },
168 sprite,
169 ));
170 }
171 let layer = self
172 .background
173 .layers
174 .last()
175 .ok_or_else(|| Error::invalid("Add a layer before scattering"))?;
176 let items = scatter(
177 self.doc,
178 ScatterContext {
179 background: &self.background.name,
180 layer,
181 operation: name,
182 owner_seed: self.background.seed,
183 position: Position::new(1, 1),
184 },
185 options,
186 &resolved,
187 &mut self.budget,
188 )?;
189 self.background
190 .layers
191 .last_mut()
192 .unwrap()
193 .items
194 .extend(items);
195 Ok(self)
196 }
197 pub fn finish(self) -> Background {
198 self.background
199 }
200}
201impl Document {
202 pub fn with_surface(&self, mut surface: Surface, limits: &Limits) -> Result<Document> {
203 self.check_new_definition(limits)?;
204 if self.surface(surface.name()).is_some() {
205 return Err(Error::new(ErrorCode::DuplicateName, "Duplicate surface"));
206 }
207 limits.check_image(surface.width, surface.height)?;
208 let palette = self.palette(surface.palette.name()).ok_or_else(|| {
209 Error::new(
210 ErrorCode::UnknownName,
211 "Surface palette must exist in receiver document",
212 )
213 })?;
214 if surface
215 .keys
216 .iter()
217 .any(|&k| k != crate::sprite::EMPTY && palette.color(k).is_none())
218 {
219 return Err(Error::new(
220 ErrorCode::UnknownName,
221 "Surface key is absent from receiver palette",
222 ));
223 }
224 surface.palette = palette.clone();
225 let mut b = Budget::new(limits);
226 b.pixels(self.scene_storage())?;
227 b.pixels(surface.storage())?;
228 b.commands(
229 self.scene_commands()
230 .checked_add(surface.commands)
231 .ok_or_else(|| Error::limit("Scene command overflow"))?,
232 )?;
233 let mut doc = self.clone();
234 doc.surfaces.push(surface);
235 Ok(doc)
236 }
237 pub fn with_background(&self, background: Background, limits: &Limits) -> Result<Document> {
238 self.check_new_definition(limits)?;
239 if self.background(background.name()).is_some() {
240 return Err(Error::new(ErrorCode::DuplicateName, "Duplicate background"));
241 }
242 limits.check_image(background.width, background.height)?;
243 if background.layers.len() > limits.max_layers {
244 return Err(Error::limit("Too many background layers"));
245 }
246 for layer in &background.layers {
247 limits.check_image(layer.width, layer.height)?;
248 if let Some(clip) = layer.options.clip {
249 check_rect(clip, layer.size())?;
250 }
251 for p in &layer.items {
252 p.crop(p.view(self)?.size()?)?;
253 if let Some(s) = &p.sprite {
254 s.effect_size(s.width, s.height, s.layers.len(), limits)?;
255 for p in std::iter::once(s.palette()).chain(s.layer_palettes()) {
256 let palette = self.palette(p.name()).ok_or_else(|| {
257 Error::new(
258 ErrorCode::UnknownName,
259 "Background sprite palette is absent from receiver",
260 )
261 })?;
262 for (owner, key) in s.palette_keys() {
263 if owner == p.name() && palette.color(key).is_none() {
264 return Err(Error::new(
265 ErrorCode::UnknownName,
266 format!(
267 "Background key `{key}` is absent from receiver palette"
268 ),
269 ));
270 }
271 }
272 }
273 }
274 }
275 }
276 let mut b = Budget::new(limits);
277 let mut shared = HashSet::new();
278 b.pixels(self.scene_storage_seen(&mut shared))?;
279 b.pixels(background.storage(&mut shared))?;
280 b.commands(
281 self.scene_commands()
282 .checked_add(background.commands)
283 .ok_or_else(|| Error::limit("Scene command overflow"))?,
284 )?;
285 let mut doc = self.clone();
286 doc.backgrounds.push(background);
287 Ok(doc)
288 }
289 fn check_new_definition(&self, limits: &Limits) -> Result<()> {
290 let count = self.palettes.len()
291 + self.sprites.len()
292 + self.animations.len()
293 + self.tilesets.len()
294 + self.tilemaps.len()
295 + self.fonts.len()
296 + self.groups.len()
297 + self.screens.len()
298 + self.themes.len()
299 + self.states.len()
300 + self.icon_sets.len()
301 + self.surfaces.len()
302 + self.backgrounds.len();
303 if count >= limits.max_definitions {
304 Err(Error::limit("More than the definition limit"))
305 } else {
306 Ok(())
307 }
308 }
309}