rlottie: Added dynamic property change feature

The keypath can handle globe(**) and wildchar(*) reg ex.
Currently only support fillcolor , fill opacity , stroke color , stroke opacity and stroke width property.
This commit is contained in:
subhransu mohanty 2019-04-23 14:59:50 +09:00 committed by Hermet Park
parent 2433238033
commit 90affa8bd1
14 changed files with 622 additions and 47 deletions

View File

@ -45,10 +45,13 @@ main(void)
app->setup();
std::string filePath = DEMO_DIR;
filePath +="3d.json";
filePath +="circuit.json";
LottieView *view = new LottieView(app->evas());
view->setFilePath(filePath.c_str());
if (view->player()) {
view->player()->setValue<rlottie::Property::FillColor>("**", rlottie::Color(0, 1, 0));
}
view->setPos(0, 0);
view->setSize(800, 800);
view->show();

View File

@ -43,6 +43,7 @@ public:
evas_object_del(renderObject());
}
RenderStrategy(Evas_Object *obj):_renderObject(obj){}
virtual rlottie::Animation *player() {return nullptr;}
virtual void loadFromFile(const char *filePath) = 0;
virtual void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath) = 0;
virtual size_t totalFrame() = 0;
@ -63,7 +64,7 @@ private:
class CppApiBase : public RenderStrategy {
public:
CppApiBase(Evas_Object *renderObject): RenderStrategy(renderObject) {}
rlottie::Animation *player() {return mPlayer.get();}
void loadFromFile(const char *filePath)
{
mPlayer = rlottie::Animation::loadFromFile(filePath);
@ -283,6 +284,7 @@ public:
};
LottieView(Evas *evas, Strategy s = Strategy::renderCppAsync);
~LottieView();
rlottie::Animation *player(){return mRenderDelegate->player();}
Evas_Object *getImage();
void setSize(int w, int h);
void setPos(int x, int y);

File diff suppressed because one or more lines are too long

View File

@ -51,6 +51,38 @@ struct LOTLayerNode;
namespace rlottie {
struct Color {
Color(){}
Color(float r, float g , float b):mr(r), mg(g), mb(b){}
public:
float mr{0}, mg{0}, mb{0};
};
struct Size {
Size(float w, float h):mw(w), mh(h){}
private:
float mw{0} , mh{0};
};
struct Point {
Point(float x, float y):mx(x), my(y){}
private:
float mx{0} , my{0};
};
enum class Property {
FillColor, /*!< Color property of Fill object , value type is rlottie::Color */
FillOpacity, /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */
StrokeColor, /*!< Color property of Stroke object , value type is rlottie::Color */
StrokeOpacity, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */
StrokeWidth, /*!< stroke with property of Stroke object , value type is float */
TrAnchor, /*!< Transform Anchor property of Layer and Group object , value type is rlottie::Point */
TrPosition, /*!< Transform Position property of Layer and Group object , value type is rlottie::Point */
TrScale, /*!< Transform Scale property of Layer and Group object , value type is rlottie::Size. range[0 ..100] */
TrRotation, /*!< Transform Scale property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/
TrOpacity /*!< Transform Opacity property of Layer and Group object , value type is float [ 0 .. 100] */
};
class LOT_EXPORT Surface {
public:
/**
@ -336,6 +368,29 @@ public:
*/
const LayerInfoList& layers() const;
/**
* @brief Sets property value for the specified {@link KeyPath}. This {@link KeyPath} can resolve
* to multiple contents. In that case, the callback's value will apply to all of them.
*
* Keypath should conatin object names separated by (.) and can handle globe(**) or wildchar(*).
*
* @usage
* To change fillcolor property of fill1 object in the layer1->group1->fill1 hirarchy to RED color
*
* player->setValue<rlottie::Property::FillColor>("layer1.group1.fill1", rlottie::Color(1, 0, 0);
*
* if all the color property inside group1 needs to be changed to GREEN color
*
* player->setValue<rlottie::Property::FillColor>("**.group1.**", rlottie::Color(0, 1, 0);
*
* @internal
*/
template<Property prop, typename AnyValue>
void setValue(const std::string &keypath, AnyValue value)
{
setValue(std::integral_constant<ValueType, mapType(prop)>{}, prop, keypath, value);
}
/**
* @brief default destructor
*
@ -344,6 +399,34 @@ public:
~Animation();
private:
enum class ValueType {Color,Point,Size,Float};
static constexpr ValueType mapType(Property prop) {
switch (prop) {
case Property::FillColor:
case Property::StrokeColor:
return ValueType::Color;
case Property::FillOpacity:
case Property::StrokeOpacity:
case Property::StrokeWidth:
case Property::TrOpacity:
case Property::TrRotation:
return ValueType::Float;
case Property::TrAnchor:
case Property::TrPosition:
return ValueType::Point;
case Property::TrScale:
return ValueType::Size;
}
}
void setValue(std::integral_constant<ValueType, ValueType::Color>,
Property, const std::string &, Color);
void setValue(std::integral_constant<ValueType, ValueType::Float>,
Property, const std::string &, float);
void setValue(std::integral_constant<ValueType, ValueType::Size>,
Property, const std::string &, Size);
void setValue(std::integral_constant<ValueType, ValueType::Point>,
Property, const std::string &, Point);
/**
* @brief default constructor
*
@ -354,6 +437,7 @@ private:
std::unique_ptr<AnimationImpl> d;
};
} // namespace lotplayer
#endif // _RLOTTIE_H_

View File

@ -7,6 +7,7 @@ target_sources(rlottie
"${CMAKE_CURRENT_LIST_DIR}/lottieproxymodel.cpp"
"${CMAKE_CURRENT_LIST_DIR}/lottieparser.cpp"
"${CMAKE_CURRENT_LIST_DIR}/lottieanimation.cpp"
"${CMAKE_CURRENT_LIST_DIR}/lottiekeypath.cpp"
)
target_include_directories(rlottie

View File

@ -51,6 +51,8 @@ public:
renderTree(size_t frameNo, const VSize &size);
const LayerInfoList& layerInfoList() const { return mModel->layerInfoList();}
void setValue(const std::string &keypath, LOTVariant &&value);
void removeFilter(const std::string &keypath, Property prop);
private:
std::string mFilePath;
std::shared_ptr<LOTModel> mModel;
@ -59,6 +61,12 @@ private:
std::atomic<bool> mRenderInProgress;
};
void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value)
{
if (keypath.empty()) return;
mCompItem->setValue(keypath, value);
}
const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size)
{
if (update(frameNo, size)) {
@ -306,6 +314,34 @@ const LayerInfoList& Animation::layers() const
return d->layerInfoList();
}
void Animation::setValue(std::integral_constant<ValueType, ValueType::Color>,Property prop,
const std::string &keypath,
Color value)
{
d->setValue(keypath, LOTVariant(prop, value));
}
void Animation::setValue(std::integral_constant<ValueType, ValueType::Float>, Property prop,
const std::string &keypath,
float value)
{
d->setValue(keypath, LOTVariant(prop, value));
}
void Animation::setValue(std::integral_constant<ValueType, ValueType::Size>,Property prop,
const std::string &keypath,
Size value)
{
d->setValue(keypath, LOTVariant(prop, value));
}
void Animation::setValue(std::integral_constant<ValueType, ValueType::Point>, Property prop,
const std::string &keypath,
Point value)
{
d->setValue(keypath, LOTVariant(prop, value));
}
Animation::Animation(): d(std::make_unique<AnimationImpl>()) {}
/*

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@ -24,6 +24,7 @@
#include "vdasher.h"
#include "vpainter.h"
#include "vraster.h"
#include "lottiekeypath.h"
/* Lottie Layer Rules
* 1. time stretch is pre calculated and applied to all the properties of the
@ -32,6 +33,45 @@
* AE. which means (start frame > endFrame) 3.
*/
static
bool transformProp(rlottie::Property prop)
{
switch (prop) {
case rlottie::Property::TrAnchor:
case rlottie::Property::TrScale:
case rlottie::Property::TrOpacity:
case rlottie::Property::TrPosition:
case rlottie::Property::TrRotation:
return true;
default:
return false;
}
}
static
bool fillProp(rlottie::Property prop)
{
switch (prop) {
case rlottie::Property::FillColor:
case rlottie::Property::FillOpacity:
return true;
default:
return false;
}
}
static
bool strokeProp(rlottie::Property prop)
{
switch (prop) {
case rlottie::Property::StrokeColor:
case rlottie::Property::StrokeOpacity:
case rlottie::Property::StrokeWidth:
return true;
default:
return false;
}
}
LOTCompItem::LOTCompItem(LOTModel *model)
: mRootModel(model), mUpdateViewBox(false), mCurFrameNo(-1)
{
@ -41,6 +81,12 @@ LOTCompItem::LOTCompItem(LOTModel *model)
mViewSize = mCompData->size();
}
void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value)
{
LOTKeyPath key(keypath);
mRootLayer->resolveKeyPath(key, 0, value);
}
std::unique_ptr<LOTLayerItem>
LOTCompItem::createLayerItem(LOTLayerData *layerData)
{
@ -369,6 +415,50 @@ LOTLayerItem::LOTLayerItem(LOTLayerData *layerData): mLayerData(layerData)
mLayerMask = std::make_unique<LOTLayerMaskItem>(mLayerData);
}
bool LOTLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value)
{
if (!keyPath.matches(name(), depth)) {
return false;
}
if (!keyPath.skip(name())) {
if (keyPath.fullyResolvesTo(name(), depth) &&
transformProp(value.property())) {
//@TODO handle propery update.
}
}
return true;
}
bool LOTShapeLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value)
{
if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)){
if (keyPath.propagate(name(), depth)) {
uint newDepth = keyPath.nextDepth(name(), depth);
mRoot->resolveKeyPath(keyPath, newDepth, value);
}
return true;
}
return false;
}
bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
LOTVariant &value)
{
if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) {
if (keyPath.propagate(name(), depth)) {
uint newDepth = keyPath.nextDepth(name(), depth);
for (const auto &layer : mLayers) {
layer->resolveKeyPath( keyPath, newDepth, value);
}
}
return true;
}
return false;
}
void LOTLayerItem::updateStaticProperty()
{
if (mParentLayer) mParentLayer->updateStaticProperty();
@ -862,6 +952,56 @@ void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
mRoot->renderList(list);
}
bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
{
if (!keyPath.matches(name(), depth)) {
return false;
}
if (!keyPath.skip(name())) {
if (keyPath.fullyResolvesTo(name(), depth) &&
transformProp(value.property())) {
//@TODO handle property update
}
}
if (keyPath.propagate(name(), depth)) {
uint newDepth = keyPath.nextDepth(name(), depth);
for (auto &child : mContents) {
child->resolveKeyPath( keyPath, newDepth, value);
}
}
return true;
}
bool LOTFillItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
{
if (!keyPath.matches(mModel.name(), depth)) {
return false;
}
if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
fillProp(value.property())) {
mModel.filter().addValue(value);
return true;
}
return false;
}
bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
{
if (!keyPath.matches(mModel.name(), depth)) {
return false;
}
if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
strokeProp(value.property())) {
mModel.filter().addValue(value);
return true;
}
return false;
}
LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) : mData(data)
{
addChildren(mData);

View File

@ -31,6 +31,7 @@
#include"rlottie.h"
#include"vpainter.h"
#include"vdrawable.h"
#include"lottiekeypath.h"
V_USE_NAMESPACE
@ -46,7 +47,6 @@ class LOTLayerItem;
class LOTMaskItem;
class VDrawable;
class LOTCompItem
{
public:
@ -58,6 +58,7 @@ public:
void buildRenderTree();
const LOTLayerNode * renderTree()const;
bool render(const rlottie::Surface &surface);
void setValue(const std::string &keypath, LOTVariant &value);
private:
VMatrix mScaleMatrix;
VSize mViewSize;
@ -86,11 +87,12 @@ public:
};
typedef vFlag<DirtyFlagBit> DirtyFlag;
class LOTLayerItem
{
public:
virtual ~LOTLayerItem() = default;
LOTLayerItem(LOTLayerData *layerData);
virtual ~LOTLayerItem()= default;
int id() const {return mLayerData->id();}
int parentId() const {return mLayerData->parentId();}
void setParentLayer(LOTLayerItem *parent){mParentLayer = parent;}
@ -105,6 +107,8 @@ public:
bool visible() const;
virtual void buildLayerNode();
LOTLayerNode * layerNode() const {return mLayerCNode.get();}
const std::string & name() const {return mLayerData->name();}
virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value);
protected:
virtual void updateContent() = 0;
inline VMatrix combinedMatrix() const {return mCombinedMatrix;}
@ -136,6 +140,7 @@ public:
void updateStaticProperty() final;
void render(VPainter *painter, const VRle &mask, const VRle &matteRle) final;
void buildLayerNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
protected:
void updateContent() final;
private:
@ -169,6 +174,7 @@ public:
static std::unique_ptr<LOTContentItem> createContentItem(LOTData *contentData);
void renderList(std::vector<VDrawable *> &list)final;
void buildLayerNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
protected:
void updateContent() final;
std::vector<LOTNode *> mCNodeList;
@ -250,11 +256,12 @@ class LOTTrimItem;
class LOTContentItem
{
public:
virtual ~LOTContentItem()= default;
virtual ~LOTContentItem() = default;
virtual void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) = 0;
virtual void renderList(std::vector<VDrawable *> &){}
void setParent(LOTContentItem *parent) {mParent = parent;}
LOTContentItem *parent() const {return mParent;}
virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) {return false;}
private:
LOTContentItem *mParent{nullptr};
};
@ -265,12 +272,18 @@ public:
LOTContentGroupItem(){}
LOTContentGroupItem(LOTGroupData *data);
void addChildren(LOTGroupData *data);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override;
void applyTrim();
void processTrimItems(std::vector<LOTPathDataItem *> &list);
void processPaintItems(std::vector<LOTPathDataItem *> &list);
void renderList(std::vector<VDrawable *> &list);
void renderList(std::vector<VDrawable *> &list) override;
const VMatrix & matrix() const { return mMatrix;}
const std::string & name() const
{
static const std::string TAG = "__";
return mData ? mData->name() : TAG;
}
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
protected:
LOTGroupData *mData{nullptr};
std::vector<std::unique_ptr<LOTContentItem>> mContents;
@ -398,6 +411,7 @@ public:
protected:
void updateContent(int frameNo) final;
void updateRenderNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final;
private:
LOTProxyModel<LOTFillData> mModel;
VColor mColor;
@ -424,6 +438,7 @@ public:
protected:
void updateContent(int frameNo) final;
void updateRenderNode() final;
bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final;
private:
LOTProxyModel<LOTStrokeData> mModel;
LOTStrokeData *mData;

