Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for partial rendering. #512

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion inc/rlottie.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class RLOTTIE_API Surface {
* @brief Sets the Draw Area available on the Surface.
*
* Lottie will use the draw region size to generate frame image
* and will update only the draw rgion of the surface.
* and will update only the draw region of the surface.
*
* @param[in] x region area x position.
* @param[in] y region area y position.
Expand Down Expand Up @@ -421,6 +421,18 @@ class RLOTTIE_API Animation {
*/
void renderSync(size_t frameNo, Surface surface, bool keepAspectRatio=true);

/**
* @brief Renders the content to partial surface synchronously.
* for performance use the async rendering @see render
*
* @param[in] frameNo Content corresponds to the @p frameNo needs to be drawn
* @param[in] surface Surface in which content will be drawn
*
* @internal
*/
void renderPartialSync(size_t frameNo, Surface surface);


/**
* @brief Returns root layer of the composition updated with
* content of the Lottie resource at frame number @p frameNo.
Expand Down
19 changes: 19 additions & 0 deletions inc/rlottie_capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,25 @@ RLOTTIE_API size_t lottie_animation_get_frame_at_pos(const Lottie_Animation *ani
*/
RLOTTIE_API void lottie_animation_render(Lottie_Animation *animation, size_t frame_num, uint32_t *buffer, size_t width, size_t height, size_t bytes_per_line);

/**
* @brief Request to render the content of the frame @p frame_num to buffer @p buffer.
*
* @param[in] animation Animation object.
* @param[in] frame_num the frame number needs to be rendered.
* @param[in] buffer surface buffer use for rendering.
* @param[in] width width of the surface
* @param[in] height height of the surface
* @param[in] top offset to render from
* @param[in] bottom offset to render from
* @param[in] bytes_per_line stride of the surface in bytes.
*
*
* @ingroup Lottie_Animation
* @internal
*/
RLOTTIE_API void lottie_animation_render_partial(Lottie_Animation *animation, size_t frame_num, uint32_t *buffer, size_t width, size_t height, size_t top, size_t bottom, size_t bytes_per_line);


/**
* @brief Request to render the content of the frame @p frame_num to buffer @p buffer asynchronously.
*
Expand Down
18 changes: 18 additions & 0 deletions src/binding/c/lottieanimation_capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,24 @@ lottie_animation_render(Lottie_Animation_S *animation,
animation->mAnimation->renderSync(frame_number, surface);
}

RLOTTIE_API void
lottie_animation_render_partial(Lottie_Animation_S *animation,
size_t frame_number,
uint32_t *buffer,
size_t width,
size_t height,
size_t top,
size_t bottom,
size_t bytes_per_line)
{
if (!animation) return;

rlottie::Surface surface(buffer, width, height, bytes_per_line);
surface.setDrawRegion(0, top, width, bottom - top);
animation->mAnimation->renderPartialSync(frame_number, surface);
}


RLOTTIE_API void
lottie_animation_render_async(Lottie_Animation_S *animation,
size_t frame_number,
Expand Down
49 changes: 45 additions & 4 deletions src/lottie/lottieanimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@ class AnimationImpl {
public:
void init(std::shared_ptr<model::Composition> composition);
bool update(size_t frameNo, const VSize &size, bool keepAspectRatio);
bool updatePartial(size_t frameNo, const VSize &size, uint32_t offset);
VSize size() const { return mModel->size(); }
double duration() const { return mModel->duration(); }
double frameRate() const { return mModel->frameRate(); }
size_t totalFrame() const { return mModel->totalFrame(); }
size_t frameAtPos(double pos) const { return mModel->frameAtPos(pos); }
bool checkRender();
Surface render(size_t frameNo, const Surface &surface,
bool keepAspectRatio);
Surface renderPartial(size_t frameNo, const Surface &surface);
std::future<Surface> renderAsync(size_t frameNo, Surface &&surface,
bool keepAspectRatio);
const LOTLayerNode * renderTree(size_t frameNo, const VSize &size);
Expand Down Expand Up @@ -105,16 +108,34 @@ bool AnimationImpl::update(size_t frameNo, const VSize &size,
return mRenderer->update(int(frameNo), size, keepAspectRatio);
}

Surface AnimationImpl::render(size_t frameNo, const Surface &surface,
bool keepAspectRatio)
bool AnimationImpl::updatePartial(size_t frameNo, const VSize &size, uint32_t offset)
{
frameNo += mModel->startFrame();

if (frameNo > mModel->endFrame()) frameNo = mModel->endFrame();

if (frameNo < mModel->startFrame()) frameNo = mModel->startFrame();

return mRenderer->updatePartial(int(frameNo), size, offset);
}


bool AnimationImpl::checkRender()
{
bool renderInProgress = mRenderInProgress.load();
if (renderInProgress) {
vCritical << "Already Rendering Scheduled for this Animation";
return surface;
return false;
}

mRenderInProgress.store(true);
return true;
}

Surface AnimationImpl::render(size_t frameNo, const Surface &surface,
bool keepAspectRatio)
{
if (!checkRender()) return surface;

update(
frameNo,
VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())),
Expand All @@ -125,6 +146,21 @@ Surface AnimationImpl::render(size_t frameNo, const Surface &surface,
return surface;
}

Surface AnimationImpl::renderPartial(size_t frameNo, const Surface &surface)
{
if (!checkRender()) return surface;

updatePartial(
frameNo,
VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())),
uint32_t(surface.drawRegionPosY()));
mRenderer->renderPartial(surface);
mRenderInProgress.store(false);

return surface;
}


void AnimationImpl::init(std::shared_ptr<model::Composition> composition)
{
mModel = composition.get();
Expand Down Expand Up @@ -370,6 +406,11 @@ void Animation::renderSync(size_t frameNo, Surface surface,
{
d->render(frameNo, surface, keepAspectRatio);
}
void Animation::renderPartialSync(size_t frameNo, Surface surface)
{
d->renderPartial(frameNo, surface);
}


const LayerInfoList &Animation::layers() const
{
Expand Down
53 changes: 53 additions & 0 deletions src/lottie/lottieitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,35 @@ bool renderer::Composition::update(int frameNo, const VSize &size,
return true;
}

bool renderer::Composition::updatePartial(int frameNo, const VSize &size,
unsigned int offset)
{
// check if cached frame is same as requested frame.
if ((mViewSize.width() == size.width()) && (mCurFrameNo == frameNo) &&
(mOffset == offset))
return false;

mViewSize = size;
mCurFrameNo = frameNo;
mKeepAspectRatio = false;
mOffset = offset;

/*
* if viewbox dosen't scale exactly to the viewport
* we scale the viewbox keeping AspectRatioPreserved and then align the
* viewbox to the viewport using AlignCenter rule.
*/
VMatrix m;
VSize viewPort = mViewSize;
VSize viewBox = mModel->size();
float sx = float(viewPort.width()) / viewBox.width();
float ty = offset;
m.translate(0, -ty).scale(sx, sx);

mRootLayer->update(frameNo, m, 1.0);
return true;
}

bool renderer::Composition::render(const rlottie::Surface &surface)
{
mSurface.reset(reinterpret_cast<uint8_t *>(surface.buffer()),
Expand All @@ -170,6 +199,30 @@ bool renderer::Composition::render(const rlottie::Surface &surface)
return true;
}

bool renderer::Composition::renderPartial(const rlottie::Surface &surface)
{
mSurface.reset(reinterpret_cast<uint8_t *>(surface.buffer()),
uint32_t(surface.width()), uint32_t(surface.drawRegionHeight()),
uint32_t(surface.bytesPerLine()),
VBitmap::Format::ARGB32_Premultiplied);

/* schedule all preprocess task for this frame at once.
*/
VRect clip(0, 0, int(surface.drawRegionWidth()),
int(surface.drawRegionHeight()));
mRootLayer->preprocess(clip);

VPainter painter(&mSurface);
// set sub surface area for drawing.
painter.setDrawRegion(
VRect(int(surface.drawRegionPosX()), 0,
int(surface.drawRegionWidth()), int(surface.drawRegionHeight())));
mRootLayer->render(&painter, {}, {}, mSurfaceCache);
painter.end();
return true;
}


void renderer::Mask::update(int frameNo, const VMatrix &parentMatrix,
float /*parentAlpha*/, const DirtyFlag &flag)
{
Expand Down
3 changes: 3 additions & 0 deletions src/lottie/lottieitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,12 @@ class Composition {
public:
explicit Composition(std::shared_ptr<model::Composition> composition);
bool update(int frameNo, const VSize &size, bool keepAspectRatio);
bool updatePartial(int frameNo, const VSize &size, unsigned int offset);
VSize size() const { return mViewSize; }
void buildRenderTree();
const LOTLayerNode *renderTree() const;
bool render(const rlottie::Surface &surface);
bool renderPartial(const rlottie::Surface &surface);
void setValue(const std::string &keypath, LOTVariant &value);

private:
Expand All @@ -207,6 +209,7 @@ class Composition {
VArenaAlloc mAllocator{2048};
int mCurFrameNo;
bool mKeepAspectRatio{true};
unsigned int mOffset{0};
};

class Layer {
Expand Down