lottiemodel: Improve opacity calculation for gradient stop 04/267704/1 accepted/tizen/6.5/unified/20211216.155657 submit/tizen_6.5/20211215.043506
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 04:16:05 +0000 (13:16 +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: Ie4e45b04dd8ef4d951d8177cb204b612760e6bda

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*/