lottie/model: Refactor filter model
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Mon, 3 Aug 2020 04:25:54 +0000 (13:25 +0900)
committerJongmin Lee <jm105.lee@samsung.com>
Sun, 9 Aug 2020 21:35:27 +0000 (06:35 +0900)
src/lottie/lottiefiltermodel.h [new file with mode: 0644]
src/lottie/lottieitem.cpp
src/lottie/lottieitem.h
src/lottie/lottieproxymodel.h [deleted file]

diff --git a/src/lottie/lottiefiltermodel.h b/src/lottie/lottiefiltermodel.h
new file mode 100644 (file)
index 0000000..5d084ce
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * 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 LOTTIEFILTERMODEL_H
+#define LOTTIEFILTERMODEL_H
+
+#include <algorithm>
+#include <bitset>
+#include <cassert>
+#include "lottiemodel.h"
+#include "rlottie.h"
+
+using namespace rlottie::internal;
+// 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:
+    using ValueFunc = std::function<float(const rlottie::FrameInfo&)>;
+    using ColorFunc = std::function<rlottie::Color(const rlottie::FrameInfo&)>;
+    using PointFunc = std::function<rlottie::Point(const rlottie::FrameInfo&)>;
+    using SizeFunc = std::function<rlottie::Size(const rlottie::FrameInfo&)>;
+
+    LOTVariant(rlottie::Property prop, const ValueFunc& v)
+        : mPropery(prop), mTag(Value)
+    {
+        construct(impl.valueFunc, v);
+    }
+
+    LOTVariant(rlottie::Property prop, ValueFunc&& v)
+        : mPropery(prop), mTag(Value)
+    {
+        moveConstruct(impl.valueFunc, std::move(v));
+    }
+
+    LOTVariant(rlottie::Property prop, const ColorFunc& v)
+        : mPropery(prop), mTag(Color)
+    {
+        construct(impl.colorFunc, v);
+    }
+
+    LOTVariant(rlottie::Property prop, ColorFunc&& v)
+        : mPropery(prop), mTag(Color)
+    {
+        moveConstruct(impl.colorFunc, std::move(v));
+    }
+
+    LOTVariant(rlottie::Property prop, const PointFunc& v)
+        : mPropery(prop), mTag(Point)
+    {
+        construct(impl.pointFunc, v);
+    }
+
+    LOTVariant(rlottie::Property prop, PointFunc&& v)
+        : mPropery(prop), mTag(Point)
+    {
+        moveConstruct(impl.pointFunc, std::move(v));
+    }
+
+    LOTVariant(rlottie::Property prop, const SizeFunc& v)
+        : mPropery(prop), mTag(Size)
+    {
+        construct(impl.sizeFunc, v);
+    }
+
+    LOTVariant(rlottie::Property prop, SizeFunc&& v)
+        : mPropery(prop), mTag(Size)
+    {
+        moveConstruct(impl.sizeFunc, std::move(v));
+    }
+
+    rlottie::Property property() const { return mPropery; }
+
+    const ColorFunc& color() const
+    {
+        assert(mTag == Color);
+        return impl.colorFunc;
+    }
+
+    const ValueFunc& value() const
+    {
+        assert(mTag == Value);
+        return impl.valueFunc;
+    }
+
+    const PointFunc& point() const
+    {
+        assert(mTag == Point);
+        return impl.pointFunc;
+    }
+
+    const SizeFunc& size() const
+    {
+        assert(mTag == Size);
+        return impl.sizeFunc;
+    }
+
+    LOTVariant() = default;
+    ~LOTVariant() noexcept { Destroy(); }
+    LOTVariant(const LOTVariant& other) { Copy(other); }
+    LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other)); }
+    LOTVariant& operator=(LOTVariant&& other)
+    {
+        Destroy();
+        Move(std::move(other));
+        return *this;
+    }
+    LOTVariant& operator=(const LOTVariant& other)
+    {
+        Destroy();
+        Copy(other);
+        return *this;
+    }
+
+private:
+    template <typename T>
+    void construct(T& member, const T& val)
+    {
+        new (&member) T(val);
+    }
+
+    template <typename T>
+    void moveConstruct(T& member, T&& val)
+    {
+        new (&member) T(std::move(val));
+    }
+
+    void Move(LOTVariant&& other)
+    {
+        switch (other.mTag) {
+        case Type::Value:
+            moveConstruct(impl.valueFunc, std::move(other.impl.valueFunc));
+            break;
+        case Type::Color:
+            moveConstruct(impl.colorFunc, std::move(other.impl.colorFunc));
+            break;
+        case Type::Point:
+            moveConstruct(impl.pointFunc, std::move(other.impl.pointFunc));
+            break;
+        case Type::Size:
+            moveConstruct(impl.sizeFunc, std::move(other.impl.sizeFunc));
+            break;
+        default:
+            break;
+        }
+        mTag = other.mTag;
+        mPropery = other.mPropery;
+        other.mTag = MonoState;
+    }
+
+    void Copy(const LOTVariant& other)
+    {
+        switch (other.mTag) {
+        case Type::Value:
+            construct(impl.valueFunc, other.impl.valueFunc);
+            break;
+        case Type::Color:
+            construct(impl.colorFunc, other.impl.colorFunc);
+            break;
+        case Type::Point:
+            construct(impl.pointFunc, other.impl.pointFunc);
+            break;
+        case Type::Size:
+            construct(impl.sizeFunc, other.impl.sizeFunc);
+            break;
+        default:
+            break;
+        }
+        mTag = other.mTag;
+        mPropery = other.mPropery;
+    }
+
+    void Destroy()
+    {
+        switch (mTag) {
+        case MonoState: {
+            break;
+        }
+        case Value: {
+            impl.valueFunc.~ValueFunc();
+            break;
+        }
+        case Color: {
+            impl.colorFunc.~ColorFunc();
+            break;
+        }
+        case Point: {
+            impl.pointFunc.~PointFunc();
+            break;
+        }
+        case Size: {
+            impl.sizeFunc.~SizeFunc();
+            break;
+        }
+        }
+    }
+
+    enum Type { MonoState, Value, Color, Point, Size };
+    rlottie::Property mPropery;
+    Type              mTag{MonoState};
+    union details {
+        ColorFunc colorFunc;
+        ValueFunc valueFunc;
+        PointFunc pointFunc;
+        SizeFunc  sizeFunc;
+        details() {}
+        ~details() {}
+    } impl;
+};
+
+namespace rlottie {
+
+namespace internal {
+
+namespace model {
+
+class FilterData {
+public:
+    void addValue(LOTVariant& value)
+    {
+        uint index = static_cast<uint>(value.property());
+        if (mBitset.test(index)) {
+            std::replace_if(mFilters.begin(), mFilters.end(),
+                            [&value](const LOTVariant& e) {
+                                return e.property() == value.property();
+                            },
+                            value);
+        } 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);
+            mFilters.erase(std::remove_if(mFilters.begin(), mFilters.end(),
+                                          [&value](const LOTVariant& e) {
+                                              return e.property() ==
+                                                     value.property();
+                                          }),
+                           mFilters.end());
+        }
+    }
+    bool hasFilter(rlottie::Property prop) const
+    {
+        return mBitset.test(static_cast<uint>(prop));
+    }
+    model::Color color(rlottie::Property prop, int frame) const
+    {
+        rlottie::FrameInfo info(frame);
+        rlottie::Color     col = data(prop).color()(info);
+        return model::Color(col.r(), col.g(), col.b());
+    }
+    VPointF point(rlottie::Property prop, int frame) const
+    {
+        rlottie::FrameInfo info(frame);
+        rlottie::Point     pt = data(prop).point()(info);
+        return VPointF(pt.x(), pt.y());
+    }
+    VSize scale(rlottie::Property prop, int frame) const
+    {
+        rlottie::FrameInfo info(frame);
+        rlottie::Size      sz = data(prop).size()(info);
+        return VSize(sz.w(), sz.h());
+    }
+    float opacity(rlottie::Property prop, int frame) const
+    {
+        rlottie::FrameInfo info(frame);
+        float              val = data(prop).value()(info);
+        return val / 100;
+    }
+    float value(rlottie::Property prop, int frame) const
+    {
+        rlottie::FrameInfo info(frame);
+        return data(prop).value()(info);
+    }
+
+private:
+    const LOTVariant& data(rlottie::Property prop) const
+    {
+        auto result = std::find_if(
+            mFilters.begin(), mFilters.end(),
+            [prop](const LOTVariant& e) { return e.property() == prop; });
+        return *result;
+    }
+    std::bitset<32>         mBitset{0};
+    std::vector<LOTVariant> mFilters;
+};
+
+template <typename T>
+struct FilterBase
+{
+    FilterBase(T *model): model_(model){}
+
+    const char*  name() const { return model_->name(); }
+
+    FilterData* filter() {
+        if (!filterData_) filterData_ = std::make_unique<FilterData>();
+        return filterData_.get();
+    }
+
+    const FilterData * filter() const { return filterData_.get(); }
+    const T* model() const { return model_;}
+
+    bool hasFilter(rlottie::Property prop) const {
+        return filterData_ ? filterData_->hasFilter(prop)
+                         : false;
+    }
+
+    T*                           model_{nullptr};
+    std::unique_ptr<FilterData>  filterData_{nullptr};
+};
+
+
+template <typename T>
+class Filter : public FilterBase<T> {
+public:
+    Filter(T* model): FilterBase<T>(model){}
+    model::Color color(int frame) const
+    {
+        if (this->hasFilter(rlottie::Property::StrokeColor)) {
+            return this->filter()->color(rlottie::Property::StrokeColor, frame);
+        }
+        return this->model()->color(frame);
+    }
+    float opacity(int frame) const
+    {
+        if (this->hasFilter(rlottie::Property::StrokeOpacity)) {
+            return this->filter()->opacity(rlottie::Property::StrokeOpacity, frame);
+        }
+        return this->model()->opacity(frame);
+    }
+
+    float strokeWidth(int frame) const
+    {
+        if (this->hasFilter(rlottie::Property::StrokeWidth)) {
+            return this->filter()->value(rlottie::Property::StrokeWidth, frame);
+        }
+        return this->model()->strokeWidth(frame);
+    }
+
+    float     miterLimit() const { return this->model()->miterLimit(); }
+    CapStyle  capStyle() const { return this->model()->capStyle(); }
+    JoinStyle joinStyle() const { return this->model()->joinStyle(); }
+    bool      hasDashInfo() const { return this->model()->hasDashInfo(); }
+    void      getDashInfo(int frameNo, std::vector<float>& result) const
+    {
+        return this->model()->getDashInfo(frameNo, result);
+    }
+};
+
+
+template <>
+class Filter<model::Fill>: public FilterBase<model::Fill>
+{
+public:
+    Filter(model::Fill* model) : FilterBase<model::Fill>(model) {}
+
+    model::Color color(int frame) const
+    {
+        if (this->hasFilter(rlottie::Property::FillColor)) {
+            return this->filter()->color(rlottie::Property::FillColor, frame);
+        }
+        return this->model()->color(frame);
+    }
+
+    float opacity(int frame) const
+    {
+        if (this->hasFilter(rlottie::Property::FillOpacity)) {
+            return this->filter()->opacity(rlottie::Property::FillOpacity, frame);
+        }
+        return this->model()->opacity(frame);
+    }
+
+    FillRule fillRule() const { return this->model()->fillRule(); }
+};
+
+template <>
+class Filter<model::Group> : public FilterBase<model::Group>
+{
+public:
+    Filter(model::Group* model = nullptr) : FilterBase<model::Group>(model) {}
+
+    bool   hasModel() const { return this->model() ? true : false; }
+
+    model::Transform* transform() const { return this->model() ? this->model()->mTransform : nullptr; }
+    VMatrix           matrix(int frame) const
+    {
+        VMatrix mS, mR, mT;
+        if (this->hasFilter(rlottie::Property::TrScale)) {
+            VSize s = this->filter()->scale(rlottie::Property::TrScale, frame);
+            mS.scale(s.width() / 100.0, s.height() / 100.0);
+        }
+        if (this->hasFilter(rlottie::Property::TrRotation)) {
+            mR.rotate(this->filter()->value(rlottie::Property::TrRotation, frame));
+        }
+        if (this->hasFilter(rlottie::Property::TrPosition)) {
+            mT.translate(this->filter()->point(rlottie::Property::TrPosition, frame));
+        }
+
+        return this->model()->mTransform->matrix(frame) * mS * mR * mT;
+    }
+};
+
+
+}  // namespace model
+
+}  // namespace internal
+
+}  // namespace rlottie
+
+#endif  // LOTTIEFILTERMODEL_H
index db59fbd861febce741ad89c0d4dcf665bb87aa73..c521dda9336c93fd8e46d311c36b8532b61a223e 100644 (file)
@@ -844,7 +844,7 @@ bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
         if (!keyPath.skip(mModel.name())) {
             if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
                 transformProp(value.property())) {
-                mModel.filter().addValue(value);
+                mModel.filter()->addValue(value);
             }
         }
     }
