47 template <u
int32_t N>
inline
48 unsigned char getByte(uint32_t val) {
return static_cast<unsigned char>((val >> (8 * N)) & 0xff); }
50 inline unsigned char getRed (uint32_t val) {
return getByte<2>(val); }
51 inline unsigned char getGreen(uint32_t val) {
return getByte<1>(val); }
52 inline unsigned char getBlue (uint32_t val) {
return getByte<0>(val); }
54 template <
class T>
inline
58 return value < 0 ? -value : value;
61 const uint32_t redMask = 0xff0000;
62 const uint32_t greenMask = 0x00ff00;
63 const uint32_t blueMask = 0x0000ff;
64 const uint32_t alphaMask = 0xff000000;
66 template <
unsigned int N,
unsigned int M>
inline
67 void alphaBlend(uint32_t& dst, uint32_t col)
75 uint32_t col_alpha = col >> 24;
77 if (!col_alpha)
return;
79 uint32_t dst_alpha = dst >> 24;
93 dst = (redMask & ((col & redMask ) * N + (dst & redMask ) * (M - N)) / M) |
94 (greenMask & ((col & greenMask ) * N + (dst & greenMask ) * (M - N)) / M) |
95 (blueMask & ((col & blueMask ) * N + (dst & blueMask ) * (M - N)) / M) |
96 (alphaMask & (((col_alpha * N + dst_alpha * (M - N)) / M) << 24));
151 uint32_t alphaBlend2(uint32_t pix1, uint32_t pix2,
double alpha)
153 return (redMask &
static_cast<uint32_t
>((pix1 & redMask ) * alpha + (pix2 & redMask ) * (1 - alpha))) |
154 (greenMask &
static_cast<uint32_t
>((pix1 & greenMask) * alpha + (pix2 & greenMask) * (1 - alpha))) |
155 (blueMask &
static_cast<uint32_t
>((pix1 & blueMask ) * alpha + (pix2 & blueMask ) * (1 - alpha)));
159 uint32_t* byteAdvance( uint32_t* ptr,
int bytes) {
return reinterpret_cast< uint32_t*
>(
reinterpret_cast< char*
>(ptr) + bytes); }
160 const uint32_t* byteAdvance(
const uint32_t* ptr,
int bytes) {
return reinterpret_cast<const uint32_t*
>(
reinterpret_cast<const char*
>(ptr) + bytes); }
165 void fillBlock(uint32_t* trg,
int pitch, uint32_t col,
int blockWidth,
int blockHeight)
170 for (
int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch))
171 for (
int x = 0; x < blockWidth; ++x)
176 void fillBlock(uint32_t* trg,
int pitch, uint32_t col,
int n) { fillBlock(trg, pitch, col,
n,
n); }
180 #define FORCE_INLINE __forceinline
181 #elif defined __GNUC__
182 #define FORCE_INLINE __attribute__((always_inline)) inline
184 #define FORCE_INLINE inline
197 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
198 struct MatrixRotation;
200 template <
size_t I,
size_t J,
size_t N>
201 struct MatrixRotation<ROT_0, I, J, N>
203 static const size_t I_old = I;
204 static const size_t J_old = J;
207 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
208 struct MatrixRotation
210 static const size_t I_old = N - 1 - MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::J_old;
211 static const size_t J_old = MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::I_old;
215 template <
size_t N, RotationDegree rotDeg>
219 OutputMatrix(uint32_t* out,
int outWidth) :
221 outWidth_(outWidth) {}
223 template <
size_t I,
size_t J>
224 uint32_t& ref()
const
226 static const size_t I_old = MatrixRotation<rotDeg, I, J, N>::I_old;
227 static const size_t J_old = MatrixRotation<rotDeg, I, J, N>::J_old;
228 return *(out_ + J_old + I_old * outWidth_);
237 template <
class T>
inline
238 T square(T value) {
return value * value; }
293 void rgbtoLab(uint32_t
c,
unsigned char& L,
signed char& A,
signed char& B)
298 double r = getRed (
c) / 255.0;
299 double g = getGreen(
c) / 255.0;
300 double b = getBlue (
c) / 255.0;
302 r = r > 0.04045 ? std::pow(( r + 0.055 ) / 1.055, 2.4) : r / 12.92;
303 r =
g > 0.04045 ? std::pow((
g + 0.055 ) / 1.055, 2.4) :
g / 12.92;
304 r =
b > 0.04045 ? std::pow((
b + 0.055 ) / 1.055, 2.4) :
b / 12.92;
310 double x = 0.4124564 * r + 0.3575761 *
g + 0.1804375 *
b;
311 double y = 0.2126729 * r + 0.7151522 *
g + 0.0721750 *
b;
312 double z = 0.0193339 * r + 0.1191920 *
g + 0.9503041 *
b;
314 const double refX = 95.047;
315 const double refY = 100.000;
316 const double refZ = 108.883;
317 double var_X = x / refX;
318 double var_Y = y / refY;
319 double var_Z = z / refZ;
321 var_X = var_X > 0.008856 ? std::pow(var_X, 1.0 / 3) : 7.787 * var_X + 4.0 / 29;
322 var_Y = var_Y > 0.008856 ? std::pow(var_Y, 1.0 / 3) : 7.787 * var_Y + 4.0 / 29;
323 var_Z = var_Z > 0.008856 ? std::pow(var_Z, 1.0 / 3) : 7.787 * var_Z + 4.0 / 29;
325 L =
static_cast<unsigned char>(116 * var_Y - 16);
326 A =
static_cast< signed char>(500 * (var_X - var_Y));
327 B =
static_cast< signed char>(200 * (var_Y - var_Z));
333 double distLAB(uint32_t pix1, uint32_t pix2)
335 unsigned char L1 = 0;
338 rgbtoLab(pix1, L1, a1, b1);
340 unsigned char L2 = 0;
343 rgbtoLab(pix2, L2, a2, b2);
349 return std::sqrt(square(1.0 * L1 - L2) +
350 square(1.0 * a1 - a2) +
351 square(1.0 * b1 - b2));
438 double distRGB(uint32_t pix1, uint32_t pix2)
440 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
441 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
442 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
445 return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff));
451 double distNonLinearRGB(uint32_t pix1, uint32_t pix2)
454 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
455 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
456 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
458 const double r_avg = (
static_cast<double>(getRed(pix1)) + getRed(pix2)) / 2;
459 return std::sqrt((2 + r_avg / 255) * square(r_diff) + 4 * square(g_diff) + (2 + (255 - r_avg) / 255) * square(b_diff));
464 double distYCbCr(uint32_t pix1, uint32_t pix2,
double lumaWeight)
468 const int r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
469 const int g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
470 const int b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
472 const double k_b = 0.0722;
473 const double k_r = 0.2126;
474 const double k_g = 1 - k_b - k_r;
476 const double scale_b = 0.5 / (1 - k_b);
477 const double scale_r = 0.5 / (1 - k_r);
479 const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;
480 const double c_b = scale_b * (b_diff - y);
481 const double c_r = scale_r * (r_diff - y);
484 return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r));
489 double distYUV(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
493 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
494 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
495 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
498 const double w_b = 0.114;
499 const double w_r = 0.299;
500 const double w_g = 1 - w_r - w_b;
502 const double u_max = 0.436;
503 const double v_max = 0.615;
505 const double scale_u = u_max / (1 - w_b);
506 const double scale_v = v_max / (1 - w_r);
508 double y = w_r * r_diff + w_g * g_diff + w_b * b_diff;
509 double u = scale_u * (b_diff - y);
510 double v = scale_v * (r_diff - y);
513 const double eps = 0.5;
515 assert(std::abs(y) <= 255 + eps);
516 assert(std::abs(u) <= 255 * 2 * u_max + eps);
517 assert(std::abs(v) <= 255 * 2 * v_max + eps);
519 return std::sqrt(square(luminanceWeight * y) + square(u) + square(v));
524 double colorDist(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
535 return distYCbCr(pix1, pix2, luminanceWeight);
553 BlendResult() : blend_f(), blend_g(), blend_j(), blend_k() {}
581 BlendResult preProcessCorners(
const Kernel_4x4& ker,
const xbrz::ScalerCfg& cfg)
585 if ((ker.f == ker.g &&
591 auto dist = [&cfg](uint32_t col1, uint32_t col2) {
return colorDist(col1, col2, cfg.
luminanceWeight_); };
593 const int weight = 4;
594 double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g);
595 double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k);
600 if (ker.f != ker.g && ker.f != ker.j)
601 result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
603 if (ker.k != ker.j && ker.k != ker.g)
604 result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
609 if (ker.j != ker.f && ker.j != ker.k)
610 result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
612 if (ker.g != ker.f && ker.g != ker.k)
613 result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
628 #define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; }
635 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_90>(const Kernel_3x3& ker) { return ker.y; }
641 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_180>(const Kernel_3x3& ker) { return ker.y; }
647 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_270>(const Kernel_3x3& ker) { return ker.y; }
655 inline BlendType getTopR (
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 2)); }
656 inline BlendType getBottomR(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 4)); }
657 inline BlendType getBottomL(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 6)); }
659 inline void setTopL (
unsigned char&
b, BlendType bt) {
b |= bt; }
660 inline void setTopR (
unsigned char&
b, BlendType bt) {
b |= (bt << 2); }
661 inline void setBottomR(
unsigned char&
b, BlendType bt) {
b |= (bt << 4); }
662 inline void setBottomL(
unsigned char&
b, BlendType bt) {
b |= (bt << 6); }
664 inline bool blendingNeeded(
unsigned char b) {
return b != 0; }
666 template <RotationDegree rotDeg>
inline
667 unsigned char rotateBlendInfo(
unsigned char b) {
return b; }
668 template <>
inline unsigned char rotateBlendInfo<ROT_90 >(
unsigned char b) {
return ((
b << 2) | (
b >> 6)) & 0xff; }
669 template <>
inline unsigned char rotateBlendInfo<ROT_180>(
unsigned char b) {
return ((
b << 4) | (
b >> 4)) & 0xff; }
670 template <>
inline unsigned char rotateBlendInfo<ROT_270>(
unsigned char b) {
return ((
b << 6) | (
b >> 2)) & 0xff; }
674 int debugPixelX = -1;
675 int debugPixelY = 84;
676 bool breakIntoDebugger =
false;
689 template <
class Scaler, RotationDegree rotDeg>
691 void scalePixel(
const Kernel_3x3& ker,
692 uint32_t* target,
int trgWidth,
693 unsigned char blendInfo,
696 #define a get_a<rotDeg>(ker)
697 #define b get_b<rotDeg>(ker)
698 #define c get_c<rotDeg>(ker)
699 #define d get_d<rotDeg>(ker)
700 #define e get_e<rotDeg>(ker)
701 #define f get_f<rotDeg>(ker)
702 #define g get_g<rotDeg>(ker)
703 #define h get_h<rotDeg>(ker)
704 #define i get_i<rotDeg>(ker)
707 (void) breakIntoDebugger;
712 const unsigned char blend = rotateBlendInfo<rotDeg>(blendInfo);
714 if (getBottomR(blend) >= BLEND_NORMAL)
718 auto dist = [&cfg](uint32_t col1, uint32_t col2) {
return colorDist(col1, col2, cfg.
luminanceWeight_); };
720 const uint32_t px = dist(
e,
f) <= dist(
e,
h) ?
f :
h;
722 OutputMatrix<Scaler::scale, rotDeg> out(target, trgWidth);
724 bool doLineBlend =
true;
726 if (getBottomR(blend) >= BLEND_DOMINANT)
730 else if (getTopR(blend) != BLEND_NONE && !eq(
e,
g))
732 else if (getBottomL(blend) != BLEND_NONE && !eq(
e,
c))
736 else if (eq(
g,
h) && eq(
h ,
i) && eq(
i,
f) && eq(
f,
c) && !eq(
e,
i))
739 else doLineBlend =
true;
744 const double fg = dist(
f,
g);
745 const double hc = dist(
h,
c);
753 Scaler::blendLineSteepAndShallow(px, out);
755 Scaler::blendLineShallow(px, out);
760 Scaler::blendLineSteep(px, out);
762 Scaler::blendLineDiagonal(px,out);
766 Scaler::blendCorner(px, out);
781 template <
class Scaler>
782 void scaleImage(
const uint32_t* src, uint32_t* trg,
int srcWidth,
int srcHeight,
const xbrz::ScalerCfg& cfg,
int yFirst,
int yLast)
784 yFirst = std::max(yFirst, 0);
785 yLast = std::min(yLast, srcHeight);
786 if (yFirst >= yLast || srcWidth <= 0)
793 const int bufferSize = srcWidth;
794 unsigned char* preProcBuffer =
reinterpret_cast<unsigned char*
>(trg + yLast *
Scaler::scale * trgWidth) - bufferSize;
795 std::fill(preProcBuffer, preProcBuffer + bufferSize,
static_cast<unsigned char>(0));
802 const int y = yFirst - 1;
804 const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
805 const uint32_t* s_0 = src + srcWidth * y;
806 const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
807 const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
809 for (
int x = 0; x < srcWidth; ++x)
811 const int x_m1 = std::max(x - 1, 0);
812 const int x_p1 = std::min(x + 1, srcWidth - 1);
813 const int x_p2 = std::min(x + 2, srcWidth - 1);
836 const BlendResult res = preProcessCorners(ker, cfg);
845 setTopR(preProcBuffer[x], res.blend_j);
847 if (x + 1 < srcWidth)
848 setTopL(preProcBuffer[x + 1], res.blend_k);
853 for (
int y = yFirst; y < yLast; ++y)
857 const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
858 const uint32_t* s_0 = src + srcWidth * y;
859 const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
860 const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
862 unsigned char blend_xy1 = 0;
867 breakIntoDebugger = debugPixelX == x && debugPixelY == y;
870 const int x_m1 = std::max(x - 1, 0);
871 const int x_p1 = std::min(x + 1, srcWidth - 1);
872 const int x_p2 = std::min(x + 2, srcWidth - 1);
875 unsigned char blend_xy = 0;
898 const BlendResult res = preProcessCorners(ker, cfg);
907 blend_xy = preProcBuffer[x];
908 setBottomR(blend_xy, res.blend_f);
910 setTopR(blend_xy1, res.blend_j);
911 preProcBuffer[x] = blend_xy1;
914 setTopL(blend_xy1, res.blend_k);
916 if (x + 1 < srcWidth)
917 setBottomL(preProcBuffer[x + 1], res.blend_g);
921 fillBlock(out, trgWidth *
sizeof(uint32_t), s_0[x],
Scaler::scale);
924 if (blendingNeeded(blend_xy))
940 scalePixel<Scaler, ROT_0 >(ker, out, trgWidth, blend_xy, cfg);
941 scalePixel<Scaler, ROT_90 >(ker, out, trgWidth, blend_xy, cfg);
942 scalePixel<Scaler, ROT_180>(ker, out, trgWidth, blend_xy, cfg);
943 scalePixel<Scaler, ROT_270>(ker, out, trgWidth, blend_xy, cfg);
952 static const int scale = 2;
954 template <
class OutputMatrix>
955 static void blendLineShallow(uint32_t col, OutputMatrix& out)
957 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
958 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
961 template <
class OutputMatrix>
962 static void blendLineSteep(uint32_t col, OutputMatrix& out)
964 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
965 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
968 template <
class OutputMatrix>
969 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
971 alphaBlend<1, 4>(out.template ref<1, 0>(), col);
972 alphaBlend<1, 4>(out.template ref<0, 1>(), col);
973 alphaBlend<5, 6>(out.template ref<1, 1>(), col);
976 template <
class OutputMatrix>
977 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
979 alphaBlend<1, 2>(out.template ref<1, 1>(), col);
982 template <
class OutputMatrix>
983 static void blendCorner(uint32_t col, OutputMatrix& out)
986 alphaBlend<21, 100>(out.template ref<1, 1>(), col);
993 static const int scale = 3;
995 template <
class OutputMatrix>
996 static void blendLineShallow(uint32_t col, OutputMatrix& out)
998 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
999 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1001 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1002 out.template ref<
scale - 1, 2>() = col;
1005 template <
class OutputMatrix>
1006 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1008 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1009 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1011 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1012 out.template ref<2,
scale - 1>() = col;
1015 template <
class OutputMatrix>
1016 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1018 alphaBlend<1, 4>(out.template ref<2, 0>(), col);
1019 alphaBlend<1, 4>(out.template ref<0, 2>(), col);
1020 alphaBlend<3, 4>(out.template ref<2, 1>(), col);
1021 alphaBlend<3, 4>(out.template ref<1, 2>(), col);
1022 out.template ref<2, 2>() = col;
1025 template <
class OutputMatrix>
1026 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1028 alphaBlend<1, 8>(out.template ref<1, 2>(), col);
1029 alphaBlend<1, 8>(out.template ref<2, 1>(), col);
1030 alphaBlend<7, 8>(out.template ref<2, 2>(), col);
1033 template <
class OutputMatrix>
1034 static void blendCorner(uint32_t col, OutputMatrix& out)
1037 alphaBlend<45, 100>(out.template ref<2, 2>(), col);
1046 static const int scale = 4;
1048 template <
class OutputMatrix>
1049 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1051 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1052 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1054 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1055 alphaBlend<3, 4>(out.template ref<scale - 2, 3>(), col);
1057 out.template ref<
scale - 1, 2>() = col;
1058 out.template ref<
scale - 1, 3>() = col;
1061 template <
class OutputMatrix>
1062 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1064 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1065 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1067 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1068 alphaBlend<3, 4>(out.template ref<3, scale - 2>(), col);
1070 out.template ref<2,
scale - 1>() = col;
1071 out.template ref<3,
scale - 1>() = col;
1074 template <
class OutputMatrix>
1075 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1077 alphaBlend<3, 4>(out.template ref<3, 1>(), col);
1078 alphaBlend<3, 4>(out.template ref<1, 3>(), col);
1079 alphaBlend<1, 4>(out.template ref<3, 0>(), col);
1080 alphaBlend<1, 4>(out.template ref<0, 3>(), col);
1081 alphaBlend<1, 3>(out.template ref<2, 2>(), col);
1082 out.template ref<3, 3>() = out.template ref<3, 2>() = out.template ref<2, 3>() = col;
1085 template <
class OutputMatrix>
1086 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1088 alphaBlend<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
1089 alphaBlend<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1090 out.template ref<
scale - 1,
scale - 1>() = col;
1093 template <
class OutputMatrix>
1094 static void blendCorner(uint32_t col, OutputMatrix& out)
1097 alphaBlend<68, 100>(out.template ref<3, 3>(), col);
1098 alphaBlend< 9, 100>(out.template ref<3, 2>(), col);
1099 alphaBlend< 9, 100>(out.template ref<2, 3>(), col);
1106 static const int scale = 5;
1108 template <
class OutputMatrix>
1109 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1111 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1112 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1113 alphaBlend<1, 4>(out.template ref<scale - 3, 4>(), col);
1115 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1116 alphaBlend<3, 4>(out.template ref<scale - 2, 3>(), col);
1118 out.template ref<
scale - 1, 2>() = col;
1119 out.template ref<
scale - 1, 3>() = col;
1120 out.template ref<
scale - 1, 4>() = col;
1121 out.template ref<
scale - 2, 4>() = col;
1124 template <
class OutputMatrix>
1125 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1127 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1128 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1129 alphaBlend<1, 4>(out.template ref<4, scale - 3>(), col);
1131 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1132 alphaBlend<3, 4>(out.template ref<3, scale - 2>(), col);
1134 out.template ref<2,
scale - 1>() = col;
1135 out.template ref<3,
scale - 1>() = col;
1136 out.template ref<4,
scale - 1>() = col;
1137 out.template ref<4,
scale - 2>() = col;
1140 template <
class OutputMatrix>
1141 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1143 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1144 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1145 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1147 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1148 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1149 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1151 out.template ref<2,
scale - 1>() = col;
1152 out.template ref<3,
scale - 1>() = col;
1154 out.template ref<
scale - 1, 2>() = col;
1155 out.template ref<
scale - 1, 3>() = col;
1157 out.template ref<4,
scale - 1>() = col;
1159 alphaBlend<2, 3>(out.template ref<3, 3>(), col);
1162 template <
class OutputMatrix>
1163 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1165 alphaBlend<1, 8>(out.template ref<scale - 1, scale / 2 >(), col);
1166 alphaBlend<1, 8>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1167 alphaBlend<1, 8>(out.template ref<scale - 3, scale / 2 + 2>(), col);
1169 alphaBlend<7, 8>(out.template ref<4, 3>(), col);
1170 alphaBlend<7, 8>(out.template ref<3, 4>(), col);
1172 out.template ref<4, 4>() = col;
1175 template <
class OutputMatrix>
1176 static void blendCorner(uint32_t col, OutputMatrix& out)
1179 alphaBlend<86, 100>(out.template ref<4, 4>(), col);
1180 alphaBlend<23, 100>(out.template ref<4, 3>(), col);
1181 alphaBlend<23, 100>(out.template ref<3, 4>(), col);
1189 void xbrz::scale(
size_t factor,
const uint32_t* src, uint32_t* trg,
int srcWidth,
int srcHeight,
const xbrz::ScalerCfg& cfg,
int yFirst,
int yLast)
1194 return scaleImage<Scaler2x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1196 return scaleImage<Scaler3x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1198 return scaleImage<Scaler4x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1200 return scaleImage<Scaler5x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1206 bool xbrz::equalColor(uint32_t col1, uint32_t col2,
double luminanceWeight,
double equalColorTolerance)
1208 return colorDist(col1, col2, luminanceWeight) < equalColorTolerance;
1213 uint32_t* trg,
int trgWidth,
int trgHeight,
int trgPitch,
1216 if (srcPitch < srcWidth *
static_cast<int>(
sizeof(uint32_t)) ||
1217 trgPitch < trgWidth *
static_cast<int>(
sizeof(uint32_t)))
1227 yFirst = std::max(yFirst, 0);
1228 yLast = std::min(yLast, srcHeight);
1229 if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0)
return;
1231 for (
int y = yFirst; y < yLast; ++y)
1237 const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight;
1238 const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight;
1239 const int blockHeight = yTrg_last - yTrg_first;
1241 if (blockHeight > 0)
1243 const uint32_t* srcLine = byteAdvance(src, y * srcPitch);
1244 uint32_t* trgLine = byteAdvance(trg, yTrg_first * trgPitch);
1247 for (
int x = 0; x < srcWidth; ++x)
1249 int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
1250 const int blockWidth = xTrg_last - xTrg_first;
1253 xTrg_first = xTrg_last;
1254 fillBlock(trgLine, trgPitch, srcLine[x], blockWidth, blockHeight);
1255 trgLine += blockWidth;
1264 yFirst = std::max(yFirst, 0);
1265 yLast = std::min(yLast, trgHeight);
1266 if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0)
return;
1268 for (
int y = yFirst; y < yLast; ++y)
1270 uint32_t* trgLine = byteAdvance(trg, y * trgPitch);
1271 const int ySrc = srcHeight * y / trgHeight;
1272 const uint32_t* srcLine = byteAdvance(src, ySrc * srcPitch);
1273 for (
int x = 0; x < trgWidth; ++x)
1275 const int xSrc = srcWidth * x / trgWidth;
1276 trgLine[x] = srcLine[xSrc];
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
bool equalColor(uint32_t col1, uint32_t col2, double luminanceWeight, double equalColorTolerance)
void nearestNeighborScale(const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight)
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
double steepDirectionThreshold
double dominantDirectionThreshold
double equalColorTolerance_
static map_location::DIRECTION n