summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp')
-rw-r--r--vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp457
1 files changed, 457 insertions, 0 deletions
diff --git a/vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp b/vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp
new file mode 100644
index 00000000..341489b3
--- /dev/null
+++ b/vendor/github.com/Benau/go_rlottie/lottie_lottieanimation.cpp
@@ -0,0 +1,457 @@
+#include "config.h"
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. 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.
+ */
+#include "config.h"
+#include "lottie_lottieitem.h"
+#include "lottie_lottiemodel.h"
+#include "rlottie.h"
+
+#include <fstream>
+
+using namespace rlottie;
+using namespace rlottie::internal;
+
+RLOTTIE_API void rlottie::configureModelCacheSize(size_t cacheSize)
+{
+ internal::model::configureModelCacheSize(cacheSize);
+}
+
+struct RenderTask {
+ RenderTask() { receiver = sender.get_future(); }
+ std::promise<Surface> sender;
+ std::future<Surface> receiver;
+ AnimationImpl * playerImpl{nullptr};
+ size_t frameNo{0};
+ Surface surface;
+ bool keepAspectRatio{true};
+};
+using SharedRenderTask = std::shared_ptr<RenderTask>;
+
+class AnimationImpl {
+public:
+ void init(std::shared_ptr<model::Composition> composition);
+ bool update(size_t frameNo, const VSize &size, bool keepAspectRatio);
+ 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); }
+ Surface render(size_t frameNo, const Surface &surface,
+ bool keepAspectRatio);
+ std::future<Surface> renderAsync(size_t frameNo, Surface &&surface,
+ bool keepAspectRatio);
+ const LOTLayerNode * renderTree(size_t frameNo, const VSize &size);
+
+ const LayerInfoList &layerInfoList() const
+ {
+ if (mLayerList.empty()) {
+ mLayerList = mModel->layerInfoList();
+ }
+ return mLayerList;
+ }
+ const MarkerList &markers() const { return mModel->markers(); }
+ void setValue(const std::string &keypath, LOTVariant &&value);
+ void removeFilter(const std::string &keypath, Property prop);
+
+private:
+ mutable LayerInfoList mLayerList;
+ model::Composition * mModel;
+ SharedRenderTask mTask;
+ std::atomic<bool> mRenderInProgress;
+ std::unique_ptr<renderer::Composition> mRenderer{nullptr};
+};
+
+void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value)
+{
+ if (keypath.empty()) return;
+ mRenderer->setValue(keypath, value);
+}
+
+const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size)
+{
+ if (update(frameNo, size, true)) {
+ mRenderer->buildRenderTree();
+ }
+ return mRenderer->renderTree();
+}
+
+bool AnimationImpl::update(size_t frameNo, const VSize &size,
+ bool keepAspectRatio)
+{
+ frameNo += mModel->startFrame();
+
+ if (frameNo > mModel->endFrame()) frameNo = mModel->endFrame();
+
+ if (frameNo < mModel->startFrame()) frameNo = mModel->startFrame();
+
+ return mRenderer->update(int(frameNo), size, keepAspectRatio);
+}
+
+Surface AnimationImpl::render(size_t frameNo, const Surface &surface,
+ bool keepAspectRatio)
+{
+ bool renderInProgress = mRenderInProgress.load();
+ if (renderInProgress) {
+ vCritical << "Already Rendering Scheduled for this Animation";
+ return surface;
+ }
+
+ mRenderInProgress.store(true);
+ update(
+ frameNo,
+ VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())),
+ keepAspectRatio);
+ mRenderer->render(surface);
+ mRenderInProgress.store(false);
+
+ return surface;
+}
+
+void AnimationImpl::init(std::shared_ptr<model::Composition> composition)
+{
+ mModel = composition.get();
+ mRenderer = std::make_unique<renderer::Composition>(composition);
+ mRenderInProgress = false;
+}
+
+#ifdef LOTTIE_THREAD_SUPPORT
+
+#include <thread>
+#include "vector_vtaskqueue.h"
+
+/*
+ * 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.
+ */
+class RenderTaskScheduler {
+ const unsigned _count{std::thread::hardware_concurrency()};
+ std::vector<std::thread> _threads;
+ std::vector<TaskQueue<SharedRenderTask>> _q{_count};
+ std::atomic<unsigned> _index{0};
+
+ void run(unsigned i)
+ {
+ while (true) {
+ bool success = false;
+ SharedRenderTask task;
+ for (unsigned n = 0; n != _count * 2; ++n) {
+ if (_q[(i + n) % _count].try_pop(task)) {
+ success = true;
+ break;
+ }
+ }
+ if (!success && !_q[i].pop(task)) break;
+
+ auto result = task->playerImpl->render(task->frameNo, task->surface,
+ task->keepAspectRatio);
+ task->sender.set_value(result);
+ }
+ }
+
+ RenderTaskScheduler()
+ {
+ for (unsigned n = 0; n != _count; ++n) {
+ _threads.emplace_back([&, n] { run(n); });
+ }
+ }
+
+public:
+ static RenderTaskScheduler &instance()
+ {
+ static RenderTaskScheduler singleton;
+ return singleton;
+ }
+
+ ~RenderTaskScheduler()
+ {
+ for (auto &e : _q) e.done();
+
+ for (auto &e : _threads) e.join();
+ }
+
+ std::future<Surface> process(SharedRenderTask task)
+ {
+ auto receiver = std::move(task->receiver);
+ auto i = _index++;
+
+ for (unsigned n = 0; n != _count; ++n) {
+ if (_q[(i + n) % _count].try_push(std::move(task))) return receiver;
+ }
+
+ if (_count > 0) {
+ _q[i % _count].push(std::move(task));
+ }
+
+ return receiver;
+ }
+};
+
+#else
+class RenderTaskScheduler {
+public:
+ static RenderTaskScheduler &instance()
+ {
+ static RenderTaskScheduler singleton;
+ return singleton;
+ }
+
+ std::future<Surface> process(SharedRenderTask task)
+ {
+ auto result = task->playerImpl->render(task->frameNo, task->surface,
+ task->keepAspectRatio);
+ task->sender.set_value(result);
+ return std::move(task->receiver);
+ }
+};
+#endif
+
+std::future<Surface> AnimationImpl::renderAsync(size_t frameNo,
+ Surface &&surface,
+ bool keepAspectRatio)
+{
+ if (!mTask) {
+ mTask = std::make_shared<RenderTask>();
+ } else {
+ mTask->sender = std::promise<Surface>();
+ mTask->receiver = mTask->sender.get_future();
+ }
+ mTask->playerImpl = this;
+ mTask->frameNo = frameNo;
+ mTask->surface = std::move(surface);
+ mTask->keepAspectRatio = keepAspectRatio;
+
+ return RenderTaskScheduler::instance().process(mTask);
+}
+
+/**
+ * \breif Brief abput the Api.
+ * Description about the setFilePath Api
+ * @param path add the details
+ */
+std::unique_ptr<Animation> Animation::loadFromData(
+ std::string jsonData, const std::string &key,
+ const std::string &resourcePath, bool cachePolicy)
+{
+ if (jsonData.empty()) {
+ vWarning << "jason data is empty";
+ return nullptr;
+ }
+
+ auto composition = model::loadFromData(std::move(jsonData), key,
+ resourcePath, cachePolicy);
+ if (composition) {
+ auto animation = std::unique_ptr<Animation>(new Animation);
+ animation->d->init(std::move(composition));
+ return animation;
+ }
+
+ return nullptr;
+}
+
+std::unique_ptr<Animation> Animation::loadFromData(std::string jsonData,
+ std::string resourcePath,
+ ColorFilter filter)
+{
+ if (jsonData.empty()) {
+ vWarning << "jason data is empty";
+ return nullptr;
+ }
+
+ auto composition = model::loadFromData(
+ std::move(jsonData), std::move(resourcePath), std::move(filter));
+ if (composition) {
+ auto animation = std::unique_ptr<Animation>(new Animation);
+ animation->d->init(std::move(composition));
+ return animation;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path,
+ bool cachePolicy)
+{
+ if (path.empty()) {
+ vWarning << "File path is empty";
+ return nullptr;
+ }
+
+ auto composition = model::loadFromFile(path, cachePolicy);
+ if (composition) {
+ auto animation = std::unique_ptr<Animation>(new Animation);
+ animation->d->init(std::move(composition));
+ 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 LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width,
+ size_t height) const
+{
+ return d->renderTree(frameNo, VSize(int(width), int(height)));
+}
+
+std::future<Surface> Animation::render(size_t frameNo, Surface surface,
+ bool keepAspectRatio)
+{
+ return d->renderAsync(frameNo, std::move(surface), keepAspectRatio);
+}
+
+void Animation::renderSync(size_t frameNo, Surface surface,
+ bool keepAspectRatio)
+{
+ d->render(frameNo, surface, keepAspectRatio);
+}
+
+const LayerInfoList &Animation::layers() const
+{
+ return d->layerInfoList();
+}
+
+const MarkerList &Animation::markers() const
+{
+ return d->markers();
+}
+
+void Animation::setValue(Color_Type, Property prop, const std::string &keypath,
+ Color value)
+{
+ d->setValue(keypath,
+ LOTVariant(prop, [value](const FrameInfo &) { return value; }));
+}
+
+void Animation::setValue(Float_Type, Property prop, const std::string &keypath,
+ float value)
+{
+ d->setValue(keypath,
+ LOTVariant(prop, [value](const FrameInfo &) { return value; }));
+}
+
+void Animation::setValue(Size_Type, Property prop, const std::string &keypath,
+ Size value)
+{
+ d->setValue(keypath,
+ LOTVariant(prop, [value](const FrameInfo &) { return value; }));
+}
+
+void Animation::setValue(Point_Type, Property prop, const std::string &keypath,
+ Point value)
+{
+ d->setValue(keypath,
+ LOTVariant(prop, [value](const FrameInfo &) { return value; }));
+}
+
+void Animation::setValue(Color_Type, Property prop, const std::string &keypath,
+ std::function<Color(const FrameInfo &)> &&value)
+{
+ d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(Float_Type, Property prop, const std::string &keypath,
+ std::function<float(const FrameInfo &)> &&value)
+{
+ d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(Size_Type, Property prop, const std::string &keypath,
+ std::function<Size(const FrameInfo &)> &&value)
+{
+ d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(Point_Type, Property prop, const std::string &keypath,
+ std::function<Point(const FrameInfo &)> &&value)
+{
+ d->setValue(keypath, LOTVariant(prop, value));
+}
+
+Animation::~Animation() = default;
+Animation::Animation() : d(std::make_unique<AnimationImpl>()) {}
+
+Surface::Surface(uint32_t *buffer, size_t width, size_t height,
+ size_t bytesPerLine)
+ : mBuffer(buffer),
+ mWidth(width),
+ mHeight(height),
+ mBytesPerLine(bytesPerLine)
+{
+ mDrawArea.w = mWidth;
+ mDrawArea.h = mHeight;
+}
+
+void Surface::setDrawRegion(size_t x, size_t y, size_t width, size_t height)
+{
+ if ((x + width > mWidth) || (y + height > mHeight)) return;
+
+ mDrawArea.x = x;
+ mDrawArea.y = y;
+ mDrawArea.w = width;
+ mDrawArea.h = height;
+}
+
+#ifdef LOTTIE_LOGGING_SUPPORT
+void initLogging()
+{
+#if defined(USE_ARM_NEON)
+ set_log_level(LogLevel::OFF);
+#else
+ initialize(GuaranteedLogger(), "/tmp/", "rlottie", 1);
+ set_log_level(LogLevel::INFO);
+#endif
+}
+
+V_CONSTRUCTOR_FUNCTION(initLogging)
+#endif