mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
lottie/builder: revise the render context for saving memory.
Allocate repeater context only when it's valid.
This commit is contained in:
parent
820547562c
commit
e1f1b9656b
1 changed files with 46 additions and 41 deletions
|
@ -34,14 +34,8 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
struct RenderContext
|
struct RenderRepeater
|
||||||
{
|
{
|
||||||
Shape* propagator = nullptr;
|
|
||||||
Shape* merging = nullptr; //merging shapes if possible (if shapes have same properties)
|
|
||||||
LottieObject** begin = nullptr; //iteration entry point
|
|
||||||
float roundness = 0.0f;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int cnt;
|
int cnt;
|
||||||
float offset;
|
float offset;
|
||||||
Point position;
|
Point position;
|
||||||
|
@ -52,9 +46,16 @@ struct RenderContext
|
||||||
uint8_t endOpacity;
|
uint8_t endOpacity;
|
||||||
bool interpOpacity;
|
bool interpOpacity;
|
||||||
bool inorder;
|
bool inorder;
|
||||||
bool valid = false;
|
};
|
||||||
} repeater;
|
|
||||||
|
|
||||||
|
|
||||||
|
struct RenderContext
|
||||||
|
{
|
||||||
|
Shape* propagator = nullptr;
|
||||||
|
Shape* merging = nullptr; //merging shapes if possible (if shapes have same properties)
|
||||||
|
LottieObject** begin = nullptr; //iteration entry point
|
||||||
|
RenderRepeater* repeater = nullptr;
|
||||||
|
float roundness = 0.0f;
|
||||||
bool fragmented = false; //context has been separated. allow adding visual properties(fill/stroking) if it is false.
|
bool fragmented = false; //context has been separated. allow adding visual properties(fill/stroking) if it is false.
|
||||||
|
|
||||||
RenderContext()
|
RenderContext()
|
||||||
|
@ -65,12 +66,16 @@ struct RenderContext
|
||||||
~RenderContext()
|
~RenderContext()
|
||||||
{
|
{
|
||||||
delete(propagator);
|
delete(propagator);
|
||||||
|
delete(repeater);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderContext(const RenderContext& rhs)
|
RenderContext(const RenderContext& rhs)
|
||||||
{
|
{
|
||||||
propagator = static_cast<Shape*>(rhs.propagator->duplicate());
|
propagator = static_cast<Shape*>(rhs.propagator->duplicate());
|
||||||
repeater = rhs.repeater;
|
if (rhs.repeater) {
|
||||||
|
repeater = new RenderRepeater();
|
||||||
|
*repeater = *rhs.repeater;
|
||||||
|
}
|
||||||
roundness = rhs.roundness;
|
roundness = rhs.roundness;
|
||||||
fragmented = rhs.fragmented;
|
fragmented = rhs.fragmented;
|
||||||
}
|
}
|
||||||
|
@ -311,26 +316,26 @@ 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, int32_t frameNo, unique_ptr<Shape> path, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
auto& repeater = ctx.repeater;
|
auto repeater = ctx.repeater;
|
||||||
|
|
||||||
Array<Shape*> shapes;
|
Array<Shape*> shapes;
|
||||||
shapes.reserve(repeater.cnt);
|
shapes.reserve(repeater->cnt);
|
||||||
|
|
||||||
for (int i = 0; i < repeater.cnt; ++i) {
|
for (int i = 0; i < repeater->cnt; ++i) {
|
||||||
auto multiplier = repeater.offset + static_cast<float>(i);
|
auto multiplier = repeater->offset + static_cast<float>(i);
|
||||||
|
|
||||||
auto shape = static_cast<Shape*>(ctx.propagator->duplicate());
|
auto shape = static_cast<Shape*>(ctx.propagator->duplicate());
|
||||||
P(shape)->rs.path = P(path.get())->rs.path;
|
P(shape)->rs.path = P(path.get())->rs.path;
|
||||||
|
|
||||||
auto opacity = repeater.interpOpacity ? mathLerp<uint8_t>(repeater.startOpacity, repeater.endOpacity, static_cast<float>(i + 1) / repeater.cnt) : repeater.startOpacity;
|
auto opacity = repeater->interpOpacity ? mathLerp<uint8_t>(repeater->startOpacity, repeater->endOpacity, static_cast<float>(i + 1) / repeater->cnt) : repeater->startOpacity;
|
||||||
shape->opacity(opacity);
|
shape->opacity(opacity);
|
||||||
|
|
||||||
Matrix m;
|
Matrix m;
|
||||||
mathIdentity(&m);
|
mathIdentity(&m);
|
||||||
mathTranslate(&m, repeater.position.x * multiplier + repeater.anchor.x, repeater.position.y * multiplier + repeater.anchor.y);
|
mathTranslate(&m, repeater->position.x * multiplier + repeater->anchor.x, repeater->position.y * multiplier + repeater->anchor.y);
|
||||||
mathScale(&m, powf(repeater.scale.x * 0.01f, multiplier), powf(repeater.scale.y * 0.01f, multiplier));
|
mathScale(&m, powf(repeater->scale.x * 0.01f, multiplier), powf(repeater->scale.y * 0.01f, multiplier));
|
||||||
mathRotate(&m, repeater.rotation * multiplier);
|
mathRotate(&m, repeater->rotation * multiplier);
|
||||||
mathTranslateR(&m, -repeater.anchor.x, -repeater.anchor.y);
|
mathTranslateR(&m, -repeater->anchor.x, -repeater->anchor.y);
|
||||||
|
|
||||||
auto pm = PP(shape)->transform();
|
auto pm = PP(shape)->transform();
|
||||||
shape->transform(pm ? mathMultiply(&m, pm) : m);
|
shape->transform(pm ? mathMultiply(&m, pm) : m);
|
||||||
|
@ -344,7 +349,7 @@ static void _repeat(LottieGroup* parent, int32_t frameNo, unique_ptr<Shape> path
|
||||||
}
|
}
|
||||||
|
|
||||||
//push repeat shapes in order.
|
//push repeat shapes in order.
|
||||||
if (repeater.inorder) {
|
if (repeater->inorder) {
|
||||||
for (auto shape = shapes.data; shape < shapes.end(); ++shape) {
|
for (auto shape = shapes.data; shape < shapes.end(); ++shape) {
|
||||||
parent->scene->push(cast<Shape>(*shape));
|
parent->scene->push(cast<Shape>(*shape));
|
||||||
}
|
}
|
||||||
|
@ -368,7 +373,7 @@ static void _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo,
|
||||||
if (roundness > size.y * 0.5f) roundness = size.y * 0.5f;
|
if (roundness > size.y * 0.5f) roundness = size.y * 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.repeater.valid) {
|
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, frameNo, std::move(path), ctx);
|
||||||
|
@ -384,7 +389,7 @@ static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_t
|
||||||
auto position = ellipse->position(frameNo);
|
auto position = ellipse->position(frameNo);
|
||||||
auto size = ellipse->size(frameNo);
|
auto size = ellipse->size(frameNo);
|
||||||
|
|
||||||
if (ctx.repeater.valid) {
|
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, frameNo, std::move(path), ctx);
|
||||||
|
@ -397,7 +402,7 @@ static void _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_t
|
||||||
|
|
||||||
static void _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo, RenderContext& ctx)
|
static void _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
if (ctx.repeater.valid) {
|
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, frameNo, std::move(p), ctx);
|
||||||
|
@ -605,7 +610,7 @@ static void _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t f
|
||||||
|
|
||||||
auto identity = mathIdentity((const Matrix*)&matrix);
|
auto identity = mathIdentity((const Matrix*)&matrix);
|
||||||
|
|
||||||
if (ctx.repeater.valid) {
|
if (ctx.repeater) {
|
||||||
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());
|
||||||
|
@ -667,17 +672,17 @@ static void _updateRoundedCorner(LottieRoundedCorner* roundedCorner, int32_t fra
|
||||||
|
|
||||||
static void _updateRepeater(LottieRepeater* repeater, int32_t frameNo, RenderContext& ctx)
|
static void _updateRepeater(LottieRepeater* repeater, int32_t frameNo, RenderContext& ctx)
|
||||||
{
|
{
|
||||||
ctx.repeater.cnt = static_cast<int>(repeater->copies(frameNo));
|
if (!ctx.repeater) ctx.repeater = new RenderRepeater();
|
||||||
ctx.repeater.offset = repeater->offset(frameNo);
|
ctx.repeater->cnt = static_cast<int>(repeater->copies(frameNo));
|
||||||
ctx.repeater.position = repeater->position(frameNo);
|
ctx.repeater->offset = repeater->offset(frameNo);
|
||||||
ctx.repeater.anchor = repeater->anchor(frameNo);
|
ctx.repeater->position = repeater->position(frameNo);
|
||||||
ctx.repeater.scale = repeater->scale(frameNo);
|
ctx.repeater->anchor = repeater->anchor(frameNo);
|
||||||
ctx.repeater.rotation = repeater->rotation(frameNo);
|
ctx.repeater->scale = repeater->scale(frameNo);
|
||||||
ctx.repeater.startOpacity = repeater->startOpacity(frameNo);
|
ctx.repeater->rotation = repeater->rotation(frameNo);
|
||||||
ctx.repeater.endOpacity = repeater->endOpacity(frameNo);
|
ctx.repeater->startOpacity = repeater->startOpacity(frameNo);
|
||||||
ctx.repeater.inorder = repeater->inorder;
|
ctx.repeater->endOpacity = repeater->endOpacity(frameNo);
|
||||||
ctx.repeater.interpOpacity = (ctx.repeater.startOpacity == ctx.repeater.endOpacity) ? false : true;
|
ctx.repeater->inorder = repeater->inorder;
|
||||||
ctx.repeater.valid = true;
|
ctx.repeater->interpOpacity = (ctx.repeater->startOpacity == ctx.repeater->endOpacity) ? false : true;
|
||||||
|
|
||||||
ctx.merging = nullptr;
|
ctx.merging = nullptr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue