mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 06:04:03 +00:00
loader lottie: adds the lottie property, model and parser.
This commit is contained in:
parent
b060959e0d
commit
03f878bb2e
10 changed files with 2501 additions and 2 deletions
|
@ -64,6 +64,8 @@ using namespace tvg;
|
||||||
|
|
||||||
enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Unknown };
|
enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Unknown };
|
||||||
|
|
||||||
|
using Size = Point;
|
||||||
|
|
||||||
#ifdef THORVG_LOG_ENABLED
|
#ifdef THORVG_LOG_ENABLED
|
||||||
constexpr auto ErrorColor = "\033[31m"; //red
|
constexpr auto ErrorColor = "\033[31m"; //red
|
||||||
constexpr auto ErrorBgColor = "\033[41m";//bg red
|
constexpr auto ErrorBgColor = "\033[41m";//bg red
|
||||||
|
|
|
@ -165,4 +165,29 @@ static inline Matrix mathMultiply(const Matrix* lhs, const Matrix* rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Point operator-(const Point& lhs, const Point& rhs)
|
||||||
|
{
|
||||||
|
return {lhs.x - rhs.x, lhs.y - rhs.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Point operator+(const Point& lhs, const Point& rhs)
|
||||||
|
{
|
||||||
|
return {lhs.x + rhs.x, lhs.y + rhs.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Point operator*(const Point& lhs, float rhs)
|
||||||
|
{
|
||||||
|
return {lhs.x * rhs, lhs.y * rhs};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T mathLerp(const T &start, const T &end, float t)
|
||||||
|
{
|
||||||
|
return static_cast<T>(start + (end - start) * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //_TVG_MATH_H_
|
#endif //_TVG_MATH_H_
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
source_file = [
|
source_file = [
|
||||||
'tvgLottieInterpolator.h',
|
'tvgLottieInterpolator.h',
|
||||||
'tvgLottieLoader.h',
|
'tvgLottieLoader.h',
|
||||||
|
'tvgLottieModel.h',
|
||||||
|
'tvgLottieParser.h',
|
||||||
|
'tvgLottieParserHandler.h',
|
||||||
|
'tvgLottieProperty.h',
|
||||||
'tvgLottieInterpolator.cpp',
|
'tvgLottieInterpolator.cpp',
|
||||||
'tvgLottieLoader.cpp',
|
'tvgLottieLoader.cpp',
|
||||||
|
'tvgLottieParserHandler.cpp',
|
||||||
|
'tvgLottieParser.cpp'
|
||||||
]
|
]
|
||||||
|
|
||||||
subloader_dep += [declare_dependency(
|
subloader_dep += [declare_dependency(
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "tvgLoader.h"
|
#include "tvgLoader.h"
|
||||||
#include "tvgLottieLoader.h"
|
#include "tvgLottieLoader.h"
|
||||||
|
#include "tvgLottieModel.h"
|
||||||
|
#include "tvgLottieParser.h"
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
|
@ -87,8 +89,8 @@ LottieLoader::~LottieLoader()
|
||||||
|
|
||||||
void LottieLoader::run(unsigned tid)
|
void LottieLoader::run(unsigned tid)
|
||||||
{
|
{
|
||||||
/* TODO: Compose current frame of Lottie Scene tree
|
LottieParser parser(content);
|
||||||
The result should be assigned to "this->root" */
|
parser.parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
475
src/loaders/lottie/tvgLottieModel.h
Normal file
475
src/loaders/lottie/tvgLottieModel.h
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_LOTTIE_MODEL_H_
|
||||||
|
#define _TVG_LOTTIE_MODEL_H_
|
||||||
|
|
||||||
|
#include "tvgCommon.h"
|
||||||
|
#include "tvgRender.h"
|
||||||
|
#include "tvgLottieProperty.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieStroke
|
||||||
|
{
|
||||||
|
bool dynamic()
|
||||||
|
{
|
||||||
|
if (dash.frames || width.frames) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieFloat dash = 0.0f;
|
||||||
|
LottieFloat width = 0.0f;
|
||||||
|
StrokeCap cap = StrokeCap::Butt;
|
||||||
|
StrokeJoin join = StrokeJoin::Miter;
|
||||||
|
float miterLimit = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieGradient
|
||||||
|
{
|
||||||
|
bool dynamic()
|
||||||
|
{
|
||||||
|
if (start.frames || end.frames || opacity.frames || height.frames || angle.frames || colorStops.frames) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fill* fill(int32_t frameNo)
|
||||||
|
{
|
||||||
|
Fill* fill = nullptr;
|
||||||
|
|
||||||
|
//Linear Graident
|
||||||
|
if (id == 1) {
|
||||||
|
fill = LinearGradient::gen().release();
|
||||||
|
static_cast<LinearGradient*>(fill)->linear(start(frameNo).x, start(frameNo).y, end(frameNo).x, end(frameNo).y);
|
||||||
|
}
|
||||||
|
//Radial Gradient
|
||||||
|
if (id == 2) {
|
||||||
|
fill = RadialGradient::gen().release();
|
||||||
|
TVGLOG("LOTTIE", "TODO: Missing Radial Gradient!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fill) return nullptr;
|
||||||
|
|
||||||
|
colorStops(frameNo, fill);
|
||||||
|
|
||||||
|
return fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottiePoint start = Point{0.0f, 0.0f};
|
||||||
|
LottiePoint end = Point{0.0f, 0.0f};
|
||||||
|
LottieOpacity opacity = 255;
|
||||||
|
LottieFloat height = 0.0f; //TODO:
|
||||||
|
LottieFloat angle = 0.0f;
|
||||||
|
LottieColorStop colorStops;
|
||||||
|
uint8_t id = 0; //1: linear, 2: radial
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieObject
|
||||||
|
{
|
||||||
|
enum Type : uint8_t
|
||||||
|
{
|
||||||
|
Composition = 0,
|
||||||
|
Layer,
|
||||||
|
Group,
|
||||||
|
Transform,
|
||||||
|
SolidFill,
|
||||||
|
SolidStroke,
|
||||||
|
GradientFill,
|
||||||
|
GradientStroke,
|
||||||
|
Rect,
|
||||||
|
Ellipse,
|
||||||
|
Path,
|
||||||
|
Polystar,
|
||||||
|
Trim,
|
||||||
|
Repeater,
|
||||||
|
RoundedCorner,
|
||||||
|
Image
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~LottieObject()
|
||||||
|
{
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* name = nullptr;
|
||||||
|
Type type;
|
||||||
|
bool statical = true; //no keyframes
|
||||||
|
bool hidden = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieShape : LottieObject
|
||||||
|
{
|
||||||
|
virtual ~LottieShape() {}
|
||||||
|
bool direction; //path direction (clock wise vs coutner clock wise)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieRoundedCorner : LottieObject
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::RoundedCorner;
|
||||||
|
if (radius.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieFloat radius = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottiePath : LottieShape
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Path;
|
||||||
|
if (pathset.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottiePathSet pathset = PathSet{nullptr, nullptr, 0, 0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieRect : LottieShape
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Rect;
|
||||||
|
if (position.frames || size.frames || round.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float roundness(int32_t frameNo)
|
||||||
|
{
|
||||||
|
return roundedCorner ? roundedCorner->radius(frameNo) : round(frameNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool roundnessChanged(int prevFrame, int curFrame)
|
||||||
|
{
|
||||||
|
//return roundedCorner ? roundedCorner->radius.changed(prevFrame, curFrame) : round.changed(prevFrame, curFrame);
|
||||||
|
TVGERR("LOTTIE", "TODO: LottieRect::roundnessChanged()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieRoundedCorner* roundedCorner = nullptr;
|
||||||
|
LottiePosition position = Point{0.0f, 0.0f};
|
||||||
|
LottiePoint size = Point{0.0f, 0.0f};
|
||||||
|
LottieFloat round = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottiePolyStar : LottieShape
|
||||||
|
{
|
||||||
|
enum Type : uint8_t {Star = 1, Polygon};
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Polystar;
|
||||||
|
if (position.frames || innerRadius.frames || outerRadius.frames || innerRoundness.frames || outerRoundness.frames || rotation.frames || ptsCnt.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottiePosition position = Point{0.0f, 0.0f};
|
||||||
|
LottieFloat innerRadius = 0.0f;
|
||||||
|
LottieFloat outerRadius = 0.0f;
|
||||||
|
LottieFloat innerRoundness = 0.0f;
|
||||||
|
LottieFloat outerRoundness = 0.0f;
|
||||||
|
LottieFloat rotation = 0.0f;
|
||||||
|
LottieFloat ptsCnt = 0.0f;
|
||||||
|
Type type = Polygon;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieEllipse : LottieShape
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Ellipse;
|
||||||
|
if (position.frames || size.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottiePosition position = Point{0.0f, 0.0f};
|
||||||
|
LottiePoint size = Point{0.0f, 0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieTransform : LottieObject
|
||||||
|
{
|
||||||
|
struct SeparateCoord
|
||||||
|
{
|
||||||
|
LottieFloat x = 0.0f;
|
||||||
|
LottieFloat y = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
~LottieTransform()
|
||||||
|
{
|
||||||
|
delete(coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Transform;
|
||||||
|
if (position.frames || rotation.frames || scale.frames || anchor.frames || opacity.frames) statical = false;
|
||||||
|
else if (coords && (coords->x.frames || coords->y.frames)) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottiePosition position = Point{0.0f, 0.0f};
|
||||||
|
LottieFloat rotation = 0.0f;
|
||||||
|
LottiePoint scale = Point{100.0f, 100.0f};
|
||||||
|
LottiePoint anchor = Point{0.0f, 0.0f};
|
||||||
|
LottieOpacity opacity = 255;
|
||||||
|
|
||||||
|
//either a position or separate coordinates
|
||||||
|
SeparateCoord* coords = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieSolidStroke : LottieObject, LottieStroke
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::SolidStroke;
|
||||||
|
if (color.frames || opacity.frames || LottieStroke::dynamic()) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieColor color = RGB24{255, 255, 255};
|
||||||
|
LottieOpacity opacity = 255;
|
||||||
|
bool disabled = false; //TODO: can't replace with hidden?
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieSolidFill : LottieObject
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::SolidFill;
|
||||||
|
if (color.frames || opacity.frames) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieColor color = RGB24{255, 255, 255};
|
||||||
|
LottieOpacity opacity = 255;
|
||||||
|
FillRule rule = FillRule::Winding;
|
||||||
|
bool disabled = false; //TODO: can't replace with hidden?
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieGradientFill : LottieObject, LottieGradient
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::GradientFill;
|
||||||
|
if (LottieGradient::dynamic()) statical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillRule rule = FillRule::Winding;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieGradientStroke : LottieObject, LottieStroke, LottieGradient
|
||||||
|
{
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::GradientStroke;
|
||||||
|
if (LottieStroke::dynamic() || LottieGradient::dynamic()) statical = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieImage : LottieObject
|
||||||
|
{
|
||||||
|
Surface surface;
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieObject::type = LottieObject::Image;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieGroup : LottieObject
|
||||||
|
{
|
||||||
|
virtual ~LottieGroup()
|
||||||
|
{
|
||||||
|
for (auto p = children.data; p < children.end(); ++p) delete(*p);
|
||||||
|
delete(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare(LottieObject::Type type = LottieObject::Group)
|
||||||
|
{
|
||||||
|
LottieObject::type = type;
|
||||||
|
if (transform) statical &= transform->statical;
|
||||||
|
for (auto child = children.data; child < children.end(); ++child) {
|
||||||
|
statical &= (*child)->statical;
|
||||||
|
if (!statical) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint8_t opacity(int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (children.empty()) return 0;
|
||||||
|
return (transform ? transform->opacity(frameNo) : 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene* scene = nullptr; //tvg render data
|
||||||
|
|
||||||
|
Array<LottieObject*> children;
|
||||||
|
LottieTransform* transform = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieLayer : LottieGroup
|
||||||
|
{
|
||||||
|
enum Type : uint8_t {Precomp = 0, Solid, Image, Null, Shape, Text};
|
||||||
|
|
||||||
|
LottieLayer()
|
||||||
|
{
|
||||||
|
autoOrient = false;
|
||||||
|
mask = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~LottieLayer()
|
||||||
|
{
|
||||||
|
if (refId) {
|
||||||
|
//No need to free assets children because the Composition owns them.
|
||||||
|
children.clear();
|
||||||
|
free(refId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
LottieGroup::prepare(LottieObject::Layer);
|
||||||
|
|
||||||
|
/* if layer is hidden, only useulf data is its transform matrix.
|
||||||
|
so force it to be a Null Layer and release all resource. */
|
||||||
|
if (hidden) {
|
||||||
|
type = LottieLayer::Null;
|
||||||
|
children.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t opacity(int32_t frameNo) override
|
||||||
|
{
|
||||||
|
//return zero if the visibility is false.
|
||||||
|
if (frameNo < inFrame || frameNo > outFrame) return 0;
|
||||||
|
if (type == Null) return 255;
|
||||||
|
return LottieGroup::opacity(frameNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frameRemap has the value in time domain(in sec)
|
||||||
|
To get the proper mapping first we get the mapped time at the current frame
|
||||||
|
Number then we need to convert mapped time to frame number using the
|
||||||
|
composition time line Ex: at frame 10 the mappend time is 0.5(500 ms) which
|
||||||
|
will be convert to frame number 30 if the frame rate is 60. or will result to
|
||||||
|
frame number 15 if the frame rate is 30. */
|
||||||
|
int32_t remap(int32_t frameNo)
|
||||||
|
{
|
||||||
|
return frameNo;
|
||||||
|
//return (int32_t)((frameNo - startFrame) / timeStretch);
|
||||||
|
}
|
||||||
|
|
||||||
|
RGB24 color = {255, 255, 255}; //Optimize: used for solidcolor
|
||||||
|
CompositeMethod matteType = CompositeMethod::None;
|
||||||
|
BlendMethod blendMethod = BlendMethod::Normal;
|
||||||
|
LottieLayer* parent = nullptr;
|
||||||
|
float timeStretch = 1.0f;
|
||||||
|
uint32_t w, h;
|
||||||
|
int32_t inFrame = 0;
|
||||||
|
int32_t outFrame = 0;
|
||||||
|
uint32_t startFrame = 0;
|
||||||
|
char* refId = nullptr; //pre-composition reference.
|
||||||
|
int16_t pid = -1; //id of the parent layer.
|
||||||
|
int16_t id = -1; //id of the current layer.
|
||||||
|
|
||||||
|
//cached data
|
||||||
|
struct {
|
||||||
|
Matrix matrix;
|
||||||
|
int32_t frameNo;
|
||||||
|
uint8_t opacity;
|
||||||
|
} cache;
|
||||||
|
|
||||||
|
Type type = Null;
|
||||||
|
|
||||||
|
bool autoOrient : 1;
|
||||||
|
bool mask : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieComposition
|
||||||
|
{
|
||||||
|
~LottieComposition()
|
||||||
|
{
|
||||||
|
delete(root);
|
||||||
|
free(version);
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
//delete interpolators
|
||||||
|
for (auto i = interpolators.data; i < interpolators.end(); ++i) {
|
||||||
|
free((*i)->key);
|
||||||
|
free(*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete assets
|
||||||
|
for (auto a = assets.data; a < assets.end(); ++a) {
|
||||||
|
delete(*a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float duration() const
|
||||||
|
{
|
||||||
|
return frameDuration() / frameRate; // in second
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frameAtPos(float pos) const
|
||||||
|
{
|
||||||
|
if (pos < 0) pos = 0;
|
||||||
|
if (pos > 1) pos = 1;
|
||||||
|
return (uint32_t)lroundf(pos * frameDuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
long frameAtTime(double timeInSec) const
|
||||||
|
{
|
||||||
|
return long(frameAtPos(timeInSec / duration()));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frameCnt() const
|
||||||
|
{
|
||||||
|
return endFrame - startFrame + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long frameDuration() const
|
||||||
|
{
|
||||||
|
return endFrame - startFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene* scene = nullptr; //tvg render data
|
||||||
|
|
||||||
|
LottieLayer* root = nullptr;
|
||||||
|
char* version = nullptr;
|
||||||
|
char* name = nullptr;
|
||||||
|
uint32_t w, h;
|
||||||
|
long startFrame, endFrame;
|
||||||
|
float frameRate;
|
||||||
|
Array<LottieObject*> assets;
|
||||||
|
Array<LottieInterpolator*> interpolators;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_TVG_LOTTIE_MODEL_H_
|
1010
src/loaders/lottie/tvgLottieParser.cpp
Normal file
1010
src/loaders/lottie/tvgLottieParser.cpp
Normal file
File diff suppressed because it is too large
Load diff
93
src/loaders/lottie/tvgLottieParser.h
Normal file
93
src/loaders/lottie/tvgLottieParser.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_LOTTIE_PARSER_H_
|
||||||
|
#define _TVG_LOTTIE_PARSER_H_
|
||||||
|
|
||||||
|
#include "tvgCommon.h"
|
||||||
|
#include "tvgLottieParserHandler.h"
|
||||||
|
|
||||||
|
struct LottieParser : LookaheadParserHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LottieParser(const char *str) : LookaheadParserHandler(str) {}
|
||||||
|
|
||||||
|
bool parse();
|
||||||
|
|
||||||
|
LottieComposition* comp = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BlendMethod getBlendMethod();
|
||||||
|
RGB24 getColor(const char *str);
|
||||||
|
CompositeMethod getMatteType();
|
||||||
|
FillRule getFillRule();
|
||||||
|
StrokeCap getStrokeCap();
|
||||||
|
StrokeJoin getStrokeJoin();
|
||||||
|
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
||||||
|
|
||||||
|
void getInperpolatorPoint(Point& pt);
|
||||||
|
void getPathSet(LottiePathSet& path);
|
||||||
|
void getValue(PathSet& path);
|
||||||
|
void getValue(Array<Point>& pts);
|
||||||
|
void getValue(ColorStop& color);
|
||||||
|
void getValue(float& val);
|
||||||
|
void getValue(uint8_t& val);
|
||||||
|
void getValue(Point& pt);
|
||||||
|
void getValue(RGB24& color);
|
||||||
|
|
||||||
|
template<typename T> bool parseTangent(const char *key, LottieVectorFrame<T>& value);
|
||||||
|
template<typename T> bool parseTangent(const char *key, LottieScalarFrame<T>& value);
|
||||||
|
template<typename T> void parseKeyFrame(T& prop);
|
||||||
|
template<typename T> void parsePropertyInternal(T& prop);
|
||||||
|
template<typename T> void parseProperty(T& prop);
|
||||||
|
|
||||||
|
LottieObject* parseObject();
|
||||||
|
LottieObject* parseAsset();
|
||||||
|
LottieImage* parseImage(const char* key);
|
||||||
|
LottieLayer* parseLayer();
|
||||||
|
LottieObject* parseGroup();
|
||||||
|
LottieRect* parseRect();
|
||||||
|
LottieEllipse* parseEllipse();
|
||||||
|
LottieSolidFill* parseSolidFill();
|
||||||
|
LottieTransform* parseTransform(bool ddd = false);
|
||||||
|
LottieSolidStroke* parseSolidStroke();
|
||||||
|
LottieGradientStroke* parseGradientStroke();
|
||||||
|
LottiePath* parsePath();
|
||||||
|
LottiePolyStar* parsePolyStar();
|
||||||
|
LottieRoundedCorner* parseRoundedCorner();
|
||||||
|
LottieGradientFill* parseGradientFill();
|
||||||
|
LottieLayer* parseLayers();
|
||||||
|
|
||||||
|
void parseObject(LottieGroup* parent);
|
||||||
|
void parseShapes(LottieLayer* layer);
|
||||||
|
void parseStrokeDash(LottieStroke* stroke);
|
||||||
|
void parseGradient(LottieGradient* gradient, const char* key);
|
||||||
|
void parseAssets();
|
||||||
|
|
||||||
|
//Current parsing context
|
||||||
|
struct Context {
|
||||||
|
LottieLayer* layer = nullptr;
|
||||||
|
LottieGradient* gradient = nullptr;
|
||||||
|
} *context;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_TVG_LOTTIE_PARSER_H_
|
235
src/loaders/lottie/tvgLottieParserHandler.cpp
Normal file
235
src/loaders/lottie/tvgLottieParserHandler.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tvgLottieParserHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* Internal Class Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
static const int PARSE_FLAGS = kParseDefaultFlags | kParseInsituFlag;
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* External Class Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
bool LookaheadParserHandler::enterArray()
|
||||||
|
{
|
||||||
|
if (state != kEnteringArray) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parseNext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LookaheadParserHandler::nextArrayValue()
|
||||||
|
{
|
||||||
|
if (state == kExitingArray) {
|
||||||
|
parseNext();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//SPECIAL CASE: same as nextObjectKey()
|
||||||
|
if (state == kExitingObject) return false;
|
||||||
|
if (state == kError || state == kHasKey) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LookaheadParserHandler::getInt()
|
||||||
|
{
|
||||||
|
if (state != kHasNumber || !val.IsInt()) {
|
||||||
|
Error();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto result = val.GetInt();
|
||||||
|
parseNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float LookaheadParserHandler::getFloat()
|
||||||
|
{
|
||||||
|
if (state != kHasNumber) {
|
||||||
|
Error();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto result = val.GetFloat();
|
||||||
|
parseNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* LookaheadParserHandler::getString()
|
||||||
|
{
|
||||||
|
if (state != kHasString) {
|
||||||
|
Error();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto result = val.GetString();
|
||||||
|
parseNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* LookaheadParserHandler::getStringCopy()
|
||||||
|
{
|
||||||
|
auto str = getString();
|
||||||
|
if (str) return strdup(str);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LookaheadParserHandler::getBool()
|
||||||
|
{
|
||||||
|
if (state != kHasBool) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto result = val.GetBool();
|
||||||
|
parseNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadParserHandler::getNull()
|
||||||
|
{
|
||||||
|
if (state != kHasNull) {
|
||||||
|
Error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LookaheadParserHandler::parseNext()
|
||||||
|
{
|
||||||
|
if (reader.HasParseError()) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!reader.IterativeParseNext<PARSE_FLAGS>(iss, *this)) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LookaheadParserHandler::enterObject()
|
||||||
|
{
|
||||||
|
if (state != kEnteringObject) {
|
||||||
|
Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parseNext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LookaheadParserHandler::peekType()
|
||||||
|
{
|
||||||
|
if (state >= kHasNull && state <= kHasKey) return val.GetType();
|
||||||
|
if (state == kEnteringArray) return kArrayType;
|
||||||
|
if (state == kEnteringObject) return kObjectType;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadParserHandler::skipOut(int depth)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if (state == kEnteringArray || state == kEnteringObject) ++depth;
|
||||||
|
else if (state == kExitingArray || state == kExitingObject) --depth;
|
||||||
|
else if (state == kError) return;
|
||||||
|
parseNext();
|
||||||
|
} while (depth > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* LookaheadParserHandler::nextObjectKey()
|
||||||
|
{
|
||||||
|
if (state == kHasKey) {
|
||||||
|
auto result = val.GetString();
|
||||||
|
parseNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SPECIAL CASE: The parser works with a prdefined rule that it will be only
|
||||||
|
while (nextObjectKey()) for each object but in case of our nested group
|
||||||
|
object we can call multiple time nextObjectKey() while exiting the object
|
||||||
|
so ignore those and don't put parser in the error state. */
|
||||||
|
if (state == kExitingArray || state == kEnteringObject) return nullptr;
|
||||||
|
|
||||||
|
if (state != kExitingObject) {
|
||||||
|
Error();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseNext();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadParserHandler::skip(const char* key)
|
||||||
|
{
|
||||||
|
if (key) TVGLOG("LOTTIE", "Skipped parsing value = %s", key);
|
||||||
|
|
||||||
|
if (peekType() == kArrayType) {
|
||||||
|
enterArray();
|
||||||
|
skipOut(1);
|
||||||
|
} else if (peekType() == kObjectType) {
|
||||||
|
enterObject();
|
||||||
|
skipOut(1);
|
||||||
|
} else {
|
||||||
|
skipOut(0);
|
||||||
|
}
|
||||||
|
}
|
202
src/loaders/lottie/tvgLottieParserHandler.h
Normal file
202
src/loaders/lottie/tvgLottieParserHandler.h
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_LOTTIE_PARSER_HANDLER_H_
|
||||||
|
#define _TVG_LOTTIE_PARSER_HANDLER_H_
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "tvgCommon.h"
|
||||||
|
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
|
||||||
|
struct LookaheadParserHandler
|
||||||
|
{
|
||||||
|
enum LookaheadParsingState {
|
||||||
|
kInit = 0,
|
||||||
|
kError,
|
||||||
|
kHasNull,
|
||||||
|
kHasBool,
|
||||||
|
kHasNumber,
|
||||||
|
kHasString,
|
||||||
|
kHasKey,
|
||||||
|
kEnteringObject,
|
||||||
|
kExitingObject,
|
||||||
|
kEnteringArray,
|
||||||
|
kExitingArray
|
||||||
|
};
|
||||||
|
|
||||||
|
Value val;
|
||||||
|
LookaheadParsingState state = kInit;
|
||||||
|
Reader reader;
|
||||||
|
InsituStringStream iss;
|
||||||
|
|
||||||
|
LookaheadParserHandler(const char *str) : iss((char*)str)
|
||||||
|
{
|
||||||
|
reader.IterativeParseInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Null()
|
||||||
|
{
|
||||||
|
state = kHasNull;
|
||||||
|
val.SetNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bool(bool b)
|
||||||
|
{
|
||||||
|
state = kHasBool;
|
||||||
|
val.SetBool(b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Int(int i)
|
||||||
|
{
|
||||||
|
state = kHasNumber;
|
||||||
|
val.SetInt(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uint(unsigned u)
|
||||||
|
{
|
||||||
|
state = kHasNumber;
|
||||||
|
val.SetUint(u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Int64(int64_t i)
|
||||||
|
{
|
||||||
|
state = kHasNumber;
|
||||||
|
val.SetInt64(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uint64(int64_t u)
|
||||||
|
{
|
||||||
|
state = kHasNumber;
|
||||||
|
val.SetUint64(u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Double(double d)
|
||||||
|
{
|
||||||
|
state = kHasNumber;
|
||||||
|
val.SetDouble(d);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RawNumber(const char *, SizeType, TVG_UNUSED bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String(const char *str, SizeType length, TVG_UNUSED bool)
|
||||||
|
{
|
||||||
|
state = kHasString;
|
||||||
|
val.SetString(str, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartObject()
|
||||||
|
{
|
||||||
|
state = kEnteringObject;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key(const char *str, SizeType length, TVG_UNUSED bool)
|
||||||
|
{
|
||||||
|
state = kHasKey;
|
||||||
|
val.SetString(str, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndObject(SizeType)
|
||||||
|
{
|
||||||
|
state = kExitingObject;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartArray()
|
||||||
|
{
|
||||||
|
state = kEnteringArray;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndArray(SizeType)
|
||||||
|
{
|
||||||
|
state = kExitingArray;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Error()
|
||||||
|
{
|
||||||
|
TVGERR("LOTTIE", "Parsing Error!");
|
||||||
|
state = kError;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Invalid()
|
||||||
|
{
|
||||||
|
return state == kError;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enterObject();
|
||||||
|
bool enterArray();
|
||||||
|
bool nextArrayValue();
|
||||||
|
int getInt();
|
||||||
|
float getFloat();
|
||||||
|
const char* getString();
|
||||||
|
char* getStringCopy();
|
||||||
|
bool getBool();
|
||||||
|
void getNull();
|
||||||
|
bool parseNext();
|
||||||
|
const char* nextObjectKey();
|
||||||
|
void skip(const char* key);
|
||||||
|
void skipOut(int depth);
|
||||||
|
int peekType();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_TVG_LOTTIE_PARSER_HANDLER_H_
|
449
src/loaders/lottie/tvgLottieProperty.h
Normal file
449
src/loaders/lottie/tvgLottieProperty.h
Normal file
|
@ -0,0 +1,449 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_LOTTIE_PROPERTY_H_
|
||||||
|
#define _TVG_LOTTIE_PROPERTY_H_
|
||||||
|
|
||||||
|
#include "tvgCommon.h"
|
||||||
|
#include "tvgArray.h"
|
||||||
|
#include "tvgMath.h"
|
||||||
|
#include "tvgBezier.h"
|
||||||
|
#include "tvgLottieInterpolator.h"
|
||||||
|
|
||||||
|
struct PathSet
|
||||||
|
{
|
||||||
|
Point* pts;
|
||||||
|
PathCommand* cmds;
|
||||||
|
uint16_t ptsCnt;
|
||||||
|
uint16_t cmdsCnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct RGB24
|
||||||
|
{
|
||||||
|
int32_t rgb[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ColorStop
|
||||||
|
{
|
||||||
|
Fill::ColorStop* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline RGB24 operator-(const RGB24& lhs, const RGB24& rhs)
|
||||||
|
{
|
||||||
|
return {lhs.rgb[0] - rhs.rgb[0], lhs.rgb[1] - rhs.rgb[1], lhs.rgb[2] - rhs.rgb[2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline RGB24 operator+(const RGB24& lhs, const RGB24& rhs)
|
||||||
|
{
|
||||||
|
return {lhs.rgb[0] + rhs.rgb[0], lhs.rgb[1] + rhs.rgb[1], lhs.rgb[2] + rhs.rgb[2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline RGB24 operator*(const RGB24& lhs, float rhs)
|
||||||
|
{
|
||||||
|
return {(int32_t)lroundf(lhs.rgb[0] * rhs), (int32_t)lroundf(lhs.rgb[1] * rhs), (int32_t)lroundf(lhs.rgb[2] * rhs)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void copy(PathSet& pathset, Array<Point>& outPts)
|
||||||
|
{
|
||||||
|
Array<Point> inPts;
|
||||||
|
inPts.data = pathset.pts;
|
||||||
|
inPts.count = pathset.ptsCnt;
|
||||||
|
outPts.push(inPts);
|
||||||
|
inPts.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void copy(PathSet& pathset, Array<PathCommand>& outCmds)
|
||||||
|
{
|
||||||
|
Array<PathCommand> inCmds;
|
||||||
|
inCmds.data = pathset.cmds;
|
||||||
|
inCmds.count = pathset.cmdsCnt;
|
||||||
|
outCmds.push(inCmds);
|
||||||
|
inCmds.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct LottieScalarFrame
|
||||||
|
{
|
||||||
|
T value; //keyframe value
|
||||||
|
int32_t no; //frame number
|
||||||
|
LottieInterpolator* interpolator;
|
||||||
|
|
||||||
|
T interpolate(LottieScalarFrame<T>* next, int32_t frameNo)
|
||||||
|
{
|
||||||
|
auto t = float(frameNo - no) / float(next->no - no);
|
||||||
|
if (interpolator) t = interpolator->progress(t);
|
||||||
|
return mathLerp(value, next->value, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct LottieVectorFrame
|
||||||
|
{
|
||||||
|
T value; //keyframe value
|
||||||
|
int32_t no; //frame number
|
||||||
|
LottieInterpolator* interpolator;
|
||||||
|
T outTangent, inTangent;
|
||||||
|
float length;
|
||||||
|
bool hasTangent = false;
|
||||||
|
|
||||||
|
T interpolate(LottieVectorFrame* next, int32_t frameNo)
|
||||||
|
{
|
||||||
|
auto t = float(frameNo - no) / float(next->no - no);
|
||||||
|
if (interpolator) t = interpolator->progress(t);
|
||||||
|
|
||||||
|
if (hasTangent) {
|
||||||
|
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
||||||
|
t = bezAt(bz, t * length, length);
|
||||||
|
return bezPointAt(bz, t);
|
||||||
|
} else {
|
||||||
|
return mathLerp(value, next->value, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float angle(LottieVectorFrame* next, int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (!hasTangent) return 0;
|
||||||
|
auto t = float(frameNo - no) / float(next->no - no);
|
||||||
|
if (interpolator) t = interpolator->progress(t);
|
||||||
|
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
||||||
|
t = bezAt(bz, t * length, length);
|
||||||
|
return -bezAngleAt(bz, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare(LottieVectorFrame* next)
|
||||||
|
{
|
||||||
|
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
||||||
|
length = bezLength(bz);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct LottieProperty
|
||||||
|
{
|
||||||
|
//Property has an either keyframes or single value.
|
||||||
|
Array<LottieScalarFrame<T>>* frames = nullptr;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
LottieProperty(T v) : value(v) {}
|
||||||
|
|
||||||
|
~LottieProperty()
|
||||||
|
{
|
||||||
|
delete(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<T>& newFrame()
|
||||||
|
{
|
||||||
|
if (!frames) frames = new Array<LottieScalarFrame<T>>;
|
||||||
|
if (frames->count + 1 >= frames->reserved) {
|
||||||
|
auto old = frames->reserved;
|
||||||
|
frames->grow(frames->count + 2);
|
||||||
|
memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame<T>) * (frames->reserved - old));
|
||||||
|
}
|
||||||
|
++frames->count;
|
||||||
|
return frames->last();
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<T>& nextFrame()
|
||||||
|
{
|
||||||
|
return frames->data[frames->count];
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator()(int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (!frames) return value;
|
||||||
|
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||||
|
if (frameNo >= frames->last().no) return frames->last().value;
|
||||||
|
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
if (frameNo > frame->no) continue;
|
||||||
|
if (frameNo == frame->no) return frame->value;
|
||||||
|
return (frame - 1)->interpolate(frame, frameNo);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float angle(int32_t frameNo) { return 0; }
|
||||||
|
void prepare() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottiePathSet
|
||||||
|
{
|
||||||
|
Array<LottieScalarFrame<PathSet>>* frames = nullptr;
|
||||||
|
PathSet value;
|
||||||
|
|
||||||
|
LottiePathSet(PathSet v) : value(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~LottiePathSet()
|
||||||
|
{
|
||||||
|
free(value.cmds);
|
||||||
|
free(value.pts);
|
||||||
|
|
||||||
|
if (!frames) return;
|
||||||
|
for (auto p = frames->data; p < frames->end(); ++p) {
|
||||||
|
free((*p).value.cmds);
|
||||||
|
free((*p).value.pts);
|
||||||
|
}
|
||||||
|
free(frames->data);
|
||||||
|
free(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<PathSet>& newFrame()
|
||||||
|
{
|
||||||
|
if (!frames) {
|
||||||
|
frames = static_cast<Array<LottieScalarFrame<PathSet>>*>(calloc(1, sizeof(Array<LottieScalarFrame<PathSet>>)));
|
||||||
|
}
|
||||||
|
if (frames->count + 1 >= frames->reserved) {
|
||||||
|
auto old = frames->reserved;
|
||||||
|
frames->grow(frames->count + 2);
|
||||||
|
memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame<PathSet>) * (frames->reserved - old));
|
||||||
|
}
|
||||||
|
++frames->count;
|
||||||
|
return frames->last();
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<PathSet>& nextFrame()
|
||||||
|
{
|
||||||
|
return frames->data[frames->count];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(int32_t frameNo, Array<PathCommand>& cmds, Array<Point>& pts)
|
||||||
|
{
|
||||||
|
if (!frames) {
|
||||||
|
copy(value, cmds);
|
||||||
|
copy(value, pts);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frames->count == 1 || frameNo <= frames->first().no) {
|
||||||
|
copy(frames->first().value, cmds);
|
||||||
|
copy(frames->first().value, pts);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameNo >= frames->last().no) {
|
||||||
|
copy(frames->last().value, cmds);
|
||||||
|
copy(frames->last().value, pts);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
if (frameNo > frame->no) continue;
|
||||||
|
if (frameNo == frame->no) {
|
||||||
|
copy(frame->value, cmds);
|
||||||
|
copy(frame->value, pts);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//interpolate
|
||||||
|
auto pframe = frame - 1;
|
||||||
|
copy(pframe->value, cmds);
|
||||||
|
|
||||||
|
auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no);
|
||||||
|
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
||||||
|
|
||||||
|
auto s = pframe->value.pts;
|
||||||
|
auto e = frame->value.pts;
|
||||||
|
|
||||||
|
for (auto i = 0; i < pframe->value.ptsCnt; ++i, ++s, ++e) {
|
||||||
|
pts.push(mathLerp(*s, *e, t));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieColorStop
|
||||||
|
{
|
||||||
|
Array<LottieScalarFrame<ColorStop>>* frames = nullptr;
|
||||||
|
ColorStop value;
|
||||||
|
uint16_t count = 0; //colorstop count
|
||||||
|
|
||||||
|
~LottieColorStop()
|
||||||
|
{
|
||||||
|
free(value.data);
|
||||||
|
if (!frames) return;
|
||||||
|
for (auto p = frames->data; p < frames->end(); ++p) {
|
||||||
|
free((*p).value.data);
|
||||||
|
}
|
||||||
|
free(frames->data);
|
||||||
|
free(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<ColorStop>& newFrame()
|
||||||
|
{
|
||||||
|
if (!frames) {
|
||||||
|
frames = static_cast<Array<LottieScalarFrame<ColorStop>>*>(calloc(1, sizeof(Array<LottieScalarFrame<ColorStop>>)));
|
||||||
|
}
|
||||||
|
if (frames->count + 1 >= frames->reserved) {
|
||||||
|
auto old = frames->reserved;
|
||||||
|
frames->grow(frames->count + 2);
|
||||||
|
memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame<ColorStop>) * (frames->reserved - old));
|
||||||
|
}
|
||||||
|
++frames->count;
|
||||||
|
return frames->last();
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieScalarFrame<ColorStop>& nextFrame()
|
||||||
|
{
|
||||||
|
return frames->data[frames->count];
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(int32_t frameNo, Fill* fill)
|
||||||
|
{
|
||||||
|
if (!frames) {
|
||||||
|
fill->colorStops(value.data, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frames->count == 1 || frameNo <= frames->first().no) {
|
||||||
|
fill->colorStops(frames->first().value.data, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameNo >= frames->last().no) {
|
||||||
|
fill->colorStops(frames->last().value.data, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
if (frameNo > frame->no) continue;
|
||||||
|
if (frameNo == frame->no) {
|
||||||
|
fill->colorStops(frame->value.data, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//interpolate
|
||||||
|
auto pframe = frame - 1;
|
||||||
|
auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no);
|
||||||
|
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
||||||
|
|
||||||
|
auto s = pframe->value.data;
|
||||||
|
auto e = frame->value.data;
|
||||||
|
|
||||||
|
Array<Fill::ColorStop> result;
|
||||||
|
|
||||||
|
for (auto i = 0; i < count; ++i, ++s, ++e) {
|
||||||
|
auto offset = mathLerp(s->offset, e->offset, t);
|
||||||
|
auto r = mathLerp(s->r, e->r, t);
|
||||||
|
auto g = mathLerp(s->g, e->g, t);
|
||||||
|
auto b = mathLerp(s->b, e->b, t);
|
||||||
|
result.push({offset, r, g, b, 255});
|
||||||
|
}
|
||||||
|
fill->colorStops(result.data, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void prepare() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottiePosition
|
||||||
|
{
|
||||||
|
Array<LottieVectorFrame<Point>>* frames = nullptr;
|
||||||
|
Point value;
|
||||||
|
|
||||||
|
LottiePosition(Point v) : value(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~LottiePosition()
|
||||||
|
{
|
||||||
|
delete(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieVectorFrame<Point>& newFrame()
|
||||||
|
{
|
||||||
|
if (!frames) frames = new Array<LottieVectorFrame<Point>>;
|
||||||
|
if (frames->count + 1 >= frames->reserved) {
|
||||||
|
auto old = frames->reserved;
|
||||||
|
frames->grow(frames->count + 2);
|
||||||
|
memset((void*)(frames->data + old), 0x00, sizeof(LottieVectorFrame<Point>) * (frames->reserved - old));
|
||||||
|
}
|
||||||
|
++frames->count;
|
||||||
|
return frames->last();
|
||||||
|
}
|
||||||
|
|
||||||
|
LottieVectorFrame<Point>& nextFrame()
|
||||||
|
{
|
||||||
|
return frames->data[frames->count];
|
||||||
|
}
|
||||||
|
|
||||||
|
Point operator()(int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (!frames) return value;
|
||||||
|
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||||
|
if (frameNo >= frames->last().no) return frames->last().value;
|
||||||
|
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
if (frameNo > frame->no) continue;
|
||||||
|
if (frameNo == frame->no) return frame->value;
|
||||||
|
return (frame - 1)->interpolate(frame, frameNo);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float angle(int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (!frames) return 0;
|
||||||
|
if (frames->count == 1 || frameNo <= frames->first().no) return 0;
|
||||||
|
if (frameNo >= frames->last().no) return 0;
|
||||||
|
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
if (frameNo > frame->no) continue;
|
||||||
|
return (frame - 1)->angle(frame, frameNo);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
if (!frames || frames->count < 2) return;
|
||||||
|
for (auto frame = frames->data + 1; frame < frames->end(); ++frame) {
|
||||||
|
(frame - 1)->prepare(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using LottiePoint = LottieProperty<Point>;
|
||||||
|
using LottieFloat = LottieProperty<float>;
|
||||||
|
using LottieOpacity = LottieProperty<uint8_t>;
|
||||||
|
using LottieColor = LottieProperty<RGB24>;
|
||||||
|
|
||||||
|
#endif //_TVG_LOTTIE_PROPERTY_H_
|
Loading…
Add table
Reference in a new issue