#ifndef Animation_hpp #define Animation_hpp #include "Lottie/Public/Primitives/AnimationTime.hpp" #include "Lottie/Private/Utility/Primitives/CoordinateSpace.hpp" #include "Lottie/Private/Model/Layers/LayerModel.hpp" #include "Lottie/Private/Model/Text/Glyph.hpp" #include "Lottie/Private/Model/Text/Font.hpp" #include "Lottie/Private/Model/Objects/Marker.hpp" #include "Lottie/Private/Model/Assets/AssetLibrary.hpp" #include "Lottie/Private/Model/Objects/FitzModifier.hpp" #include "lottiejson11/lottiejson11.hpp" #include "Lottie/Private/Parsing/JsonParsing.hpp" #include "Lottie/Private/Model/Layers/LayerModelSerialization.hpp" #include #include #include #include namespace lottie { /// The `Animation` model is the top level model object in Lottie. /// /// An `Animation` holds all of the animation data backing a Lottie Animation. /// Codable, see JSON schema [here](https://github.com/airbnb/lottie-web/tree/master/docs/json). class Animation { public: Animation( std::optional name_, std::optional tgs_, AnimationFrameTime startFrame_, AnimationFrameTime endFrame_, double framerate_, std::string const &version_, std::optional type_, int width_, int height_, std::vector> const &layers_, std::optional>> glyphs_, std::optional> fonts_, std::shared_ptr assetLibrary_, std::optional> markers_, std::optional> fitzModifiers_, std::optional meta_, std::optional comps_ ) : startFrame(startFrame_), endFrame(endFrame_), framerate(framerate_), name(name_), version(version_), tgs(tgs_), type(type_), width(width_), height(height_), layers(layers_), glyphs(glyphs_), fonts(fonts_), assetLibrary(assetLibrary_), markers(markers_), fitzModifiers(fitzModifiers_), meta(meta_), comps(comps_) { if (markers) { std::map parsedMarkerMap; for (const auto &marker : markers.value()) { parsedMarkerMap.insert(std::make_pair(marker.name, marker)); } markerMap = std::move(parsedMarkerMap); } } Animation(const Animation&) = delete; Animation& operator=(Animation&) = delete; static std::shared_ptr fromJson(lottiejson11::Json::object const &json) noexcept(false) { auto name = getOptionalString(json, "nm"); auto version = getString(json, "v"); auto tgs = getOptionalInt(json, "tgs"); std::optional type; if (const auto typeRawValue = getOptionalInt(json, "ddd")) { if (typeRawValue.value() == 0) { type = CoordinateSpace::Type2d; } else { type = CoordinateSpace::Type3d; } } AnimationFrameTime startFrame = getDouble(json, "ip"); AnimationFrameTime endFrame = getDouble(json, "op"); double framerate = getDouble(json, "fr"); int width = getInt(json, "w"); int height = getInt(json, "h"); auto layerDictionaries = getObjectArray(json, "layers"); std::vector> layers; for (size_t i = 0; i < layerDictionaries.size(); i++) { try { auto layer = parseLayerModel(layerDictionaries[i]); layers.push_back(layer); } catch(...) { throw LottieParsingException(); } } std::optional>> glyphs; if (const auto glyphDictionaries = getOptionalObjectArray(json, "chars")) { glyphs = std::vector>(); for (const auto &glyphDictionary : glyphDictionaries.value()) { glyphs->push_back(std::make_shared(glyphDictionary)); } } else { glyphs = std::nullopt; } std::optional> fonts; if (const auto fontsDictionary = getOptionalObject(json, "fonts")) { fonts = std::make_shared(fontsDictionary.value()); } std::shared_ptr assetLibrary; if (const auto assetLibraryData = getOptionalAny(json, "assets")) { assetLibrary = std::make_shared(assetLibraryData.value()); } std::optional> markers; if (const auto markerDictionaries = getOptionalObjectArray(json, "markers")) { markers = std::vector(); for (const auto &markerDictionary : markerDictionaries.value()) { markers->push_back(Marker(markerDictionary)); } } std::optional> fitzModifiers; if (const auto fitzModifierDictionaries = getOptionalObjectArray(json, "fitz")) { fitzModifiers = std::vector(); for (const auto &fitzModifierDictionary : fitzModifierDictionaries.value()) { fitzModifiers->push_back(FitzModifier(fitzModifierDictionary)); } } auto meta = getOptionalAny(json, "meta"); auto comps = getOptionalAny(json, "comps"); return std::make_shared( name, tgs, startFrame, endFrame, framerate, version, type, width, height, std::move(layers), std::move(glyphs), std::move(fonts), assetLibrary, std::move(markers), fitzModifiers, meta, comps ); } lottiejson11::Json::object toJson() const { lottiejson11::Json::object result; if (name.has_value()) { result.insert(std::make_pair("nm", name.value())); } result.insert(std::make_pair("v", lottiejson11::Json(version))); if (tgs.has_value()) { result.insert(std::make_pair("tgs", tgs.value())); } if (type.has_value()) { switch (type.value()) { case CoordinateSpace::Type2d: result.insert(std::make_pair("ddd", lottiejson11::Json(0))); break; case CoordinateSpace::Type3d: result.insert(std::make_pair("ddd", lottiejson11::Json(1))); break; } } result.insert(std::make_pair("ip", lottiejson11::Json(startFrame))); result.insert(std::make_pair("op", lottiejson11::Json(endFrame))); result.insert(std::make_pair("fr", lottiejson11::Json(framerate))); result.insert(std::make_pair("w", lottiejson11::Json(width))); result.insert(std::make_pair("h", lottiejson11::Json(height))); lottiejson11::Json::array layersArray; for (const auto &layer : layers) { lottiejson11::Json::object layerJson; layer->toJson(layerJson); layersArray.push_back(layerJson); } result.insert(std::make_pair("layers", lottiejson11::Json(layersArray))); if (glyphs.has_value()) { lottiejson11::Json::array glyphArray; for (const auto &glyph : glyphs.value()) { glyphArray.push_back(glyph->toJson()); } result.insert(std::make_pair("chars", lottiejson11::Json(glyphArray))); } if (fonts.has_value()) { result.insert(std::make_pair("fonts", fonts.value()->toJson())); } if (assetLibrary) { result.insert(std::make_pair("assets", assetLibrary->toJson())); } if (markers.has_value()) { lottiejson11::Json::array markerArray; for (const auto &marker : markers.value()) { markerArray.push_back(marker.toJson()); } result.insert(std::make_pair("markers", lottiejson11::Json(markerArray))); } if (fitzModifiers.has_value()) { lottiejson11::Json::array fitzModifierArray; for (const auto &fitzModifier : fitzModifiers.value()) { fitzModifierArray.push_back(fitzModifier.toJson()); } result.insert(std::make_pair("fitz", lottiejson11::Json(fitzModifierArray))); } if (meta.has_value()) { result.insert(std::make_pair("meta", meta.value())); } if (comps.has_value()) { result.insert(std::make_pair("comps", comps.value())); } return result; } public: /// The start time of the composition in frameTime. AnimationFrameTime startFrame; /// The end time of the composition in frameTime. AnimationFrameTime endFrame; /// The frame rate of the composition. double framerate; /// Return all marker names, in order, or an empty list if none are specified std::vector markerNames() { if (!markers.has_value()) { return {}; } std::vector result; for (const auto &marker : markers.value()) { result.push_back(marker.name); } return result; } /// Animation name std::optional name; /// The version of the JSON Schema. std::string version; std::optional tgs; /// The coordinate space of the composition. std::optional type; /// The height of the composition in points. int width; /// The width of the composition in points. int height; /// The list of animation layers std::vector> layers; /// The list of glyphs used for text rendering std::optional>> glyphs; /// The list of fonts used for text rendering std::optional> fonts; /// Asset Library std::shared_ptr assetLibrary; /// Markers std::optional> markers; std::optional> markerMap; std::optional> fitzModifiers; std::optional meta; std::optional comps; }; } #endif /* Animation_hpp */