24 #include "../global.hpp"
31 template <
unsigned int M,
unsigned int N>
inline
32 uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack)
34 static_assert(0 < M && M < N && N <= 1000);
36 auto calcColor = [](
unsigned char colFront,
unsigned char colBack) ->
unsigned char {
return (colFront * M + colBack * (N - M)) / N; };
44 template <
unsigned int M,
unsigned int N>
inline
45 uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack)
47 static_assert(0 < M && M < N && N <= 1000);
49 const unsigned int weightFront =
getAlpha(pixFront) * M;
50 const unsigned int weightBack =
getAlpha(pixBack) * (N - M);
51 const unsigned int weightSum = weightFront + weightBack;
55 auto calcColor = [=](
unsigned char colFront,
unsigned char colBack)
57 return static_cast<unsigned char>((colFront * weightFront + colBack * weightBack) / weightSum);
60 return makePixel(
static_cast<unsigned char>(weightSum / N),
80 #define FORCE_INLINE __forceinline
81 #elif defined __GNUC__
82 #define FORCE_INLINE __attribute__((always_inline)) inline
84 #define FORCE_INLINE inline
97 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
98 struct MatrixRotation;
100 template <
size_t I,
size_t J,
size_t N>
101 struct MatrixRotation<ROT_0, I, J, N>
103 static const size_t I_old = I;
104 static const size_t J_old = J;
107 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
108 struct MatrixRotation
110 static const size_t I_old = N - 1 - MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::J_old;
111 static const size_t J_old = MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::I_old;
115 template <
size_t N, RotationDegree rotDeg>
119 OutputMatrix(uint32_t* out,
int outWidth) :
121 outWidth_(outWidth) {}
123 template <
size_t I,
size_t J>
124 uint32_t& ref()
const
126 static const size_t I_old = MatrixRotation<rotDeg, I, J, N>::I_old;
127 static const size_t J_old = MatrixRotation<rotDeg, I, J, N>::J_old;
128 return *(out_ + J_old + I_old * outWidth_);
137 template <
class T>
inline
138 T square(T value) {
return value * value; }
143 double distRGB(uint32_t pix1, uint32_t pix2)
145 const double r_diff =
static_cast<int>(
getRed (pix1)) -
getRed (pix2);
147 const double b_diff =
static_cast<int>(
getBlue (pix1)) -
getBlue (pix2);
150 return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff));
156 double distYCbCr(uint32_t pix1, uint32_t pix2,
double lumaWeight)
160 const int r_diff =
static_cast<int>(
getRed (pix1)) -
getRed (pix2);
162 const int b_diff =
static_cast<int>(
getBlue (pix1)) -
getBlue (pix2);
166 const double k_b = 0.0593;
167 const double k_r = 0.2627;
168 const double k_g = 1 - k_b - k_r;
170 const double scale_b = 0.5 / (1 - k_b);
171 const double scale_r = 0.5 / (1 - k_r);
173 const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;
174 const double c_b = scale_b * (b_diff - y);
175 const double c_r = scale_r * (r_diff - y);
178 return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r));
183 double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
187 static const std::vector<float> diffToDist = []
189 std::vector<float> tmp;
191 for (uint32_t
i = 0;
i < 256 * 256 * 256; ++
i)
193 const int r_diff =
static_cast<signed char>(getByte<2>(
i)) * 2;
194 const int g_diff =
static_cast<signed char>(getByte<1>(
i)) * 2;
195 const int b_diff =
static_cast<signed char>(getByte<0>(
i)) * 2;
197 const double k_b = 0.0593;
198 const double k_r = 0.2627;
199 const double k_g = 1 - k_b - k_r;
201 const double scale_b = 0.5 / (1 - k_b);
202 const double scale_r = 0.5 / (1 - k_r);
204 const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;
205 const double c_b = scale_b * (b_diff - y);
206 const double c_r = scale_r * (r_diff - y);
208 tmp.push_back(
static_cast<float>(std::sqrt(square(y) + square(c_b) + square(c_r))));
218 const int r_diff =
static_cast<int>(
getRed (pix1)) -
getRed (pix2);
220 const int b_diff =
static_cast<int>(
getBlue (pix1)) -
getBlue (pix2);
222 const size_t index = (
static_cast<unsigned char>(r_diff / 2) << 16) |
223 (
static_cast<unsigned char>(g_diff / 2) << 8) |
224 (
static_cast<unsigned char>(b_diff / 2));
227 const size_t index = (((r_diff + 0xFF) / 2) << 16) |
228 (((g_diff + 0xFF) / 2) << 8) |
229 (( b_diff + 0xFF) / 2);
231 return diffToDist[
index];
235 #if defined _MSC_VER && !defined NDEBUG
236 const int debugPixelX = -1;
237 const int debugPixelY = 58;
239 thread_local
bool breakIntoDebugger =
false;
288 template <
class ColorDistance>
290 BlendResult preProcessCorners(
const Kernel_4x4& ker,
const xbrz::ScalerCfg& cfg)
292 #if defined _MSC_VER && !defined NDEBUG
293 if (breakIntoDebugger)
297 BlendResult result = {};
299 if ((ker.f == ker.g &&
305 auto dist = [&](uint32_t pix1, uint32_t pix2) {
return ColorDistance::dist(pix1, pix2, cfg.
luminanceWeight); };
307 double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + cfg.
centerDirectionBias * dist(ker.j, ker.g);
308 double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + cfg.
centerDirectionBias * dist(ker.f, ker.k);
313 if (ker.f != ker.g && ker.f != ker.j)
314 result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
316 if (ker.k != ker.j && ker.k != ker.g)
317 result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
322 if (ker.j != ker.f && ker.j != ker.k)
323 result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
325 if (ker.g != ker.f && ker.g != ker.k)
326 result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
332 #pragma clang diagnostic push
333 #pragma clang diagnostic ignored "-Wunused-function"
336 #define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; }
343 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_90>(const Kernel_3x3& ker) { return ker.y; }
349 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_180>(const Kernel_3x3& ker) { return ker.y; }
355 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_270>(const Kernel_3x3& ker) { return ker.y; }
362 #pragma clang diagnostic pop
367 inline BlendType getTopR (
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 2)); }
368 inline BlendType getBottomR(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 4)); }
369 inline BlendType getBottomL(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 6)); }
371 inline void clearAddTopL(
unsigned char&
b, BlendType bt) {
b =
static_cast<unsigned char>(bt); }
372 inline void addTopR (
unsigned char&
b, BlendType bt) {
b |= (bt << 2); }
373 inline void addBottomR (
unsigned char&
b, BlendType bt) {
b |= (bt << 4); }
374 inline void addBottomL (
unsigned char&
b, BlendType bt) {
b |= (bt << 6); }
376 inline bool blendingNeeded(
unsigned char b)
378 static_assert(BLEND_NONE == 0);
382 template <RotationDegree rotDeg>
inline
383 unsigned char rotateBlendInfo(
unsigned char b) {
return b; }
384 template <>
inline unsigned char rotateBlendInfo<ROT_90 >(
unsigned char b) {
return ((
b << 2) | (
b >> 6)) & 0xff; }
385 template <>
inline unsigned char rotateBlendInfo<ROT_180>(
unsigned char b) {
return ((
b << 4) | (
b >> 4)) & 0xff; }
386 template <>
inline unsigned char rotateBlendInfo<ROT_270>(
unsigned char b) {
return ((
b << 6) | (
b >> 2)) & 0xff; }
398 template <
class Scaler,
class ColorDistance, RotationDegree rotDeg>
400 void blendPixel(
const Kernel_3x3& ker,
401 uint32_t* target,
int trgWidth,
402 unsigned char blendInfo,
406 #define b get_b<rotDeg>(ker)
407 #define c get_c<rotDeg>(ker)
408 #define d get_d<rotDeg>(ker)
409 #define e get_e<rotDeg>(ker)
410 #define f get_f<rotDeg>(ker)
411 #define g get_g<rotDeg>(ker)
412 #define h get_h<rotDeg>(ker)
413 #define i get_i<rotDeg>(ker)
415 #if defined _MSC_VER && !defined NDEBUG
416 if (breakIntoDebugger)
420 const unsigned char blend = rotateBlendInfo<rotDeg>(blendInfo);
422 if (getBottomR(blend) >= BLEND_NORMAL)
425 auto dist = [&](uint32_t pix1, uint32_t pix2) {
return ColorDistance::dist(pix1, pix2, cfg.
luminanceWeight); };
427 const bool doLineBlend = [&]() ->
bool
429 if (getBottomR(blend) >= BLEND_DOMINANT)
433 if (getTopR(blend) != BLEND_NONE && !eq(
e,
g))
435 if (getBottomL(blend) != BLEND_NONE && !eq(
e,
c))
439 if (!eq(
e,
i) && eq(
g,
h) && eq(
h,
i) && eq(
i,
f) && eq(
f,
c))
445 const uint32_t px = dist(
e,
f) <= dist(
e,
h) ?
f :
h;
447 OutputMatrix<Scaler::scale, rotDeg> out(target, trgWidth);
451 const double fg = dist(
f,
g);
452 const double hc = dist(
h,
c);
460 Scaler::blendLineSteepAndShallow(px, out);
462 Scaler::blendLineShallow(px, out);
467 Scaler::blendLineSteep(px, out);
469 Scaler::blendLineDiagonal(px, out);
473 Scaler::blendCorner(px, out);
488 class OobReaderTransparent
491 OobReaderTransparent(
const uint32_t*
src,
int srcWidth,
int srcHeight,
int y) :
492 s_m1(0 <= y - 1 && y - 1 < srcHeight ?
src + srcWidth * (y - 1) : nullptr),
493 s_0 (0 <= y && y < srcHeight ?
src + srcWidth * y : nullptr),
494 s_p1(0 <= y + 1 && y + 1 < srcHeight ?
src + srcWidth * (y + 1) : nullptr),
495 s_p2(0 <= y + 2 && y + 2 < srcHeight ?
src + srcWidth * (y + 2) : nullptr),
496 srcWidth_(srcWidth) {}
498 void readDhlp(Kernel_4x4& ker,
int x)
const
500 LIKELY if (
const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
502 ker.d = s_m1 ? s_m1[x_p2] : 0;
503 ker.h = s_0 ? s_0 [x_p2] : 0;
504 ker.l = s_p1 ? s_p1[x_p2] : 0;
505 ker.p = s_p2 ? s_p2[x_p2] : 0;
517 const uint32_t*
const s_m1;
518 const uint32_t*
const s_0;
519 const uint32_t*
const s_p1;
520 const uint32_t*
const s_p2;
525 class OobReaderDuplicate
528 OobReaderDuplicate(
const uint32_t*
src,
int srcWidth,
int srcHeight,
int y) :
529 s_m1(
src + srcWidth * std::clamp(y - 1, 0, srcHeight - 1)),
530 s_0 (
src + srcWidth * std::clamp(y, 0, srcHeight - 1)),
531 s_p1(
src + srcWidth * std::clamp(y + 1, 0, srcHeight - 1)),
532 s_p2(
src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)),
533 srcWidth_(srcWidth) {}
535 void readDhlp(Kernel_4x4& ker,
int x)
const
537 const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1);
545 const uint32_t*
const s_m1;
546 const uint32_t*
const s_0;
547 const uint32_t*
const s_p1;
548 const uint32_t*
const s_p2;
553 template <
class Scaler,
class ColorDistance,
class OobReader>
554 void scaleImage(
const uint32_t*
src, uint32_t* trg,
int srcWidth,
int srcHeight,
const xbrz::ScalerCfg& cfg,
int yFirst,
int yLast)
556 yFirst = std::max(yFirst, 0);
557 yLast = std::min(yLast, srcHeight);
558 if (yFirst >= yLast || srcWidth <= 0)
565 unsigned char*
const preProcBuf =
reinterpret_cast<unsigned char*
>(trg + yLast *
Scaler::scale * trgWidth) - srcWidth;
570 const OobReader oobReader(
src, srcWidth, srcHeight, yFirst - 1);
573 Kernel_4x4 ker4 = {};
574 oobReader.readDhlp(ker4, -4);
580 oobReader.readDhlp(ker4, -3);
586 oobReader.readDhlp(ker4, -2);
592 oobReader.readDhlp(ker4, -1);
595 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
596 clearAddTopL(preProcBuf[0], res.blend_k);
599 for (
int x = 0; x < srcWidth; ++x)
616 oobReader.readDhlp(ker4, x);
624 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
625 addTopR(preProcBuf[x], res.blend_j);
627 if (x + 1 < srcWidth)
628 clearAddTopL(preProcBuf[x + 1], res.blend_k);
633 for (
int y = yFirst; y < yLast; ++y)
637 const OobReader oobReader(
src, srcWidth, srcHeight, y);
640 Kernel_4x4 ker4 = {};
641 oobReader.readDhlp(ker4, -4);
647 oobReader.readDhlp(ker4, -3);
653 oobReader.readDhlp(ker4, -2);
659 oobReader.readDhlp(ker4, -1);
661 unsigned char blend_xy1 = 0;
663 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
664 clearAddTopL(blend_xy1, res.blend_k);
666 addBottomL(preProcBuf[0], res.blend_g);
671 #if defined _MSC_VER && !defined NDEBUG
672 breakIntoDebugger = debugPixelX == x && debugPixelY == y;
689 oobReader.readDhlp(ker4, x);
692 unsigned char blend_xy = preProcBuf[x];
700 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
701 addBottomR(blend_xy, res.blend_f);
703 addTopR(blend_xy1, res.blend_j);
704 preProcBuf[x] = blend_xy1;
706 LIKELY if (x + 1 < srcWidth)
709 clearAddTopL(blend_xy1, res.blend_k);
711 addBottomL(preProcBuf[x + 1], res.blend_g);
720 if (blendingNeeded(blend_xy))
722 const auto& ker3 =
reinterpret_cast<const Kernel_3x3&
>(ker4);
723 blendPixel<Scaler, ColorDistance, ROT_0 >(ker3, out, trgWidth, blend_xy, cfg);
724 blendPixel<Scaler, ColorDistance, ROT_90 >(ker3, out, trgWidth, blend_xy, cfg);
725 blendPixel<Scaler, ColorDistance, ROT_180>(ker3, out, trgWidth, blend_xy, cfg);
726 blendPixel<Scaler, ColorDistance, ROT_270>(ker3, out, trgWidth, blend_xy, cfg);
734 template <
class ColorGradient>
735 struct Scaler2x :
public ColorGradient
737 static const int scale = 2;
739 template <
unsigned int M,
unsigned int N>
740 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
743 template <
class OutputMatrix>
744 static void blendLineShallow(uint32_t col, OutputMatrix& out)
746 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
747 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
750 template <
class OutputMatrix>
751 static void blendLineSteep(uint32_t col, OutputMatrix& out)
753 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
754 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
757 template <
class OutputMatrix>
758 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
760 alphaGrad<1, 4>(out.template ref<1, 0>(), col);
761 alphaGrad<1, 4>(out.template ref<0, 1>(), col);
762 alphaGrad<5, 6>(out.template ref<1, 1>(), col);
765 template <
class OutputMatrix>
766 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
768 alphaGrad<1, 2>(out.template ref<1, 1>(), col);
771 template <
class OutputMatrix>
772 static void blendCorner(uint32_t col, OutputMatrix& out)
775 alphaGrad<21, 100>(out.template ref<1, 1>(), col);
780 template <
class ColorGradient>
781 struct Scaler3x :
public ColorGradient
783 static const int scale = 3;
785 template <
unsigned int M,
unsigned int N>
786 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
789 template <
class OutputMatrix>
790 static void blendLineShallow(uint32_t col, OutputMatrix& out)
792 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
793 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
795 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
796 out.template ref<
scale - 1, 2>() = col;
799 template <
class OutputMatrix>
800 static void blendLineSteep(uint32_t col, OutputMatrix& out)
802 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
803 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
805 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
806 out.template ref<2,
scale - 1>() = col;
809 template <
class OutputMatrix>
810 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
812 alphaGrad<1, 4>(out.template ref<2, 0>(), col);
813 alphaGrad<1, 4>(out.template ref<0, 2>(), col);
814 alphaGrad<3, 4>(out.template ref<2, 1>(), col);
815 alphaGrad<3, 4>(out.template ref<1, 2>(), col);
816 out.template ref<2, 2>() = col;
819 template <
class OutputMatrix>
820 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
822 alphaGrad<1, 8>(out.template ref<1, 2>(), col);
823 alphaGrad<1, 8>(out.template ref<2, 1>(), col);
824 alphaGrad<7, 8>(out.template ref<2, 2>(), col);
827 template <
class OutputMatrix>
828 static void blendCorner(uint32_t col, OutputMatrix& out)
831 alphaGrad<45, 100>(out.template ref<2, 2>(), col);
838 template <
class ColorGradient>
839 struct Scaler4x :
public ColorGradient
841 static const int scale = 4;
843 template <
unsigned int M,
unsigned int N>
844 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
847 template <
class OutputMatrix>
848 static void blendLineShallow(uint32_t col, OutputMatrix& out)
850 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
851 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
853 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
854 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
856 out.template ref<
scale - 1, 2>() = col;
857 out.template ref<
scale - 1, 3>() = col;
860 template <
class OutputMatrix>
861 static void blendLineSteep(uint32_t col, OutputMatrix& out)
863 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
864 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
866 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
867 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
869 out.template ref<2,
scale - 1>() = col;
870 out.template ref<3,
scale - 1>() = col;
873 template <
class OutputMatrix>
874 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
876 alphaGrad<3, 4>(out.template ref<3, 1>(), col);
877 alphaGrad<3, 4>(out.template ref<1, 3>(), col);
878 alphaGrad<1, 4>(out.template ref<3, 0>(), col);
879 alphaGrad<1, 4>(out.template ref<0, 3>(), col);
881 alphaGrad<1, 3>(out.template ref<2, 2>(), col);
883 out.template ref<3, 3>() = col;
884 out.template ref<3, 2>() = col;
885 out.template ref<2, 3>() = col;
888 template <
class OutputMatrix>
889 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
891 alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
892 alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
893 out.template ref<
scale - 1,
scale - 1>() = col;
896 template <
class OutputMatrix>
897 static void blendCorner(uint32_t col, OutputMatrix& out)
900 alphaGrad<68, 100>(out.template ref<3, 3>(), col);
901 alphaGrad< 9, 100>(out.template ref<3, 2>(), col);
902 alphaGrad< 9, 100>(out.template ref<2, 3>(), col);
907 template <
class ColorGradient>
908 struct Scaler5x :
public ColorGradient
910 static const int scale = 5;
912 template <
unsigned int M,
unsigned int N>
913 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
916 template <
class OutputMatrix>
917 static void blendLineShallow(uint32_t col, OutputMatrix& out)
919 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
920 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
921 alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col);
923 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
924 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
926 out.template ref<
scale - 1, 2>() = col;
927 out.template ref<
scale - 1, 3>() = col;
928 out.template ref<
scale - 1, 4>() = col;
929 out.template ref<
scale - 2, 4>() = col;
932 template <
class OutputMatrix>
933 static void blendLineSteep(uint32_t col, OutputMatrix& out)
935 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
936 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
937 alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col);
939 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
940 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
942 out.template ref<2,
scale - 1>() = col;
943 out.template ref<3,
scale - 1>() = col;
944 out.template ref<4,
scale - 1>() = col;
945 out.template ref<4,
scale - 2>() = col;
948 template <
class OutputMatrix>
949 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
951 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
952 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
953 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
955 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
956 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
957 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
959 alphaGrad<2, 3>(out.template ref<3, 3>(), col);
961 out.template ref<2,
scale - 1>() = col;
962 out.template ref<3,
scale - 1>() = col;
963 out.template ref<4,
scale - 1>() = col;
965 out.template ref<
scale - 1, 2>() = col;
966 out.template ref<
scale - 1, 3>() = col;
969 template <
class OutputMatrix>
970 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
972 alphaGrad<1, 8>(out.template ref<scale - 1, scale / 2 >(), col);
973 alphaGrad<1, 8>(out.template ref<scale - 2, scale / 2 + 1>(), col);
974 alphaGrad<1, 8>(out.template ref<scale - 3, scale / 2 + 2>(), col);
976 alphaGrad<7, 8>(out.template ref<4, 3>(), col);
977 alphaGrad<7, 8>(out.template ref<3, 4>(), col);
979 out.template ref<4, 4>() = col;
982 template <
class OutputMatrix>
983 static void blendCorner(uint32_t col, OutputMatrix& out)
986 alphaGrad<86, 100>(out.template ref<4, 4>(), col);
987 alphaGrad<23, 100>(out.template ref<4, 3>(), col);
988 alphaGrad<23, 100>(out.template ref<3, 4>(), col);
995 template <
class ColorGradient>
996 struct Scaler6x :
public ColorGradient
998 static const int scale = 6;
1000 template <
unsigned int M,
unsigned int N>
1001 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
1004 template <
class OutputMatrix>
1005 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1007 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
1008 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
1009 alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col);
1011 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
1012 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
1013 alphaGrad<3, 4>(out.template ref<scale - 3, 5>(), col);
1015 out.template ref<
scale - 1, 2>() = col;
1016 out.template ref<
scale - 1, 3>() = col;
1017 out.template ref<
scale - 1, 4>() = col;
1018 out.template ref<
scale - 1, 5>() = col;
1020 out.template ref<
scale - 2, 4>() = col;
1021 out.template ref<
scale - 2, 5>() = col;
1024 template <
class OutputMatrix>
1025 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1027 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
1028 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
1029 alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col);
1031 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
1032 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
1033 alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col);
1035 out.template ref<2,
scale - 1>() = col;
1036 out.template ref<3,
scale - 1>() = col;
1037 out.template ref<4,
scale - 1>() = col;
1038 out.template ref<5,
scale - 1>() = col;
1040 out.template ref<4,
scale - 2>() = col;
1041 out.template ref<5,
scale - 2>() = col;
1044 template <
class OutputMatrix>
1045 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1047 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
1048 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
1049 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
1050 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
1052 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
1053 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
1054 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
1055 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
1057 out.template ref<2,
scale - 1>() = col;
1058 out.template ref<3,
scale - 1>() = col;
1059 out.template ref<4,
scale - 1>() = col;
1060 out.template ref<5,
scale - 1>() = col;
1062 out.template ref<4,
scale - 2>() = col;
1063 out.template ref<5,
scale - 2>() = col;
1065 out.template ref<
scale - 1, 2>() = col;
1066 out.template ref<
scale - 1, 3>() = col;
1069 template <
class OutputMatrix>
1070 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1072 alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
1073 alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1074 alphaGrad<1, 2>(out.template ref<scale - 3, scale / 2 + 2>(), col);
1076 out.template ref<
scale - 2,
scale - 1>() = col;
1077 out.template ref<
scale - 1,
scale - 1>() = col;
1078 out.template ref<
scale - 1,
scale - 2>() = col;
1081 template <
class OutputMatrix>
1082 static void blendCorner(uint32_t col, OutputMatrix& out)
1085 alphaGrad<97, 100>(out.template ref<5, 5>(), col);
1086 alphaGrad<42, 100>(out.template ref<4, 5>(), col);
1087 alphaGrad<42, 100>(out.template ref<5, 4>(), col);
1088 alphaGrad< 6, 100>(out.template ref<5, 3>(), col);
1089 alphaGrad< 6, 100>(out.template ref<3, 5>(), col);
1095 struct ColorDistanceRGB
1097 static double dist(uint32_t pix1, uint32_t pix2,
double )
1099 return distYCbCrBuffered(pix1, pix2);
1107 struct ColorDistanceARGB
1109 static double dist(uint32_t pix1, uint32_t pix2,
double )
1111 const double a1 =
getAlpha(pix1) / 255.0 ;
1112 const double a2 =
getAlpha(pix2) / 255.0 ;
1123 const double d = distYCbCrBuffered(pix1, pix2);
1125 return a1 *
d + 255 * (a2 - a1);
1127 return a2 *
d + 255 * (a1 - a2);
1134 struct ColorDistanceUnbufferedARGB
1136 static double dist(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
1138 const double a1 =
getAlpha(pix1) / 255.0 ;
1139 const double a2 =
getAlpha(pix2) / 255.0 ;
1141 const double d = distYCbCr(pix1, pix2, luminanceWeight);
1143 return a1 *
d + 255 * (a2 - a1);
1145 return a2 *
d + 255 * (a1 - a2);
1150 struct ColorGradientRGB
1152 template <
unsigned int M,
unsigned int N>
1153 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront)
1155 pixBack = gradientRGB<M, N>(pixFront, pixBack);
1159 struct ColorGradientARGB
1161 template <
unsigned int M,
unsigned int N>
1162 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront)
1164 pixBack = gradientARGB<M, N>(pixFront, pixBack);
1174 std::copy(
src + yFirst * srcWidth,
src + yLast * srcWidth, trg);
1185 return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1187 return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1189 return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1191 return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1193 return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1201 return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1203 return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1205 return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1207 return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1209 return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1217 return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1219 return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1221 return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1223 return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1225 return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1238 return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1240 return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1242 return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1250 uint32_t* trg,
int trgWidth,
int trgHeight)
1253 trg, trgWidth, trgHeight, trgWidth *
sizeof(uint32_t),
1254 0, trgHeight, [](uint32_t pix) {
return pix; });
1259 uint32_t* trg,
int trgWidth,
int trgHeight)
1262 trg, trgWidth, trgHeight, trgWidth *
sizeof(uint32_t),
1263 0, trgHeight, [](uint32_t pix) {
return pix; });
1269 void bilinearScaleCpu(
const uint32_t*
src,
int srcWidth,
int srcHeight,
1270 uint32_t* trg,
int trgWidth,
int trgHeight)
1272 const int TASK_GRANULARITY = 16;
1274 concurrency::task_group tg;
1276 for (
int i = 0;
i < trgHeight;
i += TASK_GRANULARITY)
1279 const int iLast = std::min(i + TASK_GRANULARITY, trgHeight);
1280 xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
1281 trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
1282 i, iLast, [](uint32_t pix) { return pix; });
1290 void bilinearScaleAmp(
const uint32_t*
src,
int srcWidth,
int srcHeight,
1291 uint32_t* trg,
int trgWidth,
int trgHeight)
1295 using namespace concurrency;
1298 if (srcHeight <= 0 || srcWidth <= 0)
return;
1300 const float scaleX =
static_cast<float>(trgWidth ) / srcWidth;
1301 const float scaleY =
static_cast<float>(trgHeight) / srcHeight;
1303 array_view<const uint32_t, 2> srcView(srcHeight, srcWidth,
src);
1304 array_view< uint32_t, 2> trgView(trgHeight, trgWidth, trg);
1305 trgView.discard_data();
1307 parallel_for_each(trgView.extent, [=](index<2> idx) restrict(amp)
1309 const int y = idx[0];
1310 const int x = idx[1];
1317 const int y1 = srcHeight * y / trgHeight;
1319 if (y2 == srcHeight) --y2;
1321 const float yy1 = y / scaleY - y1;
1322 const float y2y = 1 - yy1;
1324 const int x1 = srcWidth * x / trgWidth;
1326 if (x2 == srcWidth) --x2;
1328 const float xx1 = x / scaleX - x1;
1329 const float x2x = 1 - xx1;
1331 const float x2xy2y = x2x * y2y;
1332 const float xx1y2y = xx1 * y2y;
1333 const float x2xyy1 = x2x * yy1;
1334 const float xx1yy1 = xx1 * yy1;
1336 auto interpolate = [=](
int offset)
1343 const auto c11 = (srcView(y1, x1) >> (8 * offset)) & 0xff;
1344 const auto c21 = (srcView(y1, x2) >> (8 * offset)) & 0xff;
1345 const auto c12 = (srcView(y2, x1) >> (8 * offset)) & 0xff;
1346 const auto c22 = (srcView(y2, x2) >> (8 * offset)) & 0xff;
1348 return c11 * x2xy2y + c21 * xx1y2y +
1349 c12 * x2xyy1 + c22 * xx1yy1;
1352 const float bi = interpolate(0);
1353 const float gi = interpolate(1);
1354 const float ri = interpolate(2);
1355 const float ai = interpolate(3);
1357 const auto b =
static_cast<uint32_t
>(bi + 0.5f);
1358 const auto g =
static_cast<uint32_t
>(gi + 0.5f);
1359 const auto r =
static_cast<uint32_t
>(ri + 0.5f);
1360 const auto a =
static_cast<uint32_t
>(
ai + 0.5f);
1362 trgView(y, x) = (a << 24) | (r << 16) | (
g << 8) |
b;
1364 trgView.synchronize();
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
unsigned char getRed(uint32_t pix)
uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b)
unsigned char getBlue(uint32_t pix)
unsigned char getGreen(uint32_t pix)
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, ColorFormat colFmt, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance)
void nearestNeighborScale(const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight)
const int SCALE_FACTOR_MAX
void fillBlock(Pix *trg, int pitch, Pix col, int blockWidth, int blockHeight)
unsigned char getAlpha(uint32_t pix)
void bilinearScale(const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight)
rect src
Non-transparent portion of the surface to compose.
double centerDirectionBias
double steepDirectionThreshold
double dominantDirectionThreshold
double equalColorTolerance
static map_location::direction n