View File

@ -0,0 +1,81 @@
#include "lottiekeypath.h"
#include <sstream>
LOTKeyPath::LOTKeyPath(const std::string &keyPath)
{
std::stringstream ss (keyPath);
std::string item;
while (getline (ss, item, '.')) {
mKeys.push_back (item);
}
}
bool LOTKeyPath::matches(const std::string &key, uint depth)
{
if (skip(key)) {
// This is an object we programatically create.
return true;
}
if (depth > size()) {
return false;
}
if ((mKeys[depth] == key) ||
(mKeys[depth] == "*") ||
(mKeys[depth] == "**")) {
return true;
}
return false;
}
uint LOTKeyPath::nextDepth(const std::string key, uint depth) {
if (skip(key)) {
// If it's a container then we added programatically and it isn't a part of the keypath.
return depth;
}
if ( mKeys[depth] != "**") {
// If it's not a globstar then it is part of the keypath.
return depth + 1;
}
if (depth == size()) {
// The last key is a globstar.
return depth;
}
if (mKeys[depth + 1] == key) {
// We are a globstar and the next key is our current key so consume both.
return depth + 2;
}
return depth;
}
bool LOTKeyPath::fullyResolvesTo(const std::string key, uint depth) {
if (depth > mKeys.size()) {
return false;
}
bool isLastDepth = (depth == size());
if (!isGlobstar(depth)) {
bool matches = (mKeys[depth] == key) || isGlob(depth);
return (isLastDepth || (depth == size() - 1 && endsWithGlobstar())) && matches;
}
bool isGlobstarButNextKeyMatches = !isLastDepth && mKeys[depth + 1] == key;
if (isGlobstarButNextKeyMatches) {
return depth == size() - 1 ||
(depth == size() - 2 && endsWithGlobstar());
}
if (isLastDepth) {
return true;
}
if (depth + 1 < size()) {
// We are a globstar but there is more than 1 key after the globstar we we can't fully match.
return false;
}
// Return whether the next key (which we now know is the last one) is the same as the current
// key.
return mKeys[depth + 1] == key;
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LOTTIEKEYPATH_H
#define LOTTIEKEYPATH_H
#include <string>
#include <vector>
class LOTKeyPath{
public:
LOTKeyPath(const std::string &keyPath);
bool matches(const std::string &key, uint depth);
uint nextDepth(const std::string key, uint depth);
bool fullyResolvesTo(const std::string key, uint depth);
bool propagate(const std::string key, uint depth) {
return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**");
}
bool skip(const std::string &key) const { return key == "__";}
private:
bool isGlobstar(uint depth) const {return mKeys[depth] == "**";}
bool isGlob(uint depth) const {return mKeys[depth] == "*";}
bool endsWithGlobstar() const { return mKeys.back() == "**"; }
uint size() const {return mKeys.size() - 1;}
private:
std::vector<std::string> mKeys;
};
#endif //LOTTIEKEYPATH_H

View File

@ -295,7 +295,7 @@ class LOTDataVisitor;
class LOTData
{
public:
enum class Type {
enum class Type :short {
Composition = 1,
Layer,
ShapeGroup,
@ -316,7 +316,9 @@ public:
bool isStatic() const{return mStatic;}
void setStatic(bool value) {mStatic = value;}
bool hidden() const {return mHidden;}
const std::string& name() const{ return mName;}
public:
std::string mName;
bool mStatic{true};
bool mHidden{false};
LOTData::Type mType;

View File

@ -748,6 +748,7 @@ void LottieParserImpl::parseLayers(LOTCompositionData *comp)
comp->mRootLayer->mRoot = true;
comp->mRootLayer->mLayerType = LayerType::Precomp;
comp->mRootLayer->mTransform = std::make_shared<LOTTransformData>();
comp->mRootLayer->mName = std::string("__");
bool staticFlag = true;
RAPIDJSON_ASSERT(PeekType() == kArrayType);
EnterArray();
@ -857,7 +858,7 @@ std::shared_ptr<LOTData> LottieParserImpl::parseLayer(bool record)
layer->mLayerType = getLayerType();
} else if (0 == strcmp(key, "nm")) { /*Layer name*/
RAPIDJSON_ASSERT(PeekType() == kStringType);
layerName = GetString();
layer->mName = GetString();
} else if (0 == strcmp(key, "ind")) { /*Layer index in AE. Used for
parenting and expressions.*/
RAPIDJSON_ASSERT(PeekType() == kNumberType);
@ -939,7 +940,7 @@ std::shared_ptr<LOTData> LottieParserImpl::parseLayer(bool record)
layer->mCompRef = compRef;
if (record) {
mLayerInfoList.push_back(LayerInfo(layerName, layer->mInFrame, layer->mOutFrame));
mLayerInfoList.push_back(LayerInfo(layer->mName, layer->mInFrame, layer->mOutFrame));
}
return sharedLayer;
}
@ -1070,7 +1071,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGroupObject()
LOTShapeGroupData *group = sharedGroup.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "it")) {
if (0 == strcmp(key, "nm")) {
group->mName = GetString();
} else if (0 == strcmp(key, "it")) {
RAPIDJSON_ASSERT(PeekType() == kArrayType);
EnterArray();
while (NextArrayValue()) {
@ -1105,7 +1108,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseRectObject()
LOTRectData * obj = sharedRect.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "p")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "p")) {
parseProperty(obj->mPos);
} else if (0 == strcmp(key, "s")) {
parseProperty(obj->mSize);
@ -1134,7 +1139,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseEllipseObject()
LOTEllipseData *obj = sharedEllipse.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "p")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "p")) {
parseProperty(obj->mPos);
} else if (0 == strcmp(key, "s")) {
parseProperty(obj->mSize);
@ -1160,7 +1167,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseShapeObject()
LOTShapeData *obj = sharedShape.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "ks")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "ks")) {
parseShapeProperty(obj->mShape);
} else if (0 == strcmp(key, "d")) {
obj->mDirection = GetInt();
@ -1188,7 +1197,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parsePolystarObject()
LOTPolystarData *obj = sharedPolystar.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "p")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "p")) {
parseProperty(obj->mPos);
} else if (0 == strcmp(key, "pt")) {
parseProperty(obj->mPointCount);
@ -1251,7 +1262,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseTrimObject()
LOTTrimData * obj = sharedTrim.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "s")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "s")) {
parseProperty(obj->mStart);
} else if (0 == strcmp(key, "e")) {
parseProperty(obj->mEnd);
@ -1280,7 +1293,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseReapeaterObject()
LOTRepeaterData *obj = sharedRepeater.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "c")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "c")) {
parseProperty(obj->mCopies);
float maxCopy= 0.0;
if (!obj->mCopies.isStatic()) {
@ -1326,7 +1341,9 @@ std::shared_ptr<LOTTransformData> LottieParserImpl::parseTransformObject(bool dd
if (ddd) obj->m3D = std::make_unique<LOT3DData>();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "a")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "a")) {
parseProperty(obj->mAnchor);
} else if (0 == strcmp(key, "p")) {
EnterObject();
@ -1394,7 +1411,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseFillObject()
LOTFillData * obj = sharedFill.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "c")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "c")) {
parseProperty(obj->mColor);
} else if (0 == strcmp(key, "o")) {
parseProperty(obj->mOpacity);
@ -1480,7 +1499,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseStrokeObject()
LOTStrokeData *obj = sharedStroke.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "c")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "c")) {
parseProperty(obj->mColor);
} else if (0 == strcmp(key, "o")) {
parseProperty(obj->mOpacity);
@ -1561,7 +1582,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGFillObject()
LOTGFillData *obj = sharedGFill.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "r")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "r")) {
obj->mFillRule = getFillRule();
} else {
parseGradientProperty(obj, key);
@ -1607,7 +1630,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGStrokeObject()
LOTGStrokeData *obj = sharedGStroke.get();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "w")) {
if (0 == strcmp(key, "nm")) {
obj->mName = GetString();
} else if (0 == strcmp(key, "w")) {
parseProperty(obj->mWidth);
} else if (0 == strcmp(key, "lc")) {
obj->mCapStyle = getLineCap();
@ -2077,6 +2102,7 @@ public:
vDebug << level
<< "{ "
<< layerType(obj->mLayerType)
<< ", name: "<< obj->name()
<< ", id:" << obj->mId << " Pid:" << obj->mParentId
<< ", a:" << !obj->isStatic()
<< ", "<<matteType(obj->mMatteType)
@ -2120,7 +2146,7 @@ public:
switch (obj->mType) {
case LOTData::Type::Repeater: {
auto r = static_cast<LOTRepeaterData *>(obj);
vDebug << level << "{ Repeater: a:" << !obj->isStatic()
vDebug << level << "{ Repeater: name: "<<obj->name()<<" , a:" << !obj->isStatic()
<< ", copies:" << r->maxCopies()
<< ", offset:" << r->offset(0);
visitChildren(static_cast<LOTGroupData *>(obj), level);
@ -2128,7 +2154,7 @@ public:
break;
}
case LOTData::Type::ShapeGroup: {
vDebug << level << "{ ShapeGroup: a:" << !obj->isStatic();
vDebug << level << "{ ShapeGroup: name: "<<obj->name()<<" , a:" << !obj->isStatic();
visitChildren(static_cast<LOTGroupData *>(obj), level);
vDebug << level << "} ShapeGroup";
break;
@ -2138,44 +2164,44 @@ public:
break;
}
case LOTData::Type::Trim:{
vDebug << level << "{ Trim: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Trim: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Rect:{
vDebug << level << "{ Rect: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Rect: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Ellipse:{
vDebug << level << "{ Ellipse: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Ellipse: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Shape:{
vDebug << level << "{ Shape: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Shape: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Polystar:{
vDebug << level << "{ Polystar: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Polystar: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Transform:{
vDebug << level << "{ Transform: a: " << !obj->isStatic() << " }";
vDebug << level << "{ Transform: name: "<<obj->name()<<" , a: " << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Stroke:{
vDebug << level << "{ Stroke: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Stroke: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::GStroke:{
vDebug << level << "{ GStroke: a:" << !obj->isStatic() << " }";
vDebug << level << "{ GStroke: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::Fill:{
vDebug << level << "{ Fill: a:" << !obj->isStatic() << " }";
vDebug << level << "{ Fill: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
break;
}
case LOTData::Type::GFill:{
auto f = static_cast<LOTGFillData *>(obj);
vDebug << level << "{ GFill: a:" << !f->isStatic()
vDebug << level << "{ GFill: name: "<<obj->name()<<" , a:" << !f->isStatic()
<< ", ty:" << f->mGradientType << ", s:" << f->mStartPoint.value(0)
<< ", e:" << f->mEndPoint.value(0) << " }";
break;

View File

@ -19,21 +19,131 @@
#ifndef LOTTIEPROXYMODEL_H
#define LOTTIEPROXYMODEL_H
#include<bitset>
#include "lottiemodel.h"
#include "rlottie.h"
// Naive way to implement std::variant
// refactor it when we move to c++17
// users should make sure proper combination
// of id and value are passed while creating the object.
class LOTVariant
{
public:
enum Type {Color, Point, Size, Float};
LOTVariant(rlottie::Property prop, float v):property_(prop),valueType_(Type::Float),value_(v){}
LOTVariant(rlottie::Property prop, rlottie::Color col):property_(prop),valueType_(Type::Color),color_(col){}
LOTVariant(rlottie::Property prop, rlottie::Point pt):property_(prop),valueType_(Type::Point),pos_(pt){}
LOTVariant(rlottie::Property prop, rlottie::Size sz):property_(prop),valueType_(Type::Size),size_(sz){}
Type type() const {return valueType_;}
rlottie::Property property() const {return property_;}
float value() const {return value_;}
rlottie::Color color() const {return color_;}
rlottie::Point pos() const {return pos_;}
rlottie::Size size() const {return size_;}
public:
rlottie::Property property_;
Type valueType_;
union {
float value_;
rlottie::Color color_;
rlottie::Point pos_;
rlottie::Size size_;
};
};
class LOTFilter
{
public:
void addValue(LOTVariant &value)
{
uint index = static_cast<uint>(value.property());
if (mBitset.test(index)) {
for (uint i=0; i < mFilters.size(); i++ ) {
if (mFilters[i].property() == value.property()) {
mFilters[i] = value;
break;
}
}
} else {
mBitset.set(index);
mFilters.push_back(value);
}
}
void removeValue(LOTVariant &value)
{
uint index = static_cast<uint>(value.property());
if (mBitset.test(index)) {
mBitset.reset(index);
for (uint i=0; i < mFilters.size(); i++ ) {
if (mFilters[i].property() == value.property()) {
mFilters.erase(mFilters.begin() + i);
break;
}
}
}
}
bool hasFilter(rlottie::Property prop) const
{
return mBitset.test(static_cast<uint>(prop));
}
LottieColor color(rlottie::Property prop) const
{
rlottie::Color col = data(prop).color();
return LottieColor(col.mr, col.mg, col.mb);
}
float opacity(rlottie::Property prop) const
{
float val = data(prop).value();
return val/100;
}
float value(rlottie::Property prop) const
{
return data(prop).value();
}
private:
LOTVariant data(rlottie::Property prop) const
{
for (uint i=0; i < mFilters.size(); i++ ) {
if (mFilters[i].property() == prop) {
return mFilters[i];
}
}
return LOTVariant(prop, 0);
}
std::vector<LOTVariant> mFilters;
std::bitset<32> mBitset{0};
};
template <typename T>
class LOTProxyModel
{
public:
LOTProxyModel(T *model): _modelData(model) {}
void addValueProvider() {/* Impement*/}
void removeValueProvider() {/* Impement*/}
bool hasValueProvider() {return false;}
LottieColor color(int frame) const { return _modelData->color(frame);}
float opacity(int frame) const { return _modelData->opacity(frame);}
FillRule fillRule() const {return _modelData->fillRule();}
float strokeWidth(int frame) const {return _modelData->strokeWidth(frame);}
LOTFilter& filter() {return mFilter;}
const std::string & name() const {return _modelData->name();}
LottieColor color(int frame) const
{
if (mFilter.hasFilter(rlottie::Property::StrokeColor)) {
return mFilter.color(rlottie::Property::StrokeColor);
}
return _modelData->color(frame);
}
float opacity(int frame) const
{
if (mFilter.hasFilter(rlottie::Property::StrokeOpacity)) {
return mFilter.opacity(rlottie::Property::StrokeOpacity);
}
return _modelData->opacity(frame);
}
float strokeWidth(int frame) const
{
if (mFilter.hasFilter(rlottie::Property::StrokeWidth)) {
return mFilter.value(rlottie::Property::StrokeWidth);
}
return _modelData->strokeWidth(frame);
}
float meterLimit() const {return _modelData->meterLimit();}
CapStyle capStyle() const {return _modelData->capStyle();}
JoinStyle joinStyle() const {return _modelData->joinStyle();}
@ -42,6 +152,34 @@ public:
private:
T *_modelData;
LOTFilter mFilter;
};
template <>
class LOTProxyModel<LOTFillData>
{
public:
LOTProxyModel(LOTFillData *model): _modelData(model) {}
LOTFilter& filter() {return mFilter;}
const std::string & name() const {return _modelData->name();}
LottieColor color(int frame) const
{
if (mFilter.hasFilter(rlottie::Property::FillColor)) {
return mFilter.color(rlottie::Property::FillColor);
}
return _modelData->color(frame);
}
float opacity(int frame) const
{
if (mFilter.hasFilter(rlottie::Property::FillOpacity)) {
return mFilter.opacity(rlottie::Property::FillOpacity);
}
return _modelData->opacity(frame);
}
FillRule fillRule() const {return _modelData->fillRule();}
private:
LOTFillData *_modelData;
LOTFilter mFilter;
};
#endif // LOTTIEITEM_H

View File

@ -5,6 +5,7 @@ source_file += files('lottiemodel.cpp')
source_file += files('lottieproxymodel.cpp')
source_file += files('lottieanimation.cpp')
source_file += files('lottieitem.cpp')
source_file += files('lottiekeypath.cpp')
lottie_dep = declare_dependency(