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
e17cc45ba8
commit
dc02e131e9
19 changed files with 137 additions and 146 deletions
|
@ -1671,7 +1671,7 @@ public:
|
|||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
Result frame(uint32_t no) noexcept;
|
||||
Result frame(float no) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves a picture instance associated with this animation instance.
|
||||
|
@ -1695,12 +1695,12 @@ public:
|
|||
*
|
||||
* @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()
|
||||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
uint32_t curFrame() const noexcept;
|
||||
float curFrame() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the total number of frames in the animation.
|
||||
|
@ -1712,7 +1712,7 @@ public:
|
|||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
uint32_t totalFrame() const noexcept;
|
||||
float totalFrame() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the duration of the animation in seconds.
|
||||
|
|
|
@ -2173,7 +2173,7 @@ TVG_API Tvg_Animation* tvg_animation_new();
|
|||
*
|
||||
* \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);
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -2205,7 +2205,7 @@ TVG_API Tvg_Paint* tvg_animation_get_picture(Tvg_Animation* animation);
|
|||
* \see tvg_animation_get_total_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);
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -2221,7 +2221,7 @@ TVG_API Tvg_Result tvg_animation_get_frame(Tvg_Animation* animation, uint32_t* n
|
|||
* \note Frame numbering starts from 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);
|
||||
|
||||
|
||||
/*!
|
||||
|
|
|
@ -713,14 +713,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;
|
||||
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;
|
||||
*no = reinterpret_cast<Animation*>(animation)->curFrame();
|
||||
|
@ -728,7 +728,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;
|
||||
*cnt = reinterpret_cast<Animation*>(animation)->totalFrame();
|
||||
|
|
|
@ -149,10 +149,9 @@ public:
|
|||
return val(animation->totalFrame());
|
||||
}
|
||||
|
||||
bool frame(uint32_t no)
|
||||
bool frame(float no)
|
||||
{
|
||||
if (!canvas || !animation) return false;
|
||||
if (animation->curFrame() == no) return true;
|
||||
if (animation->frame(no) != Result::Success) {
|
||||
errorMsg = "frame() fail";
|
||||
return false;
|
||||
|
|
|
@ -33,10 +33,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, tvg::Animation* animation, float progres
|
|||
if (!canvas) return;
|
||||
|
||||
//Update animation frame only when it's changed
|
||||
auto frame = lroundf(animation->totalFrame() * progress);
|
||||
|
||||
if (frame != animation->curFrame()) {
|
||||
animation->frame(frame);
|
||||
if (animation->frame(animation->totalFrame() * progress) == tvg::Result::Success) {
|
||||
canvas->update(animation->picture());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,19 +257,18 @@ void transitCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress
|
|||
{
|
||||
if (!canvas) return;
|
||||
|
||||
uint32_t total_frame = 0;
|
||||
float total_frame = 0.0f;
|
||||
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);
|
||||
|
||||
//Update animation frame only when it's changed
|
||||
if (new_frame == cur_frame) return;
|
||||
|
||||
tvg_animation_set_frame(animation, new_frame);
|
||||
if (tvg_animation_set_frame(animation, new_frame) == TVG_RESULT_SUCCESS) {
|
||||
tvg_canvas_update_paint(canvas, tvg_animation_get_picture(animation));
|
||||
}
|
||||
|
||||
//Draw the canvas
|
||||
tvg_canvas_draw(canvas);
|
||||
|
|
|
@ -95,15 +95,11 @@ void tvgUpdateCmds(Elm_Transit_Effect *effect, Elm_Transit* transit, double prog
|
|||
auto animation = static_cast<tvg::Animation*>(effect);
|
||||
|
||||
//Update animation frame only when it's changed
|
||||
auto frame = lroundf(animation->totalFrame() * progress);
|
||||
|
||||
if (frame != animation->curFrame()) {
|
||||
auto before = ecore_time_get();
|
||||
animation->frame(frame);
|
||||
animation->frame(animation->totalFrame() * progress);
|
||||
auto after = ecore_time_get();
|
||||
updateTime += after - before;
|
||||
}
|
||||
}
|
||||
|
||||
void tvgSwTest(uint32_t* buffer)
|
||||
{
|
||||
|
|
|
@ -83,8 +83,8 @@ struct RenderContext
|
|||
};
|
||||
|
||||
|
||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, queue<RenderContext>& contexts);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo);
|
||||
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo);
|
||||
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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 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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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->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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -316,7 +316,7 @@ static Shape* _draw(LottieGroup* parent, int32_t frameNo, RenderContext& ctx)
|
|||
|
||||
|
||||
//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;
|
||||
|
||||
|
@ -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 size = rect->size(frameNo);
|
||||
|
@ -378,15 +378,15 @@ static void _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo,
|
|||
if (ctx.repeater) {
|
||||
auto path = Shape::gen();
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 size = ellipse->size(frameNo);
|
||||
|
@ -394,22 +394,22 @@ static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_t
|
|||
if (ctx.repeater) {
|
||||
auto path = Shape::gen();
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
auto p = Shape::gen();
|
||||
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 {
|
||||
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)) {
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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?
|
||||
Matrix matrix;
|
||||
|
@ -616,9 +616,9 @@ static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t f
|
|||
auto p = Shape::gen();
|
||||
if (star->type == LottiePolyStar::Star) _updateStar(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 {
|
||||
auto merging = _draw(parent, frameNo, ctx);
|
||||
auto merging = _draw(parent, ctx);
|
||||
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||
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;
|
||||
|
||||
|
@ -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);
|
||||
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();
|
||||
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;
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -1021,7 +1021,7 @@ static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool LottieBuilder::update(LottieComposition* comp, int32_t frameNo)
|
||||
bool LottieBuilder::update(LottieComposition* comp, float frameNo)
|
||||
{
|
||||
frameNo += comp->startFrame;
|
||||
if (frameNo < comp->startFrame) frameNo = comp->startFrame;
|
||||
|
|
|
@ -29,7 +29,7 @@ struct LottieComposition;
|
|||
|
||||
struct LottieBuilder
|
||||
{
|
||||
bool update(LottieComposition* comp, int32_t frameNo);
|
||||
bool update(LottieComposition* comp, float progress);
|
||||
void build(LottieComposition* comp);
|
||||
};
|
||||
|
||||
|
|
|
@ -191,7 +191,8 @@ bool LottieLoader::header()
|
|||
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);
|
||||
|
||||
|
@ -286,6 +287,10 @@ bool LottieLoader::read()
|
|||
|
||||
TaskScheduler::request(this);
|
||||
|
||||
if (comp && TaskScheduler::threads() == 0) {
|
||||
frameCnt = comp->frameCnt();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (!comp || frameNo >= comp->frameCnt()) return false;
|
||||
|
||||
this->frameNo = frameNo;
|
||||
this->frameNo = no;
|
||||
|
||||
TaskScheduler::request(this);
|
||||
|
||||
|
@ -325,16 +328,13 @@ bool LottieLoader::frame(uint32_t frameNo)
|
|||
}
|
||||
|
||||
|
||||
uint32_t LottieLoader::totalFrame()
|
||||
float LottieLoader::totalFrame()
|
||||
{
|
||||
this->done();
|
||||
|
||||
if (!comp) return 0;
|
||||
return comp->frameCnt();
|
||||
return frameCnt;
|
||||
}
|
||||
|
||||
|
||||
uint32_t LottieLoader::curFrame()
|
||||
float LottieLoader::curFrame()
|
||||
{
|
||||
return frameNo;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,9 @@ class LottieLoader : public FrameModule, public Task
|
|||
public:
|
||||
const char* content = nullptr; //lottie file data
|
||||
uint32_t size = 0; //lottie data size
|
||||
uint32_t frameNo = 0; //current frame number
|
||||
float frameDuration;
|
||||
float frameNo = 0.0f; //current frame number
|
||||
float frameCnt = 0.0f;
|
||||
float frameDuration = 0.0f;
|
||||
|
||||
LottieBuilder* builder = nullptr;
|
||||
LottieComposition* comp = nullptr;
|
||||
|
@ -57,9 +58,9 @@ public:
|
|||
unique_ptr<Paint> paint() override;
|
||||
|
||||
//Frame Controls
|
||||
bool frame(uint32_t frameNo) override;
|
||||
uint32_t totalFrame() override;
|
||||
uint32_t curFrame() override;
|
||||
bool frame(float no) override;
|
||||
float totalFrame() override;
|
||||
float curFrame() override;
|
||||
float duration() override;
|
||||
void sync() override;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
/* 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 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;
|
||||
|
||||
|
@ -145,14 +145,14 @@ void LottieLayer::prepare()
|
|||
}
|
||||
|
||||
|
||||
int32_t LottieLayer::remap(int32_t frameNo)
|
||||
float LottieLayer::remap(float frameNo)
|
||||
{
|
||||
if (timeRemap.frames || timeRemap.value) {
|
||||
frameNo = comp->frameAtTime(timeRemap(frameNo));
|
||||
} else {
|
||||
frameNo -= startFrame;
|
||||
}
|
||||
return (int32_t)(frameNo / timeStretch);
|
||||
return (frameNo / timeStretch);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,17 +49,17 @@ struct LottieStroke
|
|||
return dashattr->value[no];
|
||||
}
|
||||
|
||||
float dashOffset(int32_t frameNo)
|
||||
float dashOffset(float frameNo)
|
||||
{
|
||||
return dash(0)(frameNo);
|
||||
}
|
||||
|
||||
float dashGap(int32_t frameNo)
|
||||
float dashGap(float frameNo)
|
||||
{
|
||||
return dash(2)(frameNo);
|
||||
}
|
||||
|
||||
float dashSize(int32_t frameNo)
|
||||
float dashSize(float frameNo)
|
||||
{
|
||||
auto d = dash(1)(frameNo);
|
||||
if (d == 0.0f) return 0.1f;
|
||||
|
@ -177,7 +177,7 @@ struct LottieGradient
|
|||
return false;
|
||||
}
|
||||
|
||||
Fill* fill(int32_t frameNo);
|
||||
Fill* fill(float frameNo);
|
||||
|
||||
LottiePoint start = 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;
|
||||
}
|
||||
|
||||
void segment(int32_t frameNo, float& start, float& end);
|
||||
void segment(float frameNo, float& start, float& end);
|
||||
|
||||
LottieFloat start = 0.0f;
|
||||
LottieFloat end = 0.0f;
|
||||
|
@ -507,7 +507,7 @@ struct LottieLayer : LottieGroup
|
|||
delete(transform);
|
||||
}
|
||||
|
||||
uint8_t opacity(int32_t frameNo)
|
||||
uint8_t opacity(float frameNo)
|
||||
{
|
||||
//return zero if the visibility is false.
|
||||
if (type == Null) return 255;
|
||||
|
@ -515,7 +515,7 @@ struct LottieLayer : LottieGroup
|
|||
}
|
||||
|
||||
void prepare();
|
||||
int32_t remap(int32_t frameNo);
|
||||
float remap(float frameNo);
|
||||
|
||||
//Optimize: compact data??
|
||||
RGB24 color;
|
||||
|
@ -534,16 +534,16 @@ struct LottieLayer : LottieGroup
|
|||
|
||||
float timeStretch = 1.0f;
|
||||
uint32_t w = 0, h = 0;
|
||||
int32_t inFrame = 0;
|
||||
int32_t outFrame = 0;
|
||||
uint32_t startFrame = 0;
|
||||
float inFrame = 0.0f;
|
||||
float outFrame = 0.0f;
|
||||
float startFrame = 0.0f;
|
||||
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 {
|
||||
int32_t frameNo = -1;
|
||||
float frameNo = -1.0f;
|
||||
Matrix matrix;
|
||||
uint8_t opacity;
|
||||
} cache;
|
||||
|
@ -583,7 +583,7 @@ struct LottieComposition
|
|||
char* version = nullptr;
|
||||
char* name = nullptr;
|
||||
uint32_t w, h;
|
||||
int32_t startFrame, endFrame;
|
||||
float startFrame, endFrame;
|
||||
float frameRate;
|
||||
Array<LottieObject*> assets;
|
||||
Array<LottieInterpolator*> interpolators;
|
||||
|
|
|
@ -382,7 +382,7 @@ void LottieParser::parseKeyFrame(T& prop)
|
|||
}
|
||||
}
|
||||
} else if (!strcmp(key, "t")) {
|
||||
frame.no = lroundf(getFloat());
|
||||
frame.no = getFloat();
|
||||
} else if (!strcmp(key, "s")) {
|
||||
getValue(frame.value);
|
||||
} else if (!strcmp(key, "e")) {
|
||||
|
@ -1003,9 +1003,9 @@ LottieLayer* LottieParser::parseLayer()
|
|||
}
|
||||
else if (!strcmp(key, "ao")) layer->autoOrient = getInt();
|
||||
else if (!strcmp(key, "shapes")) parseShapes(layer);
|
||||
else if (!strcmp(key, "ip")) layer->inFrame = lroundf(getFloat());
|
||||
else if (!strcmp(key, "op")) layer->outFrame = lroundf(getFloat());
|
||||
else if (!strcmp(key, "st")) layer->startFrame = lroundf(getFloat());
|
||||
else if (!strcmp(key, "ip")) layer->inFrame = getFloat();
|
||||
else if (!strcmp(key, "op")) layer->outFrame = getFloat();
|
||||
else if (!strcmp(key, "st")) layer->startFrame = getFloat();
|
||||
else if (!strcmp(key, "bm")) layer->blendMethod = getBlendMethod();
|
||||
else if (!strcmp(key, "parent")) layer->pid = getInt();
|
||||
else if (!strcmp(key, "tm")) parseTimeRemap(layer);
|
||||
|
@ -1091,8 +1091,8 @@ bool LottieParser::parse()
|
|||
while (auto key = nextObjectKey()) {
|
||||
if (!strcmp(key, "v")) comp->version = getStringCopy();
|
||||
else if (!strcmp(key, "fr")) comp->frameRate = getFloat();
|
||||
else if (!strcmp(key, "ip")) comp->startFrame = lroundf(getFloat());
|
||||
else if (!strcmp(key, "op")) comp->endFrame = lroundf(getFloat());
|
||||
else if (!strcmp(key, "ip")) comp->startFrame = getFloat();
|
||||
else if (!strcmp(key, "op")) comp->endFrame = getFloat();
|
||||
else if (!strcmp(key, "w")) comp->w = getInt();
|
||||
else if (!strcmp(key, "h")) comp->h = getInt();
|
||||
else if (!strcmp(key, "nm")) comp->name = getStringCopy();
|
||||
|
|
|
@ -93,13 +93,13 @@ template<typename T>
|
|||
struct LottieScalarFrame
|
||||
{
|
||||
T value; //keyframe value
|
||||
int32_t no; //frame number
|
||||
float no; //frame number
|
||||
LottieInterpolator* interpolator;
|
||||
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 (hold) {
|
||||
|
@ -115,16 +115,16 @@ template<typename T>
|
|||
struct LottieVectorFrame
|
||||
{
|
||||
T value; //keyframe value
|
||||
int32_t no; //frame number
|
||||
float no; //frame number
|
||||
LottieInterpolator* interpolator;
|
||||
T outTangent, inTangent;
|
||||
float length;
|
||||
bool hasTangent = 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 (hold) {
|
||||
|
@ -141,10 +141,10 @@ struct LottieVectorFrame
|
|||
}
|
||||
}
|
||||
|
||||
float angle(LottieVectorFrame* next, int32_t frameNo)
|
||||
float angle(LottieVectorFrame* next, float frameNo)
|
||||
{
|
||||
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);
|
||||
Bezier bz = {value, value + outTangent, next->value + inTangent, next->value};
|
||||
t = bezAt(bz, t * length, length);
|
||||
|
@ -190,7 +190,7 @@ struct LottieProperty
|
|||
return (*frames)[frames->count];
|
||||
}
|
||||
|
||||
T operator()(int32_t frameNo)
|
||||
T operator()(float frameNo)
|
||||
{
|
||||
if (!frames) return value;
|
||||
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||
|
@ -202,7 +202,7 @@ struct LottieProperty
|
|||
while (low <= high) {
|
||||
auto mid = low + (high - low) / 2;
|
||||
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 high = mid - 1;
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ struct LottieProperty
|
|||
return (frame - 1)->interpolate(frame, frameNo);
|
||||
}
|
||||
|
||||
float angle(int32_t frameNo) { return 0; }
|
||||
float angle(float frameNo) { return 0; }
|
||||
void prepare() {}
|
||||
};
|
||||
|
||||
|
@ -258,7 +258,7 @@ struct LottiePathSet
|
|||
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) {
|
||||
copy(value, cmds);
|
||||
|
@ -284,7 +284,7 @@ struct LottiePathSet
|
|||
while (low <= high) {
|
||||
auto mid = low + (high - low) / 2;
|
||||
auto frame = frames->data + mid;
|
||||
if (frameNo == frame->no) {
|
||||
if (mathEqual(frameNo, frame->no)) {
|
||||
copy(frame->value, cmds);
|
||||
copy(frame->value, pts);
|
||||
return true;
|
||||
|
@ -300,7 +300,7 @@ struct LottiePathSet
|
|||
auto pframe = frame - 1;
|
||||
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->hold) {
|
||||
|
@ -358,7 +358,7 @@ struct LottieColorStop
|
|||
return (*frames)[frames->count];
|
||||
}
|
||||
|
||||
void operator()(int32_t frameNo, Fill* fill)
|
||||
void operator()(float frameNo, Fill* fill)
|
||||
{
|
||||
if (!frames) {
|
||||
fill->colorStops(value.data, count);
|
||||
|
@ -381,7 +381,7 @@ struct LottieColorStop
|
|||
while (low <= high) {
|
||||
auto mid = low + (high - low) / 2;
|
||||
auto frame = frames->data + mid;
|
||||
if (frameNo == frame->no) {
|
||||
if (mathEqual(frameNo, frame->no)) {
|
||||
fill->colorStops(frame->value.data, count);
|
||||
return;
|
||||
} else if (frameNo > frame->no) {
|
||||
|
@ -394,7 +394,7 @@ struct LottieColorStop
|
|||
//interpolate
|
||||
auto frame = frames->data + low;
|
||||
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->hold) {
|
||||
|
@ -453,7 +453,7 @@ struct LottiePosition
|
|||
return (*frames)[frames->count];
|
||||
}
|
||||
|
||||
Point operator()(int32_t frameNo)
|
||||
Point operator()(float frameNo)
|
||||
{
|
||||
if (!frames) return value;
|
||||
if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value;
|
||||
|
@ -465,7 +465,7 @@ struct LottiePosition
|
|||
while (low <= high) {
|
||||
auto mid = low + (high - low) / 2;
|
||||
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 high = mid - 1;
|
||||
}
|
||||
|
@ -474,7 +474,7 @@ struct LottiePosition
|
|||
return (frame - 1)->interpolate(frame, frameNo);
|
||||
}
|
||||
|
||||
float angle(int32_t frameNo)
|
||||
float angle(float frameNo)
|
||||
{
|
||||
if (!frames) 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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -33,10 +33,9 @@ class FrameModule: public LoadModule
|
|||
public:
|
||||
virtual ~FrameModule() {}
|
||||
|
||||
virtual bool frame(uint32_t frameNo) = 0; //set the current frame number
|
||||
|
||||
virtual uint32_t totalFrame() = 0; //return the total frame count
|
||||
virtual uint32_t curFrame() = 0; //return 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 float curFrame() = 0; //return the current frame number
|
||||
virtual float duration() = 0; //return the animation duration in seconds
|
||||
|
||||
virtual bool animatable() override { return true; }
|
||||
|
|
|
@ -40,16 +40,16 @@ TEST_CASE("Animation Basic", "[capiAnimation]")
|
|||
|
||||
//Negative cases
|
||||
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_get_frame(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
||||
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, &frame) == TVG_RESULT_SUCCESS);
|
||||
REQUIRE(frame == 0);
|
||||
REQUIRE(frame == 0.0f);
|
||||
|
||||
REQUIRE(tvg_animation_get_duration(animation, nullptr) == TVG_RESULT_INVALID_ARGUMENT);
|
||||
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"/test.json") == TVG_RESULT_SUCCESS);
|
||||
|
||||
uint32_t frame;
|
||||
float frame;
|
||||
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_get_frame(animation, &frame) == TVG_RESULT_SUCCESS);
|
||||
REQUIRE(frame == 119);
|
||||
REQUIRE(frame == Approx(119).margin(004004));
|
||||
|
||||
float duration;
|
||||
REQUIRE(tvg_animation_get_duration(animation, &duration) == TVG_RESULT_SUCCESS);
|
||||
|
|
|
@ -39,9 +39,9 @@ TEST_CASE("Animation Basic", "[tvgAnimation]")
|
|||
REQUIRE(picture->identifier == Picture::identifier);
|
||||
|
||||
//Negative cases
|
||||
REQUIRE(animation->frame(0) == Result::InsufficientCondition);
|
||||
REQUIRE(animation->curFrame() == 0);
|
||||
REQUIRE(animation->totalFrame() == 0);
|
||||
REQUIRE(animation->frame(0.0f) == Result::InsufficientCondition);
|
||||
REQUIRE(animation->curFrame() == 0.0f);
|
||||
REQUIRE(animation->totalFrame() == 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"/test.json") == Result::Success);
|
||||
|
||||
REQUIRE(animation->totalFrame() == 120);
|
||||
REQUIRE(animation->totalFrame() == Approx(120).margin(004004));
|
||||
REQUIRE(animation->curFrame() == 0);
|
||||
REQUIRE(animation->duration() == Approx(4).margin(004004));
|
||||
REQUIRE(animation->frame(20) == Result::Success);
|
||||
|
|
Loading…
Add table
Reference in a new issue