summaryrefslogtreecommitdiff
path: root/thirdparty/thorvg/src/lib/sw_engine
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thorvg/src/lib/sw_engine')
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h40
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp5
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwImage.cpp55
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp5
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwMemPool.cpp11
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp688
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterAvx.h22
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterC.h90
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterNeon.h24
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmap.h141
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmapInternal.h21
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.cpp341
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.h15
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp180
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwShape.cpp45
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp24
16 files changed, 1140 insertions, 567 deletions
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
index 157fdb8f82..0e9029bf73 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+/*
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_SW_COMMON_H_
#define _TVG_SW_COMMON_H_
@@ -222,11 +223,16 @@ struct SwImage
{
SwOutline* outline = nullptr;
SwRleData* rle = nullptr;
- uint32_t* data = nullptr;
+ union {
+ pixel_t* data; //system based data pointer
+ uint32_t* buf32; //for explicit 32bits channels
+ uint8_t* buf8; //for explicit 8bits grayscale
+ };
uint32_t w, h, stride;
int32_t ox = 0; //offset x
int32_t oy = 0; //offset y
float scale;
+ uint8_t channelSize;
bool direct = false; //draw image directly (with offset)
bool scaled = false; //draw scaled image
@@ -235,7 +241,7 @@ struct SwImage
struct SwBlender
{
uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
- uint32_t (*lumaValue)(uint32_t c);
+ uint8_t (*luma)(uint8_t* c);
};
struct SwCompositor;
@@ -301,12 +307,12 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee);
void shapeReset(SwShape* shape);
-bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
+bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
bool shapePrepared(const SwShape* shape);
-bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias);
+bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias);
void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
-void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
+void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform);
+bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
void shapeFree(SwShape* shape);
void shapeDelStroke(SwShape* shape);
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
@@ -316,12 +322,12 @@ void shapeResetStrokeFill(SwShape* shape);
void shapeDelFill(SwShape* shape);
void shapeDelStrokeFill(SwShape* shape);
-void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
+void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix* transform);
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
void strokeFree(SwStroke* stroke);
-bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
+bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
bool imageGenRle(SwImage* image, const SwBBox& renderRegion, bool antiAlias);
void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid);
void imageReset(SwImage* image);
@@ -334,10 +340,12 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x,
void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len);
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias);
+SwRleData* rleRender(const SwBBox* bbox);
void rleFree(SwRleData* rle);
void rleReset(SwRleData* rle);
-void rleClipPath(SwRleData *rle, const SwRleData *clip);
-void rleClipRect(SwRleData *rle, const SwBBox* clip);
+void rleMerge(SwRleData* rle, SwRleData* clip1, SwRleData* clip2);
+void rleClipPath(SwRleData* rle, const SwRleData* clip);
+void rleClipRect(SwRleData* rle, const SwBBox* clip);
SwMpool* mpoolInit(uint32_t threads);
bool mpoolTerm(SwMpool* mpool);
@@ -350,11 +358,13 @@ void mpoolRetStrokeOutline(SwMpool* mpool, unsigned idx);
bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
-bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
+bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
-bool rasterClear(SwSurface* surface);
+bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len);
-void rasterUnpremultiply(SwSurface* surface);
+void rasterUnpremultiply(Surface* surface);
+void rasterPremultiply(Surface* surface);
+bool rasterConvertCS(Surface* surface, ColorSpace to);
#endif /* _TVG_SW_COMMON_H_ */
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
index 04014a9ec3..694bc35231 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+/*
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "tvgMath.h"
#include "tvgSwCommon.h"
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwImage.cpp
index c02e28b432..9e215dbefd 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwImage.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwImage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "tvgMath.h"
#include "tvgSwCommon.h"
@@ -33,7 +34,7 @@ static inline bool _onlyShifted(const Matrix* m)
}
-static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool, unsigned tid)
+static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* transform, SwMpool* mpool, unsigned tid)
{
image->outline = mpoolReqOutline(mpool, tid);
auto outline = image->outline;
@@ -51,10 +52,50 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
outline->closed[0] = true;
}
- auto w = static_cast<float>(image->w);
- auto h = static_cast<float>(image->h);
+ Point to[4];
+ if (mesh->triangleCnt > 0) {
+ // TODO: Optimise me. We appear to calculate this exact min/max bounding area in multiple
+ // places. We should be able to re-use one we have already done? Also see:
+ // tvgPictureImpl.h --> bounds
+ // tvgSwRasterTexmap.h --> _rasterTexmapPolygonMesh
+ //
+ // TODO: Should we calculate the exact path(s) of the triangle mesh instead?
+ // i.e. copy tvgSwShape.capp -> _genOutline?
+ //
+ // TODO: Cntrs?
+ auto triangles = mesh->triangles;
+ auto min = triangles[0].vertex[0].pt;
+ auto max = triangles[0].vertex[0].pt;
+
+ for (uint32_t i = 0; i < mesh->triangleCnt; ++i) {
+ if (triangles[i].vertex[0].pt.x < min.x) min.x = triangles[i].vertex[0].pt.x;
+ else if (triangles[i].vertex[0].pt.x > max.x) max.x = triangles[i].vertex[0].pt.x;
+ if (triangles[i].vertex[0].pt.y < min.y) min.y = triangles[i].vertex[0].pt.y;
+ else if (triangles[i].vertex[0].pt.y > max.y) max.y = triangles[i].vertex[0].pt.y;
+
+ if (triangles[i].vertex[1].pt.x < min.x) min.x = triangles[i].vertex[1].pt.x;
+ else if (triangles[i].vertex[1].pt.x > max.x) max.x = triangles[i].vertex[1].pt.x;
+ if (triangles[i].vertex[1].pt.y < min.y) min.y = triangles[i].vertex[1].pt.y;
+ else if (triangles[i].vertex[1].pt.y > max.y) max.y = triangles[i].vertex[1].pt.y;
+
+ if (triangles[i].vertex[2].pt.x < min.x) min.x = triangles[i].vertex[2].pt.x;
+ else if (triangles[i].vertex[2].pt.x > max.x) max.x = triangles[i].vertex[2].pt.x;
+ if (triangles[i].vertex[2].pt.y < min.y) min.y = triangles[i].vertex[2].pt.y;
+ else if (triangles[i].vertex[2].pt.y > max.y) max.y = triangles[i].vertex[2].pt.y;
+ }
+ to[0] = {min.x, min.y};
+ to[1] = {max.x, min.y};
+ to[2] = {max.x, max.y};
+ to[3] = {min.x, max.y};
+ } else {
+ auto w = static_cast<float>(image->w);
+ auto h = static_cast<float>(image->h);
+ to[0] = {0, 0};
+ to[1] = {w, 0};
+ to[2] = {w, h};
+ to[3] = {0, h};
+ }
- Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, h}};
for (int i = 0; i < 4; i++) {
outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
@@ -78,7 +119,7 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
/* External Class Implementation */
/************************************************************************/
-bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
+bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
{
image->direct = _onlyShifted(transform);
@@ -96,7 +137,7 @@ bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipReg
else image->scaled = false;
}
- if (!_genOutline(image, transform, mpool, tid)) return false;
+ if (!_genOutline(image, mesh, transform, mpool, tid)) return false;
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion, image->direct);
}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
index 1027bb1f79..5a4f58d9a6 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+/*
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include <math.h>
#include "tvgSwCommon.h"
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMemPool.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMemPool.cpp
index d2962e6d8d..05ff9ddf0b 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMemPool.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMemPool.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "tvgSwCommon.h"
@@ -59,16 +60,16 @@ void mpoolRetStrokeOutline(SwMpool* mpool, unsigned idx)
SwMpool* mpoolInit(unsigned threads)
{
- if (threads == 0) threads = 1;
+ auto allocSize = threads + 1;
auto mpool = static_cast<SwMpool*>(calloc(sizeof(SwMpool), 1));
- mpool->outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
+ mpool->outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * allocSize));
if (!mpool->outline) goto err;
- mpool->strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
+ mpool->strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * allocSize));
if (!mpool->strokeOutline) goto err;
- mpool->allocSize = threads;
+ mpool->allocSize = allocSize;
return mpool;
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
index ffd74bdd47..1f10afd9b3 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+/*
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,8 +37,8 @@
/************************************************************************/
constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
-
-static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
+template<typename T>
+static inline T _multiply(T c, T a)
{
return ((c * a + 0xff) >> 8);
}
@@ -56,15 +56,29 @@ static inline uint32_t _ialpha(uint32_t c)
}
-static inline uint32_t _abgrLumaValue(uint32_t c)
+static inline uint8_t _alpha(uint8_t* a)
{
- return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
+ return *a;
}
-static inline uint32_t _argbLumaValue(uint32_t c)
+static inline uint8_t _ialpha(uint8_t* a)
{
- return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
+ return ~(*a);
+}
+
+
+static inline uint8_t _abgrLuma(uint8_t* c)
+{
+ auto v = *(uint32_t*)c;
+ return ((((v&0xff)*54) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
+}
+
+
+static inline uint8_t _argbLuma(uint8_t* c)
+{
+ auto v = *(uint32_t*)c;
+ return ((((v&0xff)*19) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
}
@@ -148,65 +162,95 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t
}
+void _rasterGrayscale8(uint8_t *dst, uint32_t val, uint32_t offset, int32_t len)
+{
+ cRasterPixels<uint8_t>(dst, val, offset, len);
+}
+
/************************************************************************/
/* Rect */
/************************************************************************/
-static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t(*blender)(uint8_t*))
{
- TVGLOG("SW_ENGINE", "Masked Rect");
-
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
-
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
-
- for (uint32_t y = 0; y < h; ++y) {
- auto dst = &buffer[y * surface->stride];
- auto cmp = &cbuffer[y * surface->stride];
- for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
- auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
- *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8 + ((region.min.y * surface->compositor->image.stride + region.min.x) * csize); //compositor buffer
+
+ TVGLOG("SW_ENGINE", "Masked Rect [Region: %lu %lu %u %u]", region.min.x, region.min.y, w, h);
+
+ //32bits channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, a);
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
+ for (uint32_t y = 0; y < h; ++y) {
+ auto dst = &buffer[y * surface->stride];
+ auto cmp = &cbuffer[y * surface->stride * csize];
+ for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
+ auto tmp = ALPHA_BLEND(color, blender(cmp));
+ *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
+ }
+ }
+ //8bits grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
+ for (uint32_t y = 0; y < h; ++y) {
+ auto dst = &buffer[y * surface->stride];
+ auto cmp = &cbuffer[y * surface->stride * csize];
+ for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
+ auto tmp = _multiply<uint8_t>(a, blender(cmp));
+ *dst = tmp + _multiply<uint8_t>(*dst, _ialpha(tmp));
+ }
}
}
return true;
}
-static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
+static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b)
{
- auto buffer = surface->buffer + (region.min.y * surface->stride);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
- for (uint32_t y = 0; y < h; ++y) {
- rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
+ //32bits channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, 255);
+ auto buffer = surface->buf32 + (region.min.y * surface->stride);
+ for (uint32_t y = 0; y < h; ++y) {
+ rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
+ }
+ //8bits grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ auto buffer = surface->buf8 + (region.min.y * surface->stride);
+ for (uint32_t y = 0; y < h; ++y) {
+ _rasterGrayscale8(buffer + y * surface->stride, 255, region.min.x, w);
+ }
}
return true;
}
-static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint8_t opacity)
+static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (_compositing(surface)) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterMaskedRect(surface, region, color, _alpha);
+ return _rasterMaskedRect(surface, region, r, g, b, a, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterMaskedRect(surface, region, color, _ialpha);
+ return _rasterMaskedRect(surface, region, r, g, b, a, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
+ return _rasterMaskedRect(surface, region, r, g, b, a, surface->blender.luma);
}
} else {
- if (opacity == 255) {
- return _rasterSolidRect(surface, region, color);
+ if (a == 255) {
+ return _rasterSolidRect(surface, region, r, g, b);
} else {
#if defined(THORVG_AVX_VECTOR_SUPPORT)
- return avxRasterTranslucentRect(surface, region, color);
+ return avxRasterTranslucentRect(surface, region, r, g, b, a);
#elif defined(THORVG_NEON_VECTOR_SUPPORT)
- return neonRasterTranslucentRect(surface, region, color);
+ return neonRasterTranslucentRect(surface, region, r, g, b, a);
#else
- return cRasterTranslucentRect(surface, region, color);
+ return cRasterTranslucentRect(surface, region, r, g, b, a);
#endif
}
}
@@ -218,41 +262,74 @@ static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color
/* Rle */
/************************************************************************/
-static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Masked Rle");
auto span = rle->spans;
uint32_t src;
- auto cbuffer = surface->compositor->image.data;
-
- for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
- if (span->coverage == 255) src = color;
- else src = ALPHA_BLEND(color, span->coverage);
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
- auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
- *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
+ auto cbuffer = surface->compositor->image.buf8;
+ auto csize = surface->compositor->image.channelSize;
+
+ //32bit channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, a);
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
+ if (span->coverage == 255) src = color;
+ else src = ALPHA_BLEND(color, span->coverage);
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
+ auto tmp = ALPHA_BLEND(src, blender(cmp));
+ *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
+ }
+ }
+ //8bit grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ auto dst = &surface->buf8[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
+ if (span->coverage == 255) src = a;
+ else src = _multiply<uint8_t>(a, span->coverage);
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
+ auto tmp = _multiply<uint8_t>(src, blender(cmp));
+ *dst = tmp + _multiply<uint8_t>(*dst, _ialpha(tmp));
+ }
}
}
return true;
}
-static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
+static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b)
{
auto span = rle->spans;
- for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- if (span->coverage == 255) {
- rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
- } else {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto src = ALPHA_BLEND(color, span->coverage);
- auto ialpha = 255 - span->coverage;
- for (uint32_t x = 0; x < span->len; ++x, ++dst) {
- *dst = src + ALPHA_BLEND(*dst, ialpha);
+ //32bit channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, 255);
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ if (span->coverage == 255) {
+ rasterRGBA32(surface->buf32 + span->y * surface->stride, color, span->x, span->len);
+ } else {
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto src = ALPHA_BLEND(color, span->coverage);
+ auto ialpha = 255 - span->coverage;
+ for (uint32_t x = 0; x < span->len; ++x, ++dst) {
+ *dst = src + ALPHA_BLEND(*dst, ialpha);
+ }
+ }
+ }
+ //8bit grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ if (span->coverage == 255) {
+ _rasterGrayscale8(surface->buf8 + span->y * surface->stride, 255, span->x, span->len);
+ } else {
+ auto dst = &surface->buf8[span->y * surface->stride + span->x];
+ for (uint32_t x = 0; x < span->len; ++x, ++dst) {
+ *dst = span->coverage;
+ }
}
}
}
@@ -260,28 +337,28 @@ static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t c
}
-static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8_t opacity)
+static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (!rle) return false;
if (_compositing(surface)) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterMaskedRle(surface, rle, color, _alpha);
+ return _rasterMaskedRle(surface, rle, r, g, b, a, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterMaskedRle(surface, rle, color, _ialpha);
+ return _rasterMaskedRle(surface, rle, r, g, b, a, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
+ return _rasterMaskedRle(surface, rle, r, g, b, a, surface->blender.luma);
}
} else {
- if (opacity == 255) {
- return _rasterSolidRle(surface, rle, color);
+ if (a == 255) {
+ return _rasterSolidRle(surface, rle, r, g, b);
} else {
#if defined(THORVG_AVX_VECTOR_SUPPORT)
- return avxRasterTranslucentRle(surface, rle, color);
+ return avxRasterTranslucentRle(surface, rle, r, g, b, a);
#elif defined(THORVG_NEON_VECTOR_SUPPORT)
- return neonRasterTranslucentRle(surface, rle, color);
+ return neonRasterTranslucentRle(surface, rle, r, g, b, a);
#else
- return cRasterTranslucentRle(surface, rle, color);
+ return cRasterTranslucentRle(surface, rle, r, g, b, a);
#endif
}
}
@@ -301,7 +378,7 @@ static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, c
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
+ return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.luma);
}
} else {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
@@ -313,25 +390,26 @@ static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, c
/* RLE Scaled RGBA Image */
/************************************************************************/
-static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Scaled Masked Translucent Rle Image");
auto span = image->rle->spans;
+ auto csize = surface->compositor->image.channelSize;
//Center (Down-Scaled)
if (image->scale < DOWN_SCALE_TOLERANCE) {
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
if (sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
- auto alpha = _multiplyAlpha(span->coverage, opacity);
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
- auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
+ auto tmp = ALPHA_BLEND(src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -340,14 +418,14 @@ static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = span->y * itransform->e22 + itransform->e23;
if ((uint32_t)sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
- auto alpha = _multiplyAlpha(span->coverage, opacity);
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
- auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), alpha);
+ auto tmp = ALPHA_BLEND(src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -356,32 +434,33 @@ static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const
}
-static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Scaled Masked Rle Image");
auto span = image->rle->spans;
+ auto csize = surface->compositor->image.channelSize;
//Center (Down-Scaled)
if (image->scale < DOWN_SCALE_TOLERANCE) {
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
if (sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
if (span->coverage == 255) {
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
+ auto tmp = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
- auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
+ auto tmp = ALPHA_BLEND(src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -391,21 +470,21 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = span->y * itransform->e22 + itransform->e23;
if ((uint32_t)sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
if (span->coverage == 255) {
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
+ auto tmp = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
- for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
+ for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
- auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), span->coverage);
+ auto tmp = ALPHA_BLEND(src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -424,12 +503,12 @@ static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwIma
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
if (sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto alpha = _multiplyAlpha(span->coverage, opacity);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -438,12 +517,12 @@ static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwIma
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = span->y * itransform->e22 + itransform->e23;
if ((uint32_t)sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto alpha = _multiplyAlpha(span->coverage, opacity);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), alpha);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -461,19 +540,19 @@ static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image,
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
if (sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) {
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
+ auto src = _interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
} else {
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -483,19 +562,19 @@ static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image,
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
auto sy = span->y * itransform->e22 + itransform->e23;
if ((uint32_t)sy >= image->h) continue;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) {
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
+ auto src = _interpUpScaler(image->buf32, image->w, image->h, sx, sy);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
} else {
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), span->coverage);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -522,7 +601,7 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
+ return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.luma);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
@@ -530,7 +609,7 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
+ return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.luma);
}
}
} else {
@@ -545,26 +624,27 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
/* RLE Direct RGBA Image */
/************************************************************************/
-static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
auto span = image->rle->spans;
- auto cbuffer = surface->compositor->image.data;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
- auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
- auto alpha = _multiplyAlpha(span->coverage, opacity);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
+ auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
if (alpha == 255) {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
- auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*img, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
- auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*img, _multiply<uint32_t>(alpha, blender(cmp)));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -573,25 +653,26 @@ static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const
}
-static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
auto span = image->rle->spans;
- auto cbuffer = surface->compositor->image.data;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
- auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
+ auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
if (span->coverage == 255) {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
- auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*img, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
- auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*img, _multiply<uint32_t>(span->coverage, blender(cmp)));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -605,9 +686,9 @@ static bool _rasterDirectTranslucentRleRGBAImage(SwSurface* surface, const SwIma
auto span = image->rle->spans;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
- auto alpha = _multiplyAlpha(span->coverage, opacity);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
+ auto alpha = _multiply<uint32_t>(span->coverage, opacity);
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
auto src = ALPHA_BLEND(*img, alpha);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
@@ -622,8 +703,8 @@ static bool _rasterDirectRleRGBAImage(SwSurface* surface, const SwImage* image)
auto span = image->rle->spans;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
*dst = *img + ALPHA_BLEND(*dst, _ialpha(*img));
@@ -648,7 +729,7 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
+ return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.luma);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
@@ -656,7 +737,7 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
+ return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.luma);
}
}
} else {
@@ -679,7 +760,7 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.lumaValue);
+ return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.luma);
}
} else {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr);
@@ -687,18 +768,34 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
return false;
}
+static bool _transformedRGBAImageMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint32_t opacity)
+{
+ if (_compositing(surface)) {
+ if (surface->compositor->method == CompositeMethod::AlphaMask) {
+ return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity, _alpha);
+ } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
+ return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity, _ialpha);
+ } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+ return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity, surface->blender.luma);
+ }
+ } else {
+ return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity, nullptr);
+ }
+ return false;
+}
+
/************************************************************************/
/*Scaled RGBA Image */
/************************************************************************/
-
-static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint8_t(*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Scaled Masked Image");
- auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
+ auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
// Down-Scaled
if (image->scale < DOWN_SCALE_TOLERANCE) {
@@ -707,15 +804,15 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
if (sy >= image->h) continue;
auto dst = dbuffer;
auto cmp = cbuffer;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
+ auto alpha = _multiply<uint32_t>(opacity, blender(cmp));
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
}
// Up-Scaled
} else {
@@ -724,27 +821,28 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
if ((uint32_t)sy >= image->h) continue;
auto dst = dbuffer;
auto cmp = cbuffer;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
+ auto alpha = _multiply<uint32_t>(opacity, blender(cmp));
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), alpha);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
}
}
return true;
}
-static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint8_t (*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Scaled Masked Image");
- auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
+ auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
// Down-Scaled
if (image->scale < DOWN_SCALE_TOLERANCE) {
@@ -753,14 +851,14 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag
if (sy >= image->h) continue;
auto dst = dbuffer;
auto cmp = cbuffer;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), blender(cmp));
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
}
// Up-Scaled
} else {
@@ -769,14 +867,14 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag
if ((uint32_t)sy >= image->h) continue;
auto dst = dbuffer;
auto cmp = cbuffer;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), blender(cmp));
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
}
}
return true;
@@ -785,7 +883,7 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag
static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
{
- auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
+ auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
// Down-Scaled
if (image->scale < DOWN_SCALE_TOLERANCE) {
@@ -796,7 +894,7 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage*
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), opacity);
+ auto src = ALPHA_BLEND(_interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale), opacity);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -809,7 +907,7 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage*
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
+ auto src = ALPHA_BLEND(_interpUpScaler(image->buf32, image->w, image->h, sx, sy), opacity);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -820,7 +918,7 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage*
static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
{
- auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
+ auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
// Down-Scaled
if (image->scale < DOWN_SCALE_TOLERANCE) {
@@ -831,7 +929,7 @@ static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, con
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
if (sx >= image->w) continue;
- auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
+ auto src = _interpDownScaler(image->buf32, image->stride, image->w, image->h, sx, sy, halfScale);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -844,7 +942,7 @@ static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, con
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
auto sx = x * itransform->e11 + itransform->e13;
if ((uint32_t)sx >= image->w) continue;
- auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
+ auto src = _interpUpScaler(image->buf32, image->w, image->h, sx, sy);
*dst = src + ALPHA_BLEND(*dst, _ialpha(src));
}
}
@@ -870,7 +968,7 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
+ return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.luma);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
@@ -878,7 +976,7 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
+ return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.luma);
}
}
} else {
@@ -893,54 +991,56 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
/* Direct RGBA Image */
/************************************************************************/
-static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t (*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Direct Masked Image");
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
+ auto csize = surface->compositor->image.channelSize;
- auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
+ auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
- for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
buffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
sbuffer += image->stride;
}
return true;
}
-static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint8_t (*blender)(uint8_t*))
{
TVGLOG("SW_ENGINE", "Direct Masked Translucent Image");
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
+ auto csize = surface->compositor->image.channelSize;
- auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
+ auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
- for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
- auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
+ for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, _multiply<uint32_t>(opacity, blender(cmp)));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
buffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
+ cbuffer += surface->compositor->image.stride * csize;
sbuffer += image->stride;
}
return true;
@@ -949,8 +1049,8 @@ static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
{
- auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
- auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
+ auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
+ auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
for (auto y = region.min.y; y < region.max.y; ++y) {
auto dst = dbuffer;
@@ -968,8 +1068,8 @@ static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage*
static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
{
- auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
- auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
+ auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
+ auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
for (auto y = region.min.y; y < region.max.y; ++y) {
auto dst = dbuffer;
@@ -994,7 +1094,7 @@ static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwB
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
+ return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.luma);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
@@ -1002,7 +1102,7 @@ static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwB
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
+ return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.luma);
}
}
} else {
@@ -1034,14 +1134,15 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t
/* Rect Linear Gradient */
/************************************************************************/
-static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint8_t (*blender)(uint8_t*))
{
if (fill->linear.len < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
if (!sbuffer) return false;
@@ -1051,12 +1152,12 @@ static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& re
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
- for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
buffer += surface->stride;
- cbuffer += surface->stride;
+ cbuffer += surface->stride * csize;
}
return true;
}
@@ -1066,7 +1167,7 @@ static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBo
{
if (fill->linear.len < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
@@ -1089,7 +1190,7 @@ static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& reg
{
if (fill->linear.len < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
@@ -1108,7 +1209,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
+ return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.luma);
}
} else {
if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
@@ -1122,29 +1223,30 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
/* Rle Linear Gradient */
/************************************************************************/
-static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint8_t (*blender)(uint8_t*))
{
if (fill->linear.len < FLT_EPSILON) return false;
auto span = rle->spans;
- auto cbuffer = surface->compositor->image.data;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8;
auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
if (!buffer) return false;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
fillFetchLinear(fill, buffer, span->y, span->x, span->len);
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
auto src = buffer;
if (span->coverage == 255) {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
auto ialpha = 255 - span->coverage;
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
@@ -1163,7 +1265,7 @@ static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleD
if (!buffer) return false;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
fillFetchLinear(fill, buffer, span->y, span->x, span->len);
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst) {
@@ -1191,10 +1293,10 @@ static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* r
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
if (span->coverage == 255) {
- fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
+ fillFetchLinear(fill, surface->buf32 + span->y * surface->stride + span->x, span->y, span->x, span->len);
} else {
fillFetchLinear(fill, buf, span->y, span->x, span->len);
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
for (uint32_t x = 0; x < span->len; ++x) {
dst[x] = INTERPOLATE(span->coverage, buf[x], dst[x]);
}
@@ -1214,7 +1316,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
+ return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.luma);
}
} else {
if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
@@ -1228,14 +1330,15 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
/* Rect Radial Gradient */
/************************************************************************/
-static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint8_t(*blender)(uint8_t*))
{
if (fill->radial.a < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
- auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
if (!sbuffer) return false;
@@ -1245,12 +1348,12 @@ static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& re
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
- for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
buffer += surface->stride;
- cbuffer += surface->stride;
+ cbuffer += surface->stride * csize;
}
return true;
}
@@ -1260,7 +1363,7 @@ static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBo
{
if (fill->radial.a < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
@@ -1283,7 +1386,7 @@ static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& reg
{
if (fill->radial.a < FLT_EPSILON) return false;
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
@@ -1303,7 +1406,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
+ return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.luma);
}
} else {
if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
@@ -1317,28 +1420,29 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
/* RLE Radial Gradient */
/************************************************************************/
-static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint8_t(*blender)(uint8_t*))
{
if (fill->radial.a < FLT_EPSILON) return false;
auto span = rle->spans;
- auto cbuffer = surface->compositor->image.data;
+ auto csize = surface->compositor->image.channelSize;
+ auto cbuffer = surface->compositor->image.buf8;
auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
if (!buffer) return false;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
fillFetchRadial(fill, buffer, span->y, span->x, span->len);
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
- auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
auto src = buffer;
if (span->coverage == 255) {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
- auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = ALPHA_BLEND(*src, blender(cmp));
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
} else {
- for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
- auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blendMethod(*cmp)), *dst);
+ for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src, cmp += csize) {
+ auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blender(cmp)), *dst);
*dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
}
}
@@ -1356,7 +1460,7 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD
if (!buffer) return false;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
fillFetchRadial(fill, buffer, span->y, span->x, span->len);
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst) {
@@ -1383,7 +1487,7 @@ static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* r
auto span = rle->spans;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) {
fillFetchRadial(fill, dst, span->y, span->x, span->len);
} else {
@@ -1408,7 +1512,7 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
- return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
+ return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.luma);
}
} else {
if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
@@ -1417,7 +1521,6 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
return false;
}
-
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@@ -1429,47 +1532,65 @@ void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
#elif defined(THORVG_NEON_VECTOR_SUPPORT)
neonRasterRGBA32(dst, val, offset, len);
#else
- cRasterRGBA32(dst, val, offset, len);
+ cRasterPixels<uint32_t>(dst, val, offset, len);
#endif
}
bool rasterCompositor(SwSurface* surface)
{
- if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
+ if (surface->cs == ColorSpace::ABGR8888 || surface->cs == ColorSpace::ABGR8888S) {
surface->blender.join = _abgrJoin;
- surface->blender.lumaValue = _abgrLumaValue;
- } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
+ surface->blender.luma = _abgrLuma;
+ } else if (surface->cs == ColorSpace::ARGB8888 || surface->cs == ColorSpace::ARGB8888S) {
surface->blender.join = _argbJoin;
- surface->blender.lumaValue = _argbLumaValue;
+ surface->blender.luma = _argbLuma;
} else {
- //What Color Space ???
+ TVGERR("SW_ENGINE", "Unsupported Colorspace(%d) is expected!", surface->cs);
return false;
}
return true;
}
-bool rasterClear(SwSurface* surface)
+bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
- if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
+ if (!surface || !surface->buf32 || surface->stride == 0 || surface->w == 0 || surface->h == 0) return false;
- if (surface->w == surface->stride) {
- rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
- } else {
- for (uint32_t i = 0; i < surface->h; i++) {
- rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
+ //full clear
+ if (surface->channelSize == sizeof(uint32_t)) {
+ if (w == surface->stride) {
+ rasterRGBA32(surface->buf32 + (surface->stride * y), 0x00000000, 0, w * h);
+ } else {
+ auto buffer = surface->buf32 + (surface->stride * y + x);
+ for (uint32_t i = 0; i < h; i++) {
+ rasterRGBA32(buffer + (surface->stride * i), 0x00000000, 0, w);
+ }
+ }
+ //partial clear
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ if (w == surface->stride) {
+ _rasterGrayscale8(surface->buf8 + (surface->stride * y), 0x00, 0, w * h);
+ } else {
+ auto buffer = surface->buf8 + (surface->stride * y + x);
+ for (uint32_t i = 0; i < h; i++) {
+ _rasterGrayscale8(buffer + (surface->stride * i), 0x00, 0, w);
+ }
}
}
return true;
}
-void rasterUnpremultiply(SwSurface* surface)
+void rasterUnpremultiply(Surface* surface)
{
+ if (surface->channelSize != sizeof(uint32_t)) return;
+
+ TVGLOG("SW_ENGINE", "Unpremultiply [Size: %d x %d]", surface->w, surface->h);
+
//OPTIMIZE_ME: +SIMD
for (uint32_t y = 0; y < surface->h; y++) {
- auto buffer = surface->buffer + surface->stride * y;
+ auto buffer = surface->buf32 + surface->stride * y;
for (uint32_t x = 0; x < surface->w; ++x) {
uint8_t a = buffer[x] >> 24;
if (a == 255) {
@@ -1487,11 +1608,37 @@ void rasterUnpremultiply(SwSurface* surface)
}
}
}
+ surface->premultiplied = false;
+}
+
+
+void rasterPremultiply(Surface* surface)
+{
+ if (surface->channelSize != sizeof(uint32_t)) return;
+
+ TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h);
+
+ //OPTIMIZE_ME: +SIMD
+ auto buffer = surface->buf32;
+ for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
+ auto dst = buffer;
+ for (uint32_t x = 0; x < surface->w; ++x, ++dst) {
+ auto c = *dst;
+ auto a = (c >> 24);
+ *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
+ }
+ }
+ surface->premultiplied = true;
}
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
{
+ if (surface->channelSize == sizeof(uint8_t)) {
+ TVGERR("SW_ENGINE", "Not supported grayscale gradient!");
+ return false;
+ }
+
if (!shape->fill) return false;
if (shape->fastTrack) {
@@ -1507,6 +1654,11 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
{
+ if (surface->channelSize == sizeof(uint8_t)) {
+ TVGERR("SW_ENGINE", "Not supported grayscale gradient!");
+ return false;
+ }
+
if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
@@ -1519,40 +1671,60 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (a < 255) {
- r = _multiplyAlpha(r, a);
- g = _multiplyAlpha(g, a);
- b = _multiplyAlpha(b, a);
+ r = _multiply<uint32_t>(r, a);
+ g = _multiply<uint32_t>(g, a);
+ b = _multiply<uint32_t>(b, a);
}
- auto color = surface->blender.join(r, g, b, a);
-
- if (shape->fastTrack) return _rasterRect(surface, shape->bbox, color, a);
- else return _rasterRle(surface, shape->rle, color, a);
+ if (shape->fastTrack) return _rasterRect(surface, shape->bbox, r, g, b, a);
+ else return _rasterRle(surface, shape->rle, r, g, b, a);
}
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (a < 255) {
- r = _multiplyAlpha(r, a);
- g = _multiplyAlpha(g, a);
- b = _multiplyAlpha(b, a);
+ r = _multiply<uint32_t>(r, a);
+ g = _multiply<uint32_t>(g, a);
+ b = _multiply<uint32_t>(b, a);
}
- auto color = surface->blender.join(r, g, b, a);
-
- return _rasterRle(surface, shape->strokeRle, color, a);
+ return _rasterRle(surface, shape->strokeRle, r, g, b, a);
}
-bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
+bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
{
+ if (surface->channelSize == sizeof(uint8_t)) {
+ TVGERR("SW_ENGINE", "Not supported grayscale image!");
+ return false;
+ }
+
//Verify Boundary
if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast<SwCoord>(surface->w) || bbox.min.y >= static_cast<SwCoord>(surface->h)) return false;
//TOOD: switch (image->format)
- //TODO: case: _rasterRGBImage()
- //TODO: case: _rasterGrayscaleImage()
- //TODO: case: _rasterAlphaImage()
- return _rasterRGBAImage(surface, image, transform, bbox, opacity);
+ //TODO: case: _rasterRGBImageMesh()
+ //TODO: case: _rasterGrayscaleImageMesh()
+ //TODO: case: _rasterAlphaImageMesh()
+ if (mesh && mesh->triangleCnt > 0) return _transformedRGBAImageMesh(surface, image, mesh, transform, &bbox, opacity);
+ else return _rasterRGBAImage(surface, image, transform, bbox, opacity);
+}
+
+
+bool rasterConvertCS(Surface* surface, ColorSpace to)
+{
+ //TOOD: Support SIMD accelerations
+ auto from = surface->cs;
+
+ if ((from == ColorSpace::ABGR8888 && to == ColorSpace::ARGB8888) || (from == ColorSpace::ABGR8888S && to == ColorSpace::ARGB8888S)) {
+ surface->cs = to;
+ return cRasterABGRtoARGB(surface);
+ }
+ if ((from == ColorSpace::ARGB8888 && to == ColorSpace::ABGR8888) || (from == ColorSpace::ARGB8888S && to == ColorSpace::ABGR8888S)) {
+ surface->cs = to;
+ return cRasterARGBtoABGR(surface);
+ }
+
+ return false;
}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterAvx.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterAvx.h
index 7a129a3a80..cf658a6abb 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterAvx.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterAvx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -82,9 +82,15 @@ static void avxRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_
}
-static bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
+static bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ if (surface->channelSize != sizeof(uint32_t)) {
+ TVGERR("SW_ENGINE", "Unsupported Channel Size = %d", surface->channelSize);
+ return false;
+ }
+
+ auto color = surface->blender.join(r, g, b, a);
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
@@ -125,13 +131,19 @@ static bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& region, u
}
-static bool avxRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
+static bool avxRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
+ if (surface->channelSize != sizeof(uint32_t)) {
+ TVGERR("SW_ENGINE", "Unsupported Channel Size = %d", surface->channelSize);
+ return false;
+ }
+
+ auto color = surface->blender.join(r, g, b, a);
auto span = rle->spans;
uint32_t src;
for (uint32_t i = 0; i < rle->size; ++i) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterC.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterC.h
index de6b35fd64..ad2fc57f24 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterC.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterC.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,45 +20,95 @@
* SOFTWARE.
*/
-
-static void inline cRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
+template<typename PIXEL_T>
+static void inline cRasterPixels(PIXEL_T* dst, uint32_t val, uint32_t offset, int32_t len)
{
dst += offset;
while (len--) *dst++ = val;
}
-static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
+static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
auto span = rle->spans;
- uint32_t src;
-
- for (uint32_t i = 0; i < rle->size; ++i, ++span) {
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
-
- if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
- else src = color;
- for (uint32_t x = 0; x < span->len; ++x, ++dst) {
- *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
+ //32bit channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, a);
+ uint32_t src;
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
+ if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
+ else src = color;
+ for (uint32_t x = 0; x < span->len; ++x, ++dst) {
+ *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
+ }
+ }
+ //8bit grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ uint8_t src;
+ for (uint32_t i = 0; i < rle->size; ++i, ++span) {
+ auto dst = &surface->buf8[span->y * surface->stride + span->x];
+ if (span->coverage < 255) src = _multiply<uint8_t>(span->coverage, a);
+ else src = a;
+ for (uint32_t x = 0; x < span->len; ++x, ++dst) {
+ *dst = src + _multiply<uint8_t>(*dst, ~src);
+ }
}
}
return true;
}
-static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
+static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
- auto ialpha = _ialpha(color);
- for (uint32_t y = 0; y < h; ++y) {
- auto dst = &buffer[y * surface->stride];
- for (uint32_t x = 0; x < w; ++x, ++dst) {
- *dst = color + ALPHA_BLEND(*dst, ialpha);
+ //32bits channels
+ if (surface->channelSize == sizeof(uint32_t)) {
+ auto color = surface->blender.join(r, g, b, a);
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
+ auto ialpha = _ialpha(color);
+ for (uint32_t y = 0; y < h; ++y) {
+ auto dst = &buffer[y * surface->stride];
+ for (uint32_t x = 0; x < w; ++x, ++dst) {
+ *dst = color + ALPHA_BLEND(*dst, ialpha);
+ }
+ }
+ //8bit grayscale
+ } else if (surface->channelSize == sizeof(uint8_t)) {
+ auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
+ for (uint32_t y = 0; y < h; ++y) {
+ auto dst = &buffer[y * surface->stride];
+ for (uint32_t x = 0; x < w; ++x, ++dst) {
+ *dst = a + _multiply<uint8_t>(*dst, ~a);
+ }
}
}
return true;
}
+
+
+static bool inline cRasterABGRtoARGB(Surface* surface)
+{
+ TVGLOG("SW_ENGINE", "Convert ColorSpace ABGR - ARGB [Size: %d x %d]", surface->w, surface->h);
+
+ auto buffer = surface->buf32;
+ for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
+ auto dst = buffer;
+ for (uint32_t x = 0; x < surface->w; ++x, ++dst) {
+ auto c = *dst;
+ //flip Blue, Red channels
+ *dst = (c & 0xff000000) + ((c & 0x00ff0000) >> 16) + (c & 0x0000ff00) + ((c & 0x000000ff) << 16);
+ }
+ }
+ return true;
+}
+
+
+static bool inline cRasterARGBtoABGR(Surface* surface)
+{
+ //exactly same with ABGRtoARGB
+ return cRasterABGRtoARGB(surface);
+}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterNeon.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterNeon.h
index a4b3cdaeb2..33c3d181b5 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterNeon.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterNeon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -49,8 +49,14 @@ static void neonRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32
}
-static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
+static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
+ if (surface->channelSize != sizeof(uint32_t)) {
+ TVGERR("SW_ENGINE", "Unsupported Channel Size = %d", surface->channelSize);
+ return false;
+ }
+
+ auto color = surface->blender.join(r, g, b, a);
auto span = rle->spans;
uint32_t src;
uint8x8_t *vDst = nullptr;
@@ -60,7 +66,7 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, u
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
- auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto ialpha = 255 - _alpha(src);
if ((((uint32_t) dst) & 0x7) != 0) {
@@ -88,9 +94,15 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, u
}
-static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
+static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+ if (surface->channelSize != sizeof(uint32_t)) {
+ TVGERR("SW_ENGINE", "Unsupported Channel Size = %d", surface->channelSize);
+ return false;
+ }
+
+ auto color = surface->blender.join(r, g, b, a);
+ auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto ialpha = 255 - _alpha(color);
@@ -116,7 +128,7 @@ static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region,
for (uint32_t x = 0; x < (w - align) / 2; ++x)
vDst[x] = vadd_u8((uint8x8_t)vColor, ALPHA_BLEND(vDst[x], vIalpha));
-
+
auto leftovers = (w - align) % 2;
if (leftovers > 0) dst[w - 1] = color + ALPHA_BLEND(dst[w - 1], ialpha);
}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmap.h
index abb57d7c45..52585162fc 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmap.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,17 +20,6 @@
* SOFTWARE.
*/
-struct Vertex
-{
- Point pt;
- Point uv;
-};
-
-struct Polygon
-{
- Vertex vertex[3];
-};
-
struct AALine
{
int32_t x[2];
@@ -80,7 +69,7 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in
}
-static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, uint32_t (*blendMethod)(uint32_t), AASpans* aaSpans)
+static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, uint8_t(*blender)(uint8_t*), AASpans* aaSpans)
{
#define TEXMAP_TRANSLUCENT
#define TEXMAP_MASKING
@@ -90,7 +79,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
}
-static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t (*blendMethod)(uint32_t), AASpans* aaSpans)
+static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint8_t(*blender)(uint8_t*), AASpans* aaSpans)
{
#define TEXMAP_MASKING
#include "tvgSwRasterTexmapInternal.h"
@@ -113,7 +102,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
/* This mapping algorithm is based on Mikael Kalms's. */
-static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox* region, uint32_t opacity, Polygon& polygon, uint32_t (*blendMethod)(uint32_t), AASpans* aaSpans)
+static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox* region, uint32_t opacity, Polygon& polygon, uint8_t(*blender)(uint8_t*), AASpans* aaSpans)
{
float x[3] = {polygon.vertex[0].pt.x, polygon.vertex[1].pt.x, polygon.vertex[2].pt.x};
float y[3] = {polygon.vertex[0].pt.y, polygon.vertex[1].pt.y, polygon.vertex[2].pt.y};
@@ -201,9 +190,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
dxdyb = dxdy[0];
xb = x[0] + dy * dxdyb + (off_y * dxdyb);
- if (blendMethod) {
- if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blendMethod, aaSpans);
- else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod, aaSpans);
+ if (blender) {
+ if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blender, aaSpans);
+ else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blender, aaSpans);
} else {
if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans);
else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
@@ -222,9 +211,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
// Set right edge X-slope and perform subpixel pre-stepping
dxdyb = dxdy[2];
xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb);
- if (blendMethod) {
- if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blendMethod, aaSpans);
- else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod, aaSpans);
+ if (blender) {
+ if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blender, aaSpans);
+ else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blender, aaSpans);
} else {
if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans);
else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
@@ -251,9 +240,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
ua = u[0] + dy * dudya + (off_y * dudya);
va = v[0] + dy * dvdya + (off_y * dvdya);
- if (blendMethod) {
- if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blendMethod, aaSpans);
- else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod, aaSpans);
+ if (blender) {
+ if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blender, aaSpans);
+ else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blender, aaSpans);
} else {
if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans);
else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
@@ -275,9 +264,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
ua = u[1] + dy * dudya + (off_y * dudya);
va = v[1] + dy * dvdya + (off_y * dvdya);
- if (blendMethod) {
- if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blendMethod, aaSpans);
- else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod, aaSpans);
+ if (blender) {
+ if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blender, aaSpans);
+ else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blender, aaSpans);
} else {
if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans);
else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
@@ -287,18 +276,10 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
}
-static AASpans* _AASpans(const Vertex* vertices, const SwImage* image, const SwBBox* region)
+static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwBBox* region)
{
- //Initialize Y range
- float ys = FLT_MAX, ye = -1.0f;
-
- for (int i = 0; i < 4; i++) {
- if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
- if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
- }
-
- auto yStart = static_cast<int32_t>(ys);
- auto yEnd = static_cast<int32_t>(ye);
+ auto yStart = static_cast<int32_t>(ymin);
+ auto yEnd = static_cast<int32_t>(ymax);
if (!_arrange(image, region, yStart, yEnd)) return nullptr;
@@ -521,7 +502,7 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
auto offset = y * surface->stride;
//Left edge
- dst = surface->buffer + (offset + line->x[0]);
+ dst = surface->buf32 + (offset + line->x[0]);
if (line->x[0] > 1) pixel = *(dst - 1);
else pixel = *dst;
@@ -533,10 +514,10 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
}
//Right edge
- dst = surface->buffer + (offset + line->x[1] - 1);
+ dst = surface->buf32 + (offset + line->x[1] - 1);
if (line->x[1] < (int32_t)(surface->w - 1)) pixel = *(dst + 1);
else pixel = *dst;
-
+
pos = width;
while ((int32_t)(width - line->length[1]) < pos) {
*dst = INTERPOLATE(255 - (line->coverage[1] * (line->length[1] - (width - pos))), *dst, pixel);
@@ -562,12 +543,12 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
0 -- 1
| / |
| / |
- 3 -- 2
+ 3 -- 2
*/
-static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
+static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint8_t(*blender)(uint8_t*))
{
//Exceptions: No dedicated drawing area?
- if (!region && image->rle->size == 0) return false;
+ if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
/* Prepare vertices.
shift XY coordinates to match the sub-pixeling technique. */
@@ -577,9 +558,15 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
vertices[2] = {{float(image->w), float(image->h)}, {float(image->w), float(image->h)}};
vertices[3] = {{0.0f, float(image->h)}, {0.0f, float(image->h)}};
- for (int i = 0; i < 4; i++) mathMultiply(&vertices[i].pt, transform);
+ float ys = FLT_MAX, ye = -1.0f;
+ for (int i = 0; i < 4; i++) {
+ mathMultiply(&vertices[i].pt, transform);
- auto aaSpans = _AASpans(vertices, image, region);
+ if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
+ if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
+ }
+
+ auto aaSpans = _AASpans(ys, ye, image, region);
if (!aaSpans) return true;
Polygon polygon;
@@ -589,14 +576,72 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
polygon.vertex[1] = vertices[1];
polygon.vertex[2] = vertices[3];
- _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod, aaSpans);
+ _rasterPolygonImage(surface, image, region, opacity, polygon, blender, aaSpans);
//Draw the second polygon
polygon.vertex[0] = vertices[1];
polygon.vertex[1] = vertices[2];
polygon.vertex[2] = vertices[3];
- _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod, aaSpans);
+ _rasterPolygonImage(surface, image, region, opacity, polygon, blender, aaSpans);
return _apply(surface, aaSpans);
}
+
+
+/*
+ Provide any number of triangles to draw a mesh using the supplied image.
+ Indexes are not used, so each triangle (Polygon) vertex has to be defined, even if they copy the previous one.
+ Example:
+
+ 0 -- 1 0 -- 1 0
+ | / | --> | / / |
+ | / | | / / |
+ 2 -- 3 2 1 -- 2
+
+ Should provide two Polygons, one for each triangle.
+ // TODO: region?
+*/
+static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint8_t(*blender)(uint8_t*))
+{
+ //Exceptions: No dedicated drawing area?
+ if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
+
+ // Step polygons once to transform
+ auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * mesh->triangleCnt);
+ float ys = FLT_MAX, ye = -1.0f;
+ for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
+ transformedTris[i] = mesh->triangles[i];
+ mathMultiply(&transformedTris[i].vertex[0].pt, transform);
+ mathMultiply(&transformedTris[i].vertex[1].pt, transform);
+ mathMultiply(&transformedTris[i].vertex[2].pt, transform);
+
+ if (transformedTris[i].vertex[0].pt.y < ys) ys = transformedTris[i].vertex[0].pt.y;
+ else if (transformedTris[i].vertex[0].pt.y > ye) ye = transformedTris[i].vertex[0].pt.y;
+ if (transformedTris[i].vertex[1].pt.y < ys) ys = transformedTris[i].vertex[1].pt.y;
+ else if (transformedTris[i].vertex[1].pt.y > ye) ye = transformedTris[i].vertex[1].pt.y;
+ if (transformedTris[i].vertex[2].pt.y < ys) ys = transformedTris[i].vertex[2].pt.y;
+ else if (transformedTris[i].vertex[2].pt.y > ye) ye = transformedTris[i].vertex[2].pt.y;
+
+ // Convert normalized UV coordinates to image coordinates
+ transformedTris[i].vertex[0].uv.x *= (float)image->w;
+ transformedTris[i].vertex[0].uv.y *= (float)image->h;
+ transformedTris[i].vertex[1].uv.x *= (float)image->w;
+ transformedTris[i].vertex[1].uv.y *= (float)image->h;
+ transformedTris[i].vertex[2].uv.x *= (float)image->w;
+ transformedTris[i].vertex[2].uv.y *= (float)image->h;
+ }
+
+ // Get AA spans and step polygons again to draw
+ auto aaSpans = _AASpans(ys, ye, image, region);
+ if (aaSpans) {
+ for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
+ _rasterPolygonImage(surface, image, region, opacity, transformedTris[i], blender, aaSpans);
+ }
+ // Apply to surface (note: frees the AA spans)
+ _apply(surface, aaSpans);
+ }
+ free(transformedTris);
+
+ return true;
+}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmapInternal.h
index 50536299b1..51685fe6e8 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmapInternal.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRasterTexmapInternal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,12 +19,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
{
float _dudx = dudx, _dvdx = dvdx;
float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
float _xa = xa, _xb = xb, _ua = ua, _va = va;
- auto sbuf = image->data;
- auto dbuf = surface->buffer;
+ auto sbuf = image->buf32;
+ auto dbuf = surface->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t dw = surface->stride;
@@ -36,7 +37,8 @@
SwSpan* span = nullptr; //used only when rle based.
#ifdef TEXMAP_MASKING
- uint32_t* cmp;
+ uint8_t* cmp;
+ auto csize = surface->compositor->image.channelSize;
#endif
if (!_arrange(image, region, yStart, yEnd)) return;
@@ -93,7 +95,7 @@
x = x1;
#ifdef TEXMAP_MASKING
- cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1];
+ cmp = &surface->compositor->image.buf8[(y * surface->compositor->image.stride + x1) * csize];
#endif
//Draw horizontal line
while (x++ < x2) {
@@ -104,6 +106,9 @@
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
+
+ if (vv >= sh) continue;
+
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
@@ -126,9 +131,9 @@
px = INTERPOLATE(ab, px, px2);
}
#if defined(TEXMAP_MASKING) && defined(TEXMAP_TRANSLUCENT)
- auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp)));
+ auto src = ALPHA_BLEND(px, _multiply<uint32_t>(opacity, blender(cmp)));
#elif defined(TEXMAP_MASKING)
- auto src = ALPHA_BLEND(px, blendMethod(*cmp));
+ auto src = ALPHA_BLEND(px, blender(cmp));
#elif defined(TEXMAP_TRANSLUCENT)
auto src = ALPHA_BLEND(px, opacity);
#else
@@ -137,7 +142,7 @@
*buf = src + ALPHA_BLEND(*buf, _ialpha(src));
++buf;
#ifdef TEXMAP_MASKING
- ++cmp;
+ cmp += csize;
#endif
//Step UV horizontally
u += _dudx;
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.cpp
index a1c0032a2e..6223bc8722 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "tvgMath.h"
#include "tvgSwCommon.h"
#include "tvgTaskScheduler.h"
@@ -60,6 +61,8 @@ struct SwTask : Task
}
virtual bool dispose() = 0;
+ virtual bool clip(SwRleData* target) = 0;
+ virtual SwRleData* rle() = 0;
virtual ~SwTask()
{
@@ -71,23 +74,39 @@ struct SwTask : Task
struct SwShapeTask : SwTask
{
SwShape shape;
- const Shape* sdata = nullptr;
+ const RenderShape* rshape = nullptr;
bool cmpStroking = false;
+ bool clipper = false;
+
+ bool clip(SwRleData* target) override
+ {
+ if (shape.fastTrack) rleClipRect(target, &bbox);
+ else if (shape.rle) rleClipPath(target, shape.rle);
+ else return false;
+
+ return true;
+ }
+
+ SwRleData* rle() override
+ {
+ if (!shape.rle && shape.fastTrack) {
+ shape.rle = rleRender(&shape.bbox);
+ }
+ return shape.rle;
+ }
void run(unsigned tid) override
{
- auto compMethod = CompositeMethod::None;
- auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath);
- if (opacity == 0 && !usedAsClip) return; //Invisible
+ if (opacity == 0 && !clipper) return; //Invisible
uint8_t strokeAlpha = 0;
auto visibleStroke = false;
bool visibleFill = false;
auto clipRegion = bbox;
- if (HALF_STROKE(sdata->strokeWidth()) > 0) {
- sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
- visibleStroke = sdata->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
+ if (HALF_STROKE(rshape->strokeWidth()) > 0) {
+ rshape->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
+ visibleStroke = rshape->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
}
//This checks also for the case, if the invisible shape turned to visible by alpha.
@@ -97,12 +116,12 @@ struct SwShapeTask : SwTask
//Shape
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) {
uint8_t alpha = 0;
- sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
+ rshape->fillColor(nullptr, nullptr, nullptr, &alpha);
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
- visibleFill = (alpha > 0 || sdata->fill());
- if (visibleFill || visibleStroke || usedAsClip) {
+ visibleFill = (alpha > 0 || rshape->fill);
+ if (visibleFill || visibleStroke || clipper) {
shapeReset(&shape);
- if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
+ if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
}
}
@@ -112,16 +131,16 @@ struct SwShapeTask : SwTask
//Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
- if (visibleFill || usedAsClip) {
+ if (visibleFill || clipper) {
/* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition.
Also, it shouldn't be dash style. */
- auto antiAlias = (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) ? false : true;
+ auto antiAlias = strokeAlpha < 255 || rshape->strokeWidth() <= 2 || rshape->strokeDash(nullptr) > 0 || (rshape->stroke && rshape->stroke->strokeFirst);
- if (!shapeGenRle(&shape, sdata, antiAlias)) goto err;
+ if (!shapeGenRle(&shape, rshape, antiAlias)) goto err;
}
- if (auto fill = sdata->fill()) {
+ if (auto fill = rshape->fill) {
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
if (ctable) shapeResetFill(&shape);
if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
@@ -133,10 +152,10 @@ struct SwShapeTask : SwTask
//Stroke
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
if (visibleStroke) {
- shapeResetStroke(&shape, sdata, transform);
- if (!shapeGenStrokeRle(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err;
+ shapeResetStroke(&shape, rshape, transform);
+ if (!shapeGenStrokeRle(&shape, rshape, transform, clipRegion, bbox, mpool, tid)) goto err;
- if (auto fill = sdata->strokeFill()) {
+ if (auto fill = rshape->strokeFill()) {
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
if (ctable) shapeResetStrokeFill(&shape);
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
@@ -148,27 +167,21 @@ struct SwShapeTask : SwTask
}
}
+ //Clear current task memorypool here if the clippers would use the same memory pool
+ shapeDelOutline(&shape, mpool, tid);
+
//Clip Path
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
- auto clipper = &static_cast<SwShapeTask*>(*clip)->shape;
+ auto clipper = static_cast<SwTask*>(*clip);
//Clip shape rle
- if (shape.rle) {
- if (clipper->fastTrack) rleClipRect(shape.rle, &clipper->bbox);
- else if (clipper->rle) rleClipPath(shape.rle, clipper->rle);
- else goto err;
- }
+ if (shape.rle && !clipper->clip(shape.rle)) goto err;
//Clip stroke rle
- if (shape.strokeRle) {
- if (clipper->fastTrack) rleClipRect(shape.strokeRle, &clipper->bbox);
- else if (clipper->rle) rleClipPath(shape.strokeRle, clipper->rle);
- else goto err;
- }
+ if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err;
}
- goto end;
+ return;
err:
shapeReset(&shape);
- end:
shapeDelOutline(&shape, mpool, tid);
}
@@ -180,35 +193,116 @@ struct SwShapeTask : SwTask
};
+struct SwSceneTask : SwTask
+{
+ Array<RenderData> scene; //list of paints render data (SwTask)
+ SwRleData* sceneRle = nullptr;
+
+ bool clip(SwRleData* target) override
+ {
+ //Only one shape
+ if (scene.count == 1) {
+ return static_cast<SwTask*>(*scene.data)->clip(target);
+ }
+
+ //More than one shapes
+ if (sceneRle) rleClipPath(target, sceneRle);
+ else TVGLOG("SW_ENGINE", "No clippers in a scene?");
+
+ return true;
+ }
+
+ SwRleData* rle() override
+ {
+ return sceneRle;
+ }
+
+ void run(unsigned tid) override
+ {
+ //TODO: Skip the run if the scene hans't changed.
+ if (!sceneRle) sceneRle = static_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
+ else rleReset(sceneRle);
+
+ //Merge shapes if it has more than one shapes
+ if (scene.count > 1) {
+ //Merge first two clippers
+ auto clipper1 = static_cast<SwTask*>(*scene.data);
+ auto clipper2 = static_cast<SwTask*>(*(scene.data + 1));
+
+ rleMerge(sceneRle, clipper1->rle(), clipper2->rle());
+
+ //Unify the remained clippers
+ for (auto rd = scene.data + 2; rd < (scene.data + scene.count); ++rd) {
+ auto clipper = static_cast<SwTask*>(*rd);
+ rleMerge(sceneRle, sceneRle, clipper->rle());
+ }
+ }
+ }
+
+ bool dispose() override
+ {
+ rleFree(sceneRle);
+ return true;
+ }
+};
+
+
struct SwImageTask : SwTask
{
SwImage image;
+ Surface* source; //Image source
+ const RenderMesh* mesh = nullptr; //Should be valid ptr in action
+
+ bool clip(SwRleData* target) override
+ {
+ TVGERR("SW_ENGINE", "Image is used as ClipPath?");
+ return true;
+ }
+
+ SwRleData* rle() override
+ {
+ TVGERR("SW_ENGINE", "Image is used as Scene ClipPath?");
+ return nullptr;
+ }
void run(unsigned tid) override
{
auto clipRegion = bbox;
+ //Convert colorspace if it's not aligned.
+ if (source->owner) {
+ if (source->cs != surface->cs) rasterConvertCS(source, surface->cs);
+ if (!source->premultiplied) rasterPremultiply(source);
+ }
+
+ image.data = source->data;
+ image.w = source->w;
+ image.h = source->h;
+ image.stride = source->stride;
+ image.channelSize = source->channelSize;
+
//Invisible shape turned to visible by alpha.
if ((flags & (RenderUpdateFlag::Image | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) && (opacity > 0)) {
imageReset(&image);
if (!image.data || image.w == 0 || image.h == 0) goto end;
- if (!imagePrepare(&image, transform, clipRegion, bbox, mpool, tid)) goto end;
+ if (!imagePrepare(&image, mesh, transform, clipRegion, bbox, mpool, tid)) goto end;
- if (clips.count > 0) {
+ // TODO: How do we clip the triangle mesh? Only clip non-meshed images for now
+ if (mesh->triangleCnt == 0 && clips.count > 0) {
if (!imageGenRle(&image, bbox, false)) goto end;
if (image.rle) {
+ //Clear current task memorypool here if the clippers would use the same memory pool
+ imageDelOutline(&image, mpool, tid);
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
- auto clipper = &static_cast<SwShapeTask*>(*clip)->shape;
- if (clipper->fastTrack) rleClipRect(image.rle, &clipper->bbox);
- else if (clipper->rle) rleClipPath(image.rle, clipper->rle);
- else goto err;
+ auto clipper = static_cast<SwTask*>(*clip);
+ if (!clipper->clip(image.rle)) goto err;
}
+ return;
}
}
}
goto end;
-
err:
rleReset(image.rle);
end:
@@ -232,6 +326,31 @@ static void _termEngine()
}
+static void _renderFill(SwShapeTask* task, SwSurface* surface, uint32_t opacity)
+{
+ uint8_t r, g, b, a;
+ if (auto fill = task->rshape->fill) {
+ rasterGradientShape(surface, &task->shape, fill->identifier());
+ } else {
+ task->rshape->fillColor(&r, &g, &b, &a);
+ a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
+ if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
+ }
+}
+
+static void _renderStroke(SwShapeTask* task, SwSurface* surface, uint32_t opacity)
+{
+ uint8_t r, g, b, a;
+ if (auto strokeFill = task->rshape->strokeFill()) {
+ rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
+ } else {
+ if (task->rshape->strokeColor(&r, &g, &b, &a)) {
+ a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
+ if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
+ }
+ }
+}
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@@ -293,17 +412,20 @@ bool SwRenderer::viewport(const RenderRegion& vp)
}
-bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace)
+bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs)
{
- if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
+ if (!data || stride == 0 || w == 0 || h == 0 || w > stride) return false;
if (!surface) surface = new SwSurface;
- surface->buffer = buffer;
+ surface->data = data;
surface->stride = stride;
surface->w = w;
surface->h = h;
- surface->cs = colorSpace;
+ surface->cs = cs;
+ surface->channelSize = CHANNEL_SIZE(cs);
+ surface->premultiplied = true;
+ surface->owner = true;
vport.x = vport.y = 0;
vport.w = surface->w;
@@ -315,9 +437,10 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
bool SwRenderer::preRender()
{
- return rasterClear(surface);
+ return rasterClear(surface, 0, 0, surface->w, surface->h);
}
+
void SwRenderer::clearCompositors()
{
//Free Composite Caches
@@ -333,7 +456,7 @@ void SwRenderer::clearCompositors()
bool SwRenderer::postRender()
{
//Unmultiply alpha if needed
- if (surface->cs == SwCanvas::ABGR8888_STRAIGHT || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
+ if (surface->cs == ColorSpace::ABGR8888S || surface->cs == ColorSpace::ARGB8888S) {
rasterUnpremultiply(surface);
}
@@ -354,7 +477,7 @@ bool SwRenderer::renderImage(RenderData data)
if (task->opacity == 0) return true;
- return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
+ return rasterImage(surface, &task->image, task->mesh, task->transform, task->bbox, task->opacity);
}
@@ -373,7 +496,7 @@ bool SwRenderer::renderShape(RenderData data)
//Do Stroking Composition
if (task->cmpStroking) {
opacity = 255;
- cmp = target(task->bounds());
+ cmp = target(task->bounds(), colorSpace());
beginComposite(cmp, CompositeMethod::None, task->opacity);
//No Stroking Composition
} else {
@@ -381,23 +504,12 @@ bool SwRenderer::renderShape(RenderData data)
}
//Main raster stage
- uint8_t r, g, b, a;
-
- if (auto fill = task->sdata->fill()) {
- rasterGradientShape(surface, &task->shape, fill->identifier());
- } else {
- task->sdata->fillColor(&r, &g, &b, &a);
- a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
- if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
- }
-
- if (auto strokeFill = task->sdata->strokeFill()) {
- rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
+ if (task->rshape->stroke && task->rshape->stroke->strokeFirst) {
+ _renderStroke(task, surface, opacity);
+ _renderFill(task, surface, opacity);
} else {
- if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) {
- a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
- if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
- }
+ _renderFill(task, surface, opacity);
+ _renderStroke(task, surface, opacity);
}
if (task->cmpStroking) endComposite(cmp);
@@ -450,7 +562,7 @@ bool SwRenderer::mempool(bool shared)
}
-Compositor* SwRenderer::target(const RenderRegion& region)
+Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
{
auto x = region.x;
auto y = region.y;
@@ -460,13 +572,15 @@ Compositor* SwRenderer::target(const RenderRegion& region)
auto sh = static_cast<int32_t>(surface->h);
//Out of boundary
- if (x > sw || y > sh) return nullptr;
+ if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr;
SwSurface* cmp = nullptr;
+ auto reqChannelSize = CHANNEL_SIZE(cs);
+
//Use cached data
for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
- if ((*p)->compositor->valid) {
+ if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == reqChannelSize) {
cmp = *p;
break;
}
@@ -475,17 +589,16 @@ Compositor* SwRenderer::target(const RenderRegion& region)
//New Composition
if (!cmp) {
cmp = new SwSurface;
- if (!cmp) goto err;
//Inherits attributes from main surface
*cmp = *surface;
cmp->compositor = new SwCompositor;
- if (!cmp->compositor) goto err;
- //SwImage, Optimize Me: Surface size from MainSurface(WxH) to Parameter W x H
- cmp->compositor->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->stride * surface->h);
- if (!cmp->compositor->image.data) goto err;
+ //TODO: We can optimize compositor surface size from (surface->stride x surface->h) to Parameter(w x h)
+ cmp->compositor->image.data = (pixel_t*)malloc(reqChannelSize * surface->stride * surface->h);
+ cmp->channelSize = cmp->compositor->image.channelSize = reqChannelSize;
+
compositors.push(cmp);
}
@@ -507,30 +620,16 @@ Compositor* SwRenderer::target(const RenderRegion& region)
cmp->compositor->image.h = surface->h;
cmp->compositor->image.direct = true;
- //We know partial clear region
- cmp->buffer = cmp->compositor->image.data + (cmp->stride * y + x);
- cmp->w = w;
- cmp->h = h;
-
- rasterClear(cmp);
-
- //Recover context
- cmp->buffer = cmp->compositor->image.data;
+ cmp->data = cmp->compositor->image.data;
cmp->w = cmp->compositor->image.w;
cmp->h = cmp->compositor->image.h;
+ rasterClear(cmp, x, y, w, h);
+
//Switch render target
surface = cmp;
return cmp->compositor;
-
-err:
- if (cmp) {
- if (cmp->compositor) delete(cmp->compositor);
- delete(cmp);
- }
-
- return nullptr;
}
@@ -547,13 +646,20 @@ bool SwRenderer::endComposite(Compositor* cmp)
//Default is alpha blending
if (p->method == CompositeMethod::None) {
- return rasterImage(surface, &p->image, nullptr, p->bbox, p->opacity);
+ return rasterImage(surface, &p->image, nullptr, nullptr, p->bbox, p->opacity);
}
return true;
}
+ColorSpace SwRenderer::colorSpace()
+{
+ if (surface) return surface->cs;
+ else return ColorSpace::Unsupported;
+}
+
+
bool SwRenderer::dispose(RenderData data)
{
auto task = static_cast<SwTask*>(data);
@@ -576,14 +682,15 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
//Finish previous task if it has duplicated request.
task->done();
- if (clips.count > 0) {
- //Guarantee composition targets get ready.
- for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
- static_cast<SwShapeTask*>(*clip)->done();
- }
- task->clips = clips;
+ //TODO: Failed threading them. It would be better if it's possible.
+ //See: https://github.com/thorvg/thorvg/issues/1409
+ //Guarantee composition targets get ready.
+ for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
+ static_cast<SwTask*>(*clip)->done();
}
+ task->clips = clips;
+
if (transform) {
if (!task->transform) task->transform = static_cast<Matrix*>(malloc(sizeof(Matrix)));
*task->transform = transform->m;
@@ -612,44 +719,52 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
}
-RenderData SwRenderer::prepare(Surface* image, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwImageTask*>(data);
- if (!task) {
- task = new SwImageTask;
- if (flags & RenderUpdateFlag::Image) {
- task->image.data = image->buffer;
- task->image.w = image->w;
- task->image.h = image->h;
- task->image.stride = image->stride;
- }
+ if (!task) task = new SwImageTask;
+ if (flags & RenderUpdateFlag::Image) {
+ task->source = surface;
+ task->mesh = mesh;
}
return prepareCommon(task, transform, opacity, clips, flags);
}
-RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
- auto task = static_cast<SwShapeTask*>(data);
- if (!task) {
- task = new SwShapeTask;
- task->sdata = &sdata;
+ auto task = static_cast<SwSceneTask*>(data);
+ if (!task) task = new SwSceneTask;
+ task->scene = scene;
+
+ //TODO: Failed threading them. It would be better if it's possible.
+ //See: https://github.com/thorvg/thorvg/issues/1409
+ //Guarantee composition targets get ready.
+ for (auto task = scene.data; task < (scene.data + scene.count); ++task) {
+ static_cast<SwTask*>(*task)->done();
}
return prepareCommon(task, transform, opacity, clips, flags);
}
-SwRenderer::SwRenderer():mpool(globalMpool)
+RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper)
{
+ //prepare task
+ auto task = static_cast<SwShapeTask*>(data);
+ if (!task) {
+ task = new SwShapeTask;
+ task->rshape = &rshape;
+ }
+ task->clipper = clipper;
+
+ return prepareCommon(task, transform, opacity, clips, flags);
}
-uint32_t SwRenderer::colorSpace()
+SwRenderer::SwRenderer():mpool(globalMpool)
{
- if (surface) return surface->cs;
- return tvg::SwCanvas::ARGB8888;
}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.h
index cab93f9e1c..36614fa1c1 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRenderer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_SW_RENDERER_H_
#define _TVG_SW_RENDERER_H_
@@ -35,8 +36,9 @@ namespace tvg
class SwRenderer : public RenderMethod
{
public:
- RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
- RenderData prepare(Surface* image, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
+ RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ RenderData prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
bool preRender() override;
bool renderShape(RenderData data) override;
bool renderImage(RenderData data) override;
@@ -45,19 +47,18 @@ public:
RenderRegion region(RenderData data) override;
RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override;
+ ColorSpace colorSpace() override;
bool clear() override;
bool sync() override;
- bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace);
+ bool target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs);
bool mempool(bool shared);
- Compositor* target(const RenderRegion& region) override;
+ Compositor* target(const RenderRegion& region, ColorSpace cs) override;
bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
bool endComposite(Compositor* cmp) override;
void clearCompositors();
- uint32_t colorSpace() override;
-
static SwRenderer* gen();
static bool init(uint32_t threads);
static int32_t init();
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp
index 63e7fc9447..50dec208b2 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -773,60 +773,59 @@ static int _genRle(RleWorker& rw)
}
-SwSpan* _intersectSpansRegion(const SwRleData *clip, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt)
+static SwSpan* _intersectSpansRegion(const SwRleData *clip, const SwRleData *target, SwSpan *outSpans, uint32_t outSpansCnt)
{
auto out = outSpans;
- auto spans = targetRle->spans;
- auto end = targetRle->spans + targetRle->size;
+ auto spans = target->spans;
+ auto end = target->spans + target->size;
auto clipSpans = clip->spans;
auto clipEnd = clip->spans + clip->size;
- while (spanCnt > 0 && spans < end) {
- if (clipSpans == clipEnd) {
- spans = end;
- break;
- }
+ while (spans < end && clipSpans < clipEnd) {
+ //align y cooridnates.
if (clipSpans->y > spans->y) {
++spans;
continue;
}
- if (spans->y != clipSpans->y) {
+ if (spans->y > clipSpans->y) {
++clipSpans;
continue;
}
- auto sx1 = spans->x;
- auto sx2 = sx1 + spans->len;
- auto cx1 = clipSpans->x;
- auto cx2 = cx1 + clipSpans->len;
- if (cx1 < sx1 && cx2 < sx1) {
- ++clipSpans;
- continue;
- }
- else if (sx1 < cx1 && sx2 < cx1) {
- ++spans;
- continue;
- }
- auto x = sx1 > cx1 ? sx1 : cx1;
- auto len = (sx2 < cx2 ? sx2 : cx2) - x;
- if (len) {
- auto spansCorverage = spans->coverage;
- auto clipSpansCoverage = clipSpans->coverage;
- out->x = sx1 > cx1 ? sx1 : cx1;
- out->len = (sx2 < cx2 ? sx2 : cx2) - out->x;
- out->y = spans->y;
- out->coverage = (uint8_t)(((spansCorverage * clipSpansCoverage) + 0xff) >> 8);
- ++out;
- --spanCnt;
+ //Try clipping with all clip spans which have a same y coordinate.
+ auto temp = clipSpans;
+ while(temp < clipEnd && outSpansCnt > 0 && temp->y == clipSpans->y) {
+ auto sx1 = spans->x;
+ auto sx2 = sx1 + spans->len;
+ auto cx1 = temp->x;
+ auto cx2 = cx1 + temp->len;
+
+ //The span must be left(x1) to right(x2) direction. Not intersected.
+ if (cx2 < sx1 || sx2 < cx1) {
+ ++temp;
+ continue;
+ }
+
+ //clip span region.
+ auto x = sx1 > cx1 ? sx1 : cx1;
+ auto len = (sx2 < cx2 ? sx2 : cx2) - x;
+ if (len > 0) {
+ out->x = x;
+ out->y = temp->y;
+ out->len = len;
+ out->coverage = (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8);
+ ++out;
+ --outSpansCnt;
+ }
+ ++temp;
}
- if (sx2 < cx2) ++spans;
- else ++clipSpans;
+ ++spans;
}
return out;
}
-SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt)
+static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSpan *outSpans, uint32_t outSpansCnt)
{
auto out = outSpans;
auto spans = targetRle->spans;
@@ -836,7 +835,7 @@ SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSp
auto maxx = minx + static_cast<int16_t>(bbox->max.x - bbox->min.x) - 1;
auto maxy = miny + static_cast<int16_t>(bbox->max.y - bbox->min.y) - 1;
- while (spanCnt && spans < end) {
+ while (outSpansCnt > 0 && spans < end) {
if (spans->y > maxy) {
spans = end;
break;
@@ -853,18 +852,58 @@ SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSp
out->x = spans->x;
out->len = spans->len < (maxx - spans->x + 1) ? spans->len : (maxx - spans->x + 1);
}
- if (out->len != 0) {
+ if (out->len > 0) {
out->y = spans->y;
out->coverage = spans->coverage;
++out;
+ --outSpansCnt;
}
++spans;
- --spanCnt;
}
return out;
}
+static SwSpan* _mergeSpansRegion(const SwRleData *clip1, const SwRleData *clip2, SwSpan *outSpans)
+{
+ auto out = outSpans;
+ auto spans1 = clip1->spans;
+ auto end1 = clip1->spans + clip1->size;
+ auto spans2 = clip2->spans;
+ auto end2 = clip2->spans + clip2->size;
+
+ //list two spans up in y order
+ //TODO: Remove duplicated regions?
+ while (spans1 < end1 && spans2 < end2) {
+ while (spans1 < end1 && spans1->y <= spans2->y) {
+ *out = *spans1;
+ ++spans1;
+ ++out;
+ }
+ if (spans1 >= end1) break;
+ while (spans2 < end2 && spans2->y <= spans1->y) {
+ *out = *spans2;
+ ++spans2;
+ ++out;
+ }
+ }
+
+ //Leftovers
+ while (spans1 < end1) {
+ *out = *spans1;
+ ++spans1;
+ ++out;
+ }
+ while (spans2 < end2) {
+ *out = *spans2;
+ ++spans2;
+ ++out;
+ }
+
+ return out;
+}
+
+
void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size)
{
free(rle->spans);
@@ -1001,6 +1040,28 @@ error:
}
+SwRleData* rleRender(const SwBBox* bbox)
+{
+ auto width = static_cast<uint16_t>(bbox->max.x - bbox->min.x);
+ auto height = static_cast<uint16_t>(bbox->max.y - bbox->min.y);
+
+ auto rle = static_cast<SwRleData*>(malloc(sizeof(SwRleData)));
+ rle->spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * height));
+ rle->size = height;
+ rle->alloc = height;
+
+ auto span = rle->spans;
+ for (uint16_t i = 0; i < height; ++i, ++span) {
+ span->x = bbox->min.x;
+ span->y = bbox->min.y + i;
+ span->len = width;
+ span->coverage = 255;
+ }
+
+ return rle;
+}
+
+
void rleReset(SwRleData* rle)
{
if (!rle) return;
@@ -1016,12 +1077,50 @@ void rleFree(SwRleData* rle)
}
+void rleMerge(SwRleData* rle, SwRleData* clip1, SwRleData* clip2)
+{
+ if (!rle || (!clip1 && !clip2)) return;
+ if (clip1 && clip1->size == 0 && clip2 && clip2->size == 0) return;
+
+ TVGLOG("SW_ENGINE", "Unifying Rle!");
+
+ //clip1 is empty, just copy clip2
+ if (!clip1 || clip1->size == 0) {
+ if (clip2) {
+ auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip2->size)));
+ memcpy(spans, clip2->spans, clip2->size);
+ _replaceClipSpan(rle, spans, clip2->size);
+ } else {
+ _replaceClipSpan(rle, nullptr, 0);
+ }
+ return;
+ }
+
+ //clip2 is empty, just copy clip1
+ if (!clip2 || clip2->size == 0) {
+ if (clip1) {
+ auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip1->size)));
+ memcpy(spans, clip1->spans, clip1->size);
+ _replaceClipSpan(rle, spans, clip1->size);
+ } else {
+ _replaceClipSpan(rle, nullptr, 0);
+ }
+ return;
+ }
+
+ auto spanCnt = clip1->size + clip2->size;
+ auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * spanCnt));
+ auto spansEnd = _mergeSpansRegion(clip1, clip2, spans);
+
+ _replaceClipSpan(rle, spans, spansEnd - spans);
+}
+
+
void rleClipPath(SwRleData *rle, const SwRleData *clip)
{
if (rle->size == 0 || clip->size == 0) return;
auto spanCnt = rle->size > clip->size ? rle->size : clip->size;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
- if (!spans) return;
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
_replaceClipSpan(rle, spans, spansEnd - spans);
@@ -1034,7 +1133,6 @@ void rleClipRect(SwRleData *rle, const SwBBox* clip)
{
if (rle->size == 0) return;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size)));
- if (!spans) return;
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
_replaceClipSpan(rle, spans, spansEnd - spans);
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwShape.cpp
index e5b540bcc3..7462a7b7ea 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwShape.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwShape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "tvgSwCommon.h"
#include "tvgBezier.h"
#include <float.h>
@@ -266,13 +267,13 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
}
-static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
+static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform)
{
- const PathCommand* cmds = nullptr;
- auto cmdCnt = sdata->pathCommands(&cmds);
+ const PathCommand* cmds = rshape->path.cmds;
+ auto cmdCnt = rshape->path.cmdCnt;
- const Point* pts = nullptr;
- auto ptsCnt = sdata->pathCoords(&pts);
+ const Point* pts = rshape->path.pts;
+ auto ptsCnt = rshape->path.ptsCnt;
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
@@ -285,7 +286,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
dash.curOpGap = false;
const float* pattern;
- dash.cnt = sdata->strokeDash(&pattern);
+ dash.cnt = rshape->strokeDash(&pattern);
if (dash.cnt == 0) return nullptr;
//OPTMIZE ME: Use mempool???
@@ -380,13 +381,13 @@ static bool _axisAlignedRect(const SwOutline* outline)
-static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
+static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
{
- const PathCommand* cmds = nullptr;
- auto cmdCnt = sdata->pathCommands(&cmds);
+ const PathCommand* cmds = rshape->path.cmds;
+ auto cmdCnt = rshape->path.cmdCnt;
- const Point* pts = nullptr;
- auto ptsCnt = sdata->pathCoords(&pts);
+ const Point* pts = rshape->path.pts;
+ auto ptsCnt = rshape->path.ptsCnt;
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
@@ -466,7 +467,7 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
_outlineEnd(*outline);
- outline->fillRule = sdata->fillRule();
+ outline->fillRule = rshape->rule;
shape->outline = outline;
shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline));
@@ -478,9 +479,9 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
/* External Class Implementation */
/************************************************************************/
-bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
+bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
{
- if (!_genOutline(shape, sdata, transform, mpool, tid, hasComposite)) return false;
+ if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false;
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
//Keep it for Rasterization Region
@@ -503,7 +504,7 @@ bool shapePrepared(const SwShape* shape)
}
-bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias)
+bool shapeGenRle(SwShape* shape, TVG_UNUSED const RenderShape* rshape, bool antiAlias)
{
//FIXME: Should we draw it?
//Case: Stroke Line
@@ -557,18 +558,18 @@ void shapeDelStroke(SwShape* shape)
}
-void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform)
+void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform)
{
if (!shape->stroke) shape->stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
auto stroke = shape->stroke;
if (!stroke) return;
- strokeReset(stroke, sdata, transform);
+ strokeReset(stroke, rshape, transform);
rleReset(shape->strokeRle);
}
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
+bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
{
SwOutline* shapeOutline = nullptr;
SwOutline* strokeOutline = nullptr;
@@ -576,14 +577,14 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo
bool ret = true;
//Dash Style Stroke
- if (sdata->strokeDash(nullptr) > 0) {
- shapeOutline = _genDashOutline(sdata, transform);
+ if (rshape->strokeDash(nullptr) > 0) {
+ shapeOutline = _genDashOutline(rshape, transform);
if (!shapeOutline) return false;
freeOutline = true;
//Normal Style stroke
} else {
if (!shape->outline) {
- if (!_genOutline(shape, sdata, transform, mpool, tid, false)) return false;
+ if (!_genOutline(shape, rshape, transform, mpool, tid, false)) return false;
}
shapeOutline = shape->outline;
}
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
index fa213cc5d3..2f41d5f021 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+/*
+ * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include <string.h>
#include <math.h>
#include "tvgSwCommon.h"
@@ -301,7 +302,7 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength)
bool intersect = false;
/* Only intersect borders if between two line_to's and both
- lines are long enough (line length is zero fur curves). */
+ lines are long enough (line length is zero for curves). */
if (border->movable && lineLength > 0) {
//compute minimum required length of lines
SwFixed minLength = abs(mathMultiply(stroke.width, mathTan(theta)));
@@ -381,9 +382,16 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
if (delta.zero()) return;
//compute length of line
- auto lineLength = mathLength(delta);
auto angle = mathAtan(delta);
+ /* The lineLength is used to determine the intersection of strokes outlines.
+ The scale needs to be reverted since the stroke width has not been scaled.
+ An alternative option is to scale the width of the stroke properly by
+ calculating the mixture of the sx/sy rating on the stroke direction. */
+ delta.x = static_cast<SwCoord>(delta.x / stroke.sx);
+ delta.y = static_cast<SwCoord>(delta.y / stroke.sy);
+ auto lineLength = mathLength(delta);
+
delta = {static_cast<SwCoord>(stroke.width), 0};
mathRotate(delta, angle + SW_ANGLE_PI2);
SCALE(stroke, delta);
@@ -825,7 +833,7 @@ void strokeFree(SwStroke* stroke)
}
-void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform)
+void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix* transform)
{
if (transform) {
stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f));
@@ -834,11 +842,11 @@ void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform)
stroke->sx = stroke->sy = 1.0f;
}
- stroke->width = HALF_STROKE(sdata->strokeWidth());
- stroke->cap = sdata->strokeCap();
+ stroke->width = HALF_STROKE(rshape->strokeWidth());
+ stroke->cap = rshape->strokeCap();
//Save line join: it can be temporarily changed when stroking curves...
- stroke->joinSaved = stroke->join = sdata->strokeJoin();
+ stroke->joinSaved = stroke->join = rshape->strokeJoin();
stroke->borders[0].ptsCnt = 0;
stroke->borders[0].start = -1;