sw_engine texmap: code clean up.

eliminate logic duplication by introducing a c++ template mechanism.

This will retain the opacity condition branches to minimize binary size.
This commit is contained in:
Hermet Park 2023-06-05 16:17:19 +09:00 committed by Hermet Park
parent 3399da198f
commit dbdf103e82
4 changed files with 555 additions and 629 deletions

View file

@ -4,7 +4,6 @@ source_file = [
'tvgSwRasterAvx.h',
'tvgSwRasterNeon.h',
'tvgSwRasterTexmap.h',
'tvgSwRasterTexmapInternal.h',
'tvgSwFill.cpp',
'tvgSwImage.cpp',
'tvgSwMath.cpp',

View file

@ -1,380 +0,0 @@
/*
* Copyright (c) 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifdef TEXMAP_INT_MASK
{
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->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t x1, x2, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
auto cbuffer = surface->compositor->image.buf32;
SwSpan* span = nullptr; //used only when rle based.
if (!_arrange(image, region, yStart, yEnd)) return;
//Clear out of the Polygon vertical ranges
auto size = surface->compositor->bbox.max.x - surface->compositor->bbox.min.x;
if (dirFlag == 1) { //left top case.
for(int y = surface->compositor->bbox.min.y; y < yStart; ++y) {
rasterRGBA32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
}
}
if (dirFlag == 4) { //right bottom case.
for(int y = yEnd; y < surface->compositor->bbox.max.y; ++y) {
rasterRGBA32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
}
}
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
for (int32_t y = yStart; y < yEnd; ++y) {
auto cmp = &cbuffer[y * surface->compositor->image.stride];
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
//FIXME: this aa must be applied before masking op
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
for (int32_t x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) {
//Range allowed
if (x >= x1 && x < x2) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
if ((uint32_t)v >= image->h) {
cmp[x] = 0;
} else {
if (opacity == 255) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
cmp[x] = ALPHA_BLEND(cmp[x], ALPHA(px));
//Step UV horizontally
u += _dudx;
v += _dvdx;
} else {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
cmp[x] = ALPHA_BLEND(cmp[x], MULTIPLY(ALPHA(px), opacity));
//Step UV horizontally
u += _dudx;
v += _dvdx;
}
}
} else {
//Clear out of polygon horizontal range
if (x < x1 && (dirFlag == 1 || dirFlag == 2)) cmp[x] = 0;
else if (x >= x2 && (dirFlag == 3 || dirFlag == 4)) cmp[x] = 0;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}
#else
{
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->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
SwSpan* span = nullptr; //used only when rle based.
if (!_arrange(image, region, yStart, yEnd)) return;
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
y = yStart;
while (y < yEnd) {
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
x = x1;
auto cmp = &surface->compositor->image.buf32[y * surface->compositor->image.stride + x1];
if (opacity == 255) {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
#ifdef TEXMAP_ADD_MASK
*cmp = px + ALPHA_BLEND(*cmp, IALPHA(px));
#elif defined(TEXMAP_SUB_MASK)
*cmp = ALPHA_BLEND(*cmp, IALPHA(px));
#elif defined(TEXMAP_DIF_MASK)
*cmp = ALPHA_BLEND(px, IALPHA(*cmp)) + ALPHA_BLEND(*cmp, IALPHA(px));
#endif
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
#ifdef TEXMAP_ADD_MASK
*cmp = INTERPOLATE(px, *cmp, opacity);
#elif defined(TEXMAP_SUB_MASK)
*cmp = ALPHA_BLEND(*cmp, IALPHA(ALPHA_BLEND(px, opacity)));
#elif defined(TEXMAP_DIF_MASK)
auto src = ALPHA_BLEND(px, opacity);
*cmp = ALPHA_BLEND(src, IALPHA(*cmp)) + ALPHA_BLEND(*cmp, IALPHA(src));
#endif
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
if (!region && spanIdx >= image->rle->size) break;
++y;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}
#endif

View file

@ -41,6 +41,7 @@ static inline void _swap(float& a, float& b, float& tmp)
b = tmp;
}
//Careful! Shared resource, No support threading
static float dudx, dvdx;
static float dxdya, dxdyb, dudya, dvdya;
@ -69,41 +70,561 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in
}
static void _rasterMaskedPolygonImageSegmentInt(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans, uint8_t dirFlag)
{
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->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t x1, x2, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
auto cbuffer = surface->compositor->image.buf32;
SwSpan* span = nullptr; //used only when rle based.
if (!_arrange(image, region, yStart, yEnd)) return;
//Clear out of the Polygon vertical ranges
auto size = surface->compositor->bbox.max.x - surface->compositor->bbox.min.x;
if (dirFlag == 1) { //left top case.
for(int y = surface->compositor->bbox.min.y; y < yStart; ++y) {
rasterRGBA32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
}
}
if (dirFlag == 4) { //right bottom case.
for(int y = yEnd; y < surface->compositor->bbox.max.y; ++y) {
rasterRGBA32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
}
}
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
for (int32_t y = yStart; y < yEnd; ++y) {
auto cmp = &cbuffer[y * surface->compositor->image.stride];
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
//FIXME: this aa must be applied before masking op
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
for (int32_t x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) {
//Range allowed
if (x >= x1 && x < x2) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
if ((uint32_t)v >= image->h) {
cmp[x] = 0;
} else {
if (opacity == 255) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
cmp[x] = ALPHA_BLEND(cmp[x], ALPHA(px));
//Step UV horizontally
u += _dudx;
v += _dvdx;
} else {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
cmp[x] = ALPHA_BLEND(cmp[x], MULTIPLY(ALPHA(px), opacity));
//Step UV horizontally
u += _dudx;
v += _dvdx;
}
}
} else {
//Clear out of polygon horizontal range
if (x < x1 && (dirFlag == 1 || dirFlag == 2)) cmp[x] = 0;
else if (x >= x2 && (dirFlag == 3 || dirFlag == 4)) cmp[x] = 0;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}
template<typename maskOp, typename amaskOp>
static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans)
{
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->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
SwSpan* span = nullptr; //used only when rle based.
if (!_arrange(image, region, yStart, yEnd)) return;
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
y = yStart;
while (y < yEnd) {
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
x = x1;
auto cmp = &surface->compositor->image.buf32[y * surface->compositor->image.stride + x1];
if (opacity == 255) {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
*cmp = maskOp()(px, *cmp, IALPHA(px));
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
*cmp = amaskOp()(px, *cmp, opacity);
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
if (!region && spanIdx >= image->rle->size) break;
++y;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}
static void _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans, uint8_t dirFlag = 0)
{
auto method = surface->compositor->method;
if (method == CompositeMethod::AddMask) {
#define TEXMAP_ADD_MASK
#include "tvgSwRasterMaskedTexmapInternal.h"
#undef TEXMAP_ADD_MASK
} else if (method == CompositeMethod::SubtractMask) {
#define TEXMAP_SUB_MASK
#include "tvgSwRasterMaskedTexmapInternal.h"
#undef TEXMAP_SUB_MASK
} else if (method == CompositeMethod::IntersectMask) {
#define TEXMAP_INT_MASK
#include "tvgSwRasterMaskedTexmapInternal.h"
#undef TEXMAP_INT_MASK
} else if (method == CompositeMethod::DifferenceMask) {
#define TEXMAP_DIF_MASK
#include "tvgSwRasterMaskedTexmapInternal.h"
#undef TEXMAP_DIF_MASK
}
if (method == CompositeMethod::AddMask) _rasterMaskedPolygonImageSegmentDup<AddMaskOp, AddMaskAOp>(surface, image, region, yStart, yEnd, opacity, aaSpans);
else if (method == CompositeMethod::SubtractMask) _rasterMaskedPolygonImageSegmentDup<SubMaskOp, SubMaskAOp>(surface, image, region, yStart, yEnd, opacity, aaSpans);
else if (method == CompositeMethod::DifferenceMask) _rasterMaskedPolygonImageSegmentDup<DifMaskOp, DifMaskAOp>(surface, image, region, yStart, yEnd, opacity, aaSpans);
else if (method == CompositeMethod::IntersectMask) _rasterMaskedPolygonImageSegmentInt(surface, image, region, yStart, yEnd, opacity, aaSpans, dirFlag);
}
static void _rasterMattedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans)
static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans, bool matting)
{
#define TEXMAP_MATTING
#include "tvgSwRasterTexmapInternal.h"
#undef TEXMAP_MATTING
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->buf32;
auto dbuf = surface->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t dw = surface->stride;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
uint32_t* buf;
SwSpan* span = nullptr; //used only when rle based.
//for matting(composition)
auto csize = matting ? surface->compositor->image.channelSize: 0;
auto alpha = matting ? surface->blender.alpha(surface->compositor->method) : nullptr;
uint8_t* cmp = nullptr;
if (!_arrange(image, region, yStart, yEnd)) return;
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
y = yStart;
static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, AASpans* aaSpans)
{
#include "tvgSwRasterTexmapInternal.h"
while (y < yEnd) {
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
buf = dbuf + ((y * dw) + x1);
x = x1;
if (matting) cmp = &surface->compositor->image.buf8[(y * surface->compositor->image.stride + x1) * csize];
if (opacity == 255) {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
uint32_t src;
if (matting) {
src = ALPHA_BLEND(px, alpha(cmp));
cmp += csize;
} else {
src = px;
}
*buf = src + ALPHA_BLEND(*buf, IALPHA(src));
++buf;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
uint32_t src;
if (matting) {
src = ALPHA_BLEND(px, MULTIPLY(opacity, alpha(cmp)));
cmp += csize;
} else {
src = ALPHA_BLEND(px, opacity);
}
*buf = src + ALPHA_BLEND(*buf, IALPHA(src));
++buf;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
if (!region && spanIdx >= image->rle->size) break;
++y;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}
@ -198,9 +719,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
xb = x[0] + dy * dxdyb + (off_y * dxdyb);
if (compositing) {
if (_matting(surface)) _rasterMattedPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, true);
else _rasterMaskedPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, 1);
} else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
} else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, false);
upper = true;
}
@ -216,9 +737,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
dxdyb = dxdy[2];
xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb);
if (compositing) {
if (_matting(surface)) _rasterMattedPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, true);
else _rasterMaskedPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, 2);
} else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
} else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, false);
}
//Longer edge is on the right side
} else {
@ -242,9 +763,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
va = v[0] + dy * dvdya + (off_y * dvdya);
if (compositing) {
if (_matting(surface)) _rasterMattedPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, true);
else _rasterMaskedPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, 3);
} else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans);
} else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, aaSpans, false);
upper = true;
}
@ -263,9 +784,9 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
va = v[1] + dy * dvdya + (off_y * dvdya);
if (compositing) {
if (_matting(surface)) _rasterMattedPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, true);
else _rasterMaskedPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, 4);
} else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans);
} else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, aaSpans, false);
}
}
}

View file

@ -1,214 +0,0 @@
/*
* 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* 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->buf32;
auto dbuf = surface->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t dw = surface->stride;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
uint32_t* buf;
SwSpan* span = nullptr; //used only when rle based.
#ifdef TEXMAP_MATTING
auto csize = surface->compositor->image.channelSize;
auto alpha = surface->blender.alpha(surface->compositor->method);
#endif
if (!_arrange(image, region, yStart, yEnd)) return;
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
y = yStart;
while (y < yEnd) {
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = INT32_MIN;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
buf = dbuf + ((y * dw) + x1);
x = x1;
#ifdef TEXMAP_MATTING
auto cmp = &surface->compositor->image.buf8[(y * surface->compositor->image.stride + x1) * csize];
#endif
if (opacity == 255) {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
#ifdef TEXMAP_MATTING
auto src = ALPHA_BLEND(px, alpha(cmp));
cmp += csize;
#else
auto src = px;
#endif
*buf = src + ALPHA_BLEND(*buf, IALPHA(src));
++buf;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
#ifdef TEXMAP_MATTING
auto src = ALPHA_BLEND(px, MULTIPLY(opacity, alpha(cmp)));
cmp += csize;
#else
auto src = ALPHA_BLEND(px, opacity);
#endif
*buf = src + ALPHA_BLEND(*buf, IALPHA(src));
++buf;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
if (!region && spanIdx >= image->rle->size) break;
++y;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
}