Update color blending style in LottieItem 55/291455/1
authorMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Thu, 6 Apr 2023 11:16:35 +0000 (13:16 +0200)
committerMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Mon, 17 Apr 2023 06:37:35 +0000 (08:37 +0200)
This commit modifies the LottieItem rendering process to match Adobe
After Effects blending style. Initially, the entire content of the layer
is rendered to an intermediate buffer. Then, the buffer is rendered with
applied alpha layer.

Change-Id: Ic145daa83c7d8f3007e46f08cdfcc063d22526ae

src/lottie/lottieitem.cpp
src/lottie/lottieitem.h

index 4cd22e4c5f3c1aa709b7a3487e5a4182c9bbdd65..f0e181a6613b6a0e31238584e0f5b0e46a044b1e 100644 (file)
@@ -165,6 +165,28 @@ bool renderer::Composition::render(const rlottie::Surface &surface)
     painter.setDrawRegion(
         VRect(int(surface.drawRegionPosX()), int(surface.drawRegionPosY()),
               int(surface.drawRegionWidth()), int(surface.drawRegionHeight())));
+
+    // layer surface should be created if it is not created already or its size
+    // is changed.
+    bool isLayerSurfaceCreated = mSurfaceCache.is_layer_surface_created();
+    bool isLayerSurfaceSizeChanged =
+        isLayerSurfaceCreated &&
+        (mSurfaceCache.get_layer_surface()->width() != surface.width() ||
+         mSurfaceCache.get_layer_surface()->height() != surface.height());
+
+    if (!isLayerSurfaceCreated || isLayerSurfaceSizeChanged) {
+        if (isLayerSurfaceCreated && isLayerSurfaceSizeChanged)
+            mSurfaceCache.delete_layer_surface();
+
+        mSurfaceCache.create_layer_surface(surface.width(), surface.height(),
+                                           VBitmap::Format::ARGB32_Premultiplied);
+
+        // set layer draw region
+        mSurfaceCache.get_layer_painter()->setDrawRegion(
+            VRect(int(surface.drawRegionPosX()), int(surface.drawRegionPosY()),
+                  int(surface.drawRegionWidth()), int(surface.drawRegionHeight())));
+    }
+
     mRootLayer->render(&painter, {}, {}, mSurfaceCache);
     painter.end();
     return true;
@@ -214,7 +236,7 @@ void renderer::Mask::preprocess(const VRect &clip)
 }
 
 void renderer::Layer::render(VPainter *painter, const VRle &inheritMask,
-                             const VRle &matteRle, SurfaceCache &)
+                             const VRle &matteRle, SurfaceCache &cache)
 {
     auto renderlist = renderList();
 
@@ -230,31 +252,42 @@ void renderer::Layer::render(VPainter *painter, const VRle &inheritMask,
         mask = inheritMask;
     }
 
+    VPainter *usedPainter = painter;
+
+    if (cache.get_layer_painter() != nullptr) {
+        usedPainter = cache.get_layer_painter();
+        usedPainter->begin(cache.get_layer_surface());
+    }
+
     for (auto &i : renderlist) {
-        painter->setBrush(i->mBrush);
+        usedPainter->setBrush(i->mBrush);
         VRle rle = i->rle();
         if (matteRle.empty()) {
             if (mask.empty()) {
                 // no mask no matte
-                painter->drawRle(VPoint(), rle);
+                usedPainter->drawRle(VPoint(), rle);
             } else {
                 // only mask
-                painter->drawRle(rle, mask);
+                usedPainter->drawRle(rle, mask);
             }
-
         } else {
             if (!mask.empty()) rle = rle & mask;
 
             if (rle.empty()) continue;
             if (matteType() == model::MatteType::AlphaInv) {
                 rle = rle - matteRle;
-                painter->drawRle(VPoint(), rle);
+                usedPainter->drawRle(VPoint(), rle);
             } else {
                 // render with matteRle as clip.
-                painter->drawRle(rle, matteRle);
+                usedPainter->drawRle(rle, matteRle);
             }
         }
     }
+
+    if (cache.get_layer_painter() != nullptr) {
+        usedPainter->end();
+        painter->drawBitmap(VPoint(), *cache.get_layer_surface(), mCombinedAlpha * 255.0f);
+    }
 }
 
 void renderer::LayerMask::preprocess(const VRect &clip)
@@ -1238,9 +1271,9 @@ renderer::Fill::Fill(model::Fill *data)
     mDrawable.setName(mModel.name());
 }
 
-bool renderer::Fill::updateContent(int frameNo, const VMatrix &, float alpha)
+bool renderer::Fill::updateContent(int frameNo, const VMatrix &, float)
 {
-    auto combinedAlpha = alpha * mModel.opacity(frameNo);
+    auto combinedAlpha = mModel.opacity(frameNo);
     auto color = mModel.color(frameNo).toColor(combinedAlpha);
 
     VBrush brush(color);
@@ -1284,9 +1317,9 @@ renderer::Stroke::Stroke(model::Stroke *data)
 static vthread_local std::vector<float> Dash_Vector;
 
 bool renderer::Stroke::updateContent(int frameNo, const VMatrix &matrix,
-                                     float alpha)
+                                     float)
 {
-    auto combinedAlpha = alpha * mModel.opacity(frameNo);
+    auto combinedAlpha = mModel.opacity(frameNo);
     auto color = mModel.color(frameNo).toColor(combinedAlpha);
 
     VBrush brush(color);
index 001ce667ccd79526732c745e109b18e2d6da380d..587f10bee487c11f0146ce6cae1a1e5c1d352afa 100644 (file)
@@ -106,9 +106,31 @@ public:
     }
 
     void release_surface(VBitmap &surface) { mCache.push_back(surface); }
+    bool is_layer_surface_created() const { return mIsLayerBitmapCreated; }
+    void create_layer_surface(size_t width, size_t height, VBitmap::Format format)
+    {
+        if (mIsLayerBitmapCreated) return;
+
+        mLayerBitmap = std::make_unique<VBitmap>(width, height, format);
+        mBitmapPainter = std::make_unique<VPainter>(mLayerBitmap.get());
+        mIsLayerBitmapCreated = true;
+    }
+    void delete_layer_surface()
+    {
+        if (!mIsLayerBitmapCreated) return;
+
+        mLayerBitmap.reset();
+        mBitmapPainter.reset();
+        mIsLayerBitmapCreated = false;
+    }
+    VPainter* get_layer_painter() const { return mBitmapPainter.get(); }
+    VBitmap* get_layer_surface() const { return mLayerBitmap.get(); }
 
 private:
     std::vector<VBitmap> mCache;
+    std::unique_ptr<VBitmap>   mLayerBitmap{nullptr};
+    std::unique_ptr<VPainter>  mBitmapPainter{nullptr};
+    bool                       mIsLayerBitmapCreated{false};
 };
 
 class Drawable final : public VDrawable {