17 #ifndef XBRZ_TOOLS_H_825480175091875
18 #define XBRZ_TOOLS_H_825480175091875
22 #include <type_traits>
27 template <u
int32_t N>
inline
28 unsigned char getByte(uint32_t val) {
return static_cast<unsigned char>((val >> (8 * N)) & 0xff); }
30 inline unsigned char getAlpha(uint32_t pix) {
return getByte<3>(pix); }
31 inline unsigned char getRed (uint32_t pix) {
return getByte<2>(pix); }
32 inline unsigned char getGreen(uint32_t pix) {
return getByte<1>(pix); }
33 inline unsigned char getBlue (uint32_t pix) {
return getByte<0>(pix); }
35 inline uint32_t
makePixel(
unsigned char a,
unsigned char r,
unsigned char g,
unsigned char b) {
return (a << 24) | (r << 16) | (
g << 8) |
b; }
36 inline uint32_t
makePixel(
unsigned char r,
unsigned char g,
unsigned char b) {
return (r << 16) | (
g << 8) |
b; }
38 inline uint32_t
rgb555to888(uint16_t pix) {
return ((pix & 0x7C00) << 9) | ((pix & 0x03E0) << 6) | ((pix & 0x001F) << 3); }
39 inline uint32_t
rgb565to888(uint16_t pix) {
return ((pix & 0xF800) << 8) | ((pix & 0x07E0) << 5) | ((pix & 0x001F) << 3); }
41 inline uint16_t
rgb888to555(uint32_t pix) {
return static_cast<uint16_t
>(((pix & 0xF80000) >> 9) | ((pix & 0x00F800) >> 6) | ((pix & 0x0000F8) >> 3)); }
42 inline uint16_t
rgb888to565(uint32_t pix) {
return static_cast<uint16_t
>(((pix & 0xF80000) >> 8) | ((pix & 0x00FC00) >> 5) | ((pix & 0x0000F8) >> 3)); }
45 template <
class Pix>
inline
49 using PixByte =
typename std::conditional<std::is_same<Pix, PixNonConst>::value, char,
const char>
::type;
51 static_assert(std::is_integral<PixNonConst>::value,
"Pix* is expected to be cast-able to char*");
53 return reinterpret_cast<Pix*
>(
reinterpret_cast<PixByte*
>(ptr) + bytes);
58 template <
class Pix>
inline
59 void fillBlock(Pix* trg,
int pitch , Pix col,
int blockWidth,
int blockHeight)
64 for (
int y = 0; y < blockHeight; ++y, trg =
byteAdvance(trg, pitch))
65 for (
int x = 0; x < blockWidth; ++x)
71 template <
class PixSrc,
class PixTrg,
class PixConverter>
73 PixTrg* trg,
int trgWidth,
int trgHeight,
int trgPitch ,
74 int yFirst,
int yLast, PixConverter pixCvrt )
76 static_assert(std::is_integral<PixSrc>::value,
"PixSrc* is expected to be cast-able to char*");
77 static_assert(std::is_integral<PixTrg>::value,
"PixTrg* is expected to be cast-able to char*");
79 static_assert(std::is_same<decltype(pixCvrt(PixSrc())), PixTrg>::value,
"PixConverter returning wrong pixel format");
81 if (srcPitch < srcWidth *
static_cast<int>(
sizeof(PixSrc)) ||
82 trgPitch < trgWidth *
static_cast<int>(
sizeof(PixTrg)))
88 yFirst = std::max(yFirst, 0);
89 yLast = std::min(yLast, trgHeight);
90 if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0)
return;
92 for (
int y = yFirst; y < yLast; ++y)
94 const int ySrc = srcHeight * y / trgHeight;
96 PixTrg*
const trgLine =
byteAdvance(trg, y * trgPitch);
98 for (
int x = 0; x < trgWidth; ++x)
100 const int xSrc = srcWidth * x / trgWidth;
101 trgLine[x] = pixCvrt(srcLine[xSrc]);
108 template <
class PixSrc,
class PixTrg,
class PixConverter>
110 PixTrg* trg,
int trgWidth,
int trgHeight,
int trgPitch ,
111 int yFirst,
int yLast, PixConverter pixCvrt )
113 static_assert(std::is_integral<PixSrc>::value,
"PixSrc* is expected to be cast-able to char*");
114 static_assert(std::is_integral<PixTrg>::value,
"PixTrg* is expected to be cast-able to char*");
116 static_assert(std::is_same<decltype(pixCvrt(PixSrc())), PixTrg>::value,
"PixConverter returning wrong pixel format");
118 if (srcPitch < srcWidth *
static_cast<int>(
sizeof(PixSrc)) ||
119 trgPitch < trgWidth *
static_cast<int>(
sizeof(PixTrg)))
125 yFirst = std::max(yFirst, 0);
126 yLast = std::min(yLast, srcHeight);
127 if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0)
return;
129 for (
int y = yFirst; y < yLast; ++y)
135 const int yTrgFirst = ( y * trgHeight + srcHeight - 1) / srcHeight;
136 const int yTrgLast = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight;
137 const int blockHeight = yTrgLast - yTrgFirst;
142 PixTrg* trgLine =
byteAdvance(trg, yTrgFirst * trgPitch);
145 for (
int x = 0; x < srcWidth; ++x)
147 const int xTrgLast = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
148 const int blockWidth = xTrgLast - xTrgFirst;
151 xTrgFirst = xTrgLast;
153 const auto trgPix = pixCvrt(srcLine[x]);
154 fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight);
155 trgLine += blockWidth;
163 template <
class PixTrg,
class PixConverter>
165 PixTrg* trg,
int trgWidth,
int trgHeight,
int trgPitch,
166 int yFirst,
int yLast, PixConverter pixCvrt )
168 static_assert(std::is_integral<PixTrg>::value,
"PixTrg* is expected to be cast-able to char*");
169 static_assert(std::is_same<decltype(pixCvrt(uint32_t())), PixTrg>::value,
"PixConverter returning wrong pixel format");
171 if (srcPitch < srcWidth *
static_cast<int>(
sizeof(uint32_t)) ||
172 trgPitch < trgWidth *
static_cast<int>(
sizeof(PixTrg)))
178 yFirst = std::max(yFirst, 0);
179 yLast = std::min(yLast, trgHeight);
180 if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0)
return;
182 const double scaleX =
static_cast<double>(trgWidth ) / srcWidth;
183 const double scaleY =
static_cast<double>(trgHeight) / srcHeight;
195 std::vector<CoeffsX> buf(trgWidth);
196 for (
int x = 0; x < trgWidth; ++x)
198 const int x1 = srcWidth * x / trgWidth;
200 if (x2 == srcWidth) --x2;
202 const double xx1 = x / scaleX - x1;
203 const double x2x = 1 - xx1;
205 buf[x] = { x1, x2, xx1, x2x };
208 for (
int y = yFirst; y < yLast; ++y)
210 const int y1 = srcHeight * y / trgHeight;
212 if (y2 == srcHeight) --y2;
214 const double yy1 = y / scaleY - y1;
215 const double y2y = 1 - yy1;
218 const uint32_t*
const srcLineNext =
byteAdvance(
src, y2 * srcPitch);
219 PixTrg*
const trgLine =
byteAdvance(trg, y * trgPitch);
221 for (
int x = 0; x < trgWidth; ++x)
224 const int x1 = buf[x].x1;
225 const int x2 = buf[x].x2;
226 const double xx1 = buf[x].xx1;
227 const double x2x = buf[x].x2x;
229 const double x2xy2y = x2x * y2y;
230 const double xx1y2y = xx1 * y2y;
231 const double x2xyy1 = x2x * yy1;
232 const double xx1yy1 = xx1 * yy1;
234 auto interpolate = [=](
int offset)
239 const auto c11 = (srcLine [x1] >> (8 * offset)) & 0xff;
240 const auto c21 = (srcLine [x2] >> (8 * offset)) & 0xff;
241 const auto c12 = (srcLineNext[x1] >> (8 * offset)) & 0xff;
242 const auto c22 = (srcLineNext[x2] >> (8 * offset)) & 0xff;
244 return c11 * x2xy2y + c21 * xx1y2y +
245 c12 * x2xyy1 + c22 * xx1yy1;
248 const double bi = interpolate(0);
249 const double gi = interpolate(1);
250 const double ri = interpolate(2);
251 const double ai = interpolate(3);
253 const auto b =
static_cast<uint32_t
>(bi + 0.5);
254 const auto g =
static_cast<uint32_t
>(gi + 0.5);
255 const auto r =
static_cast<uint32_t
>(ri + 0.5);
256 const auto a =
static_cast<uint32_t
>(
ai + 0.5);
258 const uint32_t trgPix = (a << 24) | (r << 16) | (
g << 8) |
b;
260 trgLine[x] = pixCvrt(trgPix);
A small explanation about what's going on here: Each action has access to two game_info objects First...
unsigned char getRed(uint32_t pix)
uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b)
uint32_t rgb565to888(uint16_t pix)
Pix * byteAdvance(Pix *ptr, int bytes)
unsigned char getBlue(uint32_t pix)
uint32_t rgb555to888(uint16_t pix)
unsigned char getGreen(uint32_t pix)
unsigned char getByte(uint32_t val)
void nearestNeighborScaleOverSource(const PixSrc *src, int srcWidth, int srcHeight, int srcPitch, PixTrg *trg, int trgWidth, int trgHeight, int trgPitch, int yFirst, int yLast, PixConverter pixCvrt)
void nearestNeighborScale(const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight)
uint16_t rgb888to555(uint32_t pix)
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)
uint16_t rgb888to565(uint32_t pix)
rect src
Non-transparent portion of the surface to compose.