inkanim_types/ink/anim/
mod.rs

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
19/// orphan interpolator
20pub struct OrphanInkAnimInterpolator {
21    pub index: usize,
22    pub interpolator: InkWrapper<InkAnimInterpolator>,
23}
24
25/// transparency interpolation direction
26#[derive(Debug, Clone, Copy, PartialEq)]
27pub enum Fade {
28    /// transparency interpolates toward `1.`
29    In,
30    /// transparency interpolates toward `0.`
31    Out,
32}
33
34/// every kind of possible interpolation
35#[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/// see [NativeDB](https://nativedb.red4ext.com/inkanimInterpolationDirection)
55#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
56pub enum Direction {
57    To = 0,
58    From = 1,
59    FromTo = 2,
60}
61
62/// see [NativeDB](https://nativedb.red4ext.com/inkanimInterpolationMode)
63#[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/// see [NativeDB](https://nativedb.red4ext.com/inkanimInterpolationType)
72#[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/// specific interpolator values interpretation
87///
88/// possible interpretations: percent-based (scale), positions-based (translation), color-based
89#[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/// generic interpolator
105#[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/// any interpolator
153///
154/// possible kinds include: scale, translation, transparency, etc
155#[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/// a sequence of interpolators
297#[derive(Debug, Clone, Serialize, Deserialize)]
298#[serde(rename_all = "camelCase")]
299pub struct InkAnimDefinition {
300    pub interpolators: Vec<InkWrapper<InkAnimInterpolator>>,
301}
302
303/// a sequence of interpolations (interpolators and events)
304#[derive(Debug, Clone, Serialize, Deserialize)]
305#[serde(rename_all = "camelCase")]
306pub struct InkAnimSequence {
307    /// describe the interpolations played
308    ///
309    /// ⚠️ `definitions` size must always match `targets` size
310    pub definitions: Vec<InkWrapper<InkAnimDefinition>>,
311    pub name: Name,
312    /// describe the targets onto which the interpolations are played
313    ///
314    /// ⚠️ `targets` size must always match `definitions` size
315    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/// when related to interpolator(s),
325/// corresponding target is a sequence of digits indicating the path to the nested element
326///
327/// see [NativeDB](https://nativedb.red4ext.com/inkanimSequenceTargetInfo)
328#[allow(non_camel_case_types)]
329#[derive(Debug, Clone, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct InkAnimSequenceTargetInfo {
332    /// path to the nested element (indexes)
333    ///
334    /// e.g. `[1,3,0,0,16]`
335    pub path: Vec<usize>,
336}
337
338/// when declaring interpolation event(s), corresponding target has a negative handle ref ID
339#[derive(Debug, Clone, Serialize, Deserialize)]
340#[serde(rename_all = "PascalCase")]
341pub struct BlankInkAnimSequenceTargetInfo {
342    /// typically here the value is `-1`
343    #[serde(deserialize_with = "deserialize_number_from_string")]
344    pub handle_ref_id: i32,
345}
346
347/// any target
348#[derive(Debug, Clone, Serialize, Deserialize)]
349#[serde(untagged)]
350pub enum Target {
351    /// a sequence of digits (path to nested element) : when related to interpolator(s)
352    WithHandleId(InkWrapper<InkAnimSequenceTargetInfo>),
353    /// a negative [handle ID](super::HandleId) (not element related) : when declaring interpolation event(s)
354    WithoutHandleId(BlankInkAnimSequenceTargetInfo),
355}
356
357impl InkAnimSequence {
358    /// find all interpolators matching filter
359    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}