lottiemodel: Improve opacity calculation for gradient stop 97/267697/1 accepted/tizen/unified/20211216.155840 submit/tizen/20211215.050000
authorJunsuChoi <jsuya.choi@samsung.com>
Thu, 9 Dec 2021 00:50:46 +0000 (09:50 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Thu, 9 Dec 2021 01:13:59 +0000 (10:13 +0900)
Basically, Graeidnt stop's color and opacity are provided as separate arrays.
Stop position and opacity position do not match each other.
Existing code is a sequential approach. It caused problems in various cases of positions.
The improved logic repeats the loop, but no exceptions are raised. It's not complicated, it's simple.

This code referenced the lottie-android library.
https://github.com/airbnb/lottie-android/blob/master/lottie/src/main/java/com/airbnb/lottie/parser/GradientColorParser.java

Change-Id: Ib23064f7f91ee35ecec2afa41a0a1ccb57c8373a

src/lottie/lottiemodel.cpp
src/lottie/lottiemodel.h

index 9da82f704bcd3e7bdb12efb8f3eee104ff096ca7..1bca99d2e3c556b2df8ce7faa927dde3a3d20160 100644 (file)
@@ -256,52 +256,12 @@ void model::Gradient::populate(VGradientStops &stops, int frameNo)
     auto   opacityArraySize = size - colorPoints * 4;
     float *opacityPtr = ptr + (colorPoints * 4);
     stops.clear();
-    size_t j = 0;
     for (int i = 0; i < colorPoints; i++) {
         float        colorStop = ptr[0];
         model::Color color = model::Color(ptr[1], ptr[2], ptr[3]);
         if (opacityArraySize) {
-            if (j == opacityArraySize) {
-                // already reached the end
-                float stop1 = opacityPtr[j - 4];
-                float op1 = opacityPtr[j - 3];
-                float stop2 = opacityPtr[j - 2];
-                float op2 = opacityPtr[j - 1];
-                if (colorStop > stop2) {
-                    stops.push_back(
-                        std::make_pair(colorStop, color.toColor(op2)));
-                } else {
-                    float progress = (colorStop - stop1) / (stop2 - stop1);
-                    float opacity = op1 + progress * (op2 - op1);
-                    stops.push_back(
-                        std::make_pair(colorStop, color.toColor(opacity)));
-                }
-                continue;
-            }
-            for (; j < opacityArraySize; j += 2) {
-                float opacityStop = opacityPtr[j];
-                if (opacityStop < colorStop) {
-                    // add a color using opacity stop
-                    stops.push_back(std::make_pair(
-                        opacityStop, color.toColor(opacityPtr[j + 1])));
-                    continue;
-                }
-                // add a color using color stop
-                if (j == 0) {
-                    stops.push_back(std::make_pair(
-                        colorStop, color.toColor(opacityPtr[j + 1])));
-                } else {
-                    float progress = (colorStop - opacityPtr[j - 2]) /
-                                     (opacityPtr[j] - opacityPtr[j - 2]);
-                    float opacity =
-                        opacityPtr[j - 1] +
-                        progress * (opacityPtr[j + 1] - opacityPtr[j - 1]);
-                    stops.push_back(
-                        std::make_pair(colorStop, color.toColor(opacity)));
-                }
-                j += 2;
-                break;
-            }
+            float opacity = getOpacityAtPosition(opacityPtr, opacityArraySize, colorStop);
+            stops.push_back(std::make_pair(colorStop, color.toColor(opacity)));
         } else {
             stops.push_back(std::make_pair(colorStop, color.toColor()));
         }
@@ -309,6 +269,21 @@ void model::Gradient::populate(VGradientStops &stops, int frameNo)
     }
 }
 
+float model::Gradient::getOpacityAtPosition(float *opacities, size_t opacityArraySize, float position)
+{
+    for (size_t i = 2; i < opacityArraySize; i += 2)
+    {
+        float lastPosition = opacities[i - 2];
+        float thisPosition = opacities[i];
+        if (opacities[i] >= position) {
+            float progress = (position - lastPosition) / (thisPosition - lastPosition);
+            progress = progress < 0.0f ? 0.0f : 1.0f < progress ? 1.0f : progress; //clamp(progress, 0, 1)
+            return opacities[i - 1] + progress * (opacities[i + 1] - opacities[i - 1]);
+        }
+    }
+    return 0.0f;
+}
+
 void model::Gradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
 {
     bool init = false;
index c6b8cf6d5c43e959711477d472d29b76076a58fe..cf87adb204df644a7ad1c92815a1a492f29960e0 100644 (file)
@@ -821,6 +821,7 @@ public:
 
 private:
     void populate(VGradientStops &stops, int frameNo);
+    float getOpacityAtPosition(float *opacities, size_t opacityArraySize, float position);
 
 public:
     int                      mGradientType{1};    /* "t" Linear=1 , Radial = 2*/