+static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
+{
+ TVGLOG("SW_ENGINE", "Scaled Masked Image");
+
+ //Top, Bottom Lines
+ SwCoord ys[2] = {region.min.y, region.max.y - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto y = ys[i];
+ auto dst = surface->buffer + (y * surface->stride + region.min.x);
+ auto cmp = surface->compositor->image.data + (y * surface->stride + region.min.x);
+ auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+ auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], _multiplyAlpha(opacity, blendMethod(*cmp)));
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Left, Right Lines
+ SwCoord xs[2] = {region.min.x, region.max.x - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto x = xs[i];
+ auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
+ auto cmp = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + x);
+ auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride, cmp += surface->stride) {
+ auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], _multiplyAlpha(opacity, blendMethod(*cmp)));
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Center (Down-Scaled)
+ if (image->scale < DOWN_SCALE_TOLERANCE) {
+ auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
+ auto cbuffer = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y) {
+ auto dst = dbuffer;
+ auto cmp = cbuffer;
+ auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
+ for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst, ++cmp) {
+ auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ dbuffer += surface->stride;
+ cbuffer += surface->compositor->image.stride;
+ }
+ //Center (Up-Scaled)
+ } else {
+ auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
+ auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride + region.min.x);
+ for (auto y = region.min.y; y < region.max.y - 1; ++y) {
+ auto dst = dbuffer;
+ auto cmp = cbuffer;
+ auto sy = y * itransform->e22 + itransform->e23;
+ for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst, ++cmp) {
+ auto sx = x * itransform->e11 + itransform->e13;
+ auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), _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 __rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
+{
+ //Top, Bottom Lines
+ SwCoord ys[2] = {region.min.y, region.max.y - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto y = ys[i];
+ auto dst = surface->buffer + (y * surface->stride + region.min.x);
+ auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+ auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], opacity);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Left, Right Lines
+ SwCoord xs[2] = {region.min.x, region.max.x - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto x = xs[i];
+ auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
+ auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
+ auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], opacity);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Center (Down-Scaled)
+ if (image->scale < DOWN_SCALE_TOLERANCE) {
+ auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
+ auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
+ auto dst = dbuffer;
+ for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
+ auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Center (Up-Scaled)
+ } else {
+ auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
+ for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
+ auto sy = y * itransform->e22 + itransform->e23;
+ auto dst = dbuffer;
+ for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
+ auto sx = x * itransform->e11 + itransform->e13;
+ auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ }
+ return true;
+}
+
+
+static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
+{
+ if (surface->compositor) {
+ if (surface->compositor->method == CompositeMethod::AlphaMask) {
+ return _rasterScaledMaskedRGBAImage(surface, image, opacity, region, itransform, halfScale, surface->blender.alpha);
+ } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
+ return _rasterScaledMaskedRGBAImage(surface, image, opacity, region, itransform, halfScale, surface->blender.ialpha);
+ }
+ }
+ return __rasterScaledTranslucentRGBAImage(surface, image, opacity, region, itransform, halfScale);
+}
+
+
+static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
+{
+ //Top, Bottom Lines
+ SwCoord ys[2] = {region.min.y, region.max.y - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto y = ys[i];
+ auto dst = surface->buffer + (y * surface->stride + region.min.x);
+ auto img = image->data + static_cast<uint32_t>((y * itransform->e22 + itransform->e23)) * image->stride;
+ for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+ auto src = img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)];
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Left, Right Lines
+ SwCoord xs[2] = {region.min.x, region.max.x - 1};
+
+ for (auto i = 0; i < 2; ++i) {
+ auto x = xs[i];
+ auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
+ auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
+ auto src = img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride];
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Center (Down-Scaled)
+ if (image->scale < DOWN_SCALE_TOLERANCE) {
+ auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
+ for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
+ auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
+ auto dst = dbuffer;
+ for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
+ auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+ auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ //Center (Up-Scaled)
+ } else {
+ auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
+ for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
+ auto sy = y * itransform->e22 + itransform->e23;
+ auto dst = dbuffer;
+ for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
+ auto sx = x * itransform->e11 + itransform->e13;
+ auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
+ *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
+ }
+ }
+ }
+ return true;
+}
+
+
+/************************************************************************/
+/* Whole Direct RGBA Image */
+/************************************************************************/
+
+static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))