mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 11:36:25 +00:00
loader/lottie: fix a missing layer timeremap.
The frame count should have been multiplied with the timeStretch property. also newly implemented the TimeRemap(tm) property
This commit is contained in:
parent
6f8504d3b9
commit
d7c70c5371
6 changed files with 130 additions and 75 deletions
1
src/examples/images/funky_chicken.json
Normal file
1
src/examples/images/funky_chicken.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -9,6 +9,7 @@ source_file = [
|
||||||
'tvgLottieBuilder.cpp',
|
'tvgLottieBuilder.cpp',
|
||||||
'tvgLottieInterpolator.cpp',
|
'tvgLottieInterpolator.cpp',
|
||||||
'tvgLottieLoader.cpp',
|
'tvgLottieLoader.cpp',
|
||||||
|
'tvgLottieModel.cpp',
|
||||||
'tvgLottieParserHandler.cpp',
|
'tvgLottieParserHandler.cpp',
|
||||||
'tvgLottieParser.cpp'
|
'tvgLottieParser.cpp'
|
||||||
]
|
]
|
||||||
|
|
101
src/loaders/lottie/tvgLottieModel.cpp
Normal file
101
src/loaders/lottie/tvgLottieModel.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "tvgLottieModel.h"
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* Internal Class Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* External Class Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
Fill* LottieGradient::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieGroup::prepare(LottieObject::Type type)
|
||||||
|
{
|
||||||
|
LottieObject::type = type;
|
||||||
|
if (transform) statical &= transform->statical;
|
||||||
|
for (auto child = children.data; child < children.end(); ++child) {
|
||||||
|
statical &= (*child)->statical;
|
||||||
|
if (!statical) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t LottieLayer::remap(int32_t frameNo)
|
||||||
|
{
|
||||||
|
if (timeRemap.frames) {
|
||||||
|
frameNo = comp->frameAtTime(timeRemap(frameNo));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeStretch == 1.0f) return frameNo;
|
||||||
|
return (int32_t)(frameNo / timeStretch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,8 @@
|
||||||
#include "tvgLottieProperty.h"
|
#include "tvgLottieProperty.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieComposition;
|
||||||
|
|
||||||
struct LottieStroke
|
struct LottieStroke
|
||||||
{
|
{
|
||||||
bool dynamic()
|
bool dynamic()
|
||||||
|
@ -52,27 +54,7 @@ struct LottieGradient
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fill* fill(int32_t frameNo)
|
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 start = Point{0.0f, 0.0f};
|
||||||
LottiePoint end = Point{0.0f, 0.0f};
|
LottiePoint end = Point{0.0f, 0.0f};
|
||||||
|
@ -322,15 +304,7 @@ struct LottieGroup : LottieObject
|
||||||
delete(transform);
|
delete(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare(LottieObject::Type type = LottieObject::Group)
|
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)
|
virtual uint8_t opacity(int32_t frameNo)
|
||||||
{
|
{
|
||||||
|
@ -379,22 +353,16 @@ struct LottieLayer : LottieGroup
|
||||||
return LottieGroup::opacity(frameNo);
|
return LottieGroup::opacity(frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* frameRemap has the value in time domain(in sec)
|
int32_t remap(int32_t frameNo);
|
||||||
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
|
//Optimize: compact data??
|
||||||
|
RGB24 color = {255, 255, 255};
|
||||||
CompositeMethod matteType = CompositeMethod::None;
|
CompositeMethod matteType = CompositeMethod::None;
|
||||||
BlendMethod blendMethod = BlendMethod::Normal;
|
BlendMethod blendMethod = BlendMethod::Normal;
|
||||||
LottieLayer* parent = nullptr;
|
LottieLayer* parent = nullptr;
|
||||||
|
LottieFloat timeRemap = 0.0f;
|
||||||
|
LottieComposition* comp = nullptr;
|
||||||
|
|
||||||
float timeStretch = 1.0f;
|
float timeStretch = 1.0f;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
int32_t inFrame = 0;
|
int32_t inFrame = 0;
|
||||||
|
@ -419,47 +387,27 @@ struct LottieLayer : LottieGroup
|
||||||
|
|
||||||
struct LottieComposition
|
struct LottieComposition
|
||||||
{
|
{
|
||||||
~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
|
float duration() const
|
||||||
{
|
{
|
||||||
return frameDuration() / frameRate; // in second
|
return frameDuration() / frameRate; // in second
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t frameAtPos(float pos) const
|
int32_t frameAtTime(float timeInSec) const
|
||||||
{
|
{
|
||||||
if (pos < 0) pos = 0;
|
auto p = timeInSec / duration();
|
||||||
if (pos > 1) pos = 1;
|
if (p < 0.0f) p = 0.0f;
|
||||||
return (uint32_t)lroundf(pos * frameDuration());
|
else if (p > 1.0f) p = 1.0f;
|
||||||
}
|
return (int32_t)lroundf(p * frameDuration());
|
||||||
|
|
||||||
long frameAtTime(double timeInSec) const
|
|
||||||
{
|
|
||||||
return long(frameAtPos(timeInSec / duration()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t frameCnt() const
|
uint32_t frameCnt() const
|
||||||
{
|
{
|
||||||
return endFrame - startFrame + 1;
|
return frameDuration() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
long frameDuration() const
|
uint32_t frameDuration() const
|
||||||
{
|
{
|
||||||
return endFrame - startFrame;
|
return endFrame - startFrame;
|
||||||
}
|
}
|
||||||
|
|
|
@ -918,6 +918,13 @@ LottieObject* LottieParser::parseGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieParser::parseTimeRemap(LottieLayer* layer)
|
||||||
|
{
|
||||||
|
layer->comp = comp;
|
||||||
|
parseProperty(layer->timeRemap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LottieParser::parseShapes(LottieLayer* layer)
|
void LottieParser::parseShapes(LottieLayer* layer)
|
||||||
{
|
{
|
||||||
enterArray();
|
enterArray();
|
||||||
|
@ -956,11 +963,7 @@ LottieLayer* LottieParser::parseLayer()
|
||||||
else if (!strcmp(key, "st")) layer->startFrame = lroundf(getFloat());
|
else if (!strcmp(key, "st")) layer->startFrame = lroundf(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"))
|
else if (!strcmp(key, "tm")) parseTimeRemap(layer);
|
||||||
{
|
|
||||||
TVGLOG("LOTTIE", "Time Remap(tm) is not supported");
|
|
||||||
skip(key);
|
|
||||||
}
|
|
||||||
else if (!strcmp(key, "w")) layer->w = getInt();
|
else if (!strcmp(key, "w")) layer->w = getInt();
|
||||||
else if (!strcmp(key, "h")) layer->h = getInt();
|
else if (!strcmp(key, "h")) layer->h = getInt();
|
||||||
else if (!strcmp(key, "sw")) layer->w = getInt();
|
else if (!strcmp(key, "sw")) layer->w = getInt();
|
||||||
|
|
|
@ -83,6 +83,7 @@ private:
|
||||||
|
|
||||||
void parseObject(LottieGroup* parent);
|
void parseObject(LottieGroup* parent);
|
||||||
void parseShapes(LottieLayer* layer);
|
void parseShapes(LottieLayer* layer);
|
||||||
|
void parseTimeRemap(LottieLayer* layer);
|
||||||
void parseStrokeDash(LottieStroke* stroke);
|
void parseStrokeDash(LottieStroke* stroke);
|
||||||
void parseGradient(LottieGradient* gradient, const char* key);
|
void parseGradient(LottieGradient* gradient, const char* key);
|
||||||
void parseAssets();
|
void parseAssets();
|
||||||
|
|
Loading…
Add table
Reference in a new issue