matterbridge/vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h

627 lines
19 KiB
C++

/*
* 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.
*/
#ifndef LOTTIEITEM_H
#define LOTTIEITEM_H
#include <memory>
#include <sstream>
#include "lottie_lottiekeypath.h"
#include "lottie_lottiefiltermodel.h"
#include "rlottie.h"
#include "rlottiecommon.h"
#include "vector_varenaalloc.h"
#include "vector_vdrawable.h"
#include "vector_vmatrix.h"
#include "vector_vpainter.h"
#include "vector_vpath.h"
#include "vector_vpathmesure.h"
#include "vector_vpoint.h"
V_USE_NAMESPACE
namespace rlottie {
namespace internal {
template <class T>
class VSpan {
public:
using reference = T &;
using pointer = T *;
using const_pointer = T const *;
using const_reference = T const &;
using index_type = size_t;
using iterator = pointer;
using const_iterator = const_pointer;
VSpan() = default;
VSpan(pointer data, index_type size) : _data(data), _size(size) {}
constexpr pointer data() const noexcept { return _data; }
constexpr index_type size() const noexcept { return _size; }
constexpr bool empty() const noexcept { return size() == 0; }
constexpr iterator begin() const noexcept { return data(); }
constexpr iterator end() const noexcept { return data() + size(); }
constexpr const_iterator cbegin() const noexcept { return data(); }
constexpr const_iterator cend() const noexcept { return data() + size(); }
constexpr reference operator[](index_type idx) const
{
return *(data() + idx);
}
private:
pointer _data{nullptr};
index_type _size{0};
};
namespace renderer {
using DrawableList = VSpan<VDrawable *>;
enum class DirtyFlagBit : uchar {
None = 0x00,
Matrix = 0x01,
Alpha = 0x02,
All = (Matrix | Alpha)
};
typedef vFlag<DirtyFlagBit> DirtyFlag;
class SurfaceCache {
public:
SurfaceCache() { mCache.reserve(10); }
VBitmap make_surface(
size_t width, size_t height,
VBitmap::Format format = VBitmap::Format::ARGB32_Premultiplied)
{
if (mCache.empty()) return {width, height, format};
auto surface = mCache.back();
surface.reset(width, height, format);
mCache.pop_back();
return surface;
}
void release_surface(VBitmap &surface) { mCache.push_back(surface); }
private:
std::vector<VBitmap> mCache;
};
class Drawable final : public VDrawable {
public:
void sync();
public:
std::unique_ptr<LOTNode> mCNode{nullptr};
~Drawable() noexcept
{
if (mCNode && mCNode->mGradient.stopPtr)
free(mCNode->mGradient.stopPtr);
}
};
struct CApiData {
CApiData();
LOTLayerNode mLayer;
std::vector<LOTMask> mMasks;
std::vector<LOTLayerNode *> mLayers;
std::vector<LOTNode *> mCNodeList;
};
class Clipper {
public:
explicit Clipper(VSize size) : mSize(size) {}
void update(const VMatrix &matrix);
void preprocess(const VRect &clip);
VRle rle(const VRle &mask);
public:
VSize mSize;
VPath mPath;
VRle mMaskedRle;
VRasterizer mRasterizer;
bool mRasterRequest{false};
};
class Mask {
public:
explicit Mask(model::Mask *data) : mData(data) {}
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag);
model::Mask::Mode maskMode() const { return mData->mMode; }
VRle rle();
void preprocess(const VRect &clip);
bool inverted() const { return mData->mInv; }
public:
model::Mask *mData{nullptr};
VPath mLocalPath;
VPath mFinalPath;
VRasterizer mRasterizer;
float mCombinedAlpha{0};
bool mRasterRequest{false};
};
/*
* Handels mask property of a layer item
*/
class LayerMask {
public:
explicit LayerMask(model::Layer *layerData);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag);
bool isStatic() const { return mStatic; }
VRle maskRle(const VRect &clipRect);
void preprocess(const VRect &clip);
public:
std::vector<Mask> mMasks;
VRle mRle;
bool mStatic{true};
bool mDirty{true};
};
class Layer;
class Composition {
public:
explicit Composition(std::shared_ptr<model::Composition> composition);
bool update(int frameNo, const VSize &size, bool keepAspectRatio);
VSize size() const { return mViewSize; }
void buildRenderTree();
const LOTLayerNode *renderTree() const;
bool render(const rlottie::Surface &surface);
void setValue(const std::string &keypath, LOTVariant &value);
private:
SurfaceCache mSurfaceCache;
VBitmap mSurface;
VMatrix mScaleMatrix;
VSize mViewSize;
std::shared_ptr<model::Composition> mModel;
Layer * mRootLayer{nullptr};
VArenaAlloc mAllocator{2048};
int mCurFrameNo;
bool mKeepAspectRatio{true};
};
class Layer {
public:
virtual ~Layer() = default;
Layer &operator=(Layer &&) noexcept = delete;
Layer(model::Layer *layerData);
int id() const { return mLayerData->id(); }
int parentId() const { return mLayerData->parentId(); }
void setParentLayer(Layer *parent) { mParentLayer = parent; }
void setComplexContent(bool value) { mComplexContent = value; }
bool complexContent() const { return mComplexContent; }
virtual void update(int frameNo, const VMatrix &parentMatrix,
float parentAlpha);
VMatrix matrix(int frameNo) const;
void preprocess(const VRect &clip);
virtual DrawableList renderList() { return {}; }
virtual void render(VPainter *painter, const VRle &mask,
const VRle &matteRle, SurfaceCache &cache);
bool hasMatte()
{
if (mLayerData->mMatteType == model::MatteType::None) return false;
return true;
}
model::MatteType matteType() const { return mLayerData->mMatteType; }
bool visible() const;
virtual void buildLayerNode();
LOTLayerNode & clayer() { return mCApiData->mLayer; }
std::vector<LOTLayerNode *> &clayers() { return mCApiData->mLayers; }
std::vector<LOTMask> & cmasks() { return mCApiData->mMasks; }
std::vector<LOTNode *> & cnodes() { return mCApiData->mCNodeList; }
const char * name() const { return mLayerData->name(); }
virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value);
protected:
virtual void preprocessStage(const VRect &clip) = 0;
virtual void updateContent() = 0;
inline VMatrix combinedMatrix() const { return mCombinedMatrix; }
inline int frameNo() const { return mFrameNo; }
inline float combinedAlpha() const { return mCombinedAlpha; }
inline bool isStatic() const { return mLayerData->isStatic(); }
float opacity(int frameNo) const { return mLayerData->opacity(frameNo); }
inline DirtyFlag flag() const { return mDirtyFlag; }
bool skipRendering() const
{
return (!visible() || vIsZero(combinedAlpha()));
}
protected:
std::unique_ptr<LayerMask> mLayerMask;
model::Layer * mLayerData{nullptr};
Layer * mParentLayer{nullptr};
VMatrix mCombinedMatrix;
float mCombinedAlpha{0.0};
int mFrameNo{-1};
DirtyFlag mDirtyFlag{DirtyFlagBit::All};
bool mComplexContent{false};
std::unique_ptr<CApiData> mCApiData;
};
class CompLayer final : public Layer {
public:
explicit CompLayer(model::Layer *layerData, VArenaAlloc *allocator);
void render(VPainter *painter, const VRle &mask, const VRle &matteRle,
SurfaceCache &cache) final;
void buildLayerNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value) override;
protected:
void preprocessStage(const VRect &clip) final;
void updateContent() final;
private:
void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle,
SurfaceCache &cache);
void renderMatteLayer(VPainter *painter, const VRle &inheritMask,
const VRle &matteRle, Layer *layer, Layer *src,
SurfaceCache &cache);
private:
std::vector<Layer *> mLayers;
std::unique_ptr<Clipper> mClipper;
};
class SolidLayer final : public Layer {
public:
explicit SolidLayer(model::Layer *layerData);
void buildLayerNode() final;
DrawableList renderList() final;
protected:
void preprocessStage(const VRect &clip) final;
void updateContent() final;
private:
Drawable mRenderNode;
VPath mPath;
VDrawable *mDrawableList{nullptr}; // to work with the Span api
};
class Group;
class ShapeLayer final : public Layer {
public:
explicit ShapeLayer(model::Layer *layerData, VArenaAlloc *allocator);
DrawableList renderList() final;
void buildLayerNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value) override;
protected:
void preprocessStage(const VRect &clip) final;
void updateContent() final;
std::vector<VDrawable *> mDrawableList;
Group * mRoot{nullptr};
};
class NullLayer final : public Layer {
public:
explicit NullLayer(model::Layer *layerData);
protected:
void preprocessStage(const VRect &) final {}
void updateContent() final;
};
class ImageLayer final : public Layer {
public:
explicit ImageLayer(model::Layer *layerData);
void buildLayerNode() final;
DrawableList renderList() final;
protected:
void preprocessStage(const VRect &clip) final;
void updateContent() final;
private:
Drawable mRenderNode;
VTexture mTexture;
VPath mPath;
VDrawable *mDrawableList{nullptr}; // to work with the Span api
};
class Object {
public:
enum class Type : uchar { Unknown, Group, Shape, Paint, Trim };
virtual ~Object() = default;
Object & operator=(Object &&) noexcept = delete;
virtual void update(int frameNo, const VMatrix &parentMatrix,
float parentAlpha, const DirtyFlag &flag) = 0;
virtual void renderList(std::vector<VDrawable *> &) {}
virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &)
{
return false;
}
virtual Object::Type type() const { return Object::Type::Unknown; }
};
class Shape;
class Group : public Object {
public:
Group() = default;
explicit Group(model::Group *data, VArenaAlloc *allocator);
void addChildren(model::Group *data, VArenaAlloc *allocator);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag) override;
void applyTrim();
void processTrimItems(std::vector<Shape *> &list);
void processPaintItems(std::vector<Shape *> &list);
void renderList(std::vector<VDrawable *> &list) override;
Object::Type type() const final { return Object::Type::Group; }
const VMatrix &matrix() const { return mMatrix; }
const char * name() const
{
static const char *TAG = "__";
return mModel.hasModel() ? mModel.name() : TAG;
}
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value) override;
protected:
std::vector<Object *> mContents;
VMatrix mMatrix;
private:
model::Filter<model::Group> mModel;
};
class Shape : public Object {
public:
Shape(bool staticPath) : mStaticPath(staticPath) {}
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag) final;
Object::Type type() const final { return Object::Type::Shape; }
bool dirty() const { return mDirtyPath; }
const VPath &localPath() const { return mTemp; }
void finalPath(VPath &result);
void updatePath(const VPath &path)
{
mTemp = path;
mDirtyPath = true;
}
bool staticPath() const { return mStaticPath; }
void setParent(Group *parent) { mParent = parent; }
Group *parent() const { return mParent; }
protected:
virtual void updatePath(VPath &path, int frameNo) = 0;
virtual bool hasChanged(int prevFrame, int curFrame) = 0;
private:
bool hasChanged(int frameNo)
{
int prevFrame = mFrameNo;
mFrameNo = frameNo;
if (prevFrame == -1) return true;
if (mStaticPath || (prevFrame == frameNo)) return false;
return hasChanged(prevFrame, frameNo);
}
Group *mParent{nullptr};
VPath mLocalPath;
VPath mTemp;
int mFrameNo{-1};
bool mDirtyPath{true};
bool mStaticPath;
};
class Rect final : public Shape {
public:
explicit Rect(model::Rect *data);
protected:
void updatePath(VPath &path, int frameNo) final;
model::Rect *mData{nullptr};
bool hasChanged(int prevFrame, int curFrame) final
{
return (mData->mPos.changed(prevFrame, curFrame) ||
mData->mSize.changed(prevFrame, curFrame) ||
mData->roundnessChanged(prevFrame, curFrame));
}
};
class Ellipse final : public Shape {
public:
explicit Ellipse(model::Ellipse *data);
private:
void updatePath(VPath &path, int frameNo) final;
model::Ellipse *mData{nullptr};
bool hasChanged(int prevFrame, int curFrame) final
{
return (mData->mPos.changed(prevFrame, curFrame) ||
mData->mSize.changed(prevFrame, curFrame));
}
};
class Path final : public Shape {
public:
explicit Path(model::Path *data);
private:
void updatePath(VPath &path, int frameNo) final;
model::Path *mData{nullptr};
bool hasChanged(int prevFrame, int curFrame) final
{
return mData->mShape.changed(prevFrame, curFrame);
}
};
class Polystar final : public Shape {
public:
explicit Polystar(model::Polystar *data);
private:
void updatePath(VPath &path, int frameNo) final;
model::Polystar *mData{nullptr};
bool hasChanged(int prevFrame, int curFrame) final
{
return (mData->mPos.changed(prevFrame, curFrame) ||
mData->mPointCount.changed(prevFrame, curFrame) ||
mData->mInnerRadius.changed(prevFrame, curFrame) ||
mData->mOuterRadius.changed(prevFrame, curFrame) ||
mData->mInnerRoundness.changed(prevFrame, curFrame) ||
mData->mOuterRoundness.changed(prevFrame, curFrame) ||
mData->mRotation.changed(prevFrame, curFrame));
}
};
class Paint : public Object {
public:
Paint(bool staticContent);
void addPathItems(std::vector<Shape *> &list, size_t startOffset);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag) override;
void renderList(std::vector<VDrawable *> &list) final;
Object::Type type() const final { return Object::Type::Paint; }
protected:
virtual bool updateContent(int frameNo, const VMatrix &matrix,
float alpha) = 0;
private:
void updateRenderNode();
protected:
std::vector<Shape *> mPathItems;
Drawable mDrawable;
VPath mPath;
DirtyFlag mFlag;
bool mStaticContent;
bool mRenderNodeUpdate{true};
bool mContentToRender{true};
};
class Fill final : public Paint {
public:
explicit Fill(model::Fill *data);
protected:
bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value) final;
private:
model::Filter<model::Fill> mModel;
};
class GradientFill final : public Paint {
public:
explicit GradientFill(model::GradientFill *data);
protected:
bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
private:
model::GradientFill * mData{nullptr};
std::unique_ptr<VGradient> mGradient;
};
class Stroke : public Paint {
public:
explicit Stroke(model::Stroke *data);
protected:
bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value) final;
private:
model::Filter<model::Stroke> mModel;
};
class GradientStroke final : public Paint {
public:
explicit GradientStroke(model::GradientStroke *data);
protected:
bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final;
private:
model::GradientStroke * mData{nullptr};
std::unique_ptr<VGradient> mGradient;
};
class Trim final : public Object {
public:
explicit Trim(model::Trim *data) : mData(data) {}
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag) final;
Object::Type type() const final { return Object::Type::Trim; }
void update();
void addPathItems(std::vector<Shape *> &list, size_t startOffset);
private:
bool pathDirty() const
{
for (auto &i : mPathItems) {
if (i->dirty()) return true;
}
return false;
}
struct Cache {
int mFrameNo{-1};
model::Trim::Segment mSegment{};
};
Cache mCache;
std::vector<Shape *> mPathItems;
model::Trim * mData{nullptr};
VPathMesure mPathMesure;
bool mDirty{true};
};
class Repeater final : public Group {
public:
explicit Repeater(model::Repeater *data, VArenaAlloc *allocator);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha,
const DirtyFlag &flag) final;
void renderList(std::vector<VDrawable *> &list) final;
private:
model::Repeater *mRepeaterData{nullptr};
bool mHidden{false};
int mCopies{0};
};
} // namespace renderer
} // namespace internal
} // namespace rlottie
#endif // LOTTIEITEM_H