From 9f6b5eb59edb623e9909e8994255b86509ec61fc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Aug 2020 13:53:00 +0900 Subject: [PATCH] common: changed premultiplied color policy. Some user have no idea of premultiplied alpha concept, We suggest more user-friendly interfaces so that they don't confuse it. Now, this pre-multipying is acommplished by backend engines. Change-Id: Ifd84d56361cb56a8b98240bbd16690accf370bad --- src/lib/sw_engine/tvgSwCommon.h | 9 ++++++++- src/lib/sw_engine/tvgSwFill.cpp | 13 +++++++++++-- src/lib/sw_engine/tvgSwRaster.cpp | 8 ++++++++ test/testBlending.cpp | 6 +++--- test/testSceneTransform.cpp | 4 ++-- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 469ce0f..b653a93 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -244,6 +244,12 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t } +static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a) +{ + return (c * a) >> 8; +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -290,7 +296,8 @@ bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterClear(Surface& surface); -inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) + +static inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { #ifdef THORVG_AVX_VECTOR_SUPPORT int32_t align = (8 - (offset % 8)) % 8; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 266acaa..80540cc 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -46,7 +46,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) if (pColors->a < 255) fill->translucent = true; - auto rgba = COLOR_ARGB_JOIN(pColors->r, pColors->g, pColors->b, pColors->a); + auto r = COLOR_ALPHA_MULTIPLY(pColors->r, pColors->a); + auto g = COLOR_ALPHA_MULTIPLY(pColors->g, pColors->a); + auto b = COLOR_ALPHA_MULTIPLY(pColors->b, pColors->a); + + auto rgba = COLOR_ARGB_JOIN(r, g, b, pColors->a); auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -65,7 +69,12 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) assert(curr && next); auto delta = 1.0f / (next->offset - curr->offset); if (next->a < 255) fill->translucent = true; - auto rgba2 = COLOR_ARGB_JOIN(next->r, next->g, next->b, next->a); + + auto r = COLOR_ALPHA_MULTIPLY(next->r, next->a); + auto g = COLOR_ALPHA_MULTIPLY(next->g, next->a); + auto b = COLOR_ALPHA_MULTIPLY(next->b, next->a); + + auto rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a); while (pos < next->offset && i < GRADIENT_STOP_SIZE) { auto t = (pos - curr->offset) * delta; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 5819bb8..ce2dc15 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -285,6 +285,10 @@ bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + r = COLOR_ALPHA_MULTIPLY(r, a); + g = COLOR_ALPHA_MULTIPLY(g, a); + b = COLOR_ALPHA_MULTIPLY(b, a); + //Fast Track if (shape.rect) { auto region = _clipRegion(surface, shape.bbox); @@ -300,6 +304,10 @@ bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + r = COLOR_ALPHA_MULTIPLY(r, a); + g = COLOR_ALPHA_MULTIPLY(g, a); + b = COLOR_ALPHA_MULTIPLY(b, a); + if (a == 255) return _rasterSolidRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); return _rasterTranslucentRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); } diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 5477b3b..59a4fad 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -19,13 +19,13 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH - shape2->fill(170, 170, 0, 170); //r, g, b, a + shape2->fill(255, 255, 0, 170); //r, g, b, a if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(400, 400, 250, 100); //cx, cy, radiusW, radiusH - shape3->fill(100, 100, 100, 100); //r, g, b, a + shape3->fill(255, 255, 255, 100); //r, g, b, a if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Prepare Star @@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->lineTo(26, 361); shape4->lineTo(146, 343); shape4->close(); - shape4->fill(200, 0, 200, 200); + shape4->fill(255, 0, 200, 200); if (canvas->push(move(shape4)) != tvg::Result::Success) return; //Prepare Opaque Ellipse diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 0d0be8e..49558fb 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -58,7 +58,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->lineTo(-173, 12.5); shape4->lineTo(-53, -5.5); shape4->close(); - shape4->fill(0, 0, 127, 127); + shape4->fill(0, 0, 255, 127); shape4->stroke(3); //width shape4->stroke(0, 0, 255, 255); //r, g, b, a scene2->push(move(shape4)); @@ -78,7 +78,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); shape5->close(); - shape5->fill(127, 0, 0, 127); + shape5->fill(255, 0, 0, 127); scene2->push(move(shape5)); scene2->translate(500, 350); -- 2.7.4