From ec5a32bb7398820a9189c191507d1615246ac2d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 11 Sep 2023 23:32:42 +0900 Subject: [PATCH] lottie: enhanced the colorstop feature. Lottie ColorStop RGB / Alpha can be dealt with individually. Since thorvg handles this one unified set, lottie model need to merge the data into one structure. --- src/loaders/lottie/tvgLottieModel.h | 95 +++++++++++++++++++++++++- src/loaders/lottie/tvgLottieParser.cpp | 29 +------- src/loaders/lottie/tvgLottieProperty.h | 1 + 3 files changed, 96 insertions(+), 29 deletions(-) diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index e276193a..d7f34f6f 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -82,8 +82,97 @@ struct LottieStroke struct LottieGradient { - bool dynamic() + uint32_t populate(ColorStop& color) { + uint32_t alphaCnt = (color.input->count - (colorStops.count * 4)) / 2; + Array output; + output.reserve(colorStops.count + alphaCnt); + + uint32_t cidx = 0; //color count + uint32_t clast = colorStops.count * 4; + uint32_t aidx = clast; //alpha count + + Fill::ColorStop cs; + + //merge color stops + uint32_t cnt = (colorStops.count > alphaCnt) ? colorStops.count : alphaCnt; + + for (uint32_t i = 0; i < cnt; ++i) { + if (cidx == clast || aidx == color.input->count) break; + + if ((*color.input)[cidx] == (*color.input)[aidx]) { + cs.offset = (*color.input)[cidx]; + cs.r = lroundf((*color.input)[cidx + 1] * 255.0f); + cs.g = lroundf((*color.input)[cidx + 2] * 255.0f); + cs.b = lroundf((*color.input)[cidx + 3] * 255.0f); + cs.a = lroundf((*color.input)[aidx + 1] * 255.0f); + cidx += 4; + aidx += 2; + } else if ((*color.input)[cidx] < (*color.input)[aidx]) { + cs.offset = (*color.input)[cidx]; + cs.r = lroundf((*color.input)[cidx + 1] * 255.0f); + cs.g = lroundf((*color.input)[cidx + 2] * 255.0f); + cs.b = lroundf((*color.input)[cidx + 3] * 255.0f); + cs.a = (output.count > 0) ? output.last().a : 255; + cidx += 4; + } else { + cs.offset = (*color.input)[aidx]; + if (output.count > 0) { + cs.r = output.last().r; + cs.g = output.last().g; + cs.b = output.last().b; + } else { + cs.r = cs.g = cs.b = 255; + } + cs.a = lroundf((*color.input)[aidx + 1] * 255.0f); + aidx += 2; + } + output.push(cs); + } + + //color remains + while (cidx < clast) { + cs.offset = (*color.input)[cidx]; + cs.r = lroundf((*color.input)[cidx + 1] * 255.0f); + cs.g = lroundf((*color.input)[cidx + 2] * 255.0f); + cs.b = lroundf((*color.input)[cidx + 3] * 255.0f); + cs.a = (output.count > 0) ? output.last().a : 255; + output.push(cs); + cidx += 4; + } + //alpha remains + while (aidx < color.input->count) { + cs.offset = (*color.input)[aidx]; + if (output.count > 0) { + cs.r = output.last().r; + cs.g = output.last().g; + cs.b = output.last().b; + } else { + cs.r = cs.g = cs.b = 255; + } + cs.a = lroundf((*color.input)[aidx + 1] * 255.0f); + output.push(cs); + aidx += 2; + } + + color.data = output.data; + output.data = nullptr; + + color.input->reset(); + delete(color.input); + + return output.count; + } + + bool prepare() + { + if (colorStops.frames) { + for (auto v = colorStops.frames->data; v < colorStops.frames->end(); ++v) { + colorStops.count = populate(v->value); + } + } else { + colorStops.count = populate(colorStops.value); + } if (start.frames || end.frames || height.frames || angle.frames || colorStops.frames) return true; return false; } @@ -317,7 +406,7 @@ struct LottieGradientFill : LottieObject, LottieGradient void prepare() { LottieObject::type = LottieObject::GradientFill; - if (LottieGradient::dynamic()) statical = false; + if (LottieGradient::prepare()) statical = false; } FillRule rule = FillRule::Winding; @@ -329,7 +418,7 @@ struct LottieGradientStroke : LottieObject, LottieStroke, LottieGradient void prepare() { LottieObject::type = LottieObject::GradientStroke; - if (LottieStroke::dynamic() || LottieGradient::dynamic()) statical = false; + if (LottieGradient::prepare() || LottieStroke::dynamic()) statical = false; } }; diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index c10277d2..c7ee345c 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -219,33 +219,10 @@ void LottieParser::getValue(ColorStop& color) { if (peekType() == kArrayType) enterArray(); - int idx = 0; - auto count = context->gradient->colorStops.count; - if (!color.data) color.data = static_cast(malloc(sizeof(Fill::ColorStop) * count)); + color.input = new Array; + color.input->reserve(context->gradient->colorStops.count); - //rgb - while (nextArrayValue()) { - auto remains = (idx % 4); - if (remains == 0) { - color.data[idx / 4].offset = getFloat(); - color.data[idx / 4].a = 255; //in default - } else if (remains == 1) { - color.data[idx / 4].r = lroundf(getFloat() * 255.0f); - } else if (remains == 2) { - color.data[idx / 4].g = lroundf(getFloat() * 255.0f); - } else if (remains == 3) { - color.data[idx / 4].b = lroundf(getFloat() * 255.0f); - } - if ((++idx / 4) == count) break; - } - - //alpha - idx = 0; - while (nextArrayValue()) { - auto offset = getFloat(); //not used for now. - if (!mathEqual(offset, color.data[idx].offset)) TVGERR("LOTTIE", "FIXME: Gradient alpha offset is ignored"); - color.data[idx++].a = lroundf(getFloat() * 255.0f); - } + while (nextArrayValue()) color.input->push(getFloat()); } diff --git a/src/loaders/lottie/tvgLottieProperty.h b/src/loaders/lottie/tvgLottieProperty.h index dcef08b9..e31b504d 100644 --- a/src/loaders/lottie/tvgLottieProperty.h +++ b/src/loaders/lottie/tvgLottieProperty.h @@ -47,6 +47,7 @@ struct RGB24 struct ColorStop { Fill::ColorStop* data = nullptr; + Array* input = nullptr; };