@@ -867,7 +867,7 @@ bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 
     if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
         fillProp(value.property())) {
-        mModel.filter().addValue(value);
+        mModel.filter()->addValue(value);
         return true;
     }
     return false;
@@ -882,7 +882,7 @@ bool renderer::Stroke::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
 
     if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
         strokeProp(value.property())) {
-        mModel.filter().addValue(value);
+        mModel.filter()->addValue(value);
         return true;
     }
     return false;
index 03ca77d077a2774b0b3a3941e343e3b7fd5ae4a5..033bc92ccdeac251dfa8562dffef7b20c8a01c6d 100644 (file)
@@ -23,7 +23,7 @@
 #include <sstream>
 
 #include "lottiekeypath.h"
-#include "lottieproxymodel.h"
+#include "lottiefiltermodel.h"
 #include "rlottie.h"
 #include "rlottiecommon.h"
 #include "varenaalloc.h"
@@ -389,7 +389,7 @@ protected:
     VMatrix               mMatrix;
 
 private:
-    LOTProxyModel<model::Group> mModel;
+    model::Filter<model::Group> mModel;
 };
 
 class Shape : public Object {
@@ -530,7 +530,7 @@ protected:
                         LOTVariant &value) final;
 
 private:
-    LOTProxyModel<model::Fill> mModel;
+    model::Filter<model::Fill> mModel;
 };
 
 class GradientFill : public Paint {
@@ -555,7 +555,7 @@ protected:
                         LOTVariant &value) final;
 
 private:
