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_4x4& ker) { return ker.x; }
343 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_0>(const Kernel_4x4& ker) { return ker.y; }
349 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_90>(const Kernel_4x4& ker) { return ker.y; }
355 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_180>(const Kernel_4x4& ker) { return ker.y; }
361 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_270>(const Kernel_4x4& ker) { return ker.y; }
368 #pragma clang diagnostic pop
373 inline BlendType getTopR (
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 2)); }
374 inline BlendType getBottomR(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 4)); }
375 inline BlendType getBottomL(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 6)); }
377 inline void clearAddTopL(
unsigned char&
b, BlendType bt) {
b =
static_cast<unsigned char>(bt); }
378 inline void addTopR (
unsigned char&
b, BlendType bt) {
b |= (bt << 2); }
379 inline void addBottomR (
unsigned char&
b, BlendType bt) {
b |= (bt << 4); }
380 inline void addBottomL (
unsigned char&
b, BlendType bt) {
b |= (bt << 6); }
382 inline bool blendingNeeded(
unsigned char b)
384 static_assert(BLEND_NONE == 0);
388 template <RotationDegree rotDeg>
inline
389 unsigned char rotateBlendInfo(
unsigned char b) {
return b; }
390 template <>
inline unsigned char rotateBlendInfo<ROT_90 >(
unsigned char b) {
return ((
b << 2) | (
b >> 6)) & 0xff; }
391 template <>
inline unsigned char rotateBlendInfo<ROT_180>(
unsigned char b) {
return ((
b << 4) | (
b >> 4)) & 0xff; }
392 template <>
inline unsigned char rotateBlendInfo<ROT_270>(
unsigned char b) {
return ((
b << 6) | (
b >> 2)) & 0xff; }
404 template <
class Scaler,
class ColorDistance, RotationDegree rotDeg>
406 void blendPixel(
const Kernel_4x4& ker,
407 uint32_t* target,
int trgWidth,
408 unsigned char blendInfo,
412 #define b get_b<rotDeg>(ker)
413 #define c get_c<rotDeg>(ker)
414 #define d get_d<rotDeg>(ker)
415 #define e get_e<rotDeg>(ker)
416 #define f get_f<rotDeg>(ker)
417 #define g get_g<rotDeg>(ker)
418 #define h get_h<rotDeg>(ker)
419 #define i get_i<rotDeg>(ker)
421 #if defined _MSC_VER && !defined NDEBUG
422 if (breakIntoDebugger)
426 const unsigned char blend = rotateBlendInfo<rotDeg>(blendInfo);
428 if (getBottomR(blend) >= BLEND_NORMAL)
431 auto dist = [&](uint32_t pix1, uint32_t pix2) {
return ColorDistance::dist(pix1, pix2, cfg.
luminanceWeight); };
433 const bool doLineBlend = [&]() ->
bool
435 if (getBottomR(blend) >= BLEND_DOMINANT)
439 if (getTopR(blend) != BLEND_NONE && !eq(
e,
g))
441 if (getBottomL(blend) != BLEND_NONE && !eq(
e,
c))
445 if (!eq(
e,
i) && eq(
g,
h) && eq(
h,
i) && eq(
i,
f) && eq(
f,
c))
451 const uint32_t px = dist(
e,
f) <= dist(
e,
h) ?
f :
h;
453 OutputMatrix<Scaler::scale, rotDeg> out(target, trgWidth);
457 const double fg = dist(
f,
g);
458 const double hc = dist(
h,
c);
466 Scaler::blendLineSteepAndShallow(px, out);
468 Scaler::blendLineShallow(px, out);
473 Scaler::blendLineSteep(px, out);
475 Scaler::blendLineDiagonal(px, out);
479 Scaler::blendCorner(px, out);
494 class OobReaderTransparent
497 OobReaderTransparent(
const uint32_t*
src,
int srcWidth,
int srcHeight,
int y) :
498 s_m1(0 <= y - 1 && y - 1 < srcHeight ?
src + srcWidth * (y - 1) : nullptr),
499 s_0 (0 <= y && y < srcHeight ?
src + srcWidth * y : nullptr),
500 s_p1(0 <= y + 1 && y + 1 < srcHeight ?
src + srcWidth * (y + 1) : nullptr),
501 s_p2(0 <= y + 2 && y + 2 < srcHeight ?
src + srcWidth * (y + 2) : nullptr),
502 srcWidth_(srcWidth) {}
504 void readDhlp(Kernel_4x4& ker,
int x)
const
506 LIKELY if (
const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
508 ker.d = s_m1 ? s_m1[x_p2] : 0;
509 ker.h = s_0 ? s_0 [x_p2] : 0;
510 ker.l = s_p1 ? s_p1[x_p2] : 0;
511 ker.p = s_p2 ? s_p2[x_p2] : 0;
523 const uint32_t*
const s_m1;
524 const uint32_t*
const s_0;
525 const uint32_t*
const s_p1;
526 const uint32_t*
const s_p2;
531 class OobReaderDuplicate
534 OobReaderDuplicate(
const uint32_t*
src,
int srcWidth,
int srcHeight,
int y) :
535 s_m1(
src + srcWidth * std::clamp(y - 1, 0, srcHeight - 1)),
536 s_0 (
src + srcWidth * std::clamp(y, 0, srcHeight - 1)),
537 s_p1(
src + srcWidth * std::clamp(y + 1, 0, srcHeight - 1)),
538 s_p2(
src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)),
539 srcWidth_(srcWidth) {}
541 void readDhlp(Kernel_4x4& ker,
int x)
const
543 const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1);
551 const uint32_t*
const s_m1;
552 const uint32_t*
const s_0;
553 const uint32_t*
const s_p1;
554 const uint32_t*
const s_p2;
559 template <
class Scaler,
class ColorDistance,
class OobReader>
560 void scaleImage(
const uint32_t*
src, uint32_t* trg,
int srcWidth,
int srcHeight,
const xbrz::ScalerCfg& cfg,
int yFirst,
int yLast)
562 yFirst = std::max(yFirst, 0);
563 yLast = std::min(yLast, srcHeight);
564 if (yFirst >= yLast || srcWidth <= 0)
571 unsigned char*
const preProcBuf =
reinterpret_cast<unsigned char*
>(trg + yLast *
Scaler::scale * trgWidth) - srcWidth;
576 const OobReader oobReader(
src, srcWidth, srcHeight, yFirst - 1);
579 Kernel_4x4 ker4 = {};
580 oobReader.readDhlp(ker4, -4);
586 oobReader.readDhlp(ker4, -3);
592 oobReader.readDhlp(ker4, -2);
598 oobReader.readDhlp(ker4, -1);
601 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
602 clearAddTopL(preProcBuf[0], res.blend_k);
605 for (
int x = 0; x < srcWidth; ++x)
622 oobReader.readDhlp(ker4, x);
630 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
631 addTopR(preProcBuf[x], res.blend_j);
633 if (x + 1 < srcWidth)
634 clearAddTopL(preProcBuf[x + 1], res.blend_k);
639 for (
int y = yFirst; y < yLast; ++y)
643 const OobReader oobReader(
src, srcWidth, srcHeight, y);
646 Kernel_4x4 ker4 = {};
647 oobReader.readDhlp(ker4, -4);
653 oobReader.readDhlp(ker4, -3);
659 oobReader.readDhlp(ker4, -2);
665 oobReader.readDhlp(ker4, -1);
667 unsigned char blend_xy1 = 0;
669 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
670 clearAddTopL(blend_xy1, res.blend_k);
672 addBottomL(preProcBuf[0], res.blend_g);
677 #if defined _MSC_VER && !defined NDEBUG
678 breakIntoDebugger = debugPixelX == x && debugPixelY == y;
695 oobReader.readDhlp(ker4, x);
698 unsigned char blend_xy = preProcBuf[x];
706 const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
707 addBottomR(blend_xy, res.blend_f);
709 addTopR(blend_xy1, res.blend_j);
710 preProcBuf[x] = blend_xy1;
712 LIKELY if (x + 1 < srcWidth)
715 clearAddTopL(blend_xy1, res.blend_k);
717 addBottomL(preProcBuf[x + 1], res.blend_g);
726 if (blendingNeeded(blend_xy))
728 blendPixel<Scaler, ColorDistance, ROT_0 >(ker4, out, trgWidth, blend_xy, cfg);
729 blendPixel<Scaler, ColorDistance, ROT_90 >(ker4, out, trgWidth, blend_xy, cfg);
730 blendPixel<Scaler, ColorDistance, ROT_180>(ker4, out, trgWidth, blend_xy, cfg);
731 blendPixel<Scaler, ColorDistance, ROT_270>(ker4, out, trgWidth, blend_xy, cfg);
739 template <
class ColorGradient>
740 struct Scaler2x :
public ColorGradient
742 static const int scale = 2;
744 template <
unsigned int M,
unsigned int N>
745 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
748 template <
class OutputMatrix>
749 static void blendLineShallow(uint32_t col, OutputMatrix& out)
751 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
752 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
755 template <
class OutputMatrix>
756 static void blendLineSteep(uint32_t col, OutputMatrix& out)
758 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
759 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
762 template <
class OutputMatrix>
763 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
765 alphaGrad<1, 4>(out.template ref<1, 0>(), col);
766 alphaGrad<1, 4>(out.template ref<0, 1>(), col);
767 alphaGrad<5, 6>(out.template ref<1, 1>(), col);
770 template <
class OutputMatrix>
771 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
773 alphaGrad<1, 2>(out.template ref<1, 1>(), col);
776 template <
class OutputMatrix>
777 static void blendCorner(uint32_t col, OutputMatrix& out)
780 alphaGrad<21, 100>(out.template ref<1, 1>(), col);
785 template <
class ColorGradient>
786 struct Scaler3x :
public ColorGradient
788 static const int scale = 3;
790 template <
unsigned int M,
unsigned int N>
791 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
794 template <
class OutputMatrix>
795 static void blendLineShallow(uint32_t col, OutputMatrix& out)
797 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
798 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
800 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
801 out.template ref<
scale - 1, 2>() = col;
804 template <
class OutputMatrix>
805 static void blendLineSteep(uint32_t col, OutputMatrix& out)
807 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
808 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
810 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
811 out.template ref<2,
scale - 1>() = col;
814 template <
class OutputMatrix>
815 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
817 alphaGrad<1, 4>(out.template ref<2, 0>(), col);
818 alphaGrad<1, 4>(out.template ref<0, 2>(), col);
819 alphaGrad<3, 4>(out.template ref<2, 1>(), col);
820 alphaGrad<3, 4>(out.template ref<1, 2>(), col);
821 out.template ref<2, 2>() = col;
824 template <
class OutputMatrix>
825 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
827 alphaGrad<1, 8>(out.template ref<1, 2>(), col);
828 alphaGrad<1, 8>(out.template ref<2, 1>(), col);
829 alphaGrad<7, 8>(out.template ref<2, 2>(), col);
832 template <
class OutputMatrix>
833 static void blendCorner(uint32_t col, OutputMatrix& out)
836 alphaGrad<45, 100>(out.template ref<2, 2>(), col);
843 template <
class ColorGradient>
844 struct Scaler4x :
public ColorGradient
846 static const int scale = 4;
848 template <
unsigned int M,
unsigned int N>
849 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
852 template <
class OutputMatrix>
853 static void blendLineShallow(uint32_t col, OutputMatrix& out)
855 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
856 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
858 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
859 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
861 out.template ref<
scale - 1, 2>() = col;
862 out.template ref<
scale - 1, 3>() = col;
865 template <
class OutputMatrix>
866 static void blendLineSteep(uint32_t col, OutputMatrix& out)
868 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
869 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
871 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
872 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
874 out.template ref<2,
scale - 1>() = col;
875 out.template ref<3,
scale - 1>() = col;
878 template <
class OutputMatrix>
879 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
881 alphaGrad<3, 4>(out.template ref<3, 1>(), col);
882 alphaGrad<3, 4>(out.template ref<1, 3>(), col);
883 alphaGrad<1, 4>(out.template ref<3, 0>(), col);
884 alphaGrad<1, 4>(out.template ref<0, 3>(), col);
886 alphaGrad<1, 3>(out.template ref<2, 2>(), col);
888 out.template ref<3, 3>() = col;
889 out.template ref<3, 2>() = col;
890 out.template ref<2, 3>() = col;
893 template <
class OutputMatrix>
894 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
896 alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
897 alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
898 out.template ref<
scale - 1,
scale - 1>() = col;
901 template <
class OutputMatrix>
902 static void blendCorner(uint32_t col, OutputMatrix& out)
905 alphaGrad<68, 100>(out.template ref<3, 3>(), col);
906 alphaGrad< 9, 100>(out.template ref<3, 2>(), col);
907 alphaGrad< 9, 100>(out.template ref<2, 3>(), col);
912 template <
class ColorGradient>
913 struct Scaler5x :
public ColorGradient
915 static const int scale = 5;
917 template <
unsigned int M,
unsigned int N>
918 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
921 template <
class OutputMatrix>
922 static void blendLineShallow(uint32_t col, OutputMatrix& out)
924 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
925 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
926 alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col);
928 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
929 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
931 out.template ref<
scale - 1, 2>() = col;
932 out.template ref<
scale - 1, 3>() = col;
933 out.template ref<
scale - 1, 4>() = col;
934 out.template ref<
scale - 2, 4>() = col;
937 template <
class OutputMatrix>
938 static void blendLineSteep(uint32_t col, OutputMatrix& out)
940 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
941 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
942 alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col);
944 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
945 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
947 out.template ref<2,
scale - 1>() = col;
948 out.template ref<3,
scale - 1>() = col;
949 out.template ref<4,
scale - 1>() = col;
950 out.template ref<4,
scale - 2>() = col;
953 template <
class OutputMatrix>
954 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
956 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
957 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
958 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
960 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
961 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
962 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
964 alphaGrad<2, 3>(out.template ref<3, 3>(), col);
966 out.template ref<2,
scale - 1>() = col;
967 out.template ref<3,
scale - 1>() = col;
968 out.template ref<4,
scale - 1>() = col;
970 out.template ref<
scale - 1, 2>() = col;
971 out.template ref<
scale - 1, 3>() = col;
974 template <
class OutputMatrix>
975 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
977 alphaGrad<1, 8>(out.template ref<scale - 1, scale / 2 >(), col);
978 alphaGrad<1, 8>(out.template ref<scale - 2, scale / 2 + 1>(), col);
979 alphaGrad<1, 8>(out.template ref<scale - 3, scale / 2 + 2>(), col);
981 alphaGrad<7, 8>(out.template ref<4, 3>(), col);
982 alphaGrad<7, 8>(out.template ref<3, 4>(), col);
984 out.template ref<4, 4>() = col;
987 template <
class OutputMatrix>
988 static void blendCorner(uint32_t col, OutputMatrix& out)
991 alphaGrad<86, 100>(out.template ref<4, 4>(), col);
992 alphaGrad<23, 100>(out.template ref<4, 3>(), col);
993 alphaGrad<23, 100>(out.template ref<3, 4>(), col);
1000 template <
class ColorGradient>
1001 struct Scaler6x :
public ColorGradient
1003 static const int scale = 6;
1005 template <
unsigned int M,
unsigned int N>
1006 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); }
1009 template <
class OutputMatrix>
1010 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1012 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
1013 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
1014 alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col);
1016 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
1017 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
1018 alphaGrad<3, 4>(out.template ref<scale - 3, 5>(), col);
1020 out.template ref<
scale - 1, 2>() = col;
1021 out.template ref<
scale - 1, 3>() = col;
1022 out.template ref<
scale - 1, 4>() = col;
1023 out.template ref<
scale - 1, 5>() = col;
1025 out.template ref<
scale - 2, 4>() = col;
1026 out.template ref<
scale - 2, 5>() = col;
1029 template <
class OutputMatrix>
1030 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1032 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
1033 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
1034 alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col);
1036 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
1037 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
1038 alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col);
1040 out.template ref<2,
scale - 1>() = col;
1041 out.template ref<3,
scale - 1>() = col;
1042 out.template ref<4,
scale - 1>() = col;
1043 out.template ref<5,
scale - 1>() = col;
1045 out.template ref<4,
scale - 2>() = col;
1046 out.template ref<5,
scale - 2>() = col;
1049 template <
class OutputMatrix>
1050 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1052 alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col);
1053 alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col);
1054 alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col);
1055 alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col);
1057 alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col);
1058 alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col);
1059 alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col);
1060 alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col);
1062 out.template ref<2,
scale - 1>() = col;
1063 out.template ref<3,
scale - 1>() = col;
1064 out.template ref<4,
scale - 1>() = col;
1065 out.template ref<5,
scale - 1>() = col;
1067 out.template ref<4,
scale - 2>() = col;
1068 out.template ref<5,
scale - 2>() = col;
1070 out.template ref<
scale - 1, 2>() = col;
1071 out.template ref<
scale - 1, 3>() = col;
1074 template <
class OutputMatrix>
1075 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1077 alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
1078 alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1079 alphaGrad<1, 2>(out.template ref<scale - 3, scale / 2 + 2>(), col);
1081 out.template ref<
scale - 2,
scale - 1>() = col;
1082 out.template ref<
scale - 1,
scale - 1>() = col;
1083 out.template ref<
scale - 1,
scale - 2>() = col;
1086 template <
class OutputMatrix>
1087 static void blendCorner(uint32_t col, OutputMatrix& out)
1090 alphaGrad<97, 100>(out.template ref<5, 5>(), col);
1091 alphaGrad<42, 100>(out.template ref<4, 5>(), col);
1092 alphaGrad<42, 100>(out.template ref<5, 4>(), col);
1093 alphaGrad< 6, 100>(out.template ref<5, 3>(), col);
1094 alphaGrad< 6, 100>(out.template ref<3, 5>(), col);
1100 struct ColorDistanceRGB
1102 static double dist(uint32_t pix1, uint32_t pix2,
double )
1104 return distYCbCrBuffered(pix1, pix2);
1112 struct ColorDistanceARGB
1114 static double dist(uint32_t pix1, uint32_t pix2,
double )
1116 const double a1 =
getAlpha(pix1) / 255.0 ;
1117 const double a2 =
getAlpha(pix2) / 255.0 ;
1128 const double d = distYCbCrBuffered(pix1, pix2);
1130 return a1 *
d + 255 * (a2 - a1);
1132 return a2 *
d + 255 * (a1 - a2);
1139 struct ColorDistanceUnbufferedARGB
1141 static double dist(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
1143 const double a1 =
getAlpha(pix1) / 255.0 ;
1144 const double a2 =
getAlpha(pix2) / 255.0 ;
1146 const double d = distYCbCr(pix1, pix2, luminanceWeight);
1148 return a1 *
d + 255 * (a2 - a1);
1150 return a2 *
d + 255 * (a1 - a2);
1155 struct ColorGradientRGB
1157 template <
unsigned int M,
unsigned int N>
1158 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront)
1160 pixBack = gradientRGB<M, N>(pixFront, pixBack);
1164 struct ColorGradientARGB
1166 template <
unsigned int M,
unsigned int N>
1167 static void alphaGrad(uint32_t& pixBack, uint32_t pixFront)
1169 pixBack = gradientARGB<M, N>(pixFront, pixBack);
1179 std::copy(
src + yFirst * srcWidth,
src + yLast * srcWidth, trg);
1190 return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1192 return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1194 return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1196 return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1198 return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1206 return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1208 return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1210 return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1212 return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1214 return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1222 return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1224 return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1226 return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1228 return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1230 return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(
src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1243 return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1245 return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1247 return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
1255 uint32_t* trg,
int trgWidth,
int trgHeight)
1258 trg, trgWidth, trgHeight, trgWidth *
sizeof(uint32_t),
1259 0, trgHeight, [](uint32_t pix) {
return pix; });
1264 uint32_t* trg,
int trgWidth,
int trgHeight)
1267 trg, trgWidth, trgHeight, trgWidth *
sizeof(uint32_t),
1268 0, trgHeight, [](uint32_t pix) {
return pix; });
1274 void bilinearScaleCpu(
const uint32_t*
src,
int srcWidth,
int srcHeight,
1275 uint32_t* trg,
int trgWidth,
int trgHeight)
1277 const int TASK_GRANULARITY = 16;
1279 concurrency::task_group tg;
1281 for (
int i = 0;
i < trgHeight;
i += TASK_GRANULARITY)
1284 const int iLast = std::min(i + TASK_GRANULARITY, trgHeight);
1285 xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
1286 trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
1287 i, iLast, [](uint32_t pix) { return pix; });
1295 void bilinearScaleAmp(
const uint32_t*
src,
int srcWidth,
int srcHeight,
1296 uint32_t* trg,
int trgWidth,
int trgHeight)
1300 using namespace concurrency;
1303 if (srcHeight <= 0 || srcWidth <= 0)
return;
1305 const float scaleX =
static_cast<float>(trgWidth ) / srcWidth;
1306 const float scaleY =
static_cast<float>(trgHeight) / srcHeight;
1308 array_view<const uint32_t, 2> srcView(srcHeight, srcWidth,
src);
1309 array_view< uint32_t, 2> trgView(trgHeight, trgWidth, trg);
1310 trgView.discard_data();
1312 parallel_for_each(trgView.extent, [=](index<2> idx) restrict(amp)
1314 const int y = idx[0];
1315 const int x = idx[1];
1322 const int y1 = srcHeight * y / trgHeight;
1324 if (y2 == srcHeight) --y2;
1326 const float yy1 = y / scaleY - y1;
1327 const float y2y = 1 - yy1;
1329 const int x1 = srcWidth * x / trgWidth;
1331 if (x2 == srcWidth) --x2;
1333 const float xx1 = x / scaleX - x1;
1334 const float x2x = 1 - xx1;
1336 const float x2xy2y = x2x * y2y;
1337 const float xx1y2y = xx1 * y2y;
1338 const float x2xyy1 = x2x * yy1;
1339 const float xx1yy1 = xx1 * yy1;
1341 auto interpolate = [=](
int offset)
1348 const auto c11 = (srcView(y1, x1) >> (8 * offset)) & 0xff;
1349 const auto c21 = (srcView(y1, x2) >> (8 * offset)) & 0xff;
1350 const auto c12 = (srcView(y2, x1) >> (8 * offset)) & 0xff;
1351 const auto c22 = (srcView(y2, x2) >> (8 * offset)) & 0xff;
1353 return c11 * x2xy2y + c21 * xx1y2y +
1354 c12 * x2xyy1 + c22 * xx1yy1;
1357 const float bi = interpolate(0);
1358 const float gi = interpolate(1);
1359 const float ri = interpolate(2);
1360 const float ai = interpolate(3);
1362 const auto b =
static_cast<uint32_t
>(bi + 0.5f);
1363 const auto g =
static_cast<uint32_t
>(gi + 0.5f);
1364 const auto r =
static_cast<uint32_t
>(ri + 0.5f);
1365 const auto a =
static_cast<uint32_t
>(
ai + 0.5f);
1367 trgView(y, x) = (a << 24) | (r << 16) | (
g << 8) |
b;
1369 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(std::string_view 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