#include "tvgMath.h"
#include "tvgRender.h"
#include "tvgSwCommon.h"
-#include "tvgSwRasterC.h"
-#include "tvgSwRasterAvx.h"
-#include "tvgSwRasterNeon.h"
/************************************************************************/
/* Internal Class Implementation */
}
+static inline uint32_t _interpolate(uint32_t a, uint32_t c0, uint32_t c1)
+{
+ return (((((((c0 >> 8) & 0xff00ff) - ((c1 >> 8) & 0xff00ff)) * a) + (c1 & 0xff00ff00)) & 0xff00ff00) + ((((((c0 & 0xff00ff) - (c1 & 0xff00ff)) * a) >> 8) + (c1 & 0xff00ff)) & 0xff00ff));
+}
+
+
+#include "tvgSwRasterTexmap.h"
+#include "tvgSwRasterC.h"
+#include "tvgSwRasterAvx.h"
+#include "tvgSwRasterNeon.h"
+
+
static inline bool _compositing(const SwSurface* surface)
{
if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
return halfScale;
}
-
//Bilinear Interpolation
static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
{
/* Transformed RGBA Image */
/************************************************************************/
-static bool _rasterTransformedMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Transformed Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterTransformedMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Transformed Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp));
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterTransformedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
-
- auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- }
- return true;
-}
-
-
-static bool _rasterDownScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Down Scaled Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) {
- src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
- } else {
- src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
- }
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterDownScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Down Scaled Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) {
- src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp));
- } else {
- src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), blendMethod(*cmp));
- }
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterDownScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity);
- else src = ALPHA_BLEND(_interpDownScaler(img, w, h, rX, rY, halfScale), opacity);
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- }
- return true;
-}
-
-
-static bool _rasterUpScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Up Scaled Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto fX = x * itransform->e11 + ey1;
- auto fY = x * itransform->e21 + ey2;
- auto rX = static_cast<uint32_t>(roundf(fX));
- auto rY = static_cast<uint32_t>(roundf(fY));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
- else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), _multiplyAlpha(opacity, blendMethod(*cmp)));
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterUpScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
-{
- TVGLOG("SW_ENGINE", "Up Scaled Masked Image");
-
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- 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];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto cmp = cbuffer;
- float ey1 = y * itransform->e12 + itransform->e13;
- float ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
- auto fX = x * itransform->e11 + ey1;
- auto fY = x * itransform->e21 + ey2;
- auto rX = static_cast<uint32_t>(roundf(fX));
- auto rY = static_cast<uint32_t>(roundf(fY));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp));
- else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), blendMethod(*cmp));
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- cbuffer += surface->compositor->image.stride;
- }
- return true;
-}
-
-
-static bool _rasterUpScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
- auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = dbuffer;
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto fX = x * itransform->e11 + ey1;
- auto fY = x * itransform->e21 + ey2;
- auto rX = static_cast<uint32_t>(roundf(fX));
- auto rY = static_cast<uint32_t>(roundf(fY));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
- else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), opacity);
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- dbuffer += surface->stride;
- }
- return true;
-}
-
-
-static bool _rasterTransformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = &surface->buffer[y * surface->stride + region.min.x];
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- auto src = img[rX + (rY * image->stride)];
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- }
- return true;
-}
-
-
-static bool _rasterDownScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = &surface->buffer[y * surface->stride + region.min.x];
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
- auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)];
- else src = _interpDownScaler(img, w, h, rX, rY, halfScale);
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- }
- return true;
-}
-
-
-static bool _rasterUpScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region)
-{
- auto img = image->data;
- auto w = image->w;
- auto h = image->h;
-
- for (auto y = region.min.y; y < region.max.y; ++y) {
- auto dst = &surface->buffer[y * surface->stride + region.min.x];
- auto ey1 = y * itransform->e12 + itransform->e13;
- auto ey2 = y * itransform->e22 + itransform->e23;
- for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
- auto fX = x * itransform->e11 + ey1;
- auto fY = x * itransform->e21 + ey2;
- auto rX = static_cast<uint32_t>(roundf(fX));
- auto rY = static_cast<uint32_t>(roundf(fY));
- if (rX >= w || rY >= h) continue;
- uint32_t src;
- if (rX == w - 1 || rY == h - 1) src = img[rX + (rY * w)];
- else src = _interpUpScaler(img, w, h, fX, fY);
- *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
- }
- }
- return true;
-}
-
-
static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
{
- Matrix itransform;
- if (transform && !mathInverse(transform, &itransform)) return false;
-
- auto halfScale = _halfScale(image->scale);
-
if (_compositing(surface)) {
- if (opacity == 255) {
- //Transformd
- if (mathEqual(image->scale, 1.0f)) {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, surface->blender.ialpha);
- }
- //Transformed + DownScaled
- } else if (image->scale < DOWN_SCALE_TOLERANCE) {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.ialpha);
- }
- //Transformed + UpScaled
- } else {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, surface->blender.ialpha);
- }
- }
- } else {
- //Transformd
- if (mathEqual(image->scale, 1.0f)) {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterTransformedMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterTransformedMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha);
- }
- //Transformed + DownScaled
- } else if (image->scale < DOWN_SCALE_TOLERANCE) {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterDownScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterDownScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
- }
- //Transformed + UpScaled
- } else {
- if (surface->compositor->method == CompositeMethod::AlphaMask) {
- return _rasterUpScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha);
- } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
- return _rasterUpScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha);
- }
- }
+ if (surface->compositor->method == CompositeMethod::AlphaMask) {
+ return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.alpha);
+ } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
+ return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.ialpha);
}
} else {
- if (opacity == 255) {
- if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRGBAImage(surface, image, &itransform, region);
- else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRGBAImage(surface, image, &itransform, region, halfScale);
- else return _rasterUpScaledRGBAImage(surface, image, &itransform, region);
- } else {
- if (mathEqual(image->scale, 1.0f)) return _rasterTransformedTranslucentRGBAImage(surface, image, &itransform, region, opacity);
- else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
- else return _rasterUpScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity);
- }
+ return _rasterTexmapPolygon(surface, image, transform, region, opacity, nullptr);
}
return false;
}
} else {
if (image->direct) return _directRGBAImage(surface, image, region, opacity);
else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity);
- //OPTIMIZE_ME: Replace with the TexMap Rasterizer
else return _transformedRGBAImage(surface, image, transform, region, opacity);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. 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.
+ */
+
+struct Vertex
+{
+ Point pt;
+ Point uv;
+};
+
+struct Polygon
+{
+ Vertex vertex[3];
+};
+
+static inline void _swap(float& a, float& b, float& tmp)
+{
+ tmp = a;
+ a = b;
+ b = tmp;
+}
+
+//Careful! Shared resource, No support threading
+static float dudx, dvdx;
+static float dxdya, dxdyb, dudya, dvdya;
+static float xa, xb, ua, va;
+
+static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
+{
+#define RASTER_COMMON() \
+ uu = (int) u; \
+ vv = (int) v; \
+ /* FIXME: sometimes u and v are < 0 - don'tc crash */ \
+ if (uu < 0) uu = 0;\
+ if (vv < 0) vv = 0; \
+ \
+ /* Range exception handling */ \
+ /* OPTIMIZE ME, handle in advance? */ \
+ if (uu >= sw) uu = sw - 1; \
+ if (vv >= sh) vv = sh - 1; \
+ \
+ ar = (int)(255 * (1 - modff(u, &iptr))); \
+ ab = (int)(255 * (1 - modff(v, &iptr))); \
+ iru = uu + 1; \
+ irv = vv + 1; \
+ px = *(sbuf + (vv * sw) + uu); \
+ \
+ /* horizontal interpolate */ \
+ if (iru < sw) { \
+ /* right pixel */ \
+ int px2 = *(sbuf + (vv * sw) + iru); \
+ px = _interpolate(ar, px, px2); \
+ } \
+ /* 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(ar, px2, px3); \
+ } \
+ px = _interpolate(ab, px, px2); \
+ }
+
+ 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;
+ int sw = static_cast<int>(image->stride);
+ int sh = image->h;
+ int dw = surface->stride;
+ int x1, x2, x, y, ar, ab, iru, irv, px;
+ int vv = 0;
+ int uu = 0;
+ float dx, u, v, iptr;
+ uint32_t* buf;
+
+ //Range exception handling
+ if (ystart >= region.max.y) return;
+ if (ystart < region.min.y) ystart = region.min.y;
+ if (yend > region.max.y) yend = region.max.y;
+
+ //Loop through all lines in the segment
+ y = ystart;
+
+ while (y < yend) {
+ x1 = _xa;
+ x2 = _xb;
+
+ //Range exception handling
+ if (x1 < region.min.x) x1 = region.min.x;
+ if (x2 > region.max.x) x2 = region.max.x;
+
+ if ((x2 - x1) < 1) goto next;
+ if ((x1 >= region.max.x) || (x2 <= region.min.x)) goto next;
+
+ //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 (blendMethod) {
+ TVGLOG("SW_ENGINE", "Transformed Masked Image");
+ auto cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1];
+ if (opacity == 255) {
+ //Draw horizontal line
+ while (x++ < x2) {
+ RASTER_COMMON();
+ auto src = ALPHA_BLEND(px, blendMethod(*cmp));
+ *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src));
+ ++cmp;
+ ++buf;
+ //Step UV horizontally
+ u += _dudx;
+ v += _dvdx;
+ }
+ } else {
+ //Draw horizontal line
+ while (x++ < x2) {
+ RASTER_COMMON();
+ auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp)));
+ *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src));
+ ++buf;
+ ++cmp;
+ //Step UV horizontally
+ u += _dudx;
+ v += _dvdx;
+ }
+ }
+ } else {
+ if (opacity == 255) {
+ //Draw horizontal line
+ while (x++ < x2) {
+ RASTER_COMMON();
+ *buf = px + ALPHA_BLEND(*buf, surface->blender.ialpha(px));
+ ++buf;
+ //Step UV horizontally
+ u += _dudx;
+ v += _dvdx;
+ }
+ } else {
+ //Draw horizontal line
+ while (x++ < x2) {
+ RASTER_COMMON();
+ auto src = ALPHA_BLEND(px, opacity);
+ *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src));
+ ++buf;
+ //Step UV horizontally
+ u += _dudx;
+ v += _dvdx;
+ }
+ }
+ }
+next:
+ //Step along both edges
+ _xa += _dxdya;
+ _xb += _dxdyb;
+ _ua += _dudya;
+ _va += _dvdya;
+
+ y++;
+ }
+ xa = _xa;
+ xb = _xb;
+ ua = _ua;
+ va = _va;
+}
+
+
+/* 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))
+{
+ 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};
+ float u[3] = {polygon.vertex[0].uv.x, polygon.vertex[1].uv.x, polygon.vertex[2].uv.x};
+ float v[3] = {polygon.vertex[0].uv.y, polygon.vertex[1].uv.y, polygon.vertex[2].uv.y};
+
+ float off_y;
+ float dxdy[3] = {0.0f, 0.0f, 0.0f};
+ float tmp;
+
+ auto upper = false;
+
+ //Sort the vertices in ascending Y order
+ if (y[0] > y[1]) {
+ _swap(x[0], x[1], tmp);
+ _swap(y[0], y[1], tmp);
+ _swap(u[0], u[1], tmp);
+ _swap(v[0], v[1], tmp);
+ }
+ if (y[0] > y[2]) {
+ _swap(x[0], x[2], tmp);
+ _swap(y[0], y[2], tmp);
+ _swap(u[0], u[2], tmp);
+ _swap(v[0], v[2], tmp);
+ }
+ if (y[1] > y[2]) {
+ _swap(x[1], x[2], tmp);
+ _swap(y[1], y[2], tmp);
+ _swap(u[1], u[2], tmp);
+ _swap(v[1], v[2], tmp);
+ }
+
+ //Y indexes
+ int yi[3] = {(int)y[0], (int)y[1], (int)y[2]};
+
+ //Skip drawing if it's too thin to cover any pixels at all.
+ if ((yi[0] == yi[1] && yi[0] == yi[2]) || ((int) x[0] == (int) x[1] && (int) x[0] == (int) x[2])) return;
+
+ //Calculate horizontal and vertical increments for UV axes (these calcs are certainly not optimal, although they're stable (handles any dy being 0)
+ auto denom = ((x[2] - x[0]) * (y[1] - y[0]) - (x[1] - x[0]) * (y[2] - y[0]));
+
+ //Skip poly if it's an infinitely thin line
+ if (mathZero(denom)) return;
+
+ denom = 1 / denom; //Reciprocal for speeding up
+ dudx = ((u[2] - u[0]) * (y[1] - y[0]) - (u[1] - u[0]) * (y[2] - y[0])) * denom;
+ dvdx = ((v[2] - v[0]) * (y[1] - y[0]) - (v[1] - v[0]) * (y[2] - y[0])) * denom;
+ auto dudy = ((u[1] - u[0]) * (x[2] - x[0]) - (u[2] - u[0]) * (x[1] - x[0])) * denom;
+ auto dvdy = ((v[1] - v[0]) * (x[2] - x[0]) - (v[2] - v[0]) * (x[1] - x[0])) * denom;
+
+ //Calculate X-slopes along the edges
+ if (y[1] > y[0]) dxdy[0] = (x[1] - x[0]) / (y[1] - y[0]);
+ if (y[2] > y[0]) dxdy[1] = (x[2] - x[0]) / (y[2] - y[0]);
+ if (y[2] > y[1]) dxdy[2] = (x[2] - x[1]) / (y[2] - y[1]);
+
+ //Determine which side of the polygon the longer edge is on
+ auto side = (dxdy[1] > dxdy[0]) ? true : false;
+
+ if (mathEqual(y[0], y[1])) side = x[0] > x[1];
+ if (mathEqual(y[1], y[2])) side = x[2] > x[1];
+
+ //Longer edge is on the left side
+ if (!side) {
+ //Calculate slopes along left edge
+ dxdya = dxdy[1];
+ dudya = dxdya * dudx + dudy;
+ dvdya = dxdya * dvdx + dvdy;
+
+ //Perform subpixel pre-stepping along left edge
+ auto dy = 1.0f - (y[0] - yi[0]);
+ xa = x[0] + dy * dxdya;
+ ua = u[0] + dy * dudya;
+ va = v[0] + dy * dvdya;
+
+ //Draw upper segment if possibly visible
+ if (yi[0] < yi[1]) {
+ off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0;
+ xa += (off_y * dxdya);
+ ua += (off_y * dudya);
+ va += (off_y * dvdya);
+
+ // Set right edge X-slope and perform subpixel pre-stepping
+ dxdyb = dxdy[0];
+ xb = x[0] + dy * dxdyb + (off_y * dxdyb);
+ _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod);
+ upper = true;
+ }
+ //Draw lower segment if possibly visible
+ if (yi[1] < yi[2]) {
+ off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0;
+ if (!upper) {
+ xa += (off_y * dxdya);
+ ua += (off_y * dudya);
+ va += (off_y * dvdya);
+ }
+ // 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);
+ _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod);
+ }
+ //Longer edge is on the right side
+ } else {
+ //Set right edge X-slope and perform subpixel pre-stepping
+ dxdyb = dxdy[1];
+ auto dy = 1.0f - (y[0] - yi[0]);
+ xb = x[0] + dy * dxdyb;
+
+ //Draw upper segment if possibly visible
+ if (yi[0] < yi[1]) {
+ off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0;
+ xb += (off_y *dxdyb);
+
+ // Set slopes along left edge and perform subpixel pre-stepping
+ dxdya = dxdy[0];
+ dudya = dxdya * dudx + dudy;
+ dvdya = dxdya * dvdx + dvdy;
+
+ xa = x[0] + dy * dxdya + (off_y * dxdya);
+ ua = u[0] + dy * dudya + (off_y * dudya);
+ va = v[0] + dy * dvdya + (off_y * dvdya);
+
+ _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod);
+
+ upper = true;
+ }
+ //Draw lower segment if possibly visible
+ if (yi[1] < yi[2]) {
+ off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0;
+ if (!upper) xb += (off_y *dxdyb);
+
+ // Set slopes along left edge and perform subpixel pre-stepping
+ dxdya = dxdy[2];
+ dudya = dxdya * dudx + dudy;
+ dvdya = dxdya * dvdx + dvdy;
+ dy = 1 - (y[1] - yi[1]);
+ xa = x[1] + dy * dxdya + (off_y * dxdya);
+ ua = u[1] + dy * dudya + (off_y * dudya);
+ va = v[1] + dy * dvdya + (off_y * dvdya);
+
+ _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod);
+ }
+ }
+}
+
+
+/*
+ 2 triangles constructs 1 mesh.
+ below figure illustrates vert[4] index info.
+ If you need better quality, please divide a mesh by more number of triangles.
+
+ 0 -- 1
+ | / |
+ | / |
+ 3 -- 2
+*/
+static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
+{
+ /* Prepare vertices.
+ shift XY coordinates to match the sub-pixeling technique. */
+ Vertex vertices[4];
+ vertices[0] = {{0.0f, 0.0f}, 0.0f, 0.0f};
+ vertices[1] = {{float(image->w), 0.0f}, float(image->w), 0.0f};
+ 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);
+
+ Polygon polygon;
+
+ //Draw the first polygon
+ polygon.vertex[0] = vertices[0];
+ polygon.vertex[1] = vertices[1];
+ polygon.vertex[2] = vertices[3];
+
+ _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod);
+
+ //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);
+
+ return true;
+}
\ No newline at end of file