File indexing completed on 2025-01-05 04:01:11

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 #pragma once
0007 
0008 #include <unordered_map>
0009 #include <vector>
0010 #include <cstdint>
0011 #include <string>
0012 #include <memory>
0013 #include <variant>
0014 #include <optional>
0015 
0016 #include <QColor>
0017 #include <QPointF>
0018 #include <QVector3D>
0019 #include <QFileInfo>
0020 #include <QGradientStops>
0021 
0022 #include "model/animation/frame_time.hpp"
0023 #include "math/math.hpp"
0024 #include "math/vector.hpp"
0025 #include "utils/iterator.hpp"
0026 
0027 namespace glaxnimate::io::aep {
0028 
0029 using Id = std::uint32_t;
0030 
0031 struct PropertyIterator;
0032 
0033 struct PropertyPair;
0034 
0035 struct PropertyBase
0036 {
0037     enum Type { Null, PropertyGroup, Property, TextProperty, EffectInstance, Mask };
0038     virtual ~PropertyBase() noexcept = default;
0039     virtual Type class_type() const noexcept { return Null; }
0040 
0041     const PropertyBase* get(const QString& key) const;
0042     virtual const PropertyPair* get_pair(const QString& key) const { Q_UNUSED(key); return nullptr; }
0043 
0044     explicit operator bool() const
0045     {
0046         return class_type() != Null;
0047     }
0048 
0049     const PropertyBase& operator[](const QString& key) const
0050     {
0051         auto prop = get(key);
0052         if ( prop )
0053             return *prop;
0054 
0055         static PropertyBase null_property;
0056         return null_property;
0057     }
0058     virtual PropertyIterator begin() const;
0059     virtual PropertyIterator end() const;
0060 };
0061 
0062 struct PropertyPair
0063 {
0064     QString match_name;
0065     std::unique_ptr<PropertyBase> value;
0066 };
0067 
0068 inline const PropertyBase* PropertyBase::get(const QString& key) const
0069 {
0070     if ( auto p = get_pair(key) )
0071         return p->value.get();
0072     return nullptr;
0073 }
0074 
0075 struct PropertyIterator : public utils::RandomAccessIteratorWrapper<PropertyIterator, std::vector<PropertyPair>::const_iterator>
0076 {
0077 public:
0078     PropertyIterator(InternalIterator it = {}) : Parent(it) {}
0079     const PropertyPair* operator->() const { return iter.operator->(); }
0080     const PropertyPair& operator*() const { return *iter; }
0081 };
0082 
0083 inline PropertyIterator PropertyBase::begin() const { return {}; }
0084 inline PropertyIterator PropertyBase::end() const { return {}; }
0085 
0086 struct PropertyGroup : PropertyBase
0087 {
0088     bool visible = true;
0089     QString name = "";
0090     std::vector<PropertyPair> properties;
0091 
0092     Type class_type() const noexcept override { return PropertyBase::PropertyGroup; }
0093 
0094     const PropertyPair* property_pair(const QString& match_name) const
0095     {
0096         for ( const auto& prop : properties )
0097         {
0098             if ( prop.match_name == match_name )
0099                 return &prop;
0100         }
0101         return nullptr;
0102     }
0103 
0104     const PropertyBase* property(const QString& match_name) const
0105     {
0106         if ( auto p = property_pair(match_name) )
0107             return p->value.get();
0108         return nullptr;
0109     }
0110 
0111     const PropertyPair* get_pair(const QString& key) const override
0112     {
0113         return property_pair(key);
0114     }
0115 
0116     PropertyIterator begin() const override
0117     {
0118         return properties.begin();
0119     }
0120 
0121     PropertyIterator end() const override
0122     {
0123         return properties.end();
0124     }
0125 };
0126 
0127 enum class KeyframeTransitionType
0128 {
0129     Linear = 1,
0130     Bezier = 2,
0131     Hold = 3,
0132 };
0133 
0134 enum class KeyframeBezierMode
0135 {
0136     Normal,
0137     Continuous,
0138     Auto,
0139 };
0140 
0141 
0142 struct BezierData
0143 {
0144     bool closed = false;
0145     QPointF minimum;
0146     QPointF maximum;
0147     std::vector<QPointF> points;
0148 
0149     /**
0150      * \brief Converts points from the weird bounding box notation to absolute
0151      */
0152     QPointF convert_point(const QPointF& p) const
0153     {
0154         return {
0155             math::lerp(minimum.x(), maximum.x(), p.x()),
0156             math::lerp(minimum.y(), maximum.y(), p.y()),
0157         };
0158     }
0159 
0160     QPointF converted_point(int index) const
0161     {
0162         return convert_point(points[index]);
0163     }
0164 };
0165 
0166 template<class Type>
0167 struct GradientStop
0168 {
0169     double offset;
0170     double mid_point;
0171     Type value;
0172 };
0173 
0174 template<class T>
0175 class GradientStops : public std::vector<GradientStop<T>>
0176 {
0177 public:
0178     using Stop = GradientStop<T>;
0179     using std::vector<Stop>::vector;
0180 
0181     int size() const
0182     {
0183         return std::vector<Stop>::size();
0184     }
0185 
0186     T value_at(double t, int& index) const
0187     {
0188         if ( this->empty() )
0189             return 1;
0190 
0191         if ( this->size() == 1 )
0192             return this->front().value;
0193 
0194         if ( t >= this->back().offset || index + 1 >= this->size() )
0195         {
0196             index = this->size();
0197             return this->back().value;
0198         }
0199 
0200         while ( t >= (*this)[index+1].offset )
0201             index++;
0202 
0203         if ( index + 1 >= this->size() )
0204             return this->back().value;
0205 
0206         const auto& before = (*this)[index];
0207         const auto& after = (*this)[index+1];
0208         auto factor = math::unlerp(before.offset, after.offset, t);
0209 
0210         if ( !qFuzzyCompare(before.mid_point, 0.5) )
0211         {
0212             auto vbefore = before.value;
0213             auto vafter = after.value;
0214             auto vmid = math::lerp(before.value, after.value, before.mid_point);
0215             if ( factor < after.mid_point )
0216             {
0217                 factor = math::unlerp(0., before.mid_point, factor);
0218                 vafter = vmid;
0219             }
0220             else
0221             {
0222                 factor = math::unlerp(before.mid_point, 1., factor);
0223                 vbefore = vmid;
0224             }
0225             return math::lerp(vbefore, vafter, factor);
0226         }
0227 
0228         return math::lerp(before.value, after.value, factor);
0229     }
0230 
0231     GradientStops split_midpoints() const
0232     {
0233         double midpoint = 0.5;
0234         Stop previous;
0235         GradientStops stops;
0236         for ( const auto& stop : *this )
0237         {
0238             if ( !qFuzzyCompare(midpoint, 0.5) )
0239             {
0240                 auto midoffset = math::lerp(previous.offset, stop.offset, midpoint);
0241                 auto midvalue = math::lerp(previous.value, stop.value, midpoint);
0242                 stops.push_back({midoffset, 0.5, midvalue});
0243             }
0244 
0245             midpoint = stop.mid_point;
0246             stops.push_back({stop.offset, 0.5, stop.value});
0247             previous = stop;
0248         }
0249 
0250         return stops;
0251     }
0252 };
0253 
0254 struct Gradient
0255 {
0256     GradientStops<double> alpha_stops;
0257     GradientStops<QColor> color_stops;
0258 
0259     QGradientStops to_qt() const
0260     {
0261         QGradientStops stops;
0262         int index = 0;
0263         for ( const auto& stop : color_stops.split_midpoints() )
0264         {
0265             auto alpha = alpha_stops.value_at(stop.offset, index);
0266             auto color = stop.value;
0267             color.setAlphaF(alpha);
0268             stops.push_back({stop.offset, color});
0269         }
0270         return stops;
0271     }
0272 };
0273 
0274 enum class LabelColors
0275 {
0276     None,
0277     Red,
0278     Yellow,
0279     Aqua,
0280     Pink,
0281     Lavender,
0282     Peach,
0283     SeaFoam,
0284     Blue,
0285     Green,
0286     Purple,
0287     Orange,
0288     Brown,
0289     Fuchsia,
0290     Cyan,
0291     Sandstone,
0292     DarkGreen,
0293 };
0294 
0295 struct Marker
0296 {
0297     model::FrameTime duration = 0;
0298     LabelColors label_color = LabelColors::None;
0299     bool is_protected = false;
0300     QString name = "";
0301 };
0302 
0303 struct Font
0304 {
0305     QString family;
0306 };
0307 
0308 enum class TextTransform
0309 {
0310     Normal,
0311     SmallCaps,
0312     AllCaps
0313 };
0314 
0315 enum class TextVerticalAlign
0316 {
0317     Normal,
0318     Superscript,
0319     Subscript,
0320 };
0321 
0322 enum class TextJustify
0323 {
0324   Left,
0325   Right,
0326   Center,
0327   JustifyLastLineLeft,
0328   JustifyLastLineRight,
0329   JustifyLastLineCenter,
0330   JustifyLastLineFull,
0331 };
0332 
0333 struct LineStyle
0334 {
0335     TextJustify text_justify = TextJustify::Left;
0336     // Number of characters the style applies to
0337     // Note that in AE LineStyle represents a line
0338     // Rather than an arbitrary span of text
0339     int character_count = 0;
0340 };
0341 
0342 struct CharacterStyle
0343 {
0344     int font_index = 0;
0345     double size = 0;
0346     bool faux_bold = false;
0347     bool faux_italic = false;
0348     TextTransform text_transform = TextTransform::Normal;
0349     TextVerticalAlign vertical_align = TextVerticalAlign::Normal;
0350     QColor fill_color;
0351     QColor stroke_color;
0352     bool stroke_enabled = false;
0353     bool stroke_over_fill = false;
0354     double stroke_width = 0;
0355     // Number of characters the style applies to
0356     int character_count = 0;
0357 };
0358 
0359 struct TextDocument
0360 {
0361     QString text;
0362     std::vector<LineStyle> line_styles;
0363     std::vector<CharacterStyle> character_styles;
0364 };
0365 
0366 enum class LayerSource
0367 {
0368     Layer = 0,
0369     Effects = -1,
0370     Masks = -2
0371 };
0372 
0373 struct LayerSelection
0374 {
0375     Id layer_id;
0376     LayerSource layer_source = LayerSource::Layer;
0377 };
0378 
0379 class PropertyValue
0380 {
0381 public:
0382     enum Index
0383     {
0384         None,
0385         Vector2D,
0386         Vector3D,
0387         Color,
0388         Number,
0389         Gradient,
0390         BezierData,
0391         Marker,
0392         TextDocument,
0393         LayerSelection
0394     };
0395 
0396     template<class T>
0397     PropertyValue(T&& v) : value(std::forward<T>(v)) {}
0398     PropertyValue() = default;
0399     PropertyValue(PropertyValue& v) = delete;
0400     PropertyValue(const PropertyValue& v) = delete;
0401     PropertyValue(PropertyValue&& v) = default;
0402     PropertyValue& operator=(PropertyValue&& v) = default;
0403 
0404     Index type() const { return Index(value.index()); }
0405 
0406     std::variant<
0407         std::nullptr_t, QPointF, QVector3D, QColor, qreal, aep::Gradient,
0408         aep::BezierData, aep::Marker, aep::TextDocument, aep::LayerSelection
0409     > value = nullptr;
0410 
0411     qreal magnitude() const
0412     {
0413         switch ( type() )
0414         {
0415             default:
0416             case None:
0417                 return 0;
0418             case Vector2D:
0419                 return math::length(std::get<QPointF>(value));
0420             case Vector3D:
0421                 return math::length(std::get<QVector3D>(value));
0422             case Color:
0423             {
0424                 const auto& c = std::get<QColor>(value);
0425                 return math::hypot(c.red(), c.green(), c.blue(), c.alpha());
0426             }
0427             case Number:
0428                 return std::get<qreal>(value);
0429         }
0430     }
0431 };
0432 
0433 struct Keyframe
0434 {
0435     PropertyValue value;
0436     model::FrameTime time = 0;
0437     std::vector<double> in_influence;
0438     std::vector<double> in_speed;
0439     std::vector<double> out_influence;
0440     std::vector<double> out_speed;
0441     QPointF in_tangent;
0442     QPointF out_tangent;
0443     KeyframeTransitionType transition_type = KeyframeTransitionType::Linear;
0444     KeyframeBezierMode bezier_mode = KeyframeBezierMode::Normal;
0445     bool roving = false;
0446     LabelColors label_color = LabelColors::None;
0447 };
0448 
0449 enum class PropertyType
0450 {
0451     Color,
0452     NoValue,
0453     Position,
0454     MultiDimensional,
0455     LayerSelection,
0456     Integer,
0457     MaskIndex,
0458 };
0459 
0460 struct Property : PropertyBase
0461 {
0462     bool split = false;
0463     bool animated = false;
0464     bool is_component = false;
0465     int components = 0;
0466     PropertyValue value;
0467     std::vector<Keyframe> keyframes;
0468     PropertyType type = PropertyType::MultiDimensional;
0469     std::optional<QString> expression;
0470 
0471     Type class_type() const noexcept override { return PropertyBase::Property; }
0472 };
0473 
0474 struct TextProperty : PropertyBase
0475 {
0476     std::vector<Font> fonts;
0477     aep::Property documents;
0478 
0479     Type class_type() const noexcept override { return PropertyBase::TextProperty; }
0480 };
0481 
0482 enum class LayerQuality
0483 {
0484     Wireframe,
0485     Draft,
0486     Best
0487 };
0488 
0489 enum class LayerType
0490 {
0491     AssetLayer,
0492     LightLayer,
0493     CameraLayer,
0494     TextLayer,
0495     ShapeLayer
0496 };
0497 
0498 
0499 enum TrackMatteType
0500 {
0501     None,
0502     Alpha,
0503     AlphaInverted,
0504     Luma,
0505     LumaInverted,
0506 };
0507 
0508 struct Layer
0509 {
0510     Id id = 0;
0511     LayerQuality quality = LayerQuality::Draft;
0512     model::FrameTime start_time = 0;
0513     qreal time_stretch = 1;
0514     model::FrameTime in_time = 0;
0515     model::FrameTime out_time = 0;
0516     bool is_guide = false;
0517     bool bicubic_sampling = false;
0518     bool auto_orient = false;
0519     bool is_adjustment = false;
0520     bool threedimensional = false;
0521     bool solo = false;
0522     bool is_null = false;
0523     bool visible = true;
0524     bool effects_enabled = false;
0525     bool motion_blur = false;
0526     bool locked = false;
0527     bool shy = false;
0528     bool continuously_rasterize = false;
0529     Id asset_id = 0;
0530     LabelColors label_color = LabelColors::None;
0531     QString name = "";
0532     LayerType type = LayerType::ShapeLayer;
0533     Id parent_id = 0;
0534     TrackMatteType matte_mode = TrackMatteType::None;
0535     Id matte_id = 0;
0536 
0537     PropertyGroup properties;
0538 };
0539 
0540 enum class EffectParameterType
0541 {
0542     Layer = 0,
0543     Scalar = 2,
0544     Angle = 3,
0545     Boolean = 4,
0546     Color = 5,
0547     Vector2D = 6,
0548     Enum = 7,
0549     Group = 9,
0550     Slider = 10,
0551     Unknown = 15,
0552     Vector3D = 16,
0553 };
0554 
0555 struct EffectParameter
0556 {
0557     QString match_name = "";
0558     QString name = "";
0559     EffectParameterType type = EffectParameterType::Unknown;
0560     PropertyValue default_value;
0561     PropertyValue last_value;
0562 };
0563 
0564 struct EffectDefinition
0565 {
0566     QString match_name;
0567     QString name;
0568     std::vector<EffectParameter*> parameters;
0569     std::map<QString, EffectParameter> parameter_map;
0570 };
0571 
0572 struct EffectInstance : PropertyBase
0573 {
0574     QString name;
0575     aep::PropertyGroup parameters;
0576 
0577     Type class_type() const noexcept override { return PropertyBase::EffectInstance; }
0578 };
0579 
0580 enum class MaskMode
0581 {
0582     None,
0583     Add,
0584     Subtract,
0585     Intersect,
0586     Darken,
0587     Lighten,
0588     Difference
0589 };
0590 
0591 struct Mask : PropertyBase
0592 {
0593     bool inverted = false;
0594     bool  locked = false;
0595     MaskMode mode = MaskMode::Add;
0596     aep::PropertyGroup properties;
0597 
0598     Type class_type() const noexcept override { return PropertyBase::Mask; }
0599 
0600 
0601     const PropertyPair* get_pair(const QString& key) const override
0602     {
0603         return properties.property_pair(key);
0604     }
0605 };
0606 
0607 struct FolderItem
0608 {
0609     enum Type { Composition, Folder, Asset, Solid };
0610     Id id;
0611     QString name = "";
0612     LabelColors label_color = LabelColors::None;
0613 
0614     virtual ~FolderItem() noexcept = default;
0615     virtual Type type() const noexcept = 0;
0616 };
0617 
0618 struct Composition : FolderItem
0619 {
0620     std::vector<std::unique_ptr<Layer>> layers;
0621     std::uint16_t resolution_x = 0;
0622     std::uint16_t resolution_y = 0;
0623     double time_scale = 0;
0624     model::FrameTime playhead_time = 0;
0625     model::FrameTime in_time = 0;
0626     model::FrameTime out_time = 0;
0627     model::FrameTime duration = 0;
0628     QColor color;
0629     bool shy = false;
0630     bool motion_blur = false;
0631     bool frame_blending = false;
0632     bool preserve_framerate = false;
0633     bool preserve_resolution = false;
0634     double width = 0;
0635     double height = 0;
0636     std::uint32_t pixel_ratio_width = 1;
0637     std::uint32_t pixel_ratio_height = 1;
0638     double framerate = 0;
0639     std::uint16_t shutter_angle = 0;
0640     std::int32_t shutter_phase = 0;
0641     std::uint32_t samples_limit = 0;
0642     std::uint32_t samples_per_frame = 0;
0643     std::unique_ptr<Layer> markers;
0644     std::vector<std::unique_ptr<Layer>> views;
0645 
0646     Type type() const noexcept override { return FolderItem::Composition; }
0647 
0648     model::FrameTime time_to_frames(model::FrameTime time) const
0649     {
0650         return time / time_scale;
0651     };
0652 };
0653 
0654 
0655 struct Asset : FolderItem
0656 {
0657     int width = 0;
0658     int height = 0;
0659 
0660 };
0661 
0662 struct FileAsset : Asset
0663 {
0664     QFileInfo path;
0665 
0666     Type type() const noexcept override { return FolderItem::Asset; }
0667 };
0668 
0669 struct Solid : Asset
0670 {
0671     QColor color;
0672 
0673     Type type() const noexcept override { return FolderItem::Solid; }
0674 };
0675 
0676 struct Folder : FolderItem
0677 {
0678     std::vector<std::unique_ptr<FolderItem>> items;
0679 
0680     template<class T>
0681     T* add()
0682     {
0683         auto item = std::make_unique<T>();
0684         auto ptr = item.get();
0685         items.push_back(std::move(item));
0686         return ptr;
0687     }
0688 
0689     Type type() const noexcept override { return FolderItem::Folder; }
0690 };
0691 
0692 struct Project
0693 {
0694     std::unordered_map<Id, FolderItem*> assets;
0695     Folder folder;
0696     std::vector<Composition*> compositions;
0697     std::unordered_map<QString, EffectDefinition> effects;
0698     FolderItem* current_item = nullptr;
0699 };
0700 
0701 } // namespace glaxnimate::io::aep