INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig)
#install header
-install(FILES inc/lotplayer.h inc/lotcommon.h src/binding/c/lotplayer_capi.h DESTINATION include)
+install(FILES inc/lottieanimation.h inc/lottieanimation_capi.h inc/lottiecommon.h DESTINATION include)
#install lib
install( TARGETS lottie-player EXPORT lottie-player-targets
#include"lottieview.h"
-using namespace lottieplayer;
+using namespace lottie;
static Eina_Bool
animator(void *data , double pos)
LottieView::LottieView(Evas *evas, bool renderMode, bool asyncRender):mVg(nullptr), mImage(nullptr)
{
+ mPlayer = nullptr;
mPalying = false;
mReverse = false;
mRepeatCount = 0;
mSpeed = 1;
mEvas = evas;
- mPlayer = new LOTPlayer();
mRenderMode = renderMode;
mAsyncRender = asyncRender;
if (mAnimator) ecore_animator_del(mAnimator);
if (mVg) evas_object_del(mVg);
if (mImage) evas_object_del(mImage);
- delete mPlayer;
}
Evas_Object *LottieView::getImage() {
void LottieView::seek(float pos)
{
+ if (!mPlayer) return;
+
if (mPalying && mReverse)
pos = 1.0 - pos;
mPos = pos;
+ // check if the pos maps to the current frame
+ if (mCurFrame == mPlayer->frameAtPos(mPos)) return;
+
+ mCurFrame = mPlayer->frameAtPos(mPos);
+
if (mRenderMode) {
- LOTBuffer buf;
- evas_object_image_size_get(mImage, &buf.width, &buf.height);
+ int width , height;
+ evas_object_image_size_get(mImage, &width, &height);
if (mAsyncRender) {
if (mRenderTask.valid()) return;
mDirty = true;
- buf.buffer = (uint32_t *)evas_object_image_data_get(mImage, EINA_TRUE);
- buf.bytesPerLine = evas_object_image_stride_get(mImage);
- mRenderTask = mPlayer->render(mPos, buf);
- mBuffer = buf;
+ auto buffer = (uint32_t *)evas_object_image_data_get(mImage, EINA_TRUE);
+ size_t bytesperline = evas_object_image_stride_get(mImage);
+ lottie::Surface surface(buffer, width, height, bytesperline);
+ mRenderTask = mPlayer->render(mCurFrame, surface);
// to force a redraw
- evas_object_image_data_update_add(mImage, 0 , 0, buf.width, buf.height);
+ evas_object_image_data_update_add(mImage, 0 , 0, surface.width(), surface.height());
} else {
- buf.buffer = (uint32_t *)evas_object_image_data_get(mImage, EINA_TRUE);
- buf.bytesPerLine = evas_object_image_stride_get(mImage);
- bool changed = mPlayer->renderSync(pos, buf);
- evas_object_image_data_set(mImage, buf.buffer);
- // if the buffer is updated notify the image object
- if (changed) {
- evas_object_image_data_update_add(mImage, 0 , 0, buf.width, buf.height);
- }
+ auto buffer = (uint32_t *)evas_object_image_data_get(mImage, EINA_TRUE);
+ size_t bytesperline = evas_object_image_stride_get(mImage);
+ lottie::Surface surface(buffer, width, height, bytesperline);
+ mPlayer->renderSync(mCurFrame, surface);
+ evas_object_image_data_set(mImage, surface.buffer());
+ evas_object_image_data_update_add(mImage, 0 , 0, surface.width(), surface.height());
}
} else {
- const std::vector<LOTNode *> &renderList = mPlayer->renderList(pos);
+ const std::vector<LOTNode *> &renderList = mPlayer->renderList(mCurFrame, mw, mh);
update(renderList);
}
}
void LottieView::render()
{
+ if (!mPlayer) return;
+
if (!mDirty) return;
mDirty = false;
if (mRenderMode) {
- if (!mBuffer.buffer) return;
- bool changed = false;
- if (mRenderTask.valid()) {
- changed = mRenderTask.get();
- }
- evas_object_image_data_set(mImage, mBuffer.buffer);
- // if the buffer is updated notify the image object
- if (changed) {
- evas_object_image_data_update_add(mImage, 0 , 0, mBuffer.width, mBuffer.height);
- }
- mBuffer.buffer = nullptr;
- } else {
- const std::vector<LOTNode *> &renderList = mPlayer->renderList(mPos);
- update(renderList);
+ if (!mRenderTask.valid()) return;
+ auto surface = mRenderTask.get();
+ evas_object_image_data_set(mImage, surface.buffer());
+ evas_object_image_data_update_add(mImage, 0 , 0, surface.width(), surface.height());
}
}
void LottieView::setFilePath(const char *filePath)
{
- mPlayer->setFilePath(filePath);
- mFrameRate = mPlayer->frameRate();
- mTotalFrame = mPlayer->totalFrame();
+ if (mPlayer = Animation::loadFromFile(filePath)) {
+ mFrameRate = mPlayer->frameRate();
+ mTotalFrame = mPlayer->totalFrame();
+ } else {
+ printf("load failed file %s\n", filePath);
+ }
}
void LottieView::loadFromData(const char *jsonData, const char *key)
{
- mPlayer->loadFromData(jsonData, key);
- mFrameRate = mPlayer->frameRate();
- mTotalFrame = mPlayer->totalFrame();
+ if (mPlayer = Animation::loadFromData(jsonData, key)) {
+ mFrameRate = mPlayer->frameRate();
+ mTotalFrame = mPlayer->totalFrame();
+ } else {
+ printf("load failed from data key : %s\n", key);
+ }
}
void LottieView::setSize(int w, int h)
{
+ mw = w; mh = h;
+
if (mRenderMode) {
evas_object_resize(mImage, w, h);
evas_object_image_size_set(mImage, w, h);
} else {
evas_object_resize(mVg, w, h);
}
- mPlayer->setSize(w, h);
}
void LottieView::setPos(int x, int y)
{
void LottieView::play()
{
+ if (!mPlayer) return;
+
mStartPos = mPos;
if (mAnimator) ecore_animator_del(mAnimator);
- mAnimator = ecore_animator_timeline_add(mPlayer->playTime()/mSpeed, animator, this);
+ mAnimator = ecore_animator_timeline_add(mPlayer->duration()/mSpeed, animator, this);
mReverse = false;
mCurCount = mRepeatCount;
mPalying = true;
void LottieView::restart()
{
+ if (!mPlayer) return;
+
mCurCount--;
if (mLoop || mRepeatCount) {
if (mRepeatMode == LottieView::RepeatMode::Reverse)
mStartPos = 0;
if (mAnimator) ecore_animator_del(mAnimator);
- mAnimator = ecore_animator_timeline_add(mPlayer->playTime()/mSpeed, animator, this);
+ mAnimator = ecore_animator_timeline_add(mPlayer->duration()/mSpeed, animator, this);
}
}
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
-#include"lotplayer.h"
+#include "lottieanimation.h"
+#include "lottieanimation_capi.h"
#include<future>
class LottieView
{
Evas_Object *mVg;
int mRepeatCount;
LottieView::RepeatMode mRepeatMode;
- lottieplayer::LOTPlayer *mPlayer;
+ std::unique_ptr<lottie::Animation> mPlayer;
+ size_t mCurFrame{UINT_MAX};
Ecore_Animator *mAnimator{nullptr};
bool mLoop;
int mCurCount;
float mPos;
float mFrameRate;
long mTotalFrame;
- std::future<bool> mRenderTask;
- LOTBuffer mBuffer;
+ std::future<lottie::Surface> mRenderTask;
};
+
+class LottieViewCApi
+{
+public:
+private:
+ Evas *mEvas;
+ Lottie_Animation *mAnimation;
+};
+
#endif //LOTTIEVIEW_H
+++ /dev/null
-#ifndef _LOT_PLAYER_H_
-#define _LOT_PLAYER_H_
-
-#include <future>
-#include <vector>
-
-#include "lotcommon.h"
-
-//TODO: Hide this.
-class LOTPlayerPrivate;
-#define _LOT_PLAYER_DECLARE_PRIVATE(A) \
- class A##Private *d;
-
-namespace lottieplayer {
-
-class LOT_EXPORT LOTPlayer {
-public:
- ~LOTPlayer();
- LOTPlayer();
-
- bool loadFromData(const char *jsonData, const char *key);
-
- bool setFilePath(const char *filePath);
-
- float playTime() const;
-
- float pos() const;
-
- float frameRate() const;
-
- long totalFrame() const;
-
- const std::vector<LOTNode *> &renderList(float pos) const;
-
- // TODO: Consider correct position...
- void setSize(int width, int height);
- void size(int &width, int &height) const;
- std::future<bool> render(float pos, LOTBuffer buffer, bool forceRender = false);
- bool renderSync(float pos, LOTBuffer buffer, bool forceRender = false);
-
-private:
- _LOT_PLAYER_DECLARE_PRIVATE(LOTPlayer)
-};
-
-} // namespace lotplayer
-
-#endif // _LOT_PLAYER_H_
--- /dev/null
+#ifndef _LOTTIE_ANIMATION_H_
+#define _LOTTIE_ANIMATION_H_
+
+#include <future>
+#include <vector>
+#include <memory>
+
+#ifdef _WIN32
+#ifdef LOT_BUILD
+#ifdef DLL_EXPORT
+#define LOT_EXPORT __declspec(dllexport)
+#else
+#define LOT_EXPORT
+#endif
+#else
+#define LOT_EXPORT __declspec(dllimport)
+#endif
+#else
+#ifdef __GNUC__
+#if __GNUC__ >= 4
+#define LOT_EXPORT __attribute__((visibility("default")))
+#else
+#define LOT_EXPORT
+#endif
+#else
+#define LOT_EXPORT
+#endif
+#endif
+
+class AnimationImpl;
+class LOTNode;
+
+namespace lottie {
+
+class LOT_EXPORT Surface {
+public:
+ Surface() = default;
+ Surface(uint32_t *buffer, size_t width, size_t height, size_t bytesPerLine);
+ size_t width() const {return mWidth;}
+ size_t height() const {return mHeight;}
+ size_t bytesPerLine() const {return mBytesPerLine;}
+ uint32_t *buffer() const {return mBuffer;}
+
+private:
+ uint32_t *mBuffer;
+ size_t mWidth;
+ size_t mHeight;
+ size_t mBytesPerLine;
+};
+
+class LOT_EXPORT Animation {
+public:
+
+ static std::unique_ptr<Animation>
+ loadFromFile(const std::string &path);
+
+ static std::unique_ptr<Animation>
+ loadFromData(const char *jsonData, const char *key);
+
+ double frameRate() const;
+ size_t totalFrame() const;
+ void size(size_t &width, size_t &height) const;
+ double duration() const;
+ size_t frameAtPos(double pos);
+
+ std::future<Surface> render(size_t frameNo, Surface surface);
+ void renderSync(size_t frameNo, Surface surface);
+
+ ~Animation();
+ Animation();
+
+ const std::vector<LOTNode *> &renderList(size_t frameNo, size_t width, size_t height) const;
+private:
+ std::unique_ptr<AnimationImpl> d;
+};
+} // namespace lotplayer
+
+#endif // _LOTTIE_ANIMATION_H_
--- /dev/null
+#ifndef _LOTPLAYER_CAPI_H_
+#define _LOTPLAYER_CAPI_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <lottiecommon.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Lottie_Animation_S Lottie_Animation;
+
+LOT_EXPORT Lottie_Animation *lottie_animation_from_file(const char *file);
+LOT_EXPORT Lottie_Animation *lottie_animation_from_data(const char *data, const char *key);
+LOT_EXPORT void lottie_animation_destroy(Lottie_Animation *animation);
+LOT_EXPORT void lottie_animation_get_size(const Lottie_Animation *animation, size_t *w, size_t *h);
+LOT_EXPORT double lottie_animation_get_duration(const Lottie_Animation *animation);
+LOT_EXPORT size_t lottie_animation_get_totalframe(const Lottie_Animation *animation);
+LOT_EXPORT double lottie_animation_get_framerate(const Lottie_Animation *animation);
+
+
+/*
+ * Request to update the content of the frame $frame_number in to Animation object.
+ * frame_number, the content of the animation in that frame number
+ * width , width of the viewbox
+ * height , height of the viewbox
+ *
+ * PS : user must call lottie_animation_get_node_count and lottie_animation_get_node
+ * to get the renderlist.
+ */
+LOT_EXPORT size_t lottie_animation_prepare_frame(Lottie_Animation *animation,
+ size_t frameNo,
+ size_t w, size_t h);
+LOT_EXPORT size_t lottie_animation_get_node_count(const Lottie_Animation *animation);
+LOT_EXPORT const LOTNode* lottie_animation_get_node(Lottie_Animation *animation, size_t idx);
+
+/*
+ * Request to render the content of the frame $frame_number to buffer $buffer asynchronously.
+ * frame_number, the frame number needs to be rendered.
+ * buffer , surface buffer use for rendering
+ * width , width of the surface
+ * height , height of the surface
+ * bytes_per_line, stride of the surface in bytes.
+ *
+ * PS : user must call lottie_animation_render_flush to make sure render is finished.
+ */
+LOT_EXPORT void
+lottie_animation_render_async(Lottie_Animation *animation,
+ size_t frame_number,
+ uint32_t *buffer,
+ size_t width,
+ size_t height,
+ size_t bytes_per_line);
+
+
+/*
+ * Request to finish the current asyn renderer job for this animation object.
+ * if render is finished then this call returns immidiately
+ * if not it waits till render job finish and then return.
+ * user must use lottie_animation_render_async and lottie_animation_render_flush
+ * together to get the benefit of async rendering.
+ */
+LOT_EXPORT void
+lottie_animation_render_flush(Lottie_Animation *animation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_LOTPLAYER_CAPI_H_
+
-#ifndef _LOT_COMMON_H_
-#define _LOT_COMMON_H_
+#ifndef _LOTTIE_COMMON_H_
+#define _LOTTIE_COMMON_H_
#ifdef _WIN32
#ifdef LOT_BUILD
LOTFillRule mFillRule;
} LOTNode;
-typedef struct LOTBuffer {
- uint32_t *buffer;
- int width;
- int height;
- int bytesPerLine;
- bool clear;
-} LOTBuffer;
-#endif // _LOT_COMMON_H_
+#endif // _LOTTIE_COMMON_H_
-install_headers(['lotplayer.h', 'lotcommon.h'])
+install_headers(['lottieanimation.h',
+ 'lotcommon.h',
+ 'lottieanimation_capi.h'])
+++ /dev/null
-#ifndef _LOTPLAYER_CAPI_H_
-#define _LOTPLAYER_CAPI_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <lotcommon.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct lotplayer_s LOTPlayer;
-
-LOT_EXPORT LOTPlayer *lotplayer_create(void);
-LOT_EXPORT int lotplayer_destroy(LOTPlayer *player);
-LOT_EXPORT int lotplayer_set_file(LOTPlayer *player, const char *file);
-LOT_EXPORT int lotplayer_set_data(LOTPlayer *player, const char *data, const char *key);
-LOT_EXPORT int lotplayer_set_size(LOTPlayer *player, int w, int h);
-LOT_EXPORT int lotplayer_get_size(const LOTPlayer *player, int* w, int* h);
-LOT_EXPORT float lotplayer_get_playtime(const LOTPlayer *player);
-LOT_EXPORT long lotplayer_get_totalframe(const LOTPlayer *player);
-LOT_EXPORT float lotplayer_get_framerate(const LOTPlayer *player);
-LOT_EXPORT float lotplayer_get_pos(const LOTPlayer *player);
-LOT_EXPORT size_t lotplayer_get_node_count(const LOTPlayer *player, float pos);
-LOT_EXPORT const LOTNode* lotplayer_get_node(LOTPlayer *player, float pos, size_t idx);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //_LOTPLAYER_CAPI_H_
-
--- /dev/null
+#include "lottieanimation.h"
+#include "vdebug.h"
+
+using namespace lottie;
+
+extern "C" {
+
+struct Lottie_Animation_S
+{
+ std::unique_ptr<Animation> mAnimation;
+ size_t mCurFrame;
+ LOTNode **mNodeArray;
+ size_t mArraySize{0};
+ std::future<Surface> mRenderTask;
+};
+
+LOT_EXPORT Lottie_Animation_S *lottie_animation_from_file(const char *file)
+{
+ if (auto animation = Animation::loadFromFile(file) ) {
+ Lottie_Animation_S *handle = new Lottie_Animation_S();
+ handle->mAnimation = std::move(animation);
+ return handle;
+ } else {
+ return nullptr;
+ }
+}
+
+Lottie_Animation_S *lottie_animation_from_data(const char *data, const char *key)
+{
+ if (auto animation = Animation::loadFromData(data, key) ) {
+ Lottie_Animation_S *handle = new Lottie_Animation_S();
+ handle->mAnimation = std::move(animation);
+ return handle;
+ } else {
+ return nullptr;
+ }
+}
+
+LOT_EXPORT void lottie_animation_destroy(Lottie_Animation_S *animation)
+{
+ if (animation)
+ delete animation;
+}
+
+LOT_EXPORT void lottie_animation_get_size(const Lottie_Animation_S *animation, size_t *w, size_t *h)
+{
+ if (!animation) return;
+
+ animation->mAnimation->size(*w, *h);
+}
+
+LOT_EXPORT double lottie_animation_get_duration(const Lottie_Animation_S *animation)
+{
+ if (!animation) return 0;
+
+ return animation->mAnimation->duration();
+}
+
+LOT_EXPORT size_t lottie_animation_get_totalframe(const Lottie_Animation_S *animation)
+{
+ if (!animation) return 0;
+
+ return animation->mAnimation->totalFrame();
+}
+
+
+LOT_EXPORT double lottie_animation_get_framerate(const Lottie_Animation_S *animation)
+{
+ if (!animation) return 0;
+
+ return animation->mAnimation->frameRate();
+}
+
+LOT_EXPORT void lottie_animation_prepare_frame(Lottie_Animation_S *animation, size_t frameNo, size_t w, size_t h)
+{
+ if (!animation) return;
+
+ auto list = animation->mAnimation->renderList(frameNo, w, h);
+ animation->mNodeArray = list.data();
+ animation->mArraySize = list.size();
+}
+
+LOT_EXPORT size_t lottie_animation_get_node_count(const Lottie_Animation_S *animation)
+{
+ if (!animation) return 0;
+
+ return animation->mArraySize;
+}
+
+LOT_EXPORT const LOTNode* lottie_animation_get_node(const Lottie_Animation_S *animation, size_t idx)
+{
+ if (!animation) return nullptr;
+
+ if (idx >= animation->mArraySize) return nullptr;
+
+ return animation->mNodeArray[idx];
+}
+
+LOT_EXPORT void
+lottie_animation_render_async(Lottie_Animation_S *animation,
+ size_t frame_number,
+ uint32_t *buffer,
+ size_t width,
+ size_t height,
+ size_t bytes_per_line)
+{
+ if (!animation) return;
+
+ lottie::Surface surface(buffer, width, height, bytes_per_line);
+ animation->mRenderTask = animation->mAnimation->render(frame_number, surface);
+}
+
+LOT_EXPORT void
+lottie_animation_render_flush(Lottie_Animation_S *animation)
+{
+ if (!animation) return;
+
+ if (animation->mRenderTask.valid()) {
+ animation->mRenderTask.get();
+ }
+}
+
+}
+++ /dev/null
-#include <lotplayer.h>
-#include "vdebug.h"
-
-using namespace lottieplayer;
-
-extern "C" {
-
-LOT_EXPORT LOTPlayer *lotplayer_create(void)
-{
- LOTPlayer* p = new LOTPlayer();
- if (!p) {
- vCritical << "Failed to initialize lotplayer";
- }
- return p;
-}
-
-LOT_EXPORT int lotplayer_destroy(LOTPlayer *player)
-{
- if (!player) return LOT_PLAYER_ERROR_INVALID_PARAMETER;
- delete(player);
-
- return LOT_PLAYER_ERROR_NONE;
-}
-
-LOT_EXPORT int lotplayer_set_data(LOTPlayer *player, const char *data, const char *key)
-{
- if (!player) return LOT_PLAYER_ERROR_INVALID_PARAMETER;
- bool ret = player->loadFromData(data, key);
-
- if (!ret) return -1;
-
- return LOT_PLAYER_ERROR_NONE;
-}
-
-LOT_EXPORT int lotplayer_set_file(LOTPlayer *player, const char *file)
-{
- if (!player) return LOT_PLAYER_ERROR_INVALID_PARAMETER;
- bool ret = player->setFilePath(file);
-
- if (!ret) return -1;
-
- return LOT_PLAYER_ERROR_NONE;
-}
-
-LOT_EXPORT int lotplayer_set_size(LOTPlayer *player, int w, int h)
-{
- if (!player) return LOT_PLAYER_ERROR_INVALID_PARAMETER;
-
- player->setSize(w, h);
-
- return LOT_PLAYER_ERROR_NONE;
-}
-
-LOT_EXPORT int lotplayer_get_size(const LOTPlayer *player, int* w, int* h)
-{
- if (!player) return LOT_PLAYER_ERROR_INVALID_PARAMETER;
-
- player->size(*w, *h);
-
- return LOT_PLAYER_ERROR_NONE;
-}
-
-LOT_EXPORT float lotplayer_get_pos(const LOTPlayer *player)
-{
- if (!player) {
- vWarning << "Invalid parameter player = nullptr";
- return -1.0f;
- }
-
- return player->pos();
-}
-
-LOT_EXPORT size_t lotplayer_get_node_count(const LOTPlayer *player, float pos)
-{
- if (!player) return LOT_PLAYER_ERROR_NONE;
-
- return player->renderList(pos).size();
-}
-
-LOT_EXPORT float lotplayer_get_playtime(const LOTPlayer *player)
-{
- if (!player) {
- vWarning << "Invalid parameter player = nullptr";
- return 0.0f;
- }
-
- return player->playTime();
-}
-
-LOT_EXPORT long lotplayer_get_totalframe(const LOTPlayer *player)
-{
- if (!player) {
- vWarning << "Invalid parameter player = nullptr";
- return 0;
- }
-
- return player->totalFrame();
-}
-
-LOT_EXPORT float lotplayer_get_framerate(const LOTPlayer *player)
-{
- if (!player) {
- vWarning << "Invalid parameter player = nullptr";
- return 0.0f;
- }
-
- return player->frameRate();
-}
-
-LOT_EXPORT const LOTNode* lotplayer_get_node(LOTPlayer *player, float pos, size_t idx)
-{
- if (!player) {
- vWarning << "Invalid parameter player = nullptr";
- return nullptr;
- }
-
- if (idx >= player->renderList(pos).size()) {
- vWarning << "Invalid parameter idx? (0 ~ " << player->renderList(pos).size() << "), given idx = " << idx;
- return nullptr;
- }
-
- return player->renderList(pos)[idx];
-}
-
-}
-install_headers(['lotplayer_capi.h'])
-
-source_file = files('lottieplayer_c.cpp')
+source_file = files('lottieanimation_c.cpp')
binding_c_dep = declare_dependency(
include_directories : include_directories('.'),
"${CMAKE_CURRENT_LIST_DIR}/lottieloader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/lottiemodel.cpp"
"${CMAKE_CURRENT_LIST_DIR}/lottieparser.cpp"
- "${CMAKE_CURRENT_LIST_DIR}/lottieplayer.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/lottieanimation.cpp"
)
target_include_directories(lottie-player
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}"
- )
\ No newline at end of file
+ )
--- /dev/null
+#include "lottieanimation.h"
+
+#include "lottieitem.h"
+#include "lottieloader.h"
+#include "lottiemodel.h"
+
+#include <fstream>
+
+using namespace lottie;
+
+class AnimationImpl {
+
+public:
+ void init(const std::shared_ptr<LOTModel> &model);
+ bool update(size_t frameNo, const VSize &size);
+ VSize size() const;
+ double duration() const;
+ double frameRate() const;
+ size_t totalFrame() const;
+ size_t frameAtPos(double pos) const;
+ const std::vector<LOTNode *> &renderList(size_t frameNo, const VSize &size);
+ Surface render(size_t frameNo, const Surface &surface);
+
+private:
+ std::string mFilePath;
+ std::shared_ptr<LOTModel> mModel;
+ std::unique_ptr<LOTCompItem> mCompItem;
+ std::atomic<bool> mRenderInProgress;
+};
+
+double AnimationImpl::frameRate() const
+{
+ return mModel->frameRate();
+}
+
+size_t AnimationImpl::totalFrame() const
+{
+ return mModel->frameDuration();
+}
+
+size_t AnimationImpl::frameAtPos(double pos) const
+{
+ if (pos < 0) pos = 0;
+ if (pos > 1) pos = 1;
+
+ if (mModel->isStatic()) return 0;
+
+ return mModel->startFrame() + pos * mModel->frameDuration();
+}
+
+VSize AnimationImpl::size() const
+{
+ return mCompItem->size();
+}
+
+const std::vector<LOTNode *> &AnimationImpl::renderList(size_t frameNo, const VSize &size)
+{
+ update(frameNo, size);
+ return mCompItem->renderList();
+}
+
+double AnimationImpl::duration() const
+{
+ if (mModel->isStatic()) return 0;
+ return double(mModel->frameDuration()) / double(mModel->frameRate());
+}
+
+bool AnimationImpl::update(size_t frameNo, const VSize &size)
+{
+ if (frameNo > mModel->frameDuration())
+ frameNo = mModel->frameDuration();
+
+ mCompItem->resize(size);
+ return mCompItem->update(frameNo);
+}
+
+Surface AnimationImpl::render(size_t frameNo, const Surface &surface)
+{
+ bool renderInProgress = mRenderInProgress.load();
+ if (renderInProgress)
+ {
+ vCritical << "Already Rendering Scheduled for this Animation";
+ return surface;
+ }
+
+ mRenderInProgress.store(true);
+ update(frameNo, VSize(surface.width(), surface.height()));
+ mCompItem->render(surface);
+ mRenderInProgress.store(false);
+
+ return surface;
+}
+
+void AnimationImpl::init(const std::shared_ptr<LOTModel> &model)
+{
+ mModel = model;
+ mCompItem = std::make_unique<LOTCompItem>(mModel.get());
+ mRenderInProgress = false;
+}
+
+/*
+ * Implement a task stealing schduler to perform render task
+ * As each player draws into its own buffer we can delegate this
+ * task to a slave thread. The scheduler creates a threadpool depending
+ * on the number of cores available in the system and does a simple fair
+ * scheduling by assigning the task in a round-robin fashion. Each thread
+ * in the threadpool has its own queue. once it finishes all the task on its
+ * own queue it goes through rest of the queue and looks for task if it founds
+ * one it steals the task from it and executes. if it couldn't find one then it
+ * just waits for new task on its own queue.
+ */
+struct RenderTask {
+ RenderTask() { receiver = sender.get_future(); }
+ std::promise<Surface> sender;
+ std::future<Surface> receiver;
+ AnimationImpl *playerImpl;
+ size_t frameNo;
+ Surface surface;
+};
+
+#include <vtaskqueue.h>
+class RenderTaskScheduler {
+ const unsigned _count{std::thread::hardware_concurrency()};
+ std::vector<std::thread> _threads;
+ std::vector<TaskQueue<RenderTask>> _q{_count};
+ std::atomic<unsigned> _index{0};
+
+ void run(unsigned i)
+ {
+ while (true) {
+ RenderTask *task = nullptr;
+
+ for (unsigned n = 0; n != _count * 32; ++n) {
+ if (_q[(i + n) % _count].try_pop(task)) break;
+ }
+ if (!task && !_q[i].pop(task)) break;
+
+ auto result = task->playerImpl->render(task->frameNo, task->surface);
+ task->sender.set_value(result);
+ delete task;
+ }
+ }
+
+public:
+ RenderTaskScheduler()
+ {
+ for (unsigned n = 0; n != _count; ++n) {
+ _threads.emplace_back([&, n] { run(n); });
+ }
+ }
+
+ ~RenderTaskScheduler()
+ {
+ for (auto &e : _q) e.done();
+
+ for (auto &e : _threads) e.join();
+ }
+
+ std::future<Surface> async(RenderTask *task)
+ {
+ auto receiver = std::move(task->receiver);
+ auto i = _index++;
+
+ for (unsigned n = 0; n != _count; ++n) {
+ if (_q[(i + n) % _count].try_push(task)) return receiver;
+ }
+
+ _q[i % _count].push(task);
+
+ return receiver;
+ }
+
+ std::future<Surface> render(AnimationImpl *impl, size_t frameNo,
+ Surface &&surface)
+ {
+ RenderTask *task = new RenderTask();
+ task->playerImpl = impl;
+ task->frameNo = frameNo;
+ task->surface = std::move(surface);
+ return async(task);
+ }
+};
+static RenderTaskScheduler render_scheduler;
+
+/**
+ * \breif Brief abput the Api.
+ * Description about the setFilePath Api
+ * @param path add the details
+ */
+std::unique_ptr<Animation>
+Animation::loadFromData(const char *jsonData, const char *key)
+{
+ if (!jsonData) {
+ vWarning << "jason data is empty";
+ return nullptr;
+ }
+
+ LottieLoader loader;
+ if (loader.loadFromData(jsonData, key)) {
+ auto animation = std::make_unique<Animation>();
+ animation->d->init(loader.model());
+ return animation;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<Animation>
+Animation::loadFromFile(const std::string &path)
+{
+ if (path.empty()) {
+ vWarning << "File path is empty";
+ return nullptr;
+ }
+
+ LottieLoader loader;
+ if (loader.load(path)) {
+ auto animation = std::make_unique<Animation>();
+ animation->d->init(loader.model());
+ return animation;
+ }
+ return nullptr;
+}
+
+void Animation::size(size_t &width, size_t &height) const
+{
+ VSize sz = d->size();
+
+ width = sz.width();
+ height = sz.height();
+}
+
+double Animation::duration() const
+{
+ return d->duration();
+}
+
+double Animation::frameRate() const
+{
+ return d->frameRate();
+}
+
+size_t Animation::totalFrame() const
+{
+ return d->totalFrame();
+}
+
+size_t Animation::frameAtPos(double pos)
+{
+ return d->frameAtPos(pos);
+}
+
+const std::vector<LOTNode *> &
+Animation::renderList(size_t frameNo, size_t width, size_t height) const
+{
+ return d->renderList(frameNo, VSize(width, height));
+}
+
+std::future<Surface> Animation::render(size_t frameNo, Surface surface)
+{
+ return render_scheduler.render(d.get(), frameNo, std::move(surface));
+}
+
+void Animation::renderSync(size_t frameNo, Surface surface)
+{
+ d->render(frameNo, surface);
+}
+
+Animation::Animation(): d(std::make_unique<AnimationImpl>()) {}
+
+/*
+ * this is only to supress build fail
+ * because unique_ptr expects the destructor in the same translation unit.
+ */
+Animation::~Animation(){}
+
+Surface::Surface(uint32_t *buffer,
+ size_t width, size_t height, size_t bytesPerLine)
+ :mBuffer(buffer),
+ mWidth(width),
+ mHeight(height),
+ mBytesPerLine(bytesPerLine) {}
+
+
+void initLogging()
+{
+#if defined(__ARM_NEON__)
+ set_log_level(LogLevel::OFF);
+#else
+ initialize(GuaranteedLogger(), "/tmp/", "lotti-player", 1);
+ set_log_level(LogLevel::INFO);
+#endif
+}
+
+V_CONSTRUCTOR_FUNCTION(initLogging)
return mRenderList;
}
-bool LOTCompItem::render(const LOTBuffer &buffer)
+bool LOTCompItem::render(const lottie::Surface &surface)
{
- VBitmap bitmap((uchar *)buffer.buffer, buffer.width, buffer.height,
- buffer.bytesPerLine, VBitmap::Format::ARGB32_Premultiplied,
+ VBitmap bitmap((uchar *)surface.buffer(), surface.width(), surface.height(),
+ surface.bytesPerLine(), VBitmap::Format::ARGB32_Premultiplied,
nullptr, nullptr);
/* schedule all preprocess task for this frame at once.
#include"vpath.h"
#include"vpoint.h"
#include"vpathmesure.h"
-#include"lotcommon.h"
+#include"lottiecommon.h"
+#include"lottieanimation.h"
#include"vpainter.h"
#include"vdrawable.h"
VSize size() const;
const std::vector<LOTNode *>& renderList()const;
void buildRenderList();
- bool render(const LOTBuffer &buffer);
+ bool render(const lottie::Surface &surface);
private:
VMatrix mScaleMatrix;
VSize mViewSize;
return CACHE;
}
std::shared_ptr<LOTModel> find(const std::string &key);
- void add(std::string &key, std::shared_ptr<LOTModel> value);
+ void add(const std::string &key, std::shared_ptr<LOTModel> value);
private:
LottieFileCache() = default;
}
}
-void LottieFileCache::add(std::string &key, std::shared_ptr<LOTModel> value)
+void LottieFileCache::add(const std::string &key, std::shared_ptr<LOTModel> value)
{
mHash[key] = std::move(value);
}
-bool LottieLoader::load(std::string &path)
+bool LottieLoader::load(const std::string &path)
{
LottieFileCache &fileCache = LottieFileCache::get();
class LottieLoader
{
public:
- bool load(std::string &filePath);
+ bool load(const std::string &filePath);
bool loadFromData(const char *jsonData, const char *key);
std::shared_ptr<LOTModel> model();
private:
{
public:
bool isStatic() const{return mRoot->isStatic();}
- int frameDuration() {return mRoot->frameDuration();}
- int frameRate() {return mRoot->frameRate();}
- int startFrame() {return mRoot->startFrame();}
+ size_t frameDuration() {return mRoot->frameDuration();}
+ size_t frameRate() {return mRoot->frameRate();}
+ size_t startFrame() {return mRoot->startFrame();}
public:
std::shared_ptr<LOTCompositionData> mRoot;
};
+++ /dev/null
-#include <lotplayer.h>
-
-#include "lottieitem.h"
-#include "lottieloader.h"
-#include "lottiemodel.h"
-
-#include <fstream>
-
-using namespace lottieplayer;
-
-class LOTPlayerPrivate {
-
-public:
- LOTPlayerPrivate();
- bool update(float pos);
- bool setFilePath(std::string path);
- bool loadFromData(const char *jsonData,
- const char *key);
- void setSize(const VSize &sz);
- void setPos(float pos);
- VSize size() const;
- float playTime() const;
- float pos();
- float frameRate() const;
- long totalFrame() const;
- const std::vector<LOTNode *> &renderList(float pos);
- bool render(float pos, const LOTBuffer &buffer, bool forceRender);
-
-private:
- std::string mFilePath;
- std::shared_ptr<LOTModel> mModel;
- std::unique_ptr<LOTCompItem> mCompItem;
- VSize mSize;
- std::atomic<bool> mRenderInProgress;
- float mPos = 0.0;
-};
-
-float LOTPlayerPrivate::frameRate() const
-{
- if (!mModel) {
- vWarning << "Model Data is not existed yet, please setFilePath() first.";
- return 0.0f;
- }
-
- return mModel->frameRate();
-}
-
-long LOTPlayerPrivate::totalFrame() const
-{
- if (!mModel) {
- vWarning << "Model Data is not existed yet, please setFilePath() first.";
- return 0.0f;
- }
-
- return mModel->frameDuration();
-}
-
-void LOTPlayerPrivate::setSize(const VSize &sz)
-{
- mSize = sz;
-}
-
-VSize LOTPlayerPrivate::size() const
-{
- if (!mCompItem) {
- return mSize;
- } else {
- return mCompItem->size();
- }
-}
-
-const std::vector<LOTNode *> &LOTPlayerPrivate::renderList(float pos)
-{
- if (!mCompItem) {
- static std::vector<LOTNode *> empty;
- return empty;
- }
-
- update(pos);
-
- return mCompItem->renderList();
-}
-
-float LOTPlayerPrivate::playTime() const
-{
- if (!mModel || mModel->isStatic()) return 0;
- return float(mModel->frameDuration()) / float(mModel->frameRate());
-}
-
-float LOTPlayerPrivate::pos()
-{
- return mPos;
-}
-
-void LOTPlayerPrivate::setPos(float pos)
-{
- if (pos > 1.0) pos = 1.0;
- if (pos < 0) pos = 0;
- mPos = pos;
-}
-
-bool LOTPlayerPrivate::update(float vPos)
-{
- if (!mCompItem) return false;
-
- mCompItem->resize(mSize);
- setPos(vPos);
-
- int frameNumber;
- if (mModel->isStatic()) frameNumber = 0;
- else frameNumber = mModel->startFrame() + pos() * mModel->frameDuration();
-
- return mCompItem->update(frameNumber);
-}
-
-bool LOTPlayerPrivate::render(float pos, const LOTBuffer &buffer, bool forceRender)
-{
- if (!mCompItem) return false;
-
- bool renderInProgress = mRenderInProgress.load();
- if (renderInProgress)
- {
- vCritical << "Already Rendering Scheduled for this Player";
- }
-
- bool result = true;
-
- if (update(pos) || forceRender)
- {
- mRenderInProgress.store(true);
- result = mCompItem->render(buffer);
- mRenderInProgress.store(false);
- }
-
- return result;
-}
-
-LOTPlayerPrivate::LOTPlayerPrivate() : mRenderInProgress(false) {}
-
-bool LOTPlayerPrivate::setFilePath(std::string path)
-{
- if (path.empty()) {
- vWarning << "File path is empty";
- return false;
- }
-
- LottieLoader loader;
- if (loader.load(path)) {
- mModel = loader.model();
- mCompItem = std::make_unique<LOTCompItem>(mModel.get());
- return true;
- }
- return false;
-}
-
-bool LOTPlayerPrivate::loadFromData(const char *jsonData, const char *key)
-{
- if (!jsonData) {
- vWarning << "jason data is empty";
- return false;
- }
-
- LottieLoader loader;
- if (loader.loadFromData(jsonData, key)) {
- mModel = loader.model();
- mCompItem = std::make_unique<LOTCompItem>(mModel.get());
- return true;
- }
- return false;
-}
-
-/*
- * Implement a task stealing schduler to perform render task
- * As each player draws into its own buffer we can delegate this
- * task to a slave thread. The scheduler creates a threadpool depending
- * on the number of cores available in the system and does a simple fair
- * scheduling by assigning the task in a round-robin fashion. Each thread
- * in the threadpool has its own queue. once it finishes all the task on its
- * own queue it goes through rest of the queue and looks for task if it founds
- * one it steals the task from it and executes. if it couldn't find one then it
- * just waits for new task on its own queue.
- */
-struct RenderTask {
- RenderTask() { receiver = sender.get_future(); }
- std::promise<bool> sender;
- std::future<bool> receiver;
- LOTPlayerPrivate * playerImpl;
- float pos;
- LOTBuffer buffer;
- bool forceRender;
-};
-
-#include <vtaskqueue.h>
-class RenderTaskScheduler {
- const unsigned _count{std::thread::hardware_concurrency()};
- std::vector<std::thread> _threads;
- std::vector<TaskQueue<RenderTask>> _q{_count};
- std::atomic<unsigned> _index{0};
-
- void run(unsigned i)
- {
- while (true) {
- RenderTask *task = nullptr;
-
- for (unsigned n = 0; n != _count * 32; ++n) {
- if (_q[(i + n) % _count].try_pop(task)) break;
- }
- if (!task && !_q[i].pop(task)) break;
-
- bool result = task->playerImpl->render(task->pos, task->buffer, task->forceRender);
- task->sender.set_value(result);
- delete task;
- }
- }
-
-public:
- RenderTaskScheduler()
- {
- for (unsigned n = 0; n != _count; ++n) {
- _threads.emplace_back([&, n] { run(n); });
- }
- }
-
- ~RenderTaskScheduler()
- {
- for (auto &e : _q) e.done();
-
- for (auto &e : _threads) e.join();
- }
-
- std::future<bool> async(RenderTask *task)
- {
- auto receiver = std::move(task->receiver);
- auto i = _index++;
-
- for (unsigned n = 0; n != _count; ++n) {
- if (_q[(i + n) % _count].try_push(task)) return receiver;
- }
-
- _q[i % _count].push(task);
-
- return receiver;
- }
-
- std::future<bool> render(LOTPlayerPrivate *impl, float pos,
- LOTBuffer &&buffer, bool forceRender)
- {
- RenderTask *task = new RenderTask();
- task->playerImpl = impl;
- task->pos = pos;
- task->buffer = std::move(buffer);
- task->forceRender = forceRender;
- return async(task);
- }
-};
-static RenderTaskScheduler render_scheduler;
-
-LOTPlayer::LOTPlayer() : d(new LOTPlayerPrivate()) {}
-
-LOTPlayer::~LOTPlayer()
-{
- delete d;
-}
-
-/**
- * \breif Brief abput the Api.
- * Description about the setFilePath Api
- * @param path add the details
- */
-
-bool LOTPlayer::loadFromData(const char *jsonData, const char *key)
-{
- return d->loadFromData(jsonData, key);
-}
-
-bool LOTPlayer::setFilePath(const char *filePath)
-{
- return d->setFilePath(filePath);
-}
-
-void LOTPlayer::setSize(int width, int height)
-{
- d->setSize(VSize(width, height));
-}
-
-void LOTPlayer::size(int &width, int &height) const
-{
- VSize sz = d->size();
-
- width = sz.width();
- height = sz.height();
-}
-
-float LOTPlayer::playTime() const
-{
- return d->playTime();
-}
-
-float LOTPlayer::pos() const
-{
- return d->pos();
-}
-
-float LOTPlayer::frameRate() const
-{
- return d->frameRate();
-}
-
-long LOTPlayer::totalFrame() const
-{
- return d->totalFrame();
-}
-
-const std::vector<LOTNode *> &LOTPlayer::renderList(float pos) const
-{
- return d->renderList(pos);
-}
-
-std::future<bool> LOTPlayer::render(float pos, LOTBuffer buffer, bool forceRender)
-{
- return render_scheduler.render(d, pos, std::move(buffer), forceRender);
-}
-
-bool LOTPlayer::renderSync(float pos, LOTBuffer buffer, bool forceRender)
-{
- return d->render(pos, buffer, forceRender);
-}
-
-void initLogging()
-{
-#if defined(__ARM_NEON__)
- set_log_level(LogLevel::OFF);
-#else
- initialize(GuaranteedLogger(), "/tmp/", "lotti-player", 1);
- set_log_level(LogLevel::INFO);
-#endif
-}
-
-V_CONSTRUCTOR_FUNCTION(initLogging)
source_file = files('lottieparser.cpp')
source_file += files('lottieloader.cpp')
source_file += files('lottiemodel.cpp')
-source_file += files('lottieplayer.cpp')
+source_file += files('lottieanimation.cpp')
source_file += files('lottieitem.cpp')