34 #include <SDL3/SDL_version.h>
36 #include <boost/circular_buffer.hpp>
37 #include <boost/math/constants/constants.hpp>
40 #define ERR_DP LOG_STREAM(err, log_display)
44 int linked_sdl_version = SDL_GetVersion();
45 return version_info(SDL_VERSIONNUM_MAJOR(linked_sdl_version), SDL_VERSIONNUM_MINOR(linked_sdl_version), SDL_VERSIONNUM_MICRO(linked_sdl_version));
50 int linked_sdl_version = SDL_GetVersion();
51 if(SDL_VERSIONNUM_MAJOR(linked_sdl_version) < major)
return false;
52 if(SDL_VERSIONNUM_MAJOR(linked_sdl_version) > major)
return true;
54 if(SDL_VERSIONNUM_MINOR(linked_sdl_version) < minor)
return false;
55 if(SDL_VERSIONNUM_MINOR(linked_sdl_version) > minor)
return true;
57 if(SDL_VERSIONNUM_MICRO(linked_sdl_version) < patch)
return false;
83 if(
surf ==
nullptr ||
dst ==
nullptr) {
84 PLAIN_LOG <<
"Could not create surface to scale onto";
112 if (
w == 0 ||
h ==0) {
117 if(
surf ==
nullptr ||
dst ==
nullptr) {
118 PLAIN_LOG <<
"Could not create surface to scale onto";
126 const uint32_t*
const src_pixels = src_lock.
pixels();
127 uint32_t*
const dst_pixels = dst_lock.
pixels();
133 for(
int ydst = 0; ydst !=
h; ++ydst, ysrc += yratio) {
135 for(
int xdst = 0; xdst !=
w; ++xdst, xsrc += xratio) {
139 const uint32_t*
const src_word = src_pixels + ysrcint*
surf->w + xsrcint;
140 uint32_t*
const dst_word = dst_pixels + ydst*
dst->w + xdst;
141 const int dx = (xsrcint + 1 <
surf->w) ? 1 : 0;
142 const int dy = (ysrcint + 1 <
surf->h) ?
surf->w : 0;
145 uint32_t rr,gg,bb,aa, temp;
147 uint32_t pix[4], bilin[4];
170 const int32_t
e = 0x000000FF & xsrc;
171 const int32_t
s = 0x000000FF & ysrc;
172 const int32_t
n = 0xFF -
s;
175 const int32_t we = 0xFF -
e;
178 pix[1] = *(src_word + dx);
179 pix[2] = *(src_word + dy);
180 pix[3] = *(src_word + dx + dy);
188 rr = bb = gg = aa = 0;
201 temp = (a * bilin[
loc]);
217 *dst_word = (a << 24) + (r << 16) + (
g << 8) +
b;
238 if(
surf ==
nullptr ||
dst ==
nullptr) {
239 PLAIN_LOG <<
"Could not create surface to scale onto";
247 const uint32_t*
const src_pixels = src_lock.
pixels();
248 uint32_t*
const dst_pixels = dst_lock.
pixels();
254 for(
int ydst = 0; ydst !=
h; ++ydst, ysrc += yratio) {
256 for(
int xdst = 0; xdst !=
w; ++xdst, xsrc += xratio) {
260 const uint32_t*
const src_word = src_pixels + ysrcint*
surf->w + xsrcint;
261 uint32_t*
const dst_word = dst_pixels + ydst*
dst->w + xdst;
262 const int dx = (xsrcint + 1 <
surf->w) ? 1 : 0;
263 const int dy = (ysrcint + 1 <
surf->h) ?
surf->w : 0;
266 uint32_t rr,gg,bb,aa;
267 uint16_t avg_r, avg_g, avg_b;
268 uint32_t pix[4], bilin[4];
282 const int32_t east = 0x000000FF & xsrc;
283 const int32_t south = 0x000000FF & ysrc;
284 const int32_t north = 0xFF - south;
285 const int32_t west = 0xFF - east;
288 pix[1] = *(src_word + dx);
289 pix[2] = *(src_word + dy);
290 pix[3] = *(src_word + dx + dy);
292 bilin[0] = north*west;
293 bilin[1] = north*east;
294 bilin[2] = south*west;
295 bilin[3] = south*east;
301 avg_r = avg_g = avg_b = 0;
330 rr = gg = bb = aa = 0;
337 r =
static_cast<uint8_t
>(avg_r);
338 g =
static_cast<uint8_t
>(avg_g);
339 b =
static_cast<uint8_t
>(avg_b);
341 rr += r * bilin[
loc];
342 gg +=
g * bilin[
loc];
343 bb +=
b * bilin[
loc];
344 aa += a * bilin[
loc];
350 *dst_word = (a << 24) + (r << 16) + (
g << 8) +
b;
360 if(
surf ==
nullptr) {
371 PLAIN_LOG <<
"Could not create surface to scale onto";
375 if(
w == 0 ||
h == 0) {
384 const uint32_t*
const src_pixels = src_lock.
pixels();
385 uint32_t*
const dst_pixels = dst_lock.
pixels();
387 const int src_w =
surf->w;
388 const int src_h =
surf->h;
390 const float xratio =
static_cast<float>(src_w) /
static_cast<float>(
w);
391 const float yratio =
static_cast<float>(src_h) /
static_cast<float>(
h);
392 for(
int ydst = 0; ydst !=
h; ++ydst) {
393 for(
int xdst = 0; xdst !=
w; ++xdst) {
395 const int xsrc = std::floor(
static_cast<float>(xdst) * xratio);
396 const int ysrc = std::floor(
static_cast<float>(ydst) * yratio);
397 dst_pixels[ydst *
dst->w + xdst] = src_pixels[ysrc * src_w + xsrc];
407 if(nsurf && (red != 0 || green != 0 || blue != 0)) {
414 for(
auto& pixel :
pixel_span.subspan(simd_processed)) {
416 r = std::clamp(
static_cast<int>(r) + red, 0, 255);
417 g = std::clamp(
static_cast<int>(
g) + green, 0, 255);
418 b = std::clamp(
static_cast<int>(
b) + blue, 0, 255);
419 pixel = (alpha << 24) + (r << 16) + (
g << 8) +
b;
436 const uint8_t avg =
static_cast<uint8_t
>((
437 77 *
static_cast<uint16_t
>(r) +
438 150 *
static_cast<uint16_t
>(
g) +
439 29 *
static_cast<uint16_t
>(
b) ) / 256);
441 pixel = (alpha << 24) | (avg << 16) | (avg << 8) | avg;
457 uint8_t result =
static_cast<uint8_t
>(0.299 * r + 0.587 *
g + 0.114 *
b) > threshold ? 255 : 0;
459 pixel = (alpha << 24) | (result << 16) | (result << 8) | result;
474 uint8_t outR = std::min(255,
static_cast<int>((r * 0.393) + (
g * 0.769) + (
b * 0.189)));
475 uint8_t outG = std::min(255,
static_cast<int>((r * 0.349) + (
g * 0.686) + (
b * 0.168)));
476 uint8_t outB = std::min(255,
static_cast<int>((r * 0.272) + (
g * 0.534) + (
b * 0.131)));
478 pixel = (alpha << 24) | (outR << 16) | (outG << 8) | (outB);
495 uint8_t newR = r > thresholdR ? 255 - r : r;
496 uint8_t newG =
g > thresholdG ? 255 -
g :
g;
497 uint8_t newB =
b > thresholdB ? 255 -
b :
b;
499 pixel = (alpha << 24) | (newR << 16) | (newG << 8) | (newB);
510 uint8_t alpha = pixel >> 24;
512 pixel = (0xff << 24) | (alpha << 16) | (alpha << 8) | alpha;
523 pixel = 0xff000000 | pixel;
541 uint8_t alpha = pixel >> 24;
545 if(alpha < 255 / 4) {
546 pixel = (alpha * 4) << 24;
561 uint8_t newRed, newGreen, newBlue, newAlpha;
631 pixel = (newAlpha << 24) | (newRed << 16) | (newGreen << 8) | newBlue;
641 if(map_rgb.empty()) {
651 uint8_t old_alpha = color.a;
654 auto iter = map_rgb.find(color);
655 if(iter == map_rgb.end()) {
660 color = iter->second;
663 pixel = color.to_argb_bytes();
672 if (amount < 0) amount = 0;
680 pixel = (alpha << 24) + (r << 16) + (
g << 8) +
b;
687 if(
surf ==
nullptr) {
691 SDL_SetSurfaceAlphaMod(
surf, alpha_mod);
702 alpha = uint8_t(std::clamp(
static_cast<int>(alpha) + amount, 0, 255));
703 pixel = (alpha << 24) + (r << 16) + (
g << 8) +
b;
710 if(nsurf ==
nullptr) {
713 if(nmask ==
nullptr) {
717 if(nsurf->w != nmask->w) {
722 std::stringstream ss;
723 ss <<
"Detected an image with bad dimensions: ";
725 ss << nsurf->w <<
"x" << nsurf->h;
727 PLAIN_LOG <<
"It will not be masked, please use: "<< nmask->w <<
"x" << nmask->h;
731 uint32_t cumulative_alpha{0};
734 bool simd_empty =
true;
736 if(simd_processed > 0) {
737 cumulative_alpha = simd_empty ? 0 : 1;
747 for(std::size_t
i = 0;
i < surf_sub.
size(); ++
i) {
750 cumulative_alpha |= min_alpha;
753 return cumulative_alpha == 0;
758 if(nsurf ==
nullptr) {
761 if(nmask ==
nullptr){
765 if (nsurf->w != nmask->w || nsurf->h != nmask->h ) {
777 for(std::size_t
i = 0;
i < surf_pixels.
size(); ++
i) {
782 if(surf_alpha && mask_alpha == 0) {
792 if(nsurf ==
nullptr) {
795 if(lightmap ==
nullptr) {
799 if (nsurf->w != lightmap->w) {
804 PLAIN_LOG <<
"Detected an image with bad dimensions: " << nsurf->w <<
"x" << nsurf->h;
805 PLAIN_LOG <<
"It will not be lighted, please use: "<< lightmap->w <<
"x" << lightmap->h;
812 uint32_t* beg = lock.
pixels();
813 uint32_t* end = beg + nsurf.
area();
814 const uint32_t* lbeg = llock.
pixels();
815 const uint32_t* lend = lbeg + lightmap.
area();
817 while(beg != end && lbeg != lend) {
821 int dr = (
static_cast<int>(lr) - 128) * 2;
822 int dg = (
static_cast<int>(
lg) - 128) * 2;
823 int db = (
static_cast<int>(lb) - 128) * 2;
826 r = std::clamp(r + dr, 0, 255);
827 g = std::clamp(
g + dg, 0, 255);
828 b = std::clamp(
b + db, 0, 255);
830 *beg = (alpha << 24) + (r << 16) + (
g << 8) +
b;
840 if(
surf ==
nullptr) {
844 const int max_blur = 256;
845 if(depth > max_blur) {
849 uint32_t queue[max_blur];
850 const uint32_t* end_queue = queue + max_blur;
852 const uint32_t ff = 0xff;
854 const unsigned pixel_offset =
rect.y *
surf->w +
rect.x;
857 for(
int y = 0; y <
rect.h; ++y) {
858 const uint32_t* front = &queue[0];
859 uint32_t* back = &queue[0];
860 uint32_t red = 0, green = 0, blue = 0, avg = 0;
861 uint32_t*
p = lock.
pixels() + pixel_offset + y *
surf->w;
862 for(
int x = 0; x <= depth && x <
rect.w; ++x, ++
p) {
863 red += ((*p) >> 16)&0xFF;
864 green += ((*p) >> 8)&0xFF;
868 if(back == end_queue) {
874 for(
int x = 0; x <
rect.w; ++x, ++
p) {
876 | (std::min(red/avg,ff) << 16)
877 | (std::min(green/avg,ff) << 8)
878 | std::min(blue/avg,ff);
881 red -= ((*front) >> 16)&0xFF;
882 green -= ((*front) >> 8)&0xFF;
886 if(front == end_queue) {
891 if(x + depth+1 <
rect.w) {
892 uint32_t* q =
p + depth+1;
893 red += ((*q) >> 16)&0xFF;
894 green += ((*q) >> 8)&0xFF;
898 if(back == end_queue) {
905 for(
int x = 0; x <
rect.w; ++x) {
906 const uint32_t* front = &queue[0];
907 uint32_t* back = &queue[0];
908 uint32_t red = 0, green = 0, blue = 0, avg = 0;
909 uint32_t*
p = lock.
pixels() + pixel_offset + x;
910 for(
int y = 0; y <= depth && y <
rect.h; ++y,
p +=
surf->w) {
911 red += ((*p) >> 16)&0xFF;
912 green += ((*p) >> 8)&0xFF;
916 if(back == end_queue) {
921 p = lock.
pixels() + pixel_offset + x;
922 for(
int y = 0; y <
rect.h; ++y,
p +=
surf->w) {
924 | (std::min(red/avg,ff) << 16)
925 | (std::min(green/avg,ff) << 8)
926 | std::min(blue/avg,ff);
929 red -= ((*front) >> 16)&0xFF;
930 green -= ((*front) >> 8)&0xFF;
934 if(front == end_queue) {
939 if(y + depth+1 <
rect.h) {
940 uint32_t* q =
p + (depth+1)*
surf->w;
941 red += ((*q) >> 16)&0xFF;
942 green += ((*q) >> 8)&0xFF;
946 if(back == end_queue) {
960 const int max_blur = 256;
961 if(depth > max_blur) {
971 : alpha(((*
p) >> 24)&0xFF)
972 , red(((*
p) >> 16)&0xFF)
973 , green(((*
p) >> 8)&0xFF)
981 Average() : alpha(), red(), green(), blue()
983 Average& operator+=(
const Pixel& pix){
984 red += pix.alpha * pix.red;
985 green += pix.alpha * pix.green;
986 blue += pix.alpha * pix.blue;
990 Average& operator-=(
const Pixel& pix){
991 red -= pix.alpha * pix.red;
992 green -= pix.alpha * pix.green;
993 blue -= pix.alpha * pix.blue;
997 uint32_t operator()(
unsigned num){
998 const uint32_t ff = 0xff;
1002 return (std::min(alpha/num,ff) << 24)
1003 | (std::min(red/alpha,ff) << 16)
1004 | (std::min(green/alpha,ff) << 8)
1005 | std::min(blue/alpha,ff);
1009 boost::circular_buffer<Pixel> queue(depth*2+1);
1014 for(y = 0; y < res->h; ++y) {
1019 uint32_t*
p = lock.
pixels() + y*res->w;
1020 for(x = 0; x <= depth && x < res->w; ++x, ++
p) {
1021 assert(!queue.full());
1022 queue.push_back(Pixel{
p});
1023 avg += queue.back();
1028 for(x = 0; x < res->w; ++x, ++
p) {
1030 const uint32_t num = queue.
size();
1035 avg -= queue.front();
1036 assert(!queue.empty());
1041 if(x + depth+1 < res->w) {
1042 uint32_t* q =
p + depth+1;
1043 assert(!queue.full());
1044 queue.push_back(Pixel{q});
1045 avg += queue.back();
1048 assert(
static_cast<int>(queue.size()) == std::min(depth, res->w));
1053 for(x = 0; x < res->w; ++x) {
1058 uint32_t*
p = lock.
pixels() + x;
1059 for(y = 0; y <= depth && y < res->h; ++y,
p += res->w) {
1060 assert(!queue.full());
1061 queue.push_back(Pixel{
p});
1062 avg += queue.back();
1067 for(y = 0; y < res->h; ++y,
p += res->w) {
1069 const uint32_t num = queue.size();
1074 avg -= queue.front();
1075 assert(!queue.empty());
1080 if(y + depth+1 < res->h) {
1081 uint32_t* q =
p + (depth+1)*res->w;
1082 assert(!queue.full());
1083 queue.push_back(Pixel{q});
1084 avg += queue.back();
1087 assert(
static_cast<int>(queue.size()) == std::min(depth, res->h));
1099 if(res ==
nullptr) {
1100 PLAIN_LOG <<
"Could not create a new surface in cut_surface()";
1104 const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(
surf->format);
1106 std::size_t sbpp = details->bytes_per_pixel;
1107 std::size_t spitch =
surf->pitch;
1108 std::size_t rbpp = details->bytes_per_pixel;
1109 std::size_t rpitch = res->pitch;
1113 rect dst_rect { 0, 0, r.w, r.h };
1115 if (src_rect.x < 0) {
1116 if (src_rect.x + src_rect.w <= 0)
1118 dst_rect.x -= src_rect.x;
1119 dst_rect.w += src_rect.x;
1120 src_rect.w += src_rect.x;
1123 if (src_rect.y < 0) {
1124 if (src_rect.y + src_rect.h <= 0)
1126 dst_rect.y -= src_rect.y;
1127 dst_rect.h += src_rect.y;
1128 src_rect.h += src_rect.y;
1132 if(src_rect.x >=
surf->w || src_rect.y >=
surf->h)
1138 const uint8_t*
src =
reinterpret_cast<const uint8_t *
>(slock.
pixels());
1139 uint8_t* dest =
reinterpret_cast<uint8_t *
>(rlock.
pixels());
1141 for(
int y = 0; y < src_rect.h && (src_rect.y + y) <
surf->h; ++y) {
1142 const uint8_t* line_src =
src + (src_rect.y + y) * spitch + src_rect.x * sbpp;
1143 uint8_t* line_dest = dest + (dst_rect.y + y) * rpitch + dst_rect.x * rbpp;
1144 std::size_t
size = src_rect.w + src_rect.x <=
surf->w ? src_rect.w :
surf->w - src_rect.x;
1146 assert(rpitch >= src_rect.w * rbpp);
1147 memcpy(line_dest, line_src,
size * rbpp);
1158 uint16_t ratio = amount * 256;
1159 const uint16_t red = ratio * color.r;
1160 const uint16_t green = ratio * color.g;
1161 const uint16_t blue = ratio * color.b;
1162 ratio = 256 - ratio;
1167 r = (ratio * r + red) >> 8;
1168 g = (ratio *
g + green) >> 8;
1169 b = (ratio *
b + blue) >> 8;
1171 pixel = (a << 24) | (r << 16) | (
g << 8) |
b;
1183 int src_w, src_h, dst_w, dst_h;
1184 float min_x, min_y, sine, cosine;
1188 const float radians = angle * boost::math::constants::pi<float>() / 180;
1189 cosine = std::cos(radians);
1190 sine = std::sin(radians);
1192 src_w =
surf->w * zoom;
1193 src_h =
surf->h * zoom;
1195 const float point_1x = src_h * -sine;
1196 const float point_1y = src_h * cosine;
1197 const float point_2x = src_w * cosine - src_h * sine;
1198 const float point_2y = src_h * cosine + src_w * sine;
1199 const float point_3x = src_w * cosine;
1200 const float point_3y = src_w * sine;
1204 min_x = std::min(0.0F, std::min(point_1x, std::min(point_2x, point_3x)));
1205 min_y = std::min(0.0F, std::min(point_1y, std::min(point_2y, point_3y)));
1206 max_x = (angle > 90 && angle < 180) ? 0 : std::max(point_1x, std::max(point_2x, point_3x));
1207 max_y = (angle > 180 && angle < 270) ? 0 : std::max(point_1y, std::max(point_2y, point_3y));
1208 dst_w =
static_cast<int>(ceil(std::abs(max_x) - min_x)) / zoom;
1209 dst_h =
static_cast<int>(ceil(std::abs(max_y) - min_y)) / zoom;
1214 uint32_t*
const dst_pixels = dst_lock.
pixels();
1218 const uint32_t*
const src_pixels = src_lock.
pixels();
1220 const float scale = 1.f / zoom;
1221 const int max_x = dst_w * zoom;
1222 const int max_y = dst_h * zoom;
1225 for (
int x = 0; x < max_x; x += offset)
1226 for (
int y = 0; y < max_y; y += offset) {
1228 const float source_x = (x + min_x)*cosine + (y + min_y)*sine;
1229 const float source_y = (y + min_y)*cosine - (x + min_x)*sine;
1231 if (source_x >= 0 && source_x < src_w && source_y >= 0 && source_y < src_h) {
1234 src_pixels[int(source_y) *
src->w + int(source_x)];
1245 if (
surf ==
nullptr )
1250 if ( nsurf ==
nullptr ) {
1251 PLAIN_LOG <<
"could not make neutral surface...";
1257 uint32_t*
const pixels = lock.
pixels();
1261 for (
int y=0; y != nsurf->h/2; ++y) {
1262 for(
int x=0; x != nsurf->w; ++x) {
1263 const int index1 = y*nsurf->w + x;
1264 const int index2 = (nsurf->h-y)*nsurf->w - x - 1;
1265 std::swap(pixels[index1],pixels[index2]);
1269 if (
is_odd(nsurf->h) ) {
1271 for (
int x=0; x != nsurf->w/2; ++x) {
1272 const int index1 = (nsurf->h/2)*nsurf->w + x;
1273 const int index2 = (nsurf->h/2)*nsurf->w + (nsurf->w - x - 1);
1274 std::swap(pixels[index1],pixels[index2]);
1290 if (
surf ==
nullptr ||
dst ==
nullptr ) {
1291 PLAIN_LOG <<
"could not make neutral surface...";
1299 const uint32_t*
const src_pixels = src_lock.
pixels();
1300 uint32_t*
const dst_pixels = dst_lock.
pixels();
1303 for(
int y = 0; y !=
surf->h; ++y) {
1304 for (
int x = 0; x !=
surf->w; ++x ) {
1305 const int src_index = y*
surf->w + x;
1306 const int dst_index = clockwise ?
1307 x*
dst->w + (
dst->w-1-y) :
1309 dst_pixels[dst_index] = src_pixels[src_index];
1326 uint32_t*
const pixels = lock.
pixels();
1327 const std::size_t width =
static_cast<std::size_t
>(nsurf->w);
1328 const std::size_t height =
static_cast<std::size_t
>(nsurf->h);
1329 const std::size_t half_width = width / 2;
1330 for(std::size_t y = 0; y < height; ++y) {
1331 for(std::size_t x = simd_x_processed; x < half_width; ++x) {
1332 const std::size_t index1 = y * width + x;
1333 const std::size_t index2 = y * width + (width - x - 1);
1334 std::swap(pixels[index1], pixels[index2]);
1344 uint32_t*
const pixels = lock.
pixels();
1346 for(
int x = 0; x != nsurf->w; ++x) {
1347 for(
int y = 0; y != nsurf->h/2; ++y) {
1348 const int index1 = y*nsurf->w + x;
1349 const int index2 = (nsurf->h-y-1)*nsurf->w + x;
1350 std::swap(pixels[index1],pixels[index2]);
1358 if (
src ==
nullptr) {
1363 if(area.x >=
src->w || area.y >=
src->h || area.x + area.w < 0 || area.y + area.h < 0) {
1367 if(area.x + area.w >
src->w) {
1368 area.w =
src->w - area.x;
1370 if(area.y + area.h >
src->h) {
1371 area.h =
src->h - area.y;
1377 if(
dst ==
nullptr) {
1378 PLAIN_LOG <<
"Could not create a new surface in get_surface_portion()";
1383 SDL_BlendMode src_blend;
1384 SDL_GetSurfaceBlendMode(
src, &src_blend);
1385 SDL_SetSurfaceBlendMode(
src, SDL_BLENDMODE_NONE);
1386 SDL_BlitSurface(
src, &area,
dst,
nullptr);
1387 SDL_SetSurfaceBlendMode(
src, src_blend);
1394 if(
surf ==
nullptr)
return;
1398 if(alpha_mod == 255)
return;
1406 for(
auto& pixel :
pixel_span.subspan(simd_processed)) {
1407 uint8_t alpha = pixel >> 24;
1411 pixel = (alpha << 24) | (r << 16) | (
g << 8) |
b;
1418 template<
typename Range>
1419 bool contains_non_transparent_pixel(
const Range& span)
1421 return std::any_of(span.begin(), span.end(),
1422 [](uint32_t pixel) { return (pixel & SDL_ALPHA_MASK) != 0; });
1433 auto cover_distance(
int i1,
int i2)
1435 return (i2 - i1) + 1;
1445 const auto row_is_not_transparent = [&](std::size_t y) {
1447 return contains_non_transparent_pixel(row_span);
1450 const auto column_is_not_transparent = [&](std::size_t x) {
1454 return contains_non_transparent_pixel(column_span);
1460 for(
int y = 0; y <
surf->h; ++y) {
1461 if(row_is_not_transparent(y)) {
1468 for(
int y =
surf->h - 1; y >= res.y; --y) {
1469 if(row_is_not_transparent(y)) {
1470 res.h = cover_distance(res.y, y);
1477 static_cast<std::size_t
>(res.y) *
surf->w,
1478 static_cast<std::size_t
>(res.h) *
surf->w);
1481 for(
int x = 0; x <
surf->w; ++x) {
1482 if(column_is_not_transparent(x)) {
1489 for(
int x =
surf->w - 1; x >= res.x; --x) {
1490 if(column_is_not_transparent(x)) {
1491 res.w = cover_distance(res.x, x);
constexpr std::enable_if< C==dynamic_extent, span< T, detail::span_sub< E, O >::value > >::type subspan() const
constexpr size_type size() const noexcept
Helper class for pinning SDL surfaces into memory.
utils::span< pixel_t > pixel_span() const
point size() const
Dimensions of the surface.
surface clone() const
Creates a new, duplicate surface in memory using the 'neutral' pixel format.
std::size_t area() const
Total area of the surface in square pixels.
Represents version numbers.
constexpr uint8_t ALPHA_OPAQUE
constexpr uint32_t SDL_ALPHA_MASK
constexpr uint8_t color_multiply(uint8_t n1, uint8_t n2)
Multiply two 8-bit colour values as if in the range [0.0,1.0].
constexpr uint8_t float_to_color(double n)
Convert a double in the range [0.0,1.0] to an 8-bit colour value.
std::unordered_map< color_t, color_t > color_mapping
void swap(config &lhs, config &rhs) noexcept
Implement non-member swap function for std::swap (calls config::swap).
Standard logging facilities (interface).
constexpr int fixed_point_to_int(int32_t n)
If positive, just bit shift.
constexpr bool is_odd(T num)
constexpr unsigned fixed_point_multiply(int32_t n1, int32_t n2)
constexpr int32_t fixed_point_divide(int n1, int n2)
version_info get_version()
Returns the runtime SDL version.
bool runtime_at_least(uint8_t major, uint8_t minor=0, uint8_t patch=0)
Returns true if the runtime SDL version is at or greater than the specified version,...
bool is_enabled()
Checks if SIMD hardware acceleration is allowed/enabeled.
auto pixel_span(const surface &surf)
Returns a read-only view over to surf's underlying pixel array.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
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())
const int SCALE_FACTOR_MAX
Contains the SDL_Rect helper code.
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
The basic class for representing 8-bit RGB or RGBA colour values.
static constexpr color_t from_argb_bytes(uint32_t c)
Creates a new color_t object from a uint32_t variable.
An abstract description of a rectangle with integer coordinates.
static map_location::direction n
static map_location::direction s
surface get_surface_portion(const surface &src, rect &area)
Get a portion of the screen.
void alpha_to_greyscale(surface &nsurf)
void recolor_image(surface &nsurf, const color_mapping &map_rgb)
Recolors a surface using a map with source and converted palette values.
surface scale_surface_legacy(const surface &surf, int w, int h)
Scale a surface using simple bilinear filtering (discarding rgb from source pixels with 0 alpha)
void blur_surface(surface &surf, rect rect, int depth)
Cross-fades a surface in place.
void wipe_alpha(surface &nsurf)
surface cut_surface(const surface &surf, const rect &r)
Cuts a rectangle from a surface.
void brighten_image(surface &nsurf, int32_t amount)
void adjust_surface_alpha(surface &surf, uint8_t alpha_mod)
void sepia_image(surface &nsurf)
void adjust_surface_alpha_add(surface &nsurf, int amount)
void blend_surface(surface &nsurf, const double amount, const color_t color)
Blends a surface with a color.
void swap_channels_image(surface &nsurf, channel r, channel g, channel b, channel a)
rect get_non_transparent_portion(const surface &surf)
void adjust_surface_color(surface &nsurf, int red, int green, int blue)
void negative_image(surface &nsurf, const int thresholdR, const int thresholdG, const int thresholdB)
void shadow_image(surface &surf, int scale)
create an heavy shadow of the image, by blurring, increasing alpha and darkening
static lg::log_domain log_display("display")
void light_surface(surface &nsurf, const surface &lightmap)
Light surf using lightmap.
surface scale_surface_xbrz(const surface &surf, std::size_t z)
Scale a surface using xBRZ algorithm.
bool in_mask_surface(const surface &nsurf, const surface &nmask)
Checks if the source surface is entirely covered by the visible area of the mask.
surface scale_surface_sharp(const surface &surf, int w, int h)
Scale a surface using modified nearest neighbour algorithm.
void blur_alpha_surface(surface &res, int depth)
Cross-fades a surface with alpha channel.
void greyscale_image(surface &nsurf)
void apply_surface_opacity(surface &surf, float opacity)
Applies an opacity modification to a surface.
void flop_surface(surface &nsurf)
surface rotate_90_surface(const surface &surf, bool clockwise)
Rotates a surface 90 degrees.
surface rotate_180_surface(const surface &surf)
Rotates a surface 180 degrees.
void flip_surface(surface &nsurf)
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
surface rotate_any_surface(const surface &surf, float angle, int zoom, int offset)
Rotates a surface by any degrees.
void monochrome_image(surface &nsurf, const int threshold)
bool mask_surface(surface &nsurf, const surface &nmask, const std::string &filename)
Applies a mask to the source surface by calculating the minimum alpha channel value for every corresp...
std::size_t flip_image_simd(surface &surf)
Flips each row of pixels (horizontal mirror) using SIMD.
std::size_t adjust_surface_color_simd(surface &surf, const int r, const int g, const int b)
Adjusts the color channels of a surface using saturated SIMD arithmetic.
std::size_t apply_surface_opacity_simd(surface &surf, const uint8_t alpha_mod)
Applies an alpha modification to the whole surface using SIMD.
std::size_t mask_surface_simd(surface &surf, const surface &mask, bool &empty)
Modifies the alpha channel of the surface pixels based on the mask.
SIMD-accelerated helper functions for image manipulation.