1mod display;
2
3use serde::{Deserialize, Serialize};
4use serde_aux::prelude::*;
5
6use crate::{HDRColor, Name, Vector2};
7
8use super::InkWrapper;
9
10#[cfg(feature = "clap")]
11mod implementation;
12
13use super::conversion::deserialize_vector2_from_anything;
14
15pub const OPACITY: InkAnimInterpolatorType = InkAnimInterpolatorType::Transparency(None);
16pub const FADEIN: InkAnimInterpolatorType = InkAnimInterpolatorType::Transparency(Some(Fade::In));
17pub const FADEOUT: InkAnimInterpolatorType = InkAnimInterpolatorType::Transparency(Some(Fade::Out));
18
19pub struct OrphanInkAnimInterpolator {
21 pub index: usize,
22 pub interpolator: InkWrapper<InkAnimInterpolator>,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq)]
27pub enum Fade {
28 In,
30 Out,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq)]
36pub enum InkAnimInterpolatorType {
37 Color,
38 Size,
39 Scale,
40 Translation,
41 Transparency(Option<Fade>),
42 TextValueProgress,
43 Effect,
44 Anchor,
45 Pivot,
46 Shear,
47 Rotation,
48 Margin,
49 Padding,
50 TextReplace,
51 TextOffset,
52}
53
54#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
56pub enum Direction {
57 To = 0,
58 From = 1,
59 FromTo = 2,
60}
61
62#[allow(clippy::enum_variant_names)]
64#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
65pub enum Mode {
66 EasyIn = 0,
67 EasyOut = 1,
68 EasyInOut = 2,
69}
70
71#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
73pub enum Type {
74 Linear = 0,
75 Quadratic = 1,
76 Qubic = 2,
77 Quartic = 3,
78 Quintic = 4,
79 Sinusoidal = 5,
80 Exponential = 6,
81 Elastic = 7,
82 Circular = 8,
83 Back = 9,
84}
85
86#[allow(non_camel_case_types)]
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
91#[serde(untagged)]
92pub enum Range {
93 Percent(f32),
94 Position(Vector2),
95 Color(HDRColor),
96}
97
98#[derive(Debug, Clone)]
99pub struct Transformation {
100 pub from: Range,
101 pub to: Range,
102}
103
104#[allow(non_camel_case_types)]
106#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct Interpolator {
109 pub duration: f32,
110 #[serde(deserialize_with = "deserialize_vector2_from_anything")]
111 pub end_value: Range,
112 pub interpolation_direction: Direction,
113 pub interpolation_mode: Mode,
114 pub interpolation_type: Type,
115 #[serde(deserialize_with = "deserialize_bool_from_anything")]
116 pub is_additive: bool,
117 pub start_delay: f32,
118 #[serde(deserialize_with = "deserialize_vector2_from_anything")]
119 pub start_value: Range,
120 #[serde(deserialize_with = "deserialize_bool_from_anything")]
121 pub use_relative_duration: bool,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[serde(rename_all = "camelCase")]
126pub struct EffectInterpolator {
127 pub effect_type: inkEffectType,
128 pub effect_name: Name,
129 pub param_name: Name,
130 #[serde(flatten)]
131 pub base: Interpolator,
132}
133
134#[allow(non_camel_case_types)]
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub enum inkEffectType {
137 ScanlineWipe = 0,
138 LinearWipe = 1,
139 RadialWipe = 2,
140 LightSweep = 3,
141 BoxBlur = 4,
142 Mask = 5,
143 Glitch = 6,
144 PointCloud = 7,
145 ColorFill = 8,
146 InnerGlow = 9,
147 ColorCorrection = 10,
148 Multisampling = 11,
149 Blackwall = 12,
150}
151
152#[allow(clippy::enum_variant_names)]
156#[allow(non_camel_case_types)]
157#[derive(Debug, Clone, Serialize, Deserialize)]
158#[serde(tag = "$type")]
159pub enum InkAnimInterpolator {
160 inkanimScaleInterpolator(Interpolator),
161 inkanimTranslationInterpolator(Interpolator),
162 inkanimTransparencyInterpolator(Interpolator),
163 inkanimSizeInterpolator(Interpolator),
164 inkanimColorInterpolator(Interpolator),
165 inkanimTextValueProgressInterpolator(Interpolator),
166 inkanimEffectInterpolator(EffectInterpolator),
167 inkanimAnchorInterpolator(Interpolator),
168 inkanimPivotInterpolator(Interpolator),
169 inkanimShearInterpolator(Interpolator),
170 inkanimRotationInterpolator(Interpolator),
171 inkanimMarginInterpolator(Interpolator),
172 inkanimPaddingInterpolator(Interpolator),
173 inkanimTextReplaceInterpolator(Interpolator),
174 inkanimTextOffsetInterpolator(Interpolator),
175}
176
177impl AsRef<Interpolator> for InkAnimInterpolator {
178 fn as_ref(&self) -> &Interpolator {
179 match self {
180 Self::inkanimEffectInterpolator(interpolator) => &interpolator.base,
181 Self::inkanimScaleInterpolator(interpolator)
182 | Self::inkanimTranslationInterpolator(interpolator)
183 | Self::inkanimTransparencyInterpolator(interpolator)
184 | Self::inkanimSizeInterpolator(interpolator)
185 | Self::inkanimColorInterpolator(interpolator)
186 | Self::inkanimTextValueProgressInterpolator(interpolator)
187 | Self::inkanimAnchorInterpolator(interpolator)
188 | Self::inkanimPivotInterpolator(interpolator)
189 | Self::inkanimShearInterpolator(interpolator)
190 | Self::inkanimRotationInterpolator(interpolator)
191 | Self::inkanimMarginInterpolator(interpolator)
192 | Self::inkanimPaddingInterpolator(interpolator)
193 | Self::inkanimTextReplaceInterpolator(interpolator)
194 | Self::inkanimTextOffsetInterpolator(interpolator) => interpolator,
195 }
196 }
197}
198
199impl InkAnimInterpolator {
200 pub fn as_short_display(&self) -> &str {
201 match self {
202 Self::inkanimScaleInterpolator(_) => "scale",
203 Self::inkanimTranslationInterpolator(_) => "translation",
204 Self::inkanimTransparencyInterpolator(_) => "transparency",
205 Self::inkanimSizeInterpolator(_) => "size",
206 Self::inkanimColorInterpolator(_) => "color",
207 Self::inkanimTextValueProgressInterpolator(_) => "text value progress",
208 Self::inkanimEffectInterpolator(effect) => match effect.effect_type {
209 inkEffectType::ScanlineWipe => "effect (scan line wipe)",
210 inkEffectType::LinearWipe => "effect (linear wipe)",
211 inkEffectType::RadialWipe => "effect (radial wipe)",
212 inkEffectType::LightSweep => "effect (light sweep)",
213 inkEffectType::BoxBlur => "effect (box blur)",
214 inkEffectType::Mask => "effect (mask)",
215 inkEffectType::Glitch => "effect (glitch)",
216 inkEffectType::PointCloud => "effect (point cloud)",
217 inkEffectType::ColorFill => "effect (color fill)",
218 inkEffectType::InnerGlow => "effect (inner glow)",
219 inkEffectType::ColorCorrection => "effect (color correction)",
220 inkEffectType::Multisampling => "effect (multisampling)",
221 inkEffectType::Blackwall => "effect (blackwall)",
222 },
223 Self::inkanimAnchorInterpolator(_) => "anchor",
224 Self::inkanimPivotInterpolator(_) => "pivot",
225 Self::inkanimShearInterpolator(_) => "shear",
226 Self::inkanimRotationInterpolator(_) => "rotation",
227 Self::inkanimMarginInterpolator(_) => "margin",
228 Self::inkanimPaddingInterpolator(_) => "padding",
229 Self::inkanimTextReplaceInterpolator(_) => "text replace",
230 Self::inkanimTextOffsetInterpolator(_) => "text offset",
231 }
232 }
233 pub fn starts(&self) -> f32 {
234 self.as_ref().start_delay
235 }
236 pub fn ends(&self) -> f32 {
237 self.starts() + self.as_ref().duration
238 }
239 pub fn direction(&self) -> Direction {
240 self.as_ref().interpolation_direction
241 }
242 pub fn r#type(&self) -> Type {
243 self.as_ref().interpolation_type
244 }
245 pub fn mode(&self) -> Mode {
246 self.as_ref().interpolation_mode
247 }
248 pub fn duration(&self) -> f32 {
249 self.as_ref().duration
250 }
251 pub fn transformation(&self) -> Transformation {
252 Transformation {
253 from: self.as_ref().start_value.clone(),
254 to: self.as_ref().end_value.clone(),
255 }
256 }
257}
258
259impl PartialEq<InkAnimInterpolatorType> for InkAnimInterpolator {
260 fn eq(&self, other: &InkAnimInterpolatorType) -> bool {
261 match self {
262 Self::inkanimScaleInterpolator(_) => other == &InkAnimInterpolatorType::Scale,
263 Self::inkanimTranslationInterpolator(_) => {
264 other == &InkAnimInterpolatorType::Translation
265 }
266 Self::inkanimTransparencyInterpolator(interpolator) => match other {
267 InkAnimInterpolatorType::Transparency(None) => true,
268 InkAnimInterpolatorType::Transparency(Some(Fade::In)) => {
269 interpolator.start_value < interpolator.end_value
270 }
271 InkAnimInterpolatorType::Transparency(Some(Fade::Out)) => {
272 interpolator.start_value > interpolator.end_value
273 }
274 _ => false,
275 },
276 Self::inkanimSizeInterpolator(_) => other == &InkAnimInterpolatorType::Size,
277 Self::inkanimColorInterpolator(_) => other == &InkAnimInterpolatorType::Color,
278 Self::inkanimTextValueProgressInterpolator(_) => {
279 other == &InkAnimInterpolatorType::TextValueProgress
280 }
281 Self::inkanimEffectInterpolator(_) => other == &InkAnimInterpolatorType::Effect,
282 Self::inkanimAnchorInterpolator(_) => other == &InkAnimInterpolatorType::Anchor,
283 Self::inkanimPivotInterpolator(_) => other == &InkAnimInterpolatorType::Pivot,
284 Self::inkanimShearInterpolator(_) => other == &InkAnimInterpolatorType::Shear,
285 Self::inkanimRotationInterpolator(_) => other == &InkAnimInterpolatorType::Rotation,
286 Self::inkanimMarginInterpolator(_) => other == &InkAnimInterpolatorType::Margin,
287 Self::inkanimPaddingInterpolator(_) => other == &InkAnimInterpolatorType::Padding,
288 Self::inkanimTextReplaceInterpolator(_) => {
289 other == &InkAnimInterpolatorType::TextReplace
290 }
291 Self::inkanimTextOffsetInterpolator(_) => other == &InkAnimInterpolatorType::TextOffset,
292 }
293 }
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize)]
298#[serde(rename_all = "camelCase")]
299pub struct InkAnimDefinition {
300 pub interpolators: Vec<InkWrapper<InkAnimInterpolator>>,
301}
302
303#[derive(Debug, Clone, Serialize, Deserialize)]
305#[serde(rename_all = "camelCase")]
306pub struct InkAnimSequence {
307 pub definitions: Vec<InkWrapper<InkAnimDefinition>>,
311 pub name: Name,
312 pub targets: Vec<Target>,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320pub struct InkAnimAnimationLibraryResource {
321 pub sequences: Vec<InkWrapper<InkAnimSequence>>,
322}
323
324#[allow(non_camel_case_types)]
329#[derive(Debug, Clone, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct InkAnimSequenceTargetInfo {
332 pub path: Vec<usize>,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340#[serde(rename_all = "PascalCase")]
341pub struct BlankInkAnimSequenceTargetInfo {
342 #[serde(deserialize_with = "deserialize_number_from_string")]
344 pub handle_ref_id: i32,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
349#[serde(untagged)]
350pub enum Target {
351 WithHandleId(InkWrapper<InkAnimSequenceTargetInfo>),
353 WithoutHandleId(BlankInkAnimSequenceTargetInfo),
355}
356
357impl InkAnimSequence {
358 pub fn get_interpolators_matching(
360 &self,
361 filter: &InkAnimInterpolatorType,
362 ) -> Vec<InkWrapper<InkAnimInterpolator>> {
363 self.definitions
364 .first()
365 .expect("at least one ink anim definition")
366 .data
367 .interpolators
368 .clone()
369 .into_iter()
370 .filter(|x| x.data == *filter)
371 .collect()
372 }
373}
374
375impl InkWrapper<InkAnimSequence> {
376 pub fn name(&self) -> &str {
377 self.data.name.as_str()
378 }
379}