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