mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
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.
This commit is contained in:
parent
e2b7bfc198
commit
ec5a32bb73
3 changed files with 96 additions and 29 deletions
|
@ -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<Fill::ColorStop> 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Fill::ColorStop*>(malloc(sizeof(Fill::ColorStop) * count));
|
||||
color.input = new Array<float>;
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ struct RGB24
|
|||
struct ColorStop
|
||||
{
|
||||
Fill::ColorStop* data = nullptr;
|
||||
Array<float>* input = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue