48 template <u
int32_t N>
inline
49 unsigned char getByte(uint32_t val) {
return static_cast<unsigned char>((val >> (8 * N)) & 0xff); }
51 inline unsigned char getRed (uint32_t val) {
return getByte<2>(val); }
52 inline unsigned char getGreen(uint32_t val) {
return getByte<1>(val); }
53 inline unsigned char getBlue (uint32_t val) {
return getByte<0>(val); }
55 template <
class T>
inline
59 return value < 0 ? -value : value;
62 const uint32_t redMask = 0xff0000;
63 const uint32_t greenMask = 0x00ff00;
64 const uint32_t blueMask = 0x0000ff;
65 const uint32_t alphaMask = 0xff000000;
67 template <
unsigned int N,
unsigned int M>
inline
68 void alphaBlend(uint32_t& dst, uint32_t col)
76 uint32_t col_alpha = col >> 24;
78 if (!col_alpha)
return;
80 uint32_t dst_alpha = dst >> 24;
94 dst = (redMask & ((col & redMask ) * N + (dst & redMask ) * (M - N)) / M) |
95 (greenMask & ((col & greenMask ) * N + (dst & greenMask ) * (M - N)) / M) |
96 (blueMask & ((col & blueMask ) * N + (dst & blueMask ) * (M - N)) / M) |
97 (alphaMask & (((col_alpha * N + dst_alpha * (M - N)) / M) << 24));
152 uint32_t alphaBlend2(uint32_t pix1, uint32_t pix2,
double alpha)
154 return (redMask &
static_cast<uint32_t
>((pix1 & redMask ) * alpha + (pix2 & redMask ) * (1 - alpha))) |
155 (greenMask &
static_cast<uint32_t
>((pix1 & greenMask) * alpha + (pix2 & greenMask) * (1 - alpha))) |
156 (blueMask &
static_cast<uint32_t
>((pix1 & blueMask ) * alpha + (pix2 & blueMask ) * (1 - alpha)));
160 uint32_t* byteAdvance( uint32_t* ptr,
int bytes) {
return reinterpret_cast< uint32_t*
>(
reinterpret_cast< char*
>(ptr) + bytes); }
161 const uint32_t* byteAdvance(
const uint32_t* ptr,
int bytes) {
return reinterpret_cast<const uint32_t*
>(
reinterpret_cast<const char*
>(ptr) + bytes); }
166 void fillBlock(uint32_t* trg,
int pitch, uint32_t col,
int blockWidth,
int blockHeight)
171 for (
int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch))
172 for (
int x = 0; x < blockWidth; ++x)
177 void fillBlock(uint32_t* trg,
int pitch, uint32_t col,
int n) { fillBlock(trg, pitch, col,
n,
n); }
181 #define FORCE_INLINE __forceinline
182 #elif defined __GNUC__
183 #define FORCE_INLINE __attribute__((always_inline)) inline
185 #define FORCE_INLINE inline
198 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
199 struct MatrixRotation;
201 template <
size_t I,
size_t J,
size_t N>
202 struct MatrixRotation<ROT_0, I, J, N>
204 static const size_t I_old = I;
205 static const size_t J_old = J;
208 template <RotationDegree rotDeg,
size_t I,
size_t J,
size_t N>
209 struct MatrixRotation
211 static const size_t I_old = N - 1 - MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::J_old;
212 static const size_t J_old = MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::I_old;
216 template <
size_t N, RotationDegree rotDeg>
220 OutputMatrix(uint32_t* out,
int outWidth) :
222 outWidth_(outWidth) {}
224 template <
size_t I,
size_t J>
225 uint32_t& ref()
const
227 static const size_t I_old = MatrixRotation<rotDeg, I, J, N>::I_old;
228 static const size_t J_old = MatrixRotation<rotDeg, I, J, N>::J_old;
229 return *(out_ + J_old + I_old * outWidth_);
238 template <
class T>
inline
239 T square(T value) {
return value * value; }
294 void rgbtoLab(uint32_t
c,
unsigned char& L,
signed char& A,
signed char& B)
299 double r = getRed (
c) / 255.0;
300 double g = getGreen(
c) / 255.0;
301 double b = getBlue (
c) / 255.0;
303 r = r > 0.04045 ? std::pow(( r + 0.055 ) / 1.055, 2.4) : r / 12.92;
304 r =
g > 0.04045 ? std::pow((
g + 0.055 ) / 1.055, 2.4) :
g / 12.92;
305 r =
b > 0.04045 ? std::pow((
b + 0.055 ) / 1.055, 2.4) :
b / 12.92;
311 double x = 0.4124564 * r + 0.3575761 *
g + 0.1804375 *
b;
312 double y = 0.2126729 * r + 0.7151522 *
g + 0.0721750 *
b;
313 double z = 0.0193339 * r + 0.1191920 *
g + 0.9503041 *
b;
315 const double refX = 95.047;
316 const double refY = 100.000;
317 const double refZ = 108.883;
318 double var_X = x / refX;
319 double var_Y = y / refY;
320 double var_Z = z / refZ;
322 var_X = var_X > 0.008856 ? std::pow(var_X, 1.0 / 3) : 7.787 * var_X + 4.0 / 29;
323 var_Y = var_Y > 0.008856 ? std::pow(var_Y, 1.0 / 3) : 7.787 * var_Y + 4.0 / 29;
324 var_Z = var_Z > 0.008856 ? std::pow(var_Z, 1.0 / 3) : 7.787 * var_Z + 4.0 / 29;
326 L =
static_cast<unsigned char>(116 * var_Y - 16);
327 A =
static_cast< signed char>(500 * (var_X - var_Y));
328 B =
static_cast< signed char>(200 * (var_Y - var_Z));
334 double distLAB(uint32_t pix1, uint32_t pix2)
336 unsigned char L1 = 0;
339 rgbtoLab(pix1, L1, a1, b1);
341 unsigned char L2 = 0;
344 rgbtoLab(pix2, L2, a2, b2);
350 return std::sqrt(square(1.0 * L1 - L2) +
351 square(1.0 * a1 - a2) +
352 square(1.0 * b1 - b2));
439 double distRGB(uint32_t pix1, uint32_t pix2)
441 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
442 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
443 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
446 return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff));
452 double distNonLinearRGB(uint32_t pix1, uint32_t pix2)
455 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
456 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
457 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
459 const double r_avg = (
static_cast<double>(getRed(pix1)) + getRed(pix2)) / 2;
460 return std::sqrt((2 + r_avg / 255) * square(r_diff) + 4 * square(g_diff) + (2 + (255 - r_avg) / 255) * square(b_diff));
465 double distYCbCr(uint32_t pix1, uint32_t pix2,
double lumaWeight)
469 const int r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
470 const int g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
471 const int b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
473 const double k_b = 0.0722;
474 const double k_r = 0.2126;
475 const double k_g = 1 - k_b - k_r;
477 const double scale_b = 0.5 / (1 - k_b);
478 const double scale_r = 0.5 / (1 - k_r);
480 const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;
481 const double c_b = scale_b * (b_diff - y);
482 const double c_r = scale_r * (r_diff - y);
485 return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r));
490 double distYUV(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
494 const double r_diff =
static_cast<int>(getRed (pix1)) - getRed (pix2);
495 const double g_diff =
static_cast<int>(getGreen(pix1)) - getGreen(pix2);
496 const double b_diff =
static_cast<int>(getBlue (pix1)) - getBlue (pix2);
499 const double w_b = 0.114;
500 const double w_r = 0.299;
501 const double w_g = 1 - w_r - w_b;
503 const double u_max = 0.436;
504 const double v_max = 0.615;
506 const double scale_u = u_max / (1 - w_b);
507 const double scale_v = v_max / (1 - w_r);
509 double y = w_r * r_diff + w_g * g_diff + w_b * b_diff;
510 double u = scale_u * (b_diff - y);
511 double v = scale_v * (r_diff - y);
514 const double eps = 0.5;
516 assert(std::abs(y) <= 255 + eps);
517 assert(std::abs(u) <= 255 * 2 * u_max + eps);
518 assert(std::abs(v) <= 255 * 2 * v_max + eps);
520 return std::sqrt(square(luminanceWeight * y) + square(u) + square(v));
525 double colorDist(uint32_t pix1, uint32_t pix2,
double luminanceWeight)
536 return distYCbCr(pix1, pix2, luminanceWeight);
554 BlendResult() : blend_f(), blend_g(), blend_j(), blend_k() {}
582 BlendResult preProcessCorners(
const Kernel_4x4& ker,
const xbrz::ScalerCfg& cfg)
586 if ((ker.f == ker.g &&
592 auto dist = [&cfg](uint32_t col1, uint32_t col2) {
return colorDist(col1, col2, cfg.
luminanceWeight_); };
594 const int weight = 4;
595 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);
596 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);
601 if (ker.f != ker.g && ker.f != ker.j)
602 result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
604 if (ker.k != ker.j && ker.k != ker.g)
605 result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
610 if (ker.j != ker.f && ker.j != ker.k)
611 result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
613 if (ker.g != ker.f && ker.g != ker.k)
614 result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
629 #define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; }
636 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_90>(const Kernel_3x3& ker) { return ker.y; }
642 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_180>(const Kernel_3x3& ker) { return ker.y; }
648 #define DEF_GETTER(x, y) template <> inline uint32_t get_##x<ROT_270>(const Kernel_3x3& ker) { return ker.y; }
656 inline BlendType getTopR (
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 2)); }
657 inline BlendType getBottomR(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 4)); }
658 inline BlendType getBottomL(
unsigned char b) {
return static_cast<BlendType
>(0x3 & (
b >> 6)); }
660 inline void setTopL (
unsigned char&
b, BlendType bt) {
b |= bt; }
661 inline void setTopR (
unsigned char&
b, BlendType bt) {
b |= (bt << 2); }
662 inline void setBottomR(
unsigned char&
b, BlendType bt) {
b |= (bt << 4); }
663 inline void setBottomL(
unsigned char&
b, BlendType bt) {
b |= (bt << 6); }
665 inline bool blendingNeeded(
unsigned char b) {
return b != 0; }
667 template <RotationDegree rotDeg>
inline
668 unsigned char rotateBlendInfo(
unsigned char b) {
return b; }
669 template <>
inline unsigned char rotateBlendInfo<ROT_90 >(
unsigned char b) {
return ((
b << 2) | (
b >> 6)) & 0xff; }
670 template <>
inline unsigned char rotateBlendInfo<ROT_180>(
unsigned char b) {
return ((
b << 4) | (
b >> 4)) & 0xff; }
671 template <>
inline unsigned char rotateBlendInfo<ROT_270>(
unsigned char b) {
return ((
b << 6) | (
b >> 2)) & 0xff; }
675 int debugPixelX = -1;
676 int debugPixelY = 84;
677 bool breakIntoDebugger =
false;
690 template <
class Scaler, RotationDegree rotDeg>
692 void scalePixel(
const Kernel_3x3& ker,
693 uint32_t* target,
int trgWidth,
694 unsigned char blendInfo,
697 #define a get_a<rotDeg>(ker)
698 #define b get_b<rotDeg>(ker)
699 #define c get_c<rotDeg>(ker)
700 #define d get_d<rotDeg>(ker)
701 #define e get_e<rotDeg>(ker)
702 #define f get_f<rotDeg>(ker)
703 #define g get_g<rotDeg>(ker)
704 #define h get_h<rotDeg>(ker)
705 #define i get_i<rotDeg>(ker)
708 (void) breakIntoDebugger;
713 const unsigned char blend = rotateBlendInfo<rotDeg>(blendInfo);
715 if (getBottomR(blend) >= BLEND_NORMAL)
719 auto dist = [&cfg](uint32_t col1, uint32_t col2) {
return colorDist(col1, col2, cfg.
luminanceWeight_); };
721 const uint32_t px = dist(
e,
f) <= dist(
e,
h) ?
f :
h;
723 OutputMatrix<Scaler::scale, rotDeg> out(target, trgWidth);
725 bool doLineBlend =
true;
727 if (getBottomR(blend) >= BLEND_DOMINANT)
731 else if (getTopR(blend) != BLEND_NONE && !eq(
e,
g))
733 else if (getBottomL(blend) != BLEND_NONE && !eq(
e,
c))
737 else if (eq(
g,
h) && eq(
h ,
i) && eq(
i,
f) && eq(
f,
c) && !eq(
e,
i))
740 else doLineBlend =
true;
745 const double fg = dist(
f,
g);
746 const double hc = dist(
h,
c);
754 Scaler::blendLineSteepAndShallow(px, out);
756 Scaler::blendLineShallow(px, out);
761 Scaler::blendLineSteep(px, out);
763 Scaler::blendLineDiagonal(px,out);
767 Scaler::blendCorner(px, out);
782 template <
class Scaler>
783 void scaleImage(
const uint32_t* src, uint32_t* trg,
int srcWidth,
int srcHeight,
const xbrz::ScalerCfg& cfg,
int yFirst,
int yLast)
785 yFirst = std::max(yFirst, 0);
786 yLast = std::min(yLast, srcHeight);
787 if (yFirst >= yLast || srcWidth <= 0)
794 const int bufferSize = srcWidth;
795 unsigned char* preProcBuffer =
reinterpret_cast<unsigned char*
>(trg + yLast *
Scaler::scale * trgWidth) - bufferSize;
796 std::fill(preProcBuffer, preProcBuffer + bufferSize,
static_cast<unsigned char>(0));
803 const int y = yFirst - 1;
805 const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
806 const uint32_t* s_0 = src + srcWidth * y;
807 const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
808 const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
810 for (
int x = 0; x < srcWidth; ++x)
812 const int x_m1 = std::max(x - 1, 0);
813 const int x_p1 = std::min(x + 1, srcWidth - 1);
814 const int x_p2 = std::min(x + 2, srcWidth - 1);
837 const BlendResult res = preProcessCorners(ker, cfg);
846 setTopR(preProcBuffer[x], res.blend_j);
848 if (x + 1 < srcWidth)
849 setTopL(preProcBuffer[x + 1], res.blend_k);
854 for (
int y = yFirst; y < yLast; ++y)
858 const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
859 const uint32_t* s_0 = src + srcWidth * y;
860 const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
861 const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
863 unsigned char blend_xy1 = 0;
868 breakIntoDebugger = debugPixelX == x && debugPixelY == y;
871 const int x_m1 = std::max(x - 1, 0);
872 const int x_p1 = std::min(x + 1, srcWidth - 1);
873 const int x_p2 = std::min(x + 2, srcWidth - 1);
876 unsigned char blend_xy = 0;
899 const BlendResult res = preProcessCorners(ker, cfg);
908 blend_xy = preProcBuffer[x];
909 setBottomR(blend_xy, res.blend_f);
911 setTopR(blend_xy1, res.blend_j);
912 preProcBuffer[x] = blend_xy1;
915 setTopL(blend_xy1, res.blend_k);
917 if (x + 1 < srcWidth)
918 setBottomL(preProcBuffer[x + 1], res.blend_g);
922 fillBlock(out, trgWidth *
sizeof(uint32_t), s_0[x],
Scaler::scale);
925 if (blendingNeeded(blend_xy))
941 scalePixel<Scaler, ROT_0 >(ker, out, trgWidth, blend_xy, cfg);
942 scalePixel<Scaler, ROT_90 >(ker, out, trgWidth, blend_xy, cfg);
943 scalePixel<Scaler, ROT_180>(ker, out, trgWidth, blend_xy, cfg);
944 scalePixel<Scaler, ROT_270>(ker, out, trgWidth, blend_xy, cfg);
953 static const int scale = 2;
955 template <
class OutputMatrix>
956 static void blendLineShallow(uint32_t col, OutputMatrix& out)
958 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
959 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
962 template <
class OutputMatrix>
963 static void blendLineSteep(uint32_t col, OutputMatrix& out)
965 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
966 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
969 template <
class OutputMatrix>
970 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
972 alphaBlend<1, 4>(out.template ref<1, 0>(), col);
973 alphaBlend<1, 4>(out.template ref<0, 1>(), col);
974 alphaBlend<5, 6>(out.template ref<1, 1>(), col);
977 template <
class OutputMatrix>
978 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
980 alphaBlend<1, 2>(out.template ref<1, 1>(), col);
983 template <
class OutputMatrix>
984 static void blendCorner(uint32_t col, OutputMatrix& out)
987 alphaBlend<21, 100>(out.template ref<1, 1>(), col);
994 static const int scale = 3;
996 template <
class OutputMatrix>
997 static void blendLineShallow(uint32_t col, OutputMatrix& out)
999 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1000 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1002 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1003 out.template ref<
scale - 1, 2>() = col;
1006 template <
class OutputMatrix>
1007 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1009 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1010 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1012 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1013 out.template ref<2,
scale - 1>() = col;
1016 template <
class OutputMatrix>
1017 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1019 alphaBlend<1, 4>(out.template ref<2, 0>(), col);
1020 alphaBlend<1, 4>(out.template ref<0, 2>(), col);
1021 alphaBlend<3, 4>(out.template ref<2, 1>(), col);
1022 alphaBlend<3, 4>(out.template ref<1, 2>(), col);
1023 out.template ref<2, 2>() = col;
1026 template <
class OutputMatrix>
1027 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1029 alphaBlend<1, 8>(out.template ref<1, 2>(), col);
1030 alphaBlend<1, 8>(out.template ref<2, 1>(), col);
1031 alphaBlend<7, 8>(out.template ref<2, 2>(), col);
1034 template <
class OutputMatrix>
1035 static void blendCorner(uint32_t col, OutputMatrix& out)
1038 alphaBlend<45, 100>(out.template ref<2, 2>(), col);
1047 static const int scale = 4;
1049 template <
class OutputMatrix>
1050 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1052 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1053 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1055 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1056 alphaBlend<3, 4>(out.template ref<scale - 2, 3>(), col);
1058 out.template ref<
scale - 1, 2>() = col;
1059 out.template ref<
scale - 1, 3>() = col;
1062 template <
class OutputMatrix>
1063 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1065 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1066 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1068 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1069 alphaBlend<3, 4>(out.template ref<3, scale - 2>(), col);
1071 out.template ref<2,
scale - 1>() = col;
1072 out.template ref<3,
scale - 1>() = col;
1075 template <
class OutputMatrix>
1076 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1078 alphaBlend<3, 4>(out.template ref<3, 1>(), col);
1079 alphaBlend<3, 4>(out.template ref<1, 3>(), col);
1080 alphaBlend<1, 4>(out.template ref<3, 0>(), col);
1081 alphaBlend<1, 4>(out.template ref<0, 3>(), col);
1082 alphaBlend<1, 3>(out.template ref<2, 2>(), col);
1083 out.template ref<3, 3>() = out.template ref<3, 2>() = out.template ref<2, 3>() = col;
1086 template <
class OutputMatrix>
1087 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1089 alphaBlend<1, 2>(out.template ref<scale - 1, scale / 2 >(), col);
1090 alphaBlend<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1091 out.template ref<
scale - 1,
scale - 1>() = col;
1094 template <
class OutputMatrix>
1095 static void blendCorner(uint32_t col, OutputMatrix& out)
1098 alphaBlend<68, 100>(out.template ref<3, 3>(), col);
1099 alphaBlend< 9, 100>(out.template ref<3, 2>(), col);
1100 alphaBlend< 9, 100>(out.template ref<2, 3>(), col);
1107 static const int scale = 5;
1109 template <
class OutputMatrix>
1110 static void blendLineShallow(uint32_t col, OutputMatrix& out)
1112 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1113 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1114 alphaBlend<1, 4>(out.template ref<scale - 3, 4>(), col);
1116 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1117 alphaBlend<3, 4>(out.template ref<scale - 2, 3>(), col);
1119 out.template ref<
scale - 1, 2>() = col;
1120 out.template ref<
scale - 1, 3>() = col;
1121 out.template ref<
scale - 1, 4>() = col;
1122 out.template ref<
scale - 2, 4>() = col;
1125 template <
class OutputMatrix>
1126 static void blendLineSteep(uint32_t col, OutputMatrix& out)
1128 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1129 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1130 alphaBlend<1, 4>(out.template ref<4, scale - 3>(), col);
1132 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1133 alphaBlend<3, 4>(out.template ref<3, scale - 2>(), col);
1135 out.template ref<2,
scale - 1>() = col;
1136 out.template ref<3,
scale - 1>() = col;
1137 out.template ref<4,
scale - 1>() = col;
1138 out.template ref<4,
scale - 2>() = col;
1141 template <
class OutputMatrix>
1142 static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out)
1144 alphaBlend<1, 4>(out.template ref<0, scale - 1>(), col);
1145 alphaBlend<1, 4>(out.template ref<2, scale - 2>(), col);
1146 alphaBlend<3, 4>(out.template ref<1, scale - 1>(), col);
1148 alphaBlend<1, 4>(out.template ref<scale - 1, 0>(), col);
1149 alphaBlend<1, 4>(out.template ref<scale - 2, 2>(), col);
1150 alphaBlend<3, 4>(out.template ref<scale - 1, 1>(), col);
1152 out.template ref<2,
scale - 1>() = col;
1153 out.template ref<3,
scale - 1>() = col;
1155 out.template ref<
scale - 1, 2>() = col;
1156 out.template ref<
scale - 1, 3>() = col;
1158 out.template ref<4,
scale - 1>() = col;
1160 alphaBlend<2, 3>(out.template ref<3, 3>(), col);
1163 template <
class OutputMatrix>
1164 static void blendLineDiagonal(uint32_t col, OutputMatrix& out)
1166 alphaBlend<1, 8>(out.template ref<scale - 1, scale / 2 >(), col);
1167 alphaBlend<1, 8>(out.template ref<scale - 2, scale / 2 + 1>(), col);
1168 alphaBlend<1, 8>(out.template ref<scale - 3, scale / 2 + 2>(), col);
1170 alphaBlend<7, 8>(out.template ref<4, 3>(), col);
1171 alphaBlend<7, 8>(out.template ref<3, 4>(), col);
1173 out.template ref<4, 4>() = col;
1176 template <
class OutputMatrix>
1177 static void blendCorner(uint32_t col, OutputMatrix& out)
1180 alphaBlend<86, 100>(out.template ref<4, 4>(), col);
1181 alphaBlend<23, 100>(out.template ref<4, 3>(), col);
1182 alphaBlend<23, 100>(out.template ref<3, 4>(), col);
1190 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)
1195 return scaleImage<Scaler2x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1197 return scaleImage<Scaler3x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1199 return scaleImage<Scaler4x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1201 return scaleImage<Scaler5x>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
1207 bool xbrz::equalColor(uint32_t col1, uint32_t col2,
double luminanceWeight,
double equalColorTolerance)
1209 return colorDist(col1, col2, luminanceWeight) < equalColorTolerance;
1214 uint32_t* trg,
int trgWidth,
int trgHeight,
int trgPitch,
1217 if (srcPitch < srcWidth *
static_cast<int>(
sizeof(uint32_t)) ||
1218 trgPitch < trgWidth *
static_cast<int>(
sizeof(uint32_t)))
1228 yFirst = std::max(yFirst, 0);
1229 yLast = std::min(yLast, srcHeight);
1230 if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0)
return;
1232 for (
int y = yFirst; y < yLast; ++y)
1238 const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight;
1239 const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight;
1240 const int blockHeight = yTrg_last - yTrg_first;
1242 if (blockHeight > 0)
1244 const uint32_t* srcLine = byteAdvance(src, y * srcPitch);
1245 uint32_t* trgLine = byteAdvance(trg, yTrg_first * trgPitch);
1248 for (
int x = 0; x < srcWidth; ++x)
1250 int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
1251 const int blockWidth = xTrg_last - xTrg_first;
1254 xTrg_first = xTrg_last;
1255 fillBlock(trgLine, trgPitch, srcLine[x], blockWidth, blockHeight);
1256 trgLine += blockWidth;
1265 yFirst = std::max(yFirst, 0);
1266 yLast = std::min(yLast, trgHeight);
1267 if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0)
return;
1269 for (
int y = yFirst; y < yLast; ++y)
1271 uint32_t* trgLine = byteAdvance(trg, y * trgPitch);
1272 const int ySrc = srcHeight * y / trgHeight;
1273 const uint32_t* srcLine = byteAdvance(src, ySrc * srcPitch);
1274 for (
int x = 0; x < trgWidth; ++x)
1276 const int xSrc = srcWidth * x / trgWidth;
1277 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