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 ∝ 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