-    LOTProxyModel<model::Stroke> mModel;
+    model::Filter<model::Stroke> mModel;
 };
 
 class GradientStroke : public Paint {
diff --git a/src/lottie/lottieproxymodel.h b/src/lottie/lottieproxymodel.h
deleted file mode 100644 (file)
index 6075169..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * 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 LOTTIEPROXYMODEL_H
-#define LOTTIEPROXYMODEL_H
-
-#include <algorithm>
-#include <bitset>
-#include <cassert>
-#include "lottiemodel.h"
-#include "rlottie.h"
-
-using namespace rlottie::internal;
-// 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:
-    using ValueFunc = std::function<float(const rlottie::FrameInfo&)>;
-    using ColorFunc = std::function<rlottie::Color(const rlottie::FrameInfo&)>;
-    using PointFunc = std::function<rlottie::Point(const rlottie::FrameInfo&)>;
-    using SizeFunc = std::function<rlottie::Size(const rlottie::FrameInfo&)>;
-
-    LOTVariant(rlottie::Property prop, const ValueFunc& v)
-        : mPropery(prop), mTag(Value)
-    {
-        construct(impl.valueFunc, v);
-    }
-
-    LOTVariant(rlottie::Property prop, ValueFunc&& v)
-        : mPropery(prop), mTag(Value)
-    {
-        moveConstruct(impl.valueFunc, std::move(v));
-    }
-
-    LOTVariant(rlottie::Property prop, const ColorFunc& v)
-        : mPropery(prop), mTag(Color)
-    {
-        construct(impl.colorFunc, v);
-    }
-
-    LOTVariant(rlottie::Property prop, ColorFunc&& v)
-        : mPropery(prop), mTag(Color)
-    {
-        moveConstruct(impl.colorFunc, std::move(v));
-    }
-
-    LOTVariant(rlottie::Property prop, const PointFunc& v)
-        : mPropery(prop), mTag(Point)
-    {
-        construct(impl.pointFunc, v);
-    }
-
-    LOTVariant(rlottie::Property prop, PointFunc&& v)
-        : mPropery(prop), mTag(Point)
-    {
-        moveConstruct(impl.pointFunc, std::move(v));
-    }
-
-    LOTVariant(rlottie::Property prop, const SizeFunc& v)
-        : mPropery(prop), mTag(Size)
-    {
-        construct(impl.sizeFunc, v);
-    }
-
-    LOTVariant(rlottie::Property prop, SizeFunc&& v)
-        : mPropery(prop), mTag(Size)
-    {
-        moveConstruct(impl.sizeFunc, std::move(v));
-    }
-
-    rlottie::Property property() const { return mPropery; }
-
-    const ColorFunc& color() const
-    {
-        assert(mTag == Color);
-        return impl.colorFunc;
-    }
-
-    const ValueFunc& value() const
-    {
-        assert(mTag == Value);
-        return impl.valueFunc;
-    }
-
-    const PointFunc& point() const
-    {
-        assert(mTag == Point);
-        return impl.pointFunc;
-    }
-
-    const SizeFunc& size() const
-    {
-        assert(mTag == Size);
-        return impl.sizeFunc;
-    }
-
-    LOTVariant() = default;
-    ~LOTVariant() noexcept { Destroy(); }
-    LOTVariant(const LOTVariant& other) { Copy(other); }
-    LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other)); }
-    LOTVariant& operator=(LOTVariant&& other)
-    {
-        Destroy();
-        Move(std::move(other));
-        return *this;
-    }
-    LOTVariant& operator=(const LOTVariant& other)
-    {
-        Destroy();
-        Copy(other);
-        return *this;
-    }
-
-private:
-    template <typename T>
-    void construct(T& member, const T& val)
-    {
-        new (&member) T(val);
-    }
-
-    template <typename T>
-    void moveConstruct(T& member, T&& val)
-    {
-        new (&member) T(std::move(val));
-    }
-
-    void Move(LOTVariant&& other)
-    {
-        switch (other.mTag) {
-        case Type::Value:
-            moveConstruct(impl.valueFunc, std::move(other.impl.valueFunc));
-            break;
-        case Type::Color:
-            moveConstruct(impl.colorFunc, std::move(other.impl.colorFunc));
-            break;
-        case Type::Point:
-            moveConstruct(impl.pointFunc, std::move(other.impl.pointFunc));
-            break;
-        case Type::Size:
-            moveConstruct(impl.sizeFunc, std::move(other.impl.sizeFunc));
-            break;
-        default:
-            break;
-        }
-        mTag = other.mTag;
-        mPropery = other.mPropery;
-        other.mTag = MonoState;
-    }
-
-    void Copy(const LOTVariant& other)
-    {
-        switch (other.mTag) {
-        case Type::Value:
-            construct(impl.valueFunc, other.impl.valueFunc);
-            break;
-        case Type::Color:
-            construct(impl.colorFunc, other.impl.colorFunc);
-            break;
-        case Type::Point:
-            construct(impl.pointFunc, other.impl.pointFunc);
-            break;
-        case Type::Size:
-            construct(impl.sizeFunc, other.impl.sizeFunc);
-            break;
-        default:
-            break;
-        }
-        mTag = other.mTag;
-        mPropery = other.mPropery;
-    }
-
-    void Destroy()
-    {
-        switch (mTag) {
-        case MonoState: {
-            break;
-        }
-        case Value: {
-            impl.valueFunc.~ValueFunc();
-            break;
-        }
-        case Color: {
-            impl.colorFunc.~ColorFunc();
-            break;
-        }
-        case Point: {
-            impl.pointFunc.~PointFunc();
-            break;
-        }
-        case Size: {
-            impl.sizeFunc.~SizeFunc();
-            break;
-        }
-        }
-    }
-
-    enum Type { MonoState, Value, Color, Point, Size };
-    rlottie::Property mPropery;
-    Type              mTag{MonoState};
-    union details {
-        ColorFunc colorFunc;
-        ValueFunc valueFunc;
-        PointFunc pointFunc;
-        SizeFunc  sizeFunc;
-        details() {}
-        ~details() {}
-    } impl;
-};
-
-class LOTFilter {
-public:
-    void addValue(LOTVariant& value)
-    {
-        uint index = static_cast<uint>(value.property());
-        if (mBitset.test(index)) {
-            std::replace_if(mFilters.begin(), mFilters.end(),
-                            [&value](const LOTVariant& e) {
-                                return e.property() == value.property();
-                            },
-                            value);
-        } 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);
-            mFilters.erase(std::remove_if(mFilters.begin(), mFilters.end(),
-                                          [&value](const LOTVariant& e) {
-                                              return e.property() ==
-                                                     value.property();
-                                          }),
-                           mFilters.end());
-        }
-    }
-    bool hasFilter(rlottie::Property prop) const
-    {
-        return mBitset.test(static_cast<uint>(prop));
-    }
-    model::Color color(rlottie::Property prop, int frame) const
-    {
-        rlottie::FrameInfo info(frame);
-        rlottie::Color     col = data(prop).color()(info);
-        return model::Color(col.r(), col.g(), col.b());
-    }
-    VPointF point(rlottie::Property prop, int frame) const
-    {
-        rlottie::FrameInfo info(frame);
-        rlottie::Point     pt = data(prop).point()(info);
-        return VPointF(pt.x(), pt.y());
-    }
-    VSize scale(rlottie::Property prop, int frame) const
-    {
-        rlottie::FrameInfo info(frame);
-        rlottie::Size      sz = data(prop).size()(info);
-        return VSize(sz.w(), sz.h());
-    }
-    float opacity(rlottie::Property prop, int frame) const
-    {
-        rlottie::FrameInfo info(frame);
-        float              val = data(prop).value()(info);
-        return val / 100;
-    }
-    float value(rlottie::Property prop, int frame) const
-    {
-        rlottie::FrameInfo info(frame);
-        return data(prop).value()(info);
-    }
-
-private:
-    const LOTVariant& data(rlottie::Property prop) const
-    {
-        auto result = std::find_if(
-            mFilters.begin(), mFilters.end(),
-            [prop](const LOTVariant& e) { return e.property() == prop; });
-        return *result;
-    }
-    std::bitset<32>         mBitset{0};
-    std::vector<LOTVariant> mFilters;
-};
-
-template <typename T>
-class LOTProxyModel {
-public:
-    LOTProxyModel(T* model) : _modelData(model) {}
-    LOTFilter&   filter() { return mFilter; }
-    const char*  name() const { return _modelData->name(); }
-    model::Color color(int frame) const
-    {
-        if (mFilter.hasFilter(rlottie::Property::StrokeColor)) {
-            return mFilter.color(rlottie::Property::StrokeColor, frame);
-        }
-        return _modelData->color(frame);
-    }
-    float opacity(int frame) const
-    {
-        if (mFilter.hasFilter(rlottie::Property::StrokeOpacity)) {
-            return mFilter.opacity(rlottie::Property::StrokeOpacity, frame);
-        }
-        return _modelData->opacity(frame);
-    }
-    float strokeWidth(int frame) const
-    {
-        if (mFilter.hasFilter(rlottie::Property::StrokeWidth)) {
-            return mFilter.value(rlottie::Property::StrokeWidth, frame);
-        }
-        return _modelData->strokeWidth(frame);
-    }
-    float     miterLimit() const { return _modelData->miterLimit(); }
-    CapStyle  capStyle() const { return _modelData->capStyle(); }
-    JoinStyle joinStyle() const { return _modelData->joinStyle(); }
-    bool      hasDashInfo() const { return _modelData->hasDashInfo(); }
-    void      getDashInfo(int frameNo, std::vector<float>& result) const
-    {
-        return _modelData->getDashInfo(frameNo, result);
-    }
-
-private:
-    T*        _modelData;
-    LOTFilter mFilter;
-};
-
-template <>
-class LOTProxyModel<model::Fill> {
-public:
-    LOTProxyModel(model::Fill* model) : _modelData(model) {}
-    LOTFilter&   filter() { return mFilter; }
-    const char*  name() const { return _modelData->name(); }
-    model::Color color(int frame) const
-    {
-        if (mFilter.hasFilter(rlottie::Property::FillColor)) {
-            return mFilter.color(rlottie::Property::FillColor, frame);
-        }
-        return _modelData->color(frame);
-    }
-    float opacity(int frame) const
-    {
-        if (mFilter.hasFilter(rlottie::Property::FillOpacity)) {
-            return mFilter.opacity(rlottie::Property::FillOpacity, frame);
-        }
-        return _modelData->opacity(frame);
-    }
-    FillRule fillRule() const { return _modelData->fillRule(); }
-
-private:
-    model::Fill* _modelData;
-    LOTFilter    mFilter;
-};
-
-template <>
-class LOTProxyModel<model::Group> {
-public:
-    LOTProxyModel(model::Group* model = nullptr) : _modelData(model) {}
-    bool              hasModel() const { return _modelData ? true : false; }
-    LOTFilter&        filter() { return mFilter; }
-    const char*       name() const { return _modelData->name(); }
-    model::Transform* transform() const { return _modelData->mTransform; }
-    VMatrix           matrix(int frame) const
-    {
-        VMatrix mS, mR, mT;
-        if (mFilter.hasFilter(rlottie::Property::TrScale)) {
-            VSize s = mFilter.scale(rlottie::Property::TrScale, frame);
-            mS.scale(s.width() / 100.0, s.height() / 100.0);
-        }
-        if (mFilter.hasFilter(rlottie::Property::TrRotation)) {
-            mR.rotate(mFilter.value(rlottie::Property::TrRotation, frame));
-        }
-        if (mFilter.hasFilter(rlottie::Property::TrPosition)) {
-            mT.translate(mFilter.point(rlottie::Property::TrPosition, frame));
-        }
-
-        return _modelData->mTransform->matrix(frame) * mS * mR * mT;
-    }
-
-private:
-    model::Group* _modelData;
-    LOTFilter     mFilter;
-};
-#endif  // LOTTIEITEM_H