mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
animation/lottie: updated the frame count unit.
replace the frame count unit from the int32_t to float since animations could smoothly interpolate key-frames. This notificably improve the animation smoothness in Lottie Beta API changes: Result Animation::frame(uint32_t no) -> Result Animation::frame(float no) uint32_t Animation::curFrame() const -> float Animation::curFrame() const uint32_t Animation::totalFrame() const -> float Animation::totalFrame() const
This commit is contained in:
parent
fea0d1bb77
commit
e570064eba
19 changed files with 137 additions and 146 deletions
|
@ -1708,7 +1708,7 @@ public:
|
||||||
*
|
*
|
||||||
* @BETA_API
|
* @BETA_API
|
||||||
*/
|
*/
|
||||||
Result frame(uint32_t no) noexcept;
|
Result frame(float no) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves a picture instance associated with this animation instance.
|
* @brief Retrieves a picture instance associated with this animation instance.
|
||||||
|
@ -1732,12 +1732,12 @@ public:
|
||||||
*
|
*
|
||||||
* @note If the Picture is not properly configured, this function will return 0.
|
* @note If the Picture is not properly configured, this function will return 0.
|
||||||
*
|
*
|
||||||
* @see Animation::frame(uint32_t no)
|
* @see Animation::frame(float no)
|
||||||
* @see Animation::totalFrame()
|
* @see Animation::totalFrame()
|
||||||
*
|
*
|
||||||
* @BETA_API
|
* @BETA_API
|
||||||
*/
|
*/
|
||||||
uint32_t curFrame() const noexcept;
|
float curFrame() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves the total number of frames in the animation.
|
* @brief Retrieves the total number of frames in the animation.
|
||||||
|
@ -1749,7 +1749,7 @@ public:
|
||||||
*
|
*
|
||||||
* @BETA_API
|
* @BETA_API
|
||||||
*/
|
*/
|
||||||
uint32_t totalFrame() const noexcept;
|
float totalFrame() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves the duration of the animation in seconds.
|
* @brief Retrieves the duration of the animation in seconds.
|
||||||
|
|
|
@ -2234,7 +2234,7 @@ TVG_API Tvg_Animation* tvg_animation_new();
|
||||||
*
|
*
|
||||||
* \see tvg_animation_get_total_frame()
|
* \see tvg_animation_get_total_frame()
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_animation_set_frame(Tvg_Animation* animation, uint32_t no);
|
TVG_API Tvg_Result tvg_animation_set_frame(Tvg_Animation* animation, float no);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -2266,7 +2266,7 @@ TVG_API Tvg_Paint* tvg_animation_get_picture(Tvg_Animation* animation);
|
||||||
* \see tvg_animation_get_total_frame()
|
* \see tvg_animation_get_total_frame()
|
||||||
* \see tvg_animation_set_frame()
|
* \see tvg_animation_set_frame()
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, uint32_t* no);
|
TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, float* no);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -2282,7 +2282,7 @@ TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, uint32_t* n
|
||||||
* \note Frame numbering starts from 0.
|
* \note Frame numbering starts from 0.
|
||||||
* \note If the Picture is not properly configured, this function will return 0.
|
* \note If the Picture is not properly configured, this function will return 0.
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_animation_get_total_frame(Tvg_Animation* animation, uint32_t* cnt);
|
TVG_API Tvg_Result tvg_animation_get_total_frame(Tvg_Animation* animation, float* cnt);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -728,14 +728,14 @@ TVG_API Tvg_Animation* tvg_animation_new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TVG_API Tvg_Result tvg_animation_set_frame(Tvg_Animation* animation, uint32_t no)
|
TVG_API Tvg_Result tvg_animation_set_frame(Tvg_Animation* animation, float no)
|
||||||
{
|
{
|
||||||
if (!animation) return TVG_RESULT_INVALID_ARGUMENT;
|
if (!animation) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
return (Tvg_Result) reinterpret_cast<Animation*>(animation)->frame(no);
|
return (Tvg_Result) reinterpret_cast<Animation*>(animation)->frame(no);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, uint32_t* no)
|
TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, float* no)
|
||||||
{
|
{
|
||||||
if (!animation || !no) return TVG_RESULT_INVALID_ARGUMENT;
|
if (!animation || !no) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
*no = reinterpret_cast<Animation*>(animation)->curFrame();
|
*no = reinterpret_cast<Animation*>(animation)->curFrame();
|
||||||
|
@ -743,7 +743,7 @@ TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, uint32_t* n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TVG_API Tvg_Result tvg_animation_get_total_frame(Tvg_Animation* animation, uint32_t* cnt)
|
TVG_API Tvg_Result tvg_animation_get_total_frame(Tvg_Animation* animation, float* cnt)
|
||||||
{
|
{
|
||||||
if (!animation || !cnt) return TVG_RESULT_INVALID_ARGUMENT;
|
if (!animation || !cnt) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
*cnt = reinterpret_cast<Animation*>(animation)->totalFrame();
|
*cnt = reinterpret_cast<Animation*>(animation)->totalFrame();
|
||||||
|
|
|
@ -149,10 +149,9 @@ public:
|
||||||
return val(animation->totalFrame());
|
return val(animation->totalFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool frame(uint32_t no)
|
bool frame(float no)
|
||||||
{
|
{
|
||||||
if (!canvas || !animation) return false;
|
if (!canvas || !animation) return false;
|
||||||
if (animation->curFrame() == no) return true;
|
|
||||||
if (animation->frame(no) != Result::Success) {
|
if (animation->frame(no) != Result::Success) {
|
||||||
errorMsg = "frame() fail";
|
errorMsg = "frame() fail";
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -34,10 +34,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, tvg::Animation* animation, float progres
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|
||||||
//Update animation frame only when it's changed
|
//Update animation frame only when it's changed
|
||||||
auto frame = lroundf(animation->totalFrame() * progress);
|
if (animation->frame(animation->totalFrame() * progress) == tvg::Result::Success) {
|
||||||
|
|
||||||
if (frame != animation->curFrame()) {
|
|
||||||
animation->frame(frame);
|
|
||||||
canvas->update(animation->picture());
|
canvas->update(animation->picture());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,19 +257,18 @@ void transitCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress
|
||||||
{
|
{
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|
||||||
uint32_t total_frame = 0;
|
float total_frame = 0.0f;
|
||||||
tvg_animation_get_total_frame(animation, &total_frame);
|
tvg_animation_get_total_frame(animation, &total_frame);
|
||||||
|
|
||||||
uint32_t new_frame = lroundf(total_frame * progress);
|
float new_frame = total_frame * progress;
|
||||||
|
|
||||||
uint32_t cur_frame = 0;
|
float cur_frame = 0.0f;
|
||||||
tvg_animation_get_frame(animation, &cur_frame);
|
tvg_animation_get_frame(animation, &cur_frame);
|
||||||
|
|
||||||
//Update animation frame only when it's changed
|
//Update animation frame only when it's changed
|
||||||
if (new_frame == cur_frame) return;
|
if (tvg_animation_set_frame(animation, new_frame) == TVG_RESULT_SUCCESS) {
|
||||||
|
tvg_canvas_update_paint(canvas, tvg_animation_get_picture(animation));
|
||||||
tvg_animation_set_frame(animation, new_frame);
|
}
|
||||||
tvg_canvas_update_paint(canvas, tvg_animation_get_picture(animation));
|
|
||||||
|
|
||||||
//Draw the canvas
|
//Draw the canvas
|
||||||
tvg_canvas_draw(canvas);
|
tvg_canvas_draw(canvas);
|
||||||
|
|
|
@ -93,14 +93,10 @@ void tvgUpdateCmds(Elm_Transit_Effect *effect, Elm_Transit* transit, double prog
|
||||||
auto animation = static_cast<tvg::Animation*>(effect);
|
auto animation = static_cast<tvg::Animation*>(effect);
|
||||||
|
|
||||||
//Update animation frame only when it's changed
|
//Update animation frame only when it's changed
|
||||||
auto frame = lroundf(animation->totalFrame() * progress);
|
auto before = ecore_time_get();
|
||||||
|
animation->frame(animation->totalFrame() * progress);
|
||||||
if (frame != animation->curFrame()) {
|
auto after = ecore_time_get();
|
||||||
auto before = ecore_time_get();
|
updateTime += after - before;
|
||||||
animation->frame(frame);
|
|
||||||
auto after = ecore_time_get();
|
|
||||||
updateTime += after - before;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tvgDrawCmds(tvg::Canvas* canvas)
|
void tvgDrawCmds(tvg::Canvas* canvas)
|
||||||
|
|
|
@ -83,8 +83,8 @@ struct RenderContext
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, queue<RenderContext>& contexts);
|
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts);
|
||||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo);
|
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo);
|
||||||
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
||||||
|
|
||||||
static void _rotateX(Matrix* m, float degree)
|
static void _rotateX(Matrix* m, float degree)
|
||||||
|
@ -114,7 +114,7 @@ static void _rotationZ(Matrix* m, float degree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool _updateTransform(LottieTransform* transform, int32_t frameNo, bool autoOrient, Matrix& matrix, uint8_t& opacity)
|
static bool _updateTransform(LottieTransform* transform, float frameNo, bool autoOrient, Matrix& matrix, uint8_t& opacity)
|
||||||
{
|
{
|
||||||
mathIdentity(&matrix);
|
mathIdentity(&matrix);
|
||||||
|
|
||||||
|
@ -154,9 +154,9 @@ static bool _updateTransform(LottieTransform* transform, int32_t frameNo, bool a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateTransform(LottieLayer* layer, int32_t frameNo)
|
static void _updateTransform(LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
if (!layer || layer->cache.frameNo == frameNo) return;
|
if (!layer || mathEqual(layer->cache.frameNo, frameNo)) return;
|
||||||
|
|
||||||
auto transform = layer->transform;
|
auto transform = layer->transform;
|
||||||
auto parent = layer->parent;
|
auto parent = layer->parent;
|
||||||
|
@ -177,7 +177,7 @@ static void _updateTransform(LottieLayer* layer, int32_t frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateTransform(LottieTransform* transform, int32_t frameNo, RenderContext& ctx)
|
static void _updateTransform(LottieTransform* transform, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (!transform) return;
|
if (!transform) return;
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ static void _updateTransform(LottieTransform* transform, int32_t frameNo, Render
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateGroup(LottieGroup* parent, LottieGroup* group, int32_t frameNo, RenderContext& ctx)
|
static void _updateGroup(LottieGroup* parent, LottieGroup* group, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (group->children.empty()) return;
|
if (group->children.empty()) return;
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ static void _updateGroup(LottieGroup* parent, LottieGroup* group, int32_t frameN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateStroke(LottieStroke* stroke, int32_t frameNo, RenderContext& ctx)
|
static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
ctx.propagator->stroke(stroke->width(frameNo));
|
ctx.propagator->stroke(stroke->width(frameNo));
|
||||||
ctx.propagator->stroke(stroke->cap);
|
ctx.propagator->stroke(stroke->cap);
|
||||||
|
@ -245,7 +245,7 @@ static bool _fragmentedStroking(LottieObject** child, queue<RenderContext>& cont
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateSolidStroke(LottieObject** child, int32_t frameNo, queue<RenderContext>& contexts, RenderContext& ctx)
|
static void _updateSolidStroke(LottieObject** child, float frameNo, queue<RenderContext>& contexts, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (_fragmentedStroking(child, contexts, ctx)) return;
|
if (_fragmentedStroking(child, contexts, ctx)) return;
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ static void _updateSolidStroke(LottieObject** child, int32_t frameNo, queue<Rend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateGradientStroke(LottieObject** child, int32_t frameNo, queue<RenderContext>& contexts, RenderContext& ctx)
|
static void _updateGradientStroke(LottieObject** child, float frameNo, queue<RenderContext>& contexts, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (_fragmentedStroking(child, contexts, ctx)) return;
|
if (_fragmentedStroking(child, contexts, ctx)) return;
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ static void _updateGradientStroke(LottieObject** child, int32_t frameNo, queue<R
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateFill(LottieSolidFill* fill, int32_t frameNo, RenderContext& ctx)
|
static void _updateFill(LottieSolidFill* fill, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (ctx.stroking) return;
|
if (ctx.stroking) return;
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ static void _updateFill(LottieSolidFill* fill, int32_t frameNo, RenderContext& c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Shape* _updateFill(LottieGradientFill* fill, int32_t frameNo, RenderContext& ctx)
|
static Shape* _updateFill(LottieGradientFill* fill, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (ctx.stroking) return nullptr;
|
if (ctx.stroking) return nullptr;
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ static Shape* _updateFill(LottieGradientFill* fill, int32_t frameNo, RenderConte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Shape* _draw(LottieGroup* parent, int32_t frameNo, RenderContext& ctx)
|
static Shape* _draw(LottieGroup* parent, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (ctx.allowMerging && ctx.merging) return ctx.merging;
|
if (ctx.allowMerging && ctx.merging) return ctx.merging;
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ static Shape* _draw(LottieGroup* parent, int32_t frameNo, RenderContext& ctx)
|
||||||
|
|
||||||
|
|
||||||
//OPTIMIZE: path?
|
//OPTIMIZE: path?
|
||||||
static void _repeat(LottieGroup* parent, int32_t frameNo, unique_ptr<Shape> path, RenderContext& ctx)
|
static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto repeater = ctx.repeater;
|
auto repeater = ctx.repeater;
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ static void _repeat(LottieGroup* parent, int32_t frameNo, unique_ptr<Shape> path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo, RenderContext& ctx)
|
static void _updateRect(LottieGroup* parent, LottieRect* rect, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto position = rect->position(frameNo);
|
auto position = rect->position(frameNo);
|
||||||
auto size = rect->size(frameNo);
|
auto size = rect->size(frameNo);
|
||||||
|
@ -378,15 +378,15 @@ static void _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo,
|
||||||
if (ctx.repeater) {
|
if (ctx.repeater) {
|
||||||
auto path = Shape::gen();
|
auto path = Shape::gen();
|
||||||
path->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
path->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
||||||
_repeat(parent, frameNo, std::move(path), ctx);
|
_repeat(parent, std::move(path), ctx);
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, frameNo, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
merging->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
merging->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_t frameNo, RenderContext& ctx)
|
static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto position = ellipse->position(frameNo);
|
auto position = ellipse->position(frameNo);
|
||||||
auto size = ellipse->size(frameNo);
|
auto size = ellipse->size(frameNo);
|
||||||
|
@ -394,22 +394,22 @@ static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_t
|
||||||
if (ctx.repeater) {
|
if (ctx.repeater) {
|
||||||
auto path = Shape::gen();
|
auto path = Shape::gen();
|
||||||
path->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
path->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
||||||
_repeat(parent, frameNo, std::move(path), ctx);
|
_repeat(parent, std::move(path), ctx);
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, frameNo, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
merging->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
merging->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo, RenderContext& ctx)
|
static void _updatePath(LottieGroup* parent, LottiePath* path, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (ctx.repeater) {
|
if (ctx.repeater) {
|
||||||
auto p = Shape::gen();
|
auto p = Shape::gen();
|
||||||
path->pathset(frameNo, P(p)->rs.path.cmds, P(p)->rs.path.pts);
|
path->pathset(frameNo, P(p)->rs.path.cmds, P(p)->rs.path.pts);
|
||||||
_repeat(parent, frameNo, std::move(p), ctx);
|
_repeat(parent, std::move(p), ctx);
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, frameNo, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
|
|
||||||
if (path->pathset(frameNo, P(merging)->rs.path.cmds, P(merging)->rs.path.pts)) {
|
if (path->pathset(frameNo, P(merging)->rs.path.cmds, P(merging)->rs.path.pts)) {
|
||||||
P(merging)->update(RenderUpdateFlag::Path);
|
P(merging)->update(RenderUpdateFlag::Path);
|
||||||
|
@ -423,7 +423,7 @@ static void _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, int32_t frameNo, Shape* merging)
|
static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, float frameNo, Shape* merging)
|
||||||
{
|
{
|
||||||
static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f;
|
static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f;
|
||||||
|
|
||||||
|
@ -532,7 +532,7 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* trans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, int32_t frameNo, Shape* merging)
|
static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, float frameNo, Shape* merging)
|
||||||
{
|
{
|
||||||
static constexpr auto POLYGON_MAGIC_NUMBER = 0.25f;
|
static constexpr auto POLYGON_MAGIC_NUMBER = 0.25f;
|
||||||
|
|
||||||
|
@ -601,7 +601,7 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t frameNo, RenderContext& ctx)
|
static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
//Optimize: Can we skip the individual coords transform?
|
//Optimize: Can we skip the individual coords transform?
|
||||||
Matrix matrix;
|
Matrix matrix;
|
||||||
|
@ -616,9 +616,9 @@ static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t f
|
||||||
auto p = Shape::gen();
|
auto p = Shape::gen();
|
||||||
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
|
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
|
||||||
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
|
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
|
||||||
_repeat(parent, frameNo, std::move(p), ctx);
|
_repeat(parent, std::move(p), ctx);
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, frameNo, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||||
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||||
P(merging)->update(RenderUpdateFlag::Path);
|
P(merging)->update(RenderUpdateFlag::Path);
|
||||||
|
@ -626,7 +626,7 @@ static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateImage(LottieGroup* parent, LottieImage* image, int32_t frameNo, RenderContext& ctx)
|
static void _updateImage(LottieGroup* parent, LottieImage* image, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto picture = image->picture;
|
auto picture = image->picture;
|
||||||
|
|
||||||
|
@ -665,14 +665,14 @@ static void _updateImage(LottieGroup* parent, LottieImage* image, int32_t frameN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateRoundedCorner(LottieRoundedCorner* roundedCorner, int32_t frameNo, RenderContext& ctx)
|
static void _updateRoundedCorner(LottieRoundedCorner* roundedCorner, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto roundness = roundedCorner->radius(frameNo);
|
auto roundness = roundedCorner->radius(frameNo);
|
||||||
if (ctx.roundness < roundness) ctx.roundness = roundness;
|
if (ctx.roundness < roundness) ctx.roundness = roundness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateRepeater(LottieRepeater* repeater, int32_t frameNo, RenderContext& ctx)
|
static void _updateRepeater(LottieRepeater* repeater, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (!ctx.repeater) ctx.repeater = new RenderRepeater();
|
if (!ctx.repeater) ctx.repeater = new RenderRepeater();
|
||||||
ctx.repeater->cnt = static_cast<int>(repeater->copies(frameNo));
|
ctx.repeater->cnt = static_cast<int>(repeater->copies(frameNo));
|
||||||
|
@ -690,7 +690,7 @@ static void _updateRepeater(LottieRepeater* repeater, int32_t frameNo, RenderCon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateTrimpath(LottieTrimpath* trimpath, int32_t frameNo, RenderContext& ctx)
|
static void _updateTrimpath(LottieTrimpath* trimpath, float frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
float begin, end;
|
float begin, end;
|
||||||
trimpath->segment(frameNo, begin, end);
|
trimpath->segment(frameNo, begin, end);
|
||||||
|
@ -709,7 +709,7 @@ static void _updateTrimpath(LottieTrimpath* trimpath, int32_t frameNo, RenderCon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, queue<RenderContext>& contexts)
|
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts)
|
||||||
{
|
{
|
||||||
contexts.front().begin = parent->children.end() - 1;
|
contexts.front().begin = parent->children.end() - 1;
|
||||||
|
|
||||||
|
@ -783,7 +783,7 @@ static void _updateChildren(LottieGroup* parent, int32_t frameNo, queue<RenderCo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updatePrecomp(LottieLayer* precomp, int32_t frameNo)
|
static void _updatePrecomp(LottieLayer* precomp, float frameNo)
|
||||||
{
|
{
|
||||||
if (precomp->children.count == 0) return;
|
if (precomp->children.count == 0) return;
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@ static void _updatePrecomp(LottieLayer* precomp, int32_t frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateSolid(LottieLayer* layer, int32_t frameNo)
|
static void _updateSolid(LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
auto shape = Shape::gen();
|
auto shape = Shape::gen();
|
||||||
shape->appendRect(0, 0, static_cast<float>(layer->w), static_cast<float>(layer->h));
|
shape->appendRect(0, 0, static_cast<float>(layer->w), static_cast<float>(layer->h));
|
||||||
|
@ -817,7 +817,7 @@ static void _updateSolid(LottieLayer* layer, int32_t frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateMaskings(LottieLayer* layer, int32_t frameNo)
|
static void _updateMaskings(LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
if (layer->masks.count == 0) return;
|
if (layer->masks.count == 0) return;
|
||||||
|
|
||||||
|
@ -855,7 +855,7 @@ static void _updateMaskings(LottieLayer* layer, int32_t frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo)
|
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
layer->scene = nullptr;
|
layer->scene = nullptr;
|
||||||
|
|
||||||
|
@ -1021,7 +1021,7 @@ static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent)
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
bool LottieBuilder::update(LottieComposition* comp, int32_t frameNo)
|
bool LottieBuilder::update(LottieComposition* comp, float frameNo)
|
||||||
{
|
{
|
||||||
frameNo += comp->startFrame;
|
frameNo += comp->startFrame;
|
||||||
if (frameNo < comp->startFrame) frameNo = comp->startFrame;
|
if (frameNo < comp->startFrame) frameNo = comp->startFrame;
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct LottieComposition;
|
||||||
|
|
||||||
struct LottieBuilder
|
struct LottieBuilder
|
||||||
{
|
{
|
||||||
bool update(LottieComposition* comp, int32_t frameNo);
|
bool update(LottieComposition* comp, float progress);
|
||||||
void build(LottieComposition* comp);
|
void build(LottieComposition* comp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,8 @@ bool LottieLoader::header()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
frameDuration = (endFrame - startFrame) / frameRate;
|
frameCnt = (endFrame - startFrame);
|
||||||
|
frameDuration = frameCnt / frameRate;
|
||||||
|
|
||||||
TVGLOG("LOTTIE", "info: frame rate = %f, duration = %f size = %d x %d", frameRate, frameDuration, (int)w, (int)h);
|
TVGLOG("LOTTIE", "info: frame rate = %f, duration = %f size = %d x %d", frameRate, frameDuration, (int)w, (int)h);
|
||||||
|
|
||||||
|
@ -286,6 +287,10 @@ bool LottieLoader::read()
|
||||||
|
|
||||||
TaskScheduler::request(this);
|
TaskScheduler::request(this);
|
||||||
|
|
||||||
|
if (comp && TaskScheduler::threads() == 0) {
|
||||||
|
frameCnt = comp->frameCnt();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,15 +314,13 @@ unique_ptr<Paint> LottieLoader::paint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LottieLoader::frame(uint32_t frameNo)
|
bool LottieLoader::frame(float no)
|
||||||
{
|
{
|
||||||
if (this->frameNo == frameNo) return true;
|
if (mathEqual(this->frameNo, no)) return false;
|
||||||
|
|
||||||
this->done();
|
this->done();
|
||||||
|
|
||||||
if (!comp || frameNo >= comp->frameCnt()) return false;
|
this->frameNo = no;
|
||||||
|
|
||||||
this->frameNo = frameNo;
|
|
||||||
|
|
||||||
TaskScheduler::request(this);
|
TaskScheduler::request(this);
|
||||||
|
|
||||||
|
@ -325,16 +328,13 @@ bool LottieLoader::frame(uint32_t frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t LottieLoader::totalFrame()
|
float LottieLoader::totalFrame()
|
||||||
{
|
{
|
||||||
this->done();
|
return frameCnt;
|
||||||
|
|
||||||
if (!comp) return 0;
|
|
||||||
return comp->frameCnt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t LottieLoader::curFrame()
|
float LottieLoader::curFrame()
|
||||||
{
|
{
|
||||||
return frameNo;
|
return frameNo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,9 @@ class LottieLoader : public FrameModule, public Task
|
||||||
public:
|
public:
|
||||||
const char* content = nullptr; //lottie file data
|
const char* content = nullptr; //lottie file data
|
||||||
uint32_t size = 0; //lottie data size
|
uint32_t size = 0; //lottie data size
|
||||||
uint32_t frameNo = 0; //current frame number
|
float frameNo = 0.0f; //current frame number
|
||||||
float frameDuration;
|
float frameCnt = 0.0f;
|
||||||
|
float frameDuration = 0.0f;
|
||||||
|
|
||||||
LottieBuilder* builder = nullptr;
|
LottieBuilder* builder = nullptr;
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
|
@ -57,9 +58,9 @@ public:
|
||||||
unique_ptr<Paint> paint() override;
|
unique_ptr<Paint> paint() override;
|
||||||
|
|
||||||
//Frame Controls
|
//Frame Controls
|
||||||
bool frame(uint32_t frameNo) override;
|
bool frame(float no) override;
|
||||||
uint32_t totalFrame() override;
|
float totalFrame() override;
|
||||||
uint32_t curFrame() override;
|
float curFrame() override;
|
||||||
float duration() override;
|
float duration() override;
|
||||||
void sync() override;
|
void sync() override;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
void LottieTrimpath::segment(int32_t frameNo, float& start, float& end)
|
void LottieTrimpath::segment(float frameNo, float& start, float& end)
|
||||||
{
|
{
|
||||||
auto s = this->start(frameNo) * 0.01f;
|
auto s = this->start(frameNo) * 0.01f;
|
||||||
auto e = this->end(frameNo) * 0.01f;
|
auto e = this->end(frameNo) * 0.01f;
|
||||||
|
@ -77,7 +77,7 @@ void LottieTrimpath::segment(int32_t frameNo, float& start, float& end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Fill* LottieGradient::fill(int32_t frameNo)
|
Fill* LottieGradient::fill(float frameNo)
|
||||||
{
|
{
|
||||||
Fill* fill = nullptr;
|
Fill* fill = nullptr;
|
||||||
|
|
||||||
|
@ -145,14 +145,14 @@ void LottieLayer::prepare()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t LottieLayer::remap(int32_t frameNo)
|
float LottieLayer::remap(float frameNo)
|
||||||
{
|
{
|
||||||
if (timeRemap.frames || timeRemap.value) {
|
if (timeRemap.frames || timeRemap.value) {
|
||||||
frameNo = comp->frameAtTime(timeRemap(frameNo));
|
frameNo = comp->frameAtTime(timeRemap(frameNo));
|
||||||
} else {
|
} else {
|
||||||
frameNo -= startFrame;
|
frameNo -= startFrame;
|
||||||
}
|
}
|
||||||
return (int32_t)(frameNo / timeStretch);
|
return (frameNo / timeStretch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,17 +49,17 @@ struct LottieStroke
|
||||||
return dashattr->value[no];
|
return dashattr->value[no];
|
||||||
}
|
}
|
||||||
|
|
||||||
float dashOffset(int32_t frameNo)
|
float dashOffset(float frameNo)
|
||||||
{
|
{
|
||||||
return dash(0)(frameNo);
|
return dash(0)(frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
float dashGap(int32_t frameNo)
|
float dashGap(float frameNo)
|
||||||
{
|
{
|
||||||
return dash(2)(frameNo);
|
return dash(2)(frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
float dashSize(int32_t frameNo)
|
float dashSize(float frameNo)
|
||||||
{
|
{
|
||||||
auto d = dash(1)(frameNo);
|
auto d = dash(1)(frameNo);
|
||||||
if (d == 0.0f) return 0.1f;
|
if (d == 0.0f) return 0.1f;
|
||||||
|
@ -177,7 +177,7 @@ struct LottieGradient
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fill* fill(int32_t frameNo);
|
Fill* fill(float frameNo);
|
||||||
|
|
||||||
LottiePoint start = Point{0.0f, 0.0f};
|
LottiePoint start = Point{0.0f, 0.0f};
|
||||||
LottiePoint end = Point{0.0f, 0.0f};
|
LottiePoint end = Point{0.0f, 0.0f};
|
||||||
|
@ -248,7 +248,7 @@ struct LottieTrimpath : LottieObject
|
||||||
if (start.frames || end.frames || offset.frames) statical = false;
|
if (start.frames || end.frames || offset.frames) statical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void segment(int32_t frameNo, float& start, float& end);
|
void segment(float frameNo, float& start, float& end);
|
||||||
|
|
||||||
LottieFloat start = 0.0f;
|
LottieFloat start = 0.0f;
|
||||||
LottieFloat end = 0.0f;
|
LottieFloat end = 0.0f;
|
||||||
|
@ -507,7 +507,7 @@ struct LottieLayer : LottieGroup
|
||||||
delete(transform);
|
delete(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t opacity(int32_t frameNo)
|
uint8_t opacity(float frameNo)
|
||||||
{
|
{
|
||||||
//return zero if the visibility is false.
|
//return zero if the visibility is false.
|
||||||
if (type == Null) return 255;
|
if (type == Null) return 255;
|
||||||
|
@ -515,7 +515,7 @@ struct LottieLayer : LottieGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare();
|
void prepare();
|
||||||
int32_t remap(int32_t frameNo);
|
float remap(float frameNo);
|
||||||
|
|
||||||
//Optimize: compact data??
|
//Optimize: compact data??
|
||||||
RGB24 color;
|
RGB24 color;
|
||||||
|
@ -534,16 +534,16 @@ struct LottieLayer : LottieGroup
|
||||||
|
|
||||||
float timeStretch = 1.0f;
|
float timeStretch = 1.0f;
|
||||||
uint32_t w = 0, h = 0;
|
uint32_t w = 0, h = 0;
|
||||||
int32_t inFrame = 0;
|
float inFrame = 0.0f;
|
||||||
int32_t outFrame = 0;
|
float outFrame = 0.0f;
|
||||||
uint32_t startFrame = 0;
|
float startFrame = 0.0f;
|
||||||
char* refId = nullptr; //pre-composition reference.
|
char* refId = nullptr; //pre-composition reference.
|
||||||
int16_t pid = -1; //id of the parent layer.
|
int16_t pid = -1; //id of the parent layer.
|
||||||
int16_t id = -1; //id of the current layer.
|
int16_t id = -1; //id of the current layer.
|
||||||
|
|
||||||
//cached data
|
//cached data
|
||||||
struct {
|
struct {
|
||||||
int32_t frameNo = -1;
|
float frameNo = -1.0f;
|
||||||
Matrix matrix;
|
Matrix matrix;
|
||||||
uint8_t opacity;
|
uint8_t opacity;
|
||||||
} cache;
|
} cache;
|
||||||
|
@ -583,7 +583,7 @@ struct LottieComposition
|
||||||
char* version = nullptr;
|
char* version = nullptr;
|
||||||
char* name = nullptr;
|
char* name = nullptr;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
int32_t startFrame, endFrame;
|
float startFrame, endFrame;
|
||||||
float frameRate;
|
float frameRate;
|
||||||
Array<LottieObject*> assets;
|
Array<LottieObject*> assets;
|
||||||
Array<LottieInterpolator*> interpolators;
|
Array<LottieInterpolator*> interpolators;
|
||||||
|
|
|
@ -382,7 +382,7 @@ void LottieParser::parseKeyFrame(T& prop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!strcmp(key, "t")) {
|
} else if (!strcmp(key, "t")) {
|
||||||
frame.no = lroundf(getFloat());
|
frame.no = getFloat();
|
||||||
} else if (!strcmp(key, "s")) {
|
} else if (!strcmp(key, "s")) {
|
||||||
getValue(frame.value);
|
getValue(frame.value);
|
||||||
} else if (!strcmp(key, "e")) {
|
} else if (!strcmp(key, "e")) {
|
||||||
|
@ -1003,9 +1003,9 @@ LottieLayer* LottieParser::parseLayer()
|
||||||
}
|
}
|
||||||
else if (!strcmp(key, "ao")) layer->autoOrient = getInt();
|
else if (!strcmp(key, "ao")) layer->autoOrient = getInt();
|
||||||
else if (!strcmp(key, "shapes")) parseShapes(layer);
|
else if (!strcmp(key, "shapes")) parseShapes(layer);
|
||||||
else if (!strcmp(key, "ip")) layer->inFrame = lroundf(getFloat());
|
else if (!strcmp(key, "ip")) layer->inFrame = getFloat();
|
||||||
else if (!strcmp(key, "op")) layer->outFrame = lroundf(getFloat());
|
else if (!strcmp(key, "op")) layer->outFrame = getFloat();
|
||||||
else if (!strcmp(key, "st")) layer->startFrame = lroundf(getFloat());
|
else if (!strcmp(key, "st")) layer->startFrame = getFloat();
|
||||||
else if (!strcmp(key, "bm")) layer->blendMethod = getBlendMethod();
|
else if (!strcmp(key, "bm")) layer->blendMethod = getBlendMethod();
|
||||||
else if (!strcmp(key, "parent")) layer->pid = getInt();
|
else if (!strcmp(key, "parent")) layer->pid = getInt();
|
||||||
else if (!strcmp(key, "tm")) parseTimeRemap(layer);
|
else if (!strcmp(key, "tm")) parseTimeRemap(layer);
|
||||||
|
@ -1091,8 +1091,8 @@ bool LottieParser::parse()
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "v")) comp->version = getStringCopy();
|
if (!strcmp(key, "v")) comp->version = getStringCopy();
|
||||||
else if (!strcmp(key, "fr")) comp->frameRate = getFloat();
|
else if (!strcmp(key, "fr")) comp->frameRate = getFloat();
|
||||||
else if (!strcmp(key, "ip")) comp->startFrame = lroundf(getFloat());
|
else if (!strcmp(key, "ip")) comp->startFrame = getFloat();
|
||||||
else if (!strcmp(key, "op")) comp->endFrame = lroundf(getFloat());
|
else if (!strcmp(key, "op")) comp->endFrame = getFloat();
|
||||||
else if (!strcmp(key, "w")) comp->w = getInt();
|
else if (!strcmp(key, "w")) comp->w = getInt();
|
||||||
else if (!strcmp(key, "h")) comp->h = getInt();
|
else if (!strcmp(key, "h")) comp->h = getInt();
|
||||||
else if (!strcmp(key, "nm")) comp->name = getStringCopy();
|
else if (!strcmp(key, "nm")) comp->name = getStringCopy();
|
||||||
|
|
|
@ -93,13 +93,13 @@ template<typename T>
|
||||||
struct LottieScalarFrame
|
struct LottieScalarFrame
|
||||||
{
|
{
|
||||||
T value; //keyframe value
|
T value; //keyframe value
|
||||||
int32_t no; //frame number
|
float no; //frame number
|
||||||
LottieInterpolator* interpolator;
|
LottieInterpolator* interpolator;
|
||||||
bool hold = false; //do not interpolate.
|
bool hold = false; //do not interpolate.
|
||||||
|
|
||||||
T interpolate(LottieScalarFrame<T>* next, int32_t frameNo)
|
T interpolate(LottieScalarFrame<T>* next, float frameNo)
|
||||||
{
|
{
|
||||||
auto t = float(frameNo - no) / float(next->no - no);
|
auto t = (frameNo - no) / (next->no - no);
|
||||||
if (interpolator) t = interpolator->progress(t);
|
if (interpolator) t = interpolator->progress(t);
|
||||||
|
|
||||||
if (hold) {
|
if (hold) {
|
||||||
|
@ -115,16 +115,16 @@ template<typename T>
|
||||||
struct LottieVectorFrame
|
struct LottieVectorFrame
|
||||||
{
|
{
|
||||||
T value; //keyframe value
|
T value; //keyframe value
|
||||||
int32_t no; //frame number
|
float no; //frame number
|
||||||
LottieInterpolator* interpolator;
|
LottieInterpolator* interpolator;
|
||||||
T outTangent, inTangent;
|
T outTangent, inTangent;
|
||||||
float length;
|
float length;
|
||||||
bool hasTangent = false;
|
bool hasTangent = false;
|
||||||
bool hold = false;
|
bool hold = false;
|
||||||
|
|
||||||
T interpolate(LottieVectorFrame* next, int32_t frameNo)
|
T interpolate(LottieVectorFrame* next, float frameNo)
|
||||||
{
|
{
|
||||||
auto t = float(frameNo - no) / float(next->no - no);
|
auto t = (frameNo - no) / (next->no - no);
|
||||||
if (interpolator) t = interpolator->progress(t);
|
if (interpolator) t = interpolator->progress(t);
|
||||||
|
|
||||||
if (hold) {
|
if (hold) {
|
||||||
|
@ -141,10 +141,10 @@ struct LottieVectorFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float angle(LottieVectorFrame* next, int32_t frameNo)
|
float angle(LottieVectorFrame* next, float frameNo)
|
||||||
{
|
{
|
||||||
if (!hasTangent) return 0;
|
if (!hasTangent) return 0;
|
||||||
auto t = float(frameNo - no) / float(next->no - no);
|
auto t = (frameNo - no) / (next->no - no);
|
||||||
if (interpolator) t = interpolator->progress(t);
|
if (interpolator) t = interpolator->progress(t);
|
||||||
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
||||||
t = bezAt(bz, t * length, length);
|
t = bezAt(bz, t * length, length);
|
||||||
|
@ -190,7 +190,7 @@ struct LottieProperty
|
||||||
return (*frames)[frames->count];
|
return (*frames)[frames->count];
|
||||||
}
|
}
|
||||||
|
|
||||||
T operator()(int32_t frameNo)
|
T operator()(float frameNo)
|
||||||
{
|
{
|
||||||
if (!frames) return value;
|
if (!frames) return value;
|
||||||
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||||
|
@ -202,7 +202,7 @@ struct LottieProperty
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
auto mid = low + (high - low) / 2;
|
auto mid = low + (high - low) / 2;
|
||||||
auto frame = frames->data + mid;
|
auto frame = frames->data + mid;
|
||||||
if (frameNo == frame->no) return frame->value;
|
if (mathEqual(frameNo, frame->no)) return frame->value;
|
||||||
else if (frameNo > frame->no) low = mid + 1;
|
else if (frameNo > frame->no) low = mid + 1;
|
||||||
else high = mid - 1;
|
else high = mid - 1;
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ struct LottieProperty
|
||||||
return (frame - 1)->interpolate(frame, frameNo);
|
return (frame - 1)->interpolate(frame, frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
float angle(int32_t frameNo) { return 0; }
|
float angle(float frameNo) { return 0; }
|
||||||
void prepare() {}
|
void prepare() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ struct LottiePathSet
|
||||||
return (*frames)[frames->count];
|
return (*frames)[frames->count];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(int32_t frameNo, Array<PathCommand>& cmds, Array<Point>& pts)
|
bool operator()(float frameNo, Array<PathCommand>& cmds, Array<Point>& pts)
|
||||||
{
|
{
|
||||||
if (!frames) {
|
if (!frames) {
|
||||||
copy(value, cmds);
|
copy(value, cmds);
|
||||||
|
@ -284,7 +284,7 @@ struct LottiePathSet
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
auto mid = low + (high - low) / 2;
|
auto mid = low + (high - low) / 2;
|
||||||
auto frame = frames->data + mid;
|
auto frame = frames->data + mid;
|
||||||
if (frameNo == frame->no) {
|
if (mathEqual(frameNo, frame->no)) {
|
||||||
copy(frame->value, cmds);
|
copy(frame->value, cmds);
|
||||||
copy(frame->value, pts);
|
copy(frame->value, pts);
|
||||||
return true;
|
return true;
|
||||||
|
@ -300,7 +300,7 @@ struct LottiePathSet
|
||||||
auto pframe = frame - 1;
|
auto pframe = frame - 1;
|
||||||
copy(pframe->value, cmds);
|
copy(pframe->value, cmds);
|
||||||
|
|
||||||
auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no);
|
auto t = (frameNo - pframe->no) / (frame->no - pframe->no);
|
||||||
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
||||||
|
|
||||||
if (pframe->hold) {
|
if (pframe->hold) {
|
||||||
|
@ -358,7 +358,7 @@ struct LottieColorStop
|
||||||
return (*frames)[frames->count];
|
return (*frames)[frames->count];
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(int32_t frameNo, Fill* fill)
|
void operator()(float frameNo, Fill* fill)
|
||||||
{
|
{
|
||||||
if (!frames) {
|
if (!frames) {
|
||||||
fill->colorStops(value.data, count);
|
fill->colorStops(value.data, count);
|
||||||
|
@ -381,7 +381,7 @@ struct LottieColorStop
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
auto mid = low + (high - low) / 2;
|
auto mid = low + (high - low) / 2;
|
||||||
auto frame = frames->data + mid;
|
auto frame = frames->data + mid;
|
||||||
if (frameNo == frame->no) {
|
if (mathEqual(frameNo, frame->no)) {
|
||||||
fill->colorStops(frame->value.data, count);
|
fill->colorStops(frame->value.data, count);
|
||||||
return;
|
return;
|
||||||
} else if (frameNo > frame->no) {
|
} else if (frameNo > frame->no) {
|
||||||
|
@ -394,7 +394,7 @@ struct LottieColorStop
|
||||||
//interpolate
|
//interpolate
|
||||||
auto frame = frames->data + low;
|
auto frame = frames->data + low;
|
||||||
auto pframe = frame - 1;
|
auto pframe = frame - 1;
|
||||||
auto t = float(frameNo - pframe->no) / float(frame->no - pframe->no);
|
auto t = (frameNo - pframe->no) / (frame->no - pframe->no);
|
||||||
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
if (pframe->interpolator) t = pframe->interpolator->progress(t);
|
||||||
|
|
||||||
if (pframe->hold) {
|
if (pframe->hold) {
|
||||||
|
@ -453,7 +453,7 @@ struct LottiePosition
|
||||||
return (*frames)[frames->count];
|
return (*frames)[frames->count];
|
||||||
}
|
}
|
||||||
|
|
||||||
Point operator()(int32_t frameNo)
|
Point operator()(float frameNo)
|
||||||
{
|
{
|
||||||
if (!frames) return value;
|
if (!frames) return value;
|
||||||
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||||
|
@ -465,7 +465,7 @@ struct LottiePosition
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
auto mid = low + (high - low) / 2;
|
auto mid = low + (high - low) / 2;
|
||||||
auto frame = frames->data + mid;
|
auto frame = frames->data + mid;
|
||||||
if (frameNo == frame->no) return frame->value;
|
if (mathEqual(frameNo, frame->no)) return frame->value;
|
||||||
else if (frameNo > frame->no) low = mid + 1;
|
else if (frameNo > frame->no) low = mid + 1;
|
||||||
else high = mid - 1;
|
else high = mid - 1;
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ struct LottiePosition
|
||||||
return (frame - 1)->interpolate(frame, frameNo);
|
return (frame - 1)->interpolate(frame, frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
float angle(int32_t frameNo)
|
float angle(float frameNo)
|
||||||
{
|
{
|
||||||
if (!frames) return 0;
|
if (!frames) return 0;
|
||||||
if (frames->count == 1 || frameNo <= frames->first().no) return 0;
|
if (frames->count == 1 || frameNo <= frames->first().no) return 0;
|
||||||
|
|
|
@ -62,7 +62,7 @@ Animation::Animation() : pImpl(new Impl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Animation::frame(uint32_t no) noexcept
|
Result Animation::frame(float no) noexcept
|
||||||
{
|
{
|
||||||
auto loader = pImpl->picture->pImpl->loader.get();
|
auto loader = pImpl->picture->pImpl->loader.get();
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ Picture* Animation::picture() const noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t Animation::curFrame() const noexcept
|
float Animation::curFrame() const noexcept
|
||||||
{
|
{
|
||||||
auto loader = pImpl->picture->pImpl->loader.get();
|
auto loader = pImpl->picture->pImpl->loader.get();
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ uint32_t Animation::curFrame() const noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t Animation::totalFrame() const noexcept
|
float Animation::totalFrame() const noexcept
|
||||||
{
|
{
|
||||||
auto loader = pImpl->picture->pImpl->loader.get();
|
auto loader = pImpl->picture->pImpl->loader.get();
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,9 @@ class FrameModule: public LoadModule
|
||||||
public:
|
public:
|
||||||
virtual ~FrameModule() {}
|
virtual ~FrameModule() {}
|
||||||
|
|
||||||
virtual bool frame(uint32_t frameNo) = 0; //set the current frame number
|
virtual bool frame(float no) = 0; //set the current frame number
|
||||||
|
virtual float totalFrame() = 0; //return the total frame count
|
||||||
virtual uint32_t totalFrame() = 0; //return the total frame count
|
virtual float curFrame() = 0; //return the current frame number
|
||||||
virtual uint32_t curFrame() = 0; //return the current frame number
|
|
||||||
virtual float duration() = 0; //return the animation duration in seconds
|
virtual float duration() = 0; //return the animation duration in seconds
|
||||||
|
|
||||||
virtual bool animatable() override { return true; }
|
virtual bool animatable() override { return true; }
|
||||||
|
|
|
@ -40,16 +40,16 @@ TEST_CASE("Animation Basic", "[capiAnimation]")
|
||||||
|
|
||||||
//Negative cases
|
//Negative cases
|
||||||
REQUIRE(tvg_animation_set_frame(animation, 0) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
REQUIRE(tvg_animation_set_frame(animation, 0) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
||||||
uint32_t frame = 0;
|
auto frame = 0.0f;
|
||||||
REQUIRE(tvg_animation_set_frame(animation, frame) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
REQUIRE(tvg_animation_set_frame(animation, frame) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
||||||
|
|
||||||
REQUIRE(tvg_animation_get_frame(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
REQUIRE(tvg_animation_get_frame(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
||||||
REQUIRE(tvg_animation_get_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_get_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(frame == 0);
|
REQUIRE(frame == 0.0f);
|
||||||
|
|
||||||
REQUIRE(tvg_animation_get_total_frame(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
REQUIRE(tvg_animation_get_total_frame(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
||||||
REQUIRE(tvg_animation_get_total_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_get_total_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(frame == 0);
|
REQUIRE(frame == 0.0f);
|
||||||
|
|
||||||
REQUIRE(tvg_animation_get_duration(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
REQUIRE(tvg_animation_get_duration(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
||||||
float duration = 0.0f;
|
float duration = 0.0f;
|
||||||
|
@ -79,13 +79,13 @@ TEST_CASE("Animation Lottie", "[capiAnimation]")
|
||||||
REQUIRE(tvg_picture_load(picture, TEST_DIR"/invalid.json") == TVG_RESULT_INVALID_ARGUMENT);
|
REQUIRE(tvg_picture_load(picture, TEST_DIR"/invalid.json") == TVG_RESULT_INVALID_ARGUMENT);
|
||||||
REQUIRE(tvg_picture_load(picture, TEST_DIR"/test.json") == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_picture_load(picture, TEST_DIR"/test.json") == TVG_RESULT_SUCCESS);
|
||||||
|
|
||||||
uint32_t frame;
|
float frame;
|
||||||
REQUIRE(tvg_animation_get_total_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_get_total_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(frame == 120);
|
REQUIRE(frame == Approx(120).margin(004004));
|
||||||
|
|
||||||
REQUIRE(tvg_animation_set_frame(animation, frame - 1) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_set_frame(animation, frame - 1) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(tvg_animation_get_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_get_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(frame == 119);
|
REQUIRE(frame == Approx(119).margin(004004));
|
||||||
|
|
||||||
float duration;
|
float duration;
|
||||||
REQUIRE(tvg_animation_get_duration(animation, &duration) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_animation_get_duration(animation, &duration) == TVG_RESULT_SUCCESS);
|
||||||
|
|
|
@ -39,9 +39,9 @@ TEST_CASE("Animation Basic", "[tvgAnimation]")
|
||||||
REQUIRE(picture->identifier == Picture::identifier);
|
REQUIRE(picture->identifier == Picture::identifier);
|
||||||
|
|
||||||
//Negative cases
|
//Negative cases
|
||||||
REQUIRE(animation->frame(0) == Result::InsufficientCondition);
|
REQUIRE(animation->frame(0.0f) == Result::InsufficientCondition);
|
||||||
REQUIRE(animation->curFrame() == 0);
|
REQUIRE(animation->curFrame() == 0.0f);
|
||||||
REQUIRE(animation->totalFrame() == 0);
|
REQUIRE(animation->totalFrame() == 0.0f);
|
||||||
REQUIRE(animation->duration() == 0.0f);
|
REQUIRE(animation->duration() == 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ TEST_CASE("Animation Lottie", "[tvgAnimation]")
|
||||||
REQUIRE(picture->load(TEST_DIR"/invalid.json") == Result::InvalidArguments);
|
REQUIRE(picture->load(TEST_DIR"/invalid.json") == Result::InvalidArguments);
|
||||||
REQUIRE(picture->load(TEST_DIR"/test.json") == Result::Success);
|
REQUIRE(picture->load(TEST_DIR"/test.json") == Result::Success);
|
||||||
|
|
||||||
REQUIRE(animation->totalFrame() == 120);
|
REQUIRE(animation->totalFrame() == Approx(120).margin(004004));
|
||||||
REQUIRE(animation->curFrame() == 0);
|
REQUIRE(animation->curFrame() == 0);
|
||||||
REQUIRE(animation->duration() == Approx(4).margin(004004));
|
REQUIRE(animation->duration() == Approx(4).margin(004004));
|
||||||
REQUIRE(animation->frame(20) == Result::Success);
|
REQUIRE(animation->frame(20) == Result::Success);
|
||||||
|
|
Loading…
Add table
Reference in a new issue