The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
utils.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Support-routines for the SDL-graphics-library.
18  */
19 
20 #include "global.hpp"
21 #include "color_range.hpp"
22 
23 #include "sdl/utils.hpp"
24 #include "sdl/alpha.hpp"
25 #include "sdl/rect.hpp"
26 
28 #include "neon.hpp"
29 #include "video.hpp"
30 #include "xBRZ/xbrz.hpp"
31 
32 #include <algorithm>
33 #include <cassert>
34 #include <cstring>
35 #include <iostream>
36 
37 #include <boost/math/constants/constants.hpp>
38 
39 surface_lock::surface_lock(surface &surf) : surface_(surf), locked_(false)
40 {
41  if (SDL_MUSTLOCK(surface_))
42  locked_ = SDL_LockSurface(surface_) == 0;
43 }
44 
46 {
47  if (locked_)
48  SDL_UnlockSurface(surface_);
49 }
50 
51 const_surface_lock::const_surface_lock(const surface &surf) : surface_(surf), locked_(false)
52 {
53  if (SDL_MUSTLOCK(surface_))
54  locked_ = SDL_LockSurface(surface_) == 0;
55 }
56 
58 {
59  if (locked_)
60  SDL_UnlockSurface(surface_);
61 }
62 
63 SDL_Color int_to_color(const Uint32 rgb)
64 {
65  SDL_Color result;
66  result.r = (0x00FF0000 & rgb )>> 16;
67  result.g = (0x0000FF00 & rgb) >> 8;
68  result.b = (0x000000FF & rgb);
69 #ifdef SDL_GPU
70  result.unused = SDL_ALPHA_OPAQUE;
71 #else
72  result.a = SDL_ALPHA_OPAQUE;
73 #endif
74  return result;
75 }
76 
77 SDL_Color string_to_color(const std::string& color_string)
78 {
79  SDL_Color color;
80 
81  std::vector<Uint32> temp_rgb;
82  if(string2rgb(color_string, temp_rgb) && !temp_rgb.empty()) {
83  color = int_to_color(temp_rgb[0]);
84  }
85 
86  return color;
87 }
88 
89 SDL_Color create_color(const unsigned char red
90  , unsigned char green
91  , unsigned char blue
92  , unsigned char alpha)
93 {
94  SDL_Color result;
95  result.r = red;
96  result.g = green;
97  result.b = blue;
98  result.a = alpha;
99 
100  return result;
101 }
102 
104 {
105  return SDL_GetKeyFromName(keyname.c_str());
106 }
107 
108 bool operator<(const surface& a, const surface& b)
109 {
110  return a.get() < b.get();
111 }
112 
113 bool is_neutral(const surface& surf)
114 {
115  return (surf->format->BytesPerPixel == 4 &&
116  surf->format->Rmask == 0xFF0000u &&
117  (surf->format->Amask | 0xFF000000u) == 0xFF000000u);
118 }
119 
120 static SDL_PixelFormat& get_neutral_pixel_format()
121  {
122  static bool first_time = true;
123  static SDL_PixelFormat format;
124 
125  if(first_time) {
126  first_time = false;
127  surface surf(SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,32,0xFF0000,0xFF00,0xFF,0xFF000000));
128  format = *surf->format;
129  format.palette = nullptr;
130  }
131 
132  return format;
133  }
134 
136 {
137  if(surf == nullptr) {
138  std::cerr << "null neutral surface...\n";
139  return nullptr;
140  }
141 
142  surface const result = SDL_ConvertSurface(surf,&get_neutral_pixel_format(),SDL_SWSURFACE);
143  if(result != nullptr) {
144  SDL_SetAlpha(result,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
145  }
146 
147  return result;
148 }
149 
151 {
152  if (w < 0 || h < 0) {
153  std::cerr << "error : neutral surface with negative dimensions\n";
154  return nullptr;
155  }
156 
157  SDL_PixelFormat format = get_neutral_pixel_format();
158  surface result = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
159  format.BitsPerPixel,
160  format.Rmask,
161  format.Gmask,
162  format.Bmask,
163  format.Amask);
164 
165  return result;
166 }
167 
169 {
170  if(surf == nullptr)
171  return nullptr;
172 
173  SDL_SetAlpha(surf,SDL_SRCALPHA|SDL_RLEACCEL,SDL_ALPHA_OPAQUE);
174 
175  return surf;
176 }
177 
179  const surface& surf, const unsigned w, const bool optimize)
180 {
181  // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
182  assert(SDL_ALPHA_TRANSPARENT==0);
183 
184  if(surf == nullptr)
185  return nullptr;
186 
187  if(static_cast<int>(w) == surf->w) {
188  return surf;
189  }
190  assert(w > 0);
191 
192  surface dst(create_neutral_surface(w, surf->h));
193 
195  // Now both surfaces are always in the "neutral" pixel format
196 
197  if(src == nullptr || dst == nullptr) {
198  std::cerr << "Could not create surface to scale onto\n";
199  return nullptr;
200  }
201 
202  {
203  // Extra scoping used for the surface_lock.
204  const_surface_lock src_lock(src);
205  surface_lock dst_lock(dst);
206 
207  const Uint32* const src_pixels = src_lock.pixels();
208  Uint32* dst_pixels = dst_lock.pixels();
209 
210  for(unsigned y = 0; y < static_cast<unsigned>(src->h); ++y) {
211  const Uint32 pixel = src_pixels [y * src->w];
212  for(unsigned x = 0; x < w; ++x) {
213 
214  *dst_pixels++ = pixel;
215 
216  }
217  }
218  }
219 
220  return optimize ? create_optimized_surface(dst) : dst;
221 }
222 
224  const surface& surf, const unsigned h, const bool optimize)
225 {
226  // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
227  assert(SDL_ALPHA_TRANSPARENT==0);
228 
229  if(surf == nullptr)
230  return nullptr;
231 
232  if(static_cast<int>(h) == surf->h) {
233  return surf;
234  }
235  assert(h > 0);
236 
237  surface dst(create_neutral_surface(surf->w, h));
238 
240  // Now both surfaces are always in the "neutral" pixel format
241 
242  if(src == nullptr || dst == nullptr) {
243  std::cerr << "Could not create surface to scale onto\n";
244  return nullptr;
245  }
246 
247  {
248  // Extra scoping used for the surface_lock.
249  const_surface_lock src_lock(src);
250  surface_lock dst_lock(dst);
251 
252  const Uint32* const src_pixels = src_lock.pixels();
253  Uint32* dst_pixels = dst_lock.pixels();
254 
255  for(unsigned y = 0; y < static_cast<unsigned>(h); ++y) {
256  for(unsigned x = 0; x < static_cast<unsigned>(src->w); ++x) {
257 
258  *dst_pixels++ = src_pixels[x];
259  }
260  }
261  }
262 
263  return optimize ? create_optimized_surface(dst) : dst;
264 }
265 
266 #ifdef PANDORA
267 static void
268 scale_surface_down(surface& dst, const surface& src, const int w_dst, const int h_dst)
269 {
270  const_surface_lock src_lock(src);
271  surface_lock dst_lock(dst);
272 
273  const Uint32* const src_pixels = src_lock.pixels();
274  Uint32* const dst_pixels = dst_lock.pixels();
275 
276  int y_dst = 0; // The current y in the destination surface
277 
278  int y_src = 0; // The current y in the source surface
279  int y_src_next = 0; // The next y in the source surface
280  int y_step = 0; // The y stepper
281  int h_src = src->h; // The height of the source surface
282 
283  for( ; y_dst != h_dst; ++y_dst, y_src = y_src_next) {
284 
285  y_step += h_src;
286  do {
287  ++y_src_next;
288  y_step -= h_dst;
289  } while(y_step >= h_dst);
290 
291  int x_dst = 0; // The current x in the destination surface
292 
293  int x_src = 0; // The current x in the source surface
294  int x_src_next = 0; // The next x in the source surface
295  int x_step = 0; // The x stepper
296  int w_src = src->w; // The width of the source surface
297 
298  for( ; x_dst != w_dst; ++x_dst, x_src = x_src_next) {
299 
300  x_step += w_src;
301  do {
302  ++x_src_next;
303  x_step -= w_dst;
304  } while(x_step >= w_dst);
305 
306  int r_sum = 0, g_sum = 0, b_sum = 0, a_sum = 0;
307  int samples = 0;
308 
309  // We now have a rectangle, (xsrc,ysrc,xratio,yratio)
310  // which we want to derive the pixel from
311  for(int x = x_src; x < x_src_next; ++x) {
312  for(int y = y_src; y < y_src_next; ++y) {
313 
314  ++samples;
315 
316  const Uint32 pixel = src_pixels[y_src * w_src + x_src];
317  const Uint8 a = pixel >> 24;
318  if(a) {
319  a_sum += a;
320  r_sum += a * static_cast<Uint8>(pixel >> 16);
321  g_sum += a * static_cast<Uint8>(pixel >> 8);
322  b_sum += a * static_cast<Uint8>(pixel);
323  }
324  }
325  }
326 
327  if(a_sum) {
328 
329  const int adjustment = (a_sum | 1) >> 1;
330  r_sum += adjustment;
331  g_sum += adjustment;
332  b_sum += adjustment;
333 
334  r_sum /= a_sum;
335  g_sum /= a_sum;
336  b_sum /= a_sum;
337 
338  assert(samples == (x_src_next - x_src) * (y_src_next - y_src));
339  if(samples != 1) {
340  a_sum += (samples | 1) >> 1;
341  a_sum /= samples;
342  }
343  }
344 
345  dst_pixels[y_dst * w_dst + x_dst] =
346  static_cast<Uint8>(a_sum) << 24
347  | static_cast<Uint8>(r_sum) << 16
348  | static_cast<Uint8>(g_sum) << 8
349  | static_cast<Uint8>(b_sum);
350  }
351  }
352 }
353 
354 #endif
355 
356 Uint32 blend_rgba(const surface& surf, unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned char drop)
357 {
358  // We simply decrement each component.
359  if(r < drop) r = 0; else r -= drop;
360  if(g < drop) g = 0; else g -= drop;
361  if(b < drop) b = 0; else b -= drop;
362 
363  return SDL_MapRGBA(surf->format, r, g, b, a);
364 }
365 
367 {
368  if(surf == nullptr)
369  return nullptr;
370 
371  if (z > 5) {
372  std::cerr << "Cannot use xbrz scaling with zoom factor > 5." << std::endl;
373  z = 1;
374  }
375 
376 
377  if (z == 1) {
378  return create_optimized_surface(surf);
379  }
380 
381  surface dst(create_neutral_surface(surf->w *z, surf->h * z));
382 
383  if (z == 0) {
384  std::cerr << "Create an empty image\n";
385  return create_optimized_surface(dst);
386  }
387 
389 
390  if(src == nullptr || dst == nullptr) {
391  std::cerr << "Could not create surface to scale onto\n";
392  return nullptr;
393  }
394 
395  {
396  const_surface_lock src_lock(src);
397  surface_lock dst_lock(dst);
398 
399  xbrz::scale(z, src_lock.pixels(), dst_lock.pixels(), surf->w, surf->h);
400  }
401  return create_optimized_surface(dst);
402 }
403 
404 surface scale_surface_nn (const surface & surf, int w, int h)
405 {
406  // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
407  assert(SDL_ALPHA_TRANSPARENT==0);
408 
409  if (surf == nullptr)
410  return nullptr;
411 
412  if(w == surf->w && h == surf->h) {
413  return surf;
414  }
415  assert(w >= 0);
416  assert(h >= 0);
417 
419 
420  if (w == 0 || h ==0) {
421  std::cerr << "Create an empty image\n";
422  return create_optimized_surface(dst);
423  }
424 
426  // Now both surfaces are always in the "neutral" pixel format
427 
428  if(src == nullptr || dst == nullptr) {
429  std::cerr << "Could not create surface to scale onto\n";
430  return nullptr;
431  }
432 
433  {
434  const_surface_lock src_lock(src);
435  surface_lock dst_lock(dst);
436 
437  xbrz::nearestNeighborScale(src_lock.pixels(), surf->w, surf->h, dst_lock.pixels(), w, h);
438  }
439  return create_optimized_surface(dst);
440 }
441 
442 // NOTE: Don't pass this function 0 scaling arguments.
443 surface scale_surface(const surface &surf, int w, int h) {
444  return scale_surface(surf, w, h, true);
445 }
446 
447 surface scale_surface(const surface &surf, int w, int h, bool optimize)
448 {
449  // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
450  assert(SDL_ALPHA_TRANSPARENT==0);
451 
452  if(surf == nullptr)
453  return nullptr;
454 
455  if(w == surf->w && h == surf->h) {
456  return surf;
457  }
458  assert(w >= 0);
459  assert(h >= 0);
460 
462 
463  if (w == 0 || h ==0) {
464  std::cerr << "Create an empty image\n";
465  return create_optimized_surface(dst);
466  }
467 
469  // Now both surfaces are always in the "neutral" pixel format
470 
471  if(src == nullptr || dst == nullptr) {
472  std::cerr << "Could not create surface to scale onto\n";
473  return nullptr;
474  }
475 
476  {
477  const_surface_lock src_lock(src);
478  surface_lock dst_lock(dst);
479 
480  const Uint32* const src_pixels = src_lock.pixels();
481  Uint32* const dst_pixels = dst_lock.pixels();
482 
483  fixed_t xratio = fxpdiv(surf->w,w);
484  fixed_t yratio = fxpdiv(surf->h,h);
485 
486  fixed_t ysrc = ftofxp(0.0);
487  for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
488  fixed_t xsrc = ftofxp(0.0);
489  for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
490  const int xsrcint = fxptoi(xsrc);
491  const int ysrcint = fxptoi(ysrc);
492 
493  const Uint32* const src_word = src_pixels + ysrcint*src->w + xsrcint;
494  Uint32* const dst_word = dst_pixels + ydst*dst->w + xdst;
495  const int dx = (xsrcint + 1 < src->w) ? 1 : 0;
496  const int dy = (ysrcint + 1 < src->h) ? src->w : 0;
497 
498  Uint8 r,g,b,a;
499  Uint32 rr,gg,bb,aa, temp;
500 
501  Uint32 pix[4], bilin[4];
502 
503  // This next part is the fixed point
504  // equivalent of "take everything to
505  // the right of the decimal point."
506  // These fundamental weights decide
507  // the contributions from various
508  // input pixels. The labels assume
509  // that the upper left corner of the
510  // screen ("northeast") is 0,0 but the
511  // code should still be consistent if
512  // the graphics origin is actually
513  // somewhere else.
514  //
515  // That is, the bilin array holds the
516  // "geometric" weights. I.E. If I'm scaling
517  // a 2 x 2 block a 10 x 10 block, then for
518  // pixel (2,2) of ouptut, the upper left
519  // pixel should be 10:1 more influential than
520  // the upper right, and also 10:1 more influential
521  // than lower left, and 100:1 more influential
522  // than lower right.
523 
524  const fixed_t e = 0x000000FF & xsrc;
525  const fixed_t s = 0x000000FF & ysrc;
526  const fixed_t n = 0xFF - s;
527  const fixed_t w = 0xFF - e;
528 
529  pix[0] = *src_word; // northwest
530  pix[1] = *(src_word + dx); // northeast
531  pix[2] = *(src_word + dy); // southwest
532  pix[3] = *(src_word + dx + dy); // southeast
533 
534  bilin[0] = n*w;
535  bilin[1] = n*e;
536  bilin[2] = s*w;
537  bilin[3] = s*e;
538 
539  int loc;
540  rr = bb = gg = aa = 0;
541  for (loc=0; loc<4; loc++) {
542  a = pix[loc] >> 24;
543  r = pix[loc] >> 16;
544  g = pix[loc] >> 8;
545  b = pix[loc] >> 0;
546 
547  //We also have to implement weighting by alpha for the RGB components
548  //If a unit has some parts solid and some parts translucent,
549  //i.e. a red cloak but a dark shadow, then when we scale in
550  //the shadow shouldn't appear to become red at the edges.
551  //This part also smoothly interpolates between alpha=0 being
552  //transparent and having no contribution, vs being opaque.
553  temp = (a * bilin[loc]);
554  rr += r * temp;
555  gg += g * temp;
556  bb += b * temp;
557  aa += temp;
558  }
559 
560  a = aa >> (16); // we average the alphas, they don't get weighted by any other factor besides bilin
561  if (a != 0) {
562  rr /= a; // finish alpha weighting: divide by sum of alphas
563  gg /= a;
564  bb /= a;
565  }
566  r = rr >> (16); // now shift over by 16 for the bilin part
567  g = gg >> (16);
568  b = bb >> (16);
569  *dst_word = (a << 24) + (r << 16) + (g << 8) + b;
570  }
571  }
572  }
573 
574  return optimize ? create_optimized_surface(dst) : dst;
575 }
576 
577 surface scale_surface_sharp(const surface& surf, int w, int h, bool optimize)
578 {
579  // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
580  assert(SDL_ALPHA_TRANSPARENT==0);
581 
582  if(surf == nullptr)
583  return nullptr;
584 
585  if(w == surf->w && h == surf->h) {
586  return surf;
587  }
588  assert(w >= 0);
589  assert(h >= 0);
590 
592 
593  if (w == 0 || h ==0) {
594  std::cerr << "Create an empty image\n";
595  return create_optimized_surface(dst);
596  }
597 
599  // Now both surfaces are always in the "neutral" pixel format
600 
601  if(src == nullptr || dst == nullptr) {
602  std::cerr << "Could not create surface to scale onto\n";
603  return nullptr;
604  }
605 
606 #ifdef PANDORA
607  scale_surface_down(dst, src, w, h);
608 #else
609  {
610  const_surface_lock src_lock(src);
611  surface_lock dst_lock(dst);
612 
613  const Uint32* const src_pixels = src_lock.pixels();
614  Uint32* const dst_pixels = dst_lock.pixels();
615 
616  tfloat xratio = tfloat(surf->w) / w;
617  tfloat yratio = tfloat(surf->h) / h;
618 
619  tfloat ysrc;
620  for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
621  tfloat xsrc;
622  for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
623  tfloat red, green, blue, alpha;
624 
625  tfloat summation;
626 
627  // We now have a rectangle, (xsrc,ysrc,xratio,yratio)
628  // which we want to derive the pixel from
629  for(tfloat xloc = xsrc; xloc < xsrc+xratio; xloc += 1) {
630  const tfloat xsize = std::min<tfloat>(floor(xloc + 1)-xloc,xsrc+xratio-xloc);
631 
632  for(tfloat yloc = ysrc; yloc < ysrc+yratio; yloc += 1) {
633  const int xsrcint = std::max<int>(0,std::min<int>(src->w-1,xsrc.to_int()));
634  const int ysrcint = std::max<int>(0,std::min<int>(src->h-1,ysrc.to_int()));
635  const tfloat ysize = std::min<tfloat>(floor(yloc+1)-yloc,ysrc+yratio-yloc);
636 
637  Uint8 r,g,b,a;
638 
639  SDL_GetRGBA(src_pixels[ysrcint*src->w + xsrcint],src->format,&r,&g,&b,&a);
640  tfloat value = xsize * ysize;
641  summation += value;
642  if (!a) continue;
643  value *= a;
644  alpha += value;
645  red += r * value;
646  green += g * value;
647  blue += b * value;
648  }
649  }
650 
651  if (alpha != 0) {
652  red = red / alpha + 0.5;
653  green = green / alpha + 0.5;
654  blue = blue / alpha + 0.5;
655  alpha = alpha / summation + 0.5;
656  }
657 
658  dst_pixels[ydst*dst->w + xdst] = SDL_MapRGBA(
659  dst->format
660  , red.to_int()
661  , green.to_int()
662  , blue.to_int()
663  , alpha.to_int());
664  }
665 
666  }
667  }
668 #endif
669 
670  return optimize ? create_optimized_surface(dst) : dst;
671 }
672 
673 
674 surface tile_surface(const surface& surf, int w, int h, bool optimize)
675 {
676  if (surf->w == w && surf->h == h) {
677  return surf;
678  }
679 
680  surface dest(create_neutral_surface(w, h));
682 
683  if (src == nullptr || dest == nullptr) {
684  std::cerr << "failed to make neutral surface\n";
685  return nullptr;
686  }
687 
688  {
689  const_surface_lock srclock(src);
690  surface_lock destlock(dest);
691 
692  const Uint32* srcpixels = srclock.pixels();
693  Uint32* destpixels = destlock.pixels();
694 
695  const int& sw = src->w;
696  const int& sh = src->h;
697 
698  const int xoff = (w - sw) / 2;
699  const int yoff = (h - sh) / 2;
700 
701  for (int i = 0; i<w*h; ++i) {
702  int x = ((i % w) - xoff);
703  int y = ((i / w) - yoff);
704 
705  while ((x += sw) < 0) { /* DO NOTHING */ }
706  while ((y += sh) < 0) { /* DO NOTHING */ }
707 
708  const int sx = x % sw;
709  const int sy = y % sh;
710 
711  destpixels[i] = srcpixels[sy*sw + sx];
712  }
713  }
714 
715  return optimize ? create_optimized_surface(dest) : dest;
716 }
717 
718 surface adjust_surface_color(const surface &surf, int red, int green, int blue, bool optimize)
719 {
720  if(surf == nullptr)
721  return nullptr;
722 
723  if((red == 0 && green == 0 && blue == 0))
724  return optimize ? create_optimized_surface(surf) : surf;
725 
726  surface nsurf(make_neutral_surface(surf));
727 
728  if(nsurf == nullptr) {
729  std::cerr << "failed to make neutral surface\n";
730  return nullptr;
731  }
732 
733  {
734  surface_lock lock(nsurf);
735  Uint32* beg = lock.pixels();
736  Uint32* end = beg + nsurf->w*surf->h;
737 
738  while(beg != end) {
739  Uint8 alpha = (*beg) >> 24;
740 
741  if(alpha) {
742  Uint8 r, g, b;
743  r = (*beg) >> 16;
744  g = (*beg) >> 8;
745  b = (*beg) >> 0;
746 
747  r = std::max<int>(0,std::min<int>(255,int(r)+red));
748  g = std::max<int>(0,std::min<int>(255,int(g)+green));
749  b = std::max<int>(0,std::min<int>(255,int(b)+blue));
750 
751  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
752  }
753 
754  ++beg;
755  }
756  }
757 
758  return optimize ? create_optimized_surface(nsurf) : nsurf;
759 }
760 
761 surface greyscale_image(const surface &surf, bool optimize)
762 {
763  if(surf == nullptr)
764  return nullptr;
765 
766  surface nsurf(make_neutral_surface(surf));
767  if(nsurf == nullptr) {
768  std::cerr << "failed to make neutral surface\n";
769  return nullptr;
770  }
771 
772  {
773  surface_lock lock(nsurf);
774  Uint32* beg = lock.pixels();
775  Uint32* end = beg + nsurf->w*surf->h;
776 
777  while(beg != end) {
778  Uint8 alpha = (*beg) >> 24;
779 
780  if(alpha) {
781  Uint8 r, g, b;
782  r = (*beg) >> 16;
783  g = (*beg) >> 8;
784  b = (*beg);
785  //const Uint8 avg = (red+green+blue)/3;
786 
787  // Use the correct formula for RGB to grayscale conversion.
788  // Ok, this is no big deal :)
789  // The correct formula being:
790  // gray=0.299red+0.587green+0.114blue
791  const Uint8 avg = static_cast<Uint8>((
792  77 * static_cast<Uint16>(r) +
793  150 * static_cast<Uint16>(g) +
794  29 * static_cast<Uint16>(b) ) / 256);
795 
796  *beg = (alpha << 24) | (avg << 16) | (avg << 8) | avg;
797  }
798 
799  ++beg;
800  }
801  }
802 
803  return optimize ? create_optimized_surface(nsurf) : nsurf;
804 }
805 
806 surface monochrome_image(const surface &surf, const int threshold, bool optimize)
807 {
808  if(surf == nullptr)
809  return nullptr;
810 
811  surface nsurf(make_neutral_surface(surf));
812  if(nsurf == nullptr) {
813  std::cerr << "failed to make neutral surface\n";
814  return nullptr;
815  }
816 
817  {
818  surface_lock lock(nsurf);
819  Uint32* beg = lock.pixels();
820  Uint32* end = beg + nsurf->w*surf->h;
821 
822  while(beg != end) {
823  Uint8 alpha = (*beg) >> 24;
824 
825  if(alpha) {
826  Uint8 r, g, b, result;
827  r = (*beg) >> 16;
828  g = (*beg) >> 8;
829  b = (*beg);
830 
831  // first convert the pixel to grayscale
832  // if the resulting value is above the threshold make it black
833  // else make it white
834  result = static_cast<Uint8>(0.299 * r + 0.587 * g + 0.114 * b) > threshold ? 255 : 0;
835 
836  *beg = (alpha << 24) | (result << 16) | (result << 8) | result;
837  }
838 
839  ++beg;
840  }
841  }
842 
843  return optimize ? create_optimized_surface(nsurf) : nsurf;
844 }
845 
846 surface sepia_image(const surface &surf, bool optimize)
847 {
848  if(surf == nullptr)
849  return nullptr;
850 
851  surface nsurf(make_neutral_surface(surf));
852  if(nsurf == nullptr) {
853  std::cerr << "failed to make neutral surface\n";
854  return nullptr;
855  }
856 
857  {
858  surface_lock lock(nsurf);
859  Uint32* beg = lock.pixels();
860  Uint32* end = beg + nsurf->w*surf->h;
861 
862  while(beg != end) {
863  Uint8 alpha = (*beg) >> 24;
864 
865  if(alpha) {
866  Uint8 r, g, b;
867  r = (*beg) >> 16;
868  g = (*beg) >> 8;
869  b = (*beg);
870 
871  // this is the formula for applying a sepia effect
872  // that can be found on various web sites
873  // for example here: https://software.intel.com/sites/default/files/article/346220/sepiafilter-intelcilkplus.pdf
874  Uint8 outRed = std::min(255, static_cast<int>((r * 0.393) + (g * 0.769) + (b * 0.189)));
875  Uint8 outGreen = std::min(255, static_cast<int>((r * 0.349) + (g * 0.686) + (b * 0.168)));
876  Uint8 outBlue = std::min(255, static_cast<int>((r * 0.272) + (g * 0.534) + (b * 0.131)));
877 
878  *beg = (alpha << 24) | (outRed << 16) | (outGreen << 8) | (outBlue);
879  }
880 
881  ++beg;
882  }
883  }
884 
885  return optimize ? create_optimized_surface(nsurf) : nsurf;
886 }
887 
888 surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB, bool optimize)
889 {
890  if(surf == nullptr)
891  return nullptr;
892 
893  surface nsurf(make_neutral_surface(surf));
894  if(nsurf == nullptr) {
895  std::cerr << "failed to make neutral surface\n";
896  return nullptr;
897  }
898 
899  {
900  surface_lock lock(nsurf);
901  Uint32* beg = lock.pixels();
902  Uint32* end = beg + nsurf->w*surf->h;
903 
904  while(beg != end) {
905  Uint8 alpha = (*beg) >> 24;
906 
907  if(alpha) {
908  Uint8 r, g, b, newR, newG, newB;
909  r = (*beg) >> 16;
910  g = (*beg) >> 8;
911  b = (*beg);
912 
913  // invert he channel only if its value is greater than the supplied threshold
914  // this can be used for solarization effects
915  // for a full negative effect, use a value of -1
916  // 255 is a no-op value (doesn't do anything, since a Uint8 cannot contain a greater value than that)
917  newR = r > thresholdR ? 255 - r : r;
918  newG = g > thresholdG ? 255 - g : g;
919  newB = b > thresholdB ? 255 - b : b;
920 
921  *beg = (alpha << 24) | (newR << 16) | (newG << 8) | (newB);
922  }
923 
924  ++beg;
925  }
926  }
927 
928  return optimize ? create_optimized_surface(nsurf) : nsurf;
929 }
930 
931 surface alpha_to_greyscale(const surface &surf, bool optimize)
932 {
933  if(surf == nullptr)
934  return nullptr;
935 
936  surface nsurf(make_neutral_surface(surf));
937  if(nsurf == nullptr) {
938  std::cerr << "failed to make neutral surface\n";
939  return nullptr;
940  }
941 
942  {
943  surface_lock lock(nsurf);
944  Uint32* beg = lock.pixels();
945  Uint32* end = beg + nsurf->w*surf->h;
946 
947  while(beg != end) {
948  Uint8 alpha = (*beg) >> 24;
949 
950  *beg = (0xff << 24) | (alpha << 16) | (alpha << 8) | alpha;
951 
952  ++beg;
953  }
954  }
955 
956  return optimize ? create_optimized_surface(nsurf) : nsurf;
957 }
958 
959 surface wipe_alpha(const surface &surf, bool optimize)
960 {
961  if(surf == nullptr)
962  return nullptr;
963 
964  surface nsurf(make_neutral_surface(surf));
965  if(nsurf == nullptr) {
966  std::cerr << "failed to make neutral surface\n";
967  return nullptr;
968  }
969 
970  {
971  surface_lock lock(nsurf);
972  Uint32* beg = lock.pixels();
973  Uint32* end = beg + nsurf->w*surf->h;
974 
975  while(beg != end) {
976 
977  *beg = 0xff000000 | *beg;
978 
979  ++beg;
980  }
981  }
982 
983  return optimize ? create_optimized_surface(nsurf) : nsurf;
984 }
985 
986 
987 surface shadow_image(const surface &surf, bool optimize)
988 {
989  if(surf == nullptr)
990  return nullptr;
991 
992  // we blur it, and reuse the neutral surface created by the blur function (optimized = false)
993  surface nsurf (blur_alpha_surface(surf, 2, false));
994 
995  if(nsurf == nullptr) {
996  std::cerr << "failed to blur the shadow surface\n";
997  return nullptr;
998  }
999 
1000  {
1001  surface_lock lock(nsurf);
1002  Uint32* beg = lock.pixels();
1003  Uint32* end = beg + nsurf->w*surf->h;
1004 
1005  while(beg != end) {
1006  Uint8 alpha = (*beg) >> 24;
1007 
1008  if(alpha) {
1009  // increase alpha and color in black (RGB=0)
1010  // with some stupid optimization for handling maximum values
1011  if (alpha < 255/4)
1012  *beg = (alpha*4) << 24;
1013  else
1014  *beg = 0xFF000000; // we hit the maximum
1015  }
1016 
1017  ++beg;
1018  }
1019  }
1020 
1021  return optimize ? create_optimized_surface(nsurf) : nsurf;
1022 }
1023 
1025  if(surf == nullptr)
1026  return nullptr;
1027 
1028  surface nsurf(make_neutral_surface(surf));
1029  if(nsurf == nullptr) {
1030  std::cerr << "failed to make neutral surface\n";
1031  return nullptr;
1032  }
1033 
1034  {
1035  surface_lock lock(nsurf);
1036  Uint32* beg = lock.pixels();
1037  Uint32* end = beg + nsurf->w*surf->h;
1038 
1039  while(beg != end) {
1040  Uint8 alpha = (*beg) >> 24;
1041 
1042  if(alpha) {
1043  Uint8 red, green, blue, newRed, newGreen, newBlue, newAlpha;
1044  red = (*beg) >> 16;
1045  green = (*beg) >> 8;
1046  blue = (*beg);
1047 
1048  switch (r) {
1049  case RED:
1050  newRed = red;
1051  break;
1052  case GREEN:
1053  newRed = green;
1054  break;
1055  case BLUE:
1056  newRed = blue;
1057  break;
1058  case ALPHA:
1059  newRed = alpha;
1060  break;
1061  default:
1062  return nullptr;
1063  }
1064 
1065  switch (g) {
1066  case RED:
1067  newGreen = red;
1068  break;
1069  case GREEN:
1070  newGreen = green;
1071  break;
1072  case BLUE:
1073  newGreen = blue;
1074  break;
1075  case ALPHA:
1076  newGreen = alpha;
1077  break;
1078  default:
1079  return nullptr;
1080  }
1081 
1082  switch (b) {
1083  case RED:
1084  newBlue = red;
1085  break;
1086  case GREEN:
1087  newBlue = green;
1088  break;
1089  case BLUE:
1090  newBlue = blue;
1091  break;
1092  case ALPHA:
1093  newBlue = alpha;
1094  break;
1095  default:
1096  return nullptr;
1097  }
1098 
1099  switch (a) {
1100  case RED:
1101  newAlpha = red;
1102  break;
1103  case GREEN:
1104  newAlpha = green;
1105  break;
1106  case BLUE:
1107  newAlpha = blue;
1108  break;
1109  case ALPHA:
1110  newAlpha = alpha;
1111  break;
1112  default:
1113  return nullptr;
1114  }
1115 
1116  *beg = (newAlpha << 24) | (newRed << 16) | (newGreen << 8) | newBlue;
1117  }
1118 
1119  ++beg;
1120  }
1121  }
1122 
1123  return optimize ? create_optimized_surface(nsurf) : nsurf;
1124 }
1125 
1126 surface recolor_image(surface surf, const std::map<Uint32, Uint32>& map_rgb, bool optimize){
1127  if(surf == nullptr)
1128  return nullptr;
1129 
1130  if(!map_rgb.empty()){
1131  surface nsurf(make_neutral_surface(surf));
1132  if(nsurf == nullptr) {
1133  std::cerr << "failed to make neutral surface\n";
1134  return nullptr;
1135  }
1136 
1137  surface_lock lock(nsurf);
1138  Uint32* beg = lock.pixels();
1139  Uint32* end = beg + nsurf->w*surf->h;
1140 
1141  while(beg != end) {
1142  Uint8 alpha = (*beg) >> 24;
1143 
1144  if(alpha){ // don't recolor invisible pixels.
1145  // palette use only RGB channels, so remove alpha
1146  Uint32 oldrgb = (*beg) & 0x00FFFFFF;
1147  std::map<Uint32, Uint32>::const_iterator i = map_rgb.find(oldrgb);
1148  if(i != map_rgb.end()){
1149  *beg = (alpha << 24) + i->second;
1150  }
1151  }
1152  ++beg;
1153  }
1154 
1155  return optimize ? create_optimized_surface(nsurf) : nsurf;
1156  }
1157  return surf;
1158 }
1159 
1161 {
1162  if(surf == nullptr) {
1163  return nullptr;
1164  }
1165 
1166  surface nsurf(make_neutral_surface(surf));
1167 
1168  if(nsurf == nullptr) {
1169  std::cerr << "could not make neutral surface...\n";
1170  return nullptr;
1171  }
1172 
1173  {
1174  surface_lock lock(nsurf);
1175  Uint32* beg = lock.pixels();
1176  Uint32* end = beg + nsurf->w*surf->h;
1177 
1178  if (amount < 0) amount = 0;
1179  while(beg != end) {
1180  Uint8 alpha = (*beg) >> 24;
1181 
1182  if(alpha) {
1183  Uint8 r, g, b;
1184  r = (*beg) >> 16;
1185  g = (*beg) >> 8;
1186  b = (*beg);
1187 
1188  r = std::min<unsigned>(unsigned(fxpmult(r, amount)),255);
1189  g = std::min<unsigned>(unsigned(fxpmult(g, amount)),255);
1190  b = std::min<unsigned>(unsigned(fxpmult(b, amount)),255);
1191 
1192  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1193  }
1194 
1195  ++beg;
1196  }
1197  }
1198 
1199  return optimize ? create_optimized_surface(nsurf) : nsurf;
1200 }
1201 
1203 {
1204  if(surf== nullptr) {
1205  return nullptr;
1206  }
1207 
1208  surface nsurf(make_neutral_surface(surf));
1209 
1210  if(nsurf == nullptr) {
1211  std::cerr << "could not make neutral surface...\n";
1212  return nullptr;
1213  }
1214 
1215  {
1216  surface_lock lock(nsurf);
1217  Uint32* beg = lock.pixels();
1218  Uint32* end = beg + nsurf->w*surf->h;
1219 
1220  if (amount < 0) amount = 0;
1221  while(beg != end) {
1222  Uint8 alpha = (*beg) >> 24;
1223 
1224  if(alpha) {
1225  Uint8 r, g, b;
1226  r = (*beg) >> 16;
1227  g = (*beg) >> 8;
1228  b = (*beg);
1229 
1230  alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
1231  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1232  }
1233 
1234  ++beg;
1235  }
1236  }
1237 
1238  return optimize ? create_optimized_surface(nsurf) : nsurf;
1239 }
1240 
1242 {
1243  if(surf== nullptr) {
1244  return nullptr;
1245  }
1246 
1247  surface nsurf(make_neutral_surface(surf));
1248 
1249  if(nsurf == nullptr) {
1250  std::cerr << "could not make neutral surface...\n";
1251  return nullptr;
1252  }
1253 
1254  {
1255  surface_lock lock(nsurf);
1256  Uint32* beg = lock.pixels();
1257  Uint32* end = beg + nsurf->w*surf->h;
1258 
1259  while(beg != end) {
1260  Uint8 alpha = (*beg) >> 24;
1261 
1262  if(alpha) {
1263  Uint8 r, g, b;
1264  r = (*beg) >> 16;
1265  g = (*beg) >> 8;
1266  b = (*beg);
1267 
1268  alpha = Uint8(std::max<int>(0,std::min<int>(255,int(alpha) + amount)));
1269  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1270  }
1271 
1272  ++beg;
1273  }
1274  }
1275 
1276  return optimize ? create_optimized_surface(nsurf) : nsurf;
1277 }
1278 
1279 surface mask_surface(const surface &surf, const surface &mask, bool* empty_result, const std::string& filename)
1280 {
1281  if(surf == nullptr) {
1282  return nullptr;
1283  }
1284  if(mask == nullptr) {
1285  return surf;
1286  }
1287 
1288  surface nsurf = make_neutral_surface(surf);
1289  surface nmask(make_neutral_surface(mask));
1290 
1291  if(nsurf == nullptr || nmask == nullptr) {
1292  std::cerr << "could not make neutral surface...\n";
1293  return nullptr;
1294  }
1295  if (nsurf->w != nmask->w) {
1296  // we don't support efficiently different width.
1297  // (different height is not a real problem)
1298  // This function is used on all hexes and usually only for that
1299  // so better keep it simple and efficient for the normal case
1300  std::stringstream ss;
1301  ss << "Detected an image with bad dimensions: ";
1302  if(!filename.empty()) ss << filename << ": ";
1303  ss << nsurf->w << "x" << nsurf->h << "\n";
1304  std::cerr << ss.str();
1305  std::cerr << "It will not be masked, please use: "<< nmask->w << "x" << nmask->h << "\n";
1306  return nsurf;
1307  }
1308 
1309  bool empty = true;
1310  {
1311  surface_lock lock(nsurf);
1312  const_surface_lock mlock(nmask);
1313 
1314  Uint32* beg = lock.pixels();
1315  Uint32* end = beg + nsurf->w*surf->h;
1316  const Uint32* mbeg = mlock.pixels();
1317  const Uint32* mend = mbeg + nmask->w*nmask->h;
1318 
1319  while(beg != end && mbeg != mend) {
1320  Uint8 alpha = (*beg) >> 24;
1321 
1322  if(alpha) {
1323  Uint8 r, g, b;
1324  r = (*beg) >> 16;
1325  g = (*beg) >> 8;
1326  b = (*beg);
1327 
1328  Uint8 malpha = (*mbeg) >> 24;
1329  if (alpha > malpha) {
1330  alpha = malpha;
1331  }
1332  if(alpha)
1333  empty = false;
1334 
1335  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1336  }
1337 
1338  ++beg;
1339  ++mbeg;
1340  }
1341  }
1342  if(empty_result)
1343  *empty_result = empty;
1344 
1345  return nsurf;
1346  //return create_optimized_surface(nsurf);
1347 }
1348 
1350 {
1351  if(surf == nullptr) {
1352  return false;
1353  }
1354  if(mask == nullptr){
1355  return true;
1356  }
1357 
1358  if (surf->w != mask->w || surf->h != mask->h ) {
1359  // not same size, consider it doesn't fit
1360  return false;
1361  }
1362 
1363  surface nsurf = make_neutral_surface(surf);
1364  surface nmask(make_neutral_surface(mask));
1365 
1366  if(nsurf == nullptr || nmask == nullptr) {
1367  std::cerr << "could not make neutral surface...\n";
1368  return false;
1369  }
1370 
1371  {
1372  surface_lock lock(nsurf);
1373  const_surface_lock mlock(nmask);
1374 
1375  const Uint32* mbeg = mlock.pixels();
1376  const Uint32* mend = mbeg + nmask->w*nmask->h;
1377  Uint32* beg = lock.pixels();
1378  // no need for 'end', because both surfaces have same size
1379 
1380  while(mbeg != mend) {
1381  Uint8 malpha = (*mbeg) >> 24;
1382  if(malpha == 0) {
1383  Uint8 alpha = (*beg) >> 24;
1384  if (alpha)
1385  return false;
1386  }
1387  ++mbeg;
1388  ++beg;
1389  }
1390  }
1391 
1392  return true;
1393 }
1394 
1395 surface submerge_alpha(const surface &surf, int depth, float alpha_base, float alpha_delta, bool optimize)
1396 {
1397  if(surf== nullptr) {
1398  return nullptr;
1399  }
1400 
1401  surface nsurf(make_neutral_surface(surf));
1402 
1403  {
1404  surface_lock lock(nsurf);
1405 
1406  Uint32* beg = lock.pixels();
1407  Uint32* limit = beg + (nsurf->h-depth) * nsurf->w ;
1408  Uint32* end = beg + nsurf->w * nsurf->h;
1409  beg = limit; // directlt jump to the bottom part
1410 
1411  while(beg != end){
1412  Uint8 alpha = (*beg) >> 24;
1413 
1414  if(alpha) {
1415  Uint8 r, g, b;
1416  r = (*beg) >> 16;
1417  g = (*beg) >> 8;
1418  b = (*beg);
1419  int d = (beg-limit)/nsurf->w; // current depth in pixels
1420  float a = alpha_base - d * alpha_delta;
1421  fixed_t amount = ftofxp(a<0?0:a);
1422  alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
1423  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1424  }
1425 
1426  ++beg;
1427  }
1428 
1429 /*
1430  for(int y = submerge_height; y < nsurf->h; ++y) {
1431  Uint32* cur = beg + y * nsurf->w;
1432  Uint32* row_end = beg + (y+1) * nsurf->w;
1433  float d = y * 1.0 / depth;
1434  double a = 0.2;//std::max<double>(0, (1-d)*0.3);
1435  fixed_t amount = ftofxp(a);
1436  while(cur != row_end) {
1437  Uint8 alpha = (*cur) >> 24;
1438 
1439  if(alpha) {
1440  Uint8 r, g, b;
1441  r = (*cur) >> 16;
1442  g = (*cur) >> 8;
1443  b = (*cur);
1444  alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
1445  *cur = (alpha << 24) + (r << 16) + (g << 8) + b;
1446  }
1447 
1448  ++cur;
1449  }
1450  }*/
1451 
1452  }
1453 
1454  return optimize ? create_optimized_surface(nsurf) : nsurf;
1455 
1456 }
1457 
1458 surface light_surface(const surface &surf, const surface &lightmap, bool optimize)
1459 {
1460  if(surf == nullptr) {
1461  return nullptr;
1462  }
1463  if(lightmap == nullptr) {
1464  return surf;
1465  }
1466 
1467  surface nsurf = make_neutral_surface(surf);
1468 
1469  if(nsurf == nullptr) {
1470  std::cerr << "could not make neutral surface...\n";
1471  return nullptr;
1472  }
1473  if (nsurf->w != lightmap->w) {
1474  // we don't support efficiently different width.
1475  // (different height is not a real problem)
1476  // This function is used on all hexes and usually only for that
1477  // so better keep it simple and efficient for the normal case
1478  std::cerr << "Detected an image with bad dimensions: " << nsurf->w << "x" << nsurf->h << "\n";
1479  std::cerr << "It will not be lighted, please use: "<< lightmap->w << "x" << lightmap->h << "\n";
1480  return nsurf;
1481  }
1482  {
1483  surface_lock lock(nsurf);
1484  const_surface_lock llock(lightmap);
1485 
1486  Uint32* beg = lock.pixels();
1487  Uint32* end = beg + nsurf->w * nsurf->h;
1488  const Uint32* lbeg = llock.pixels();
1489  const Uint32* lend = lbeg + lightmap->w * lightmap->h;
1490 
1491  while(beg != end && lbeg != lend) {
1492  Uint8 alpha = (*beg) >> 24;
1493  if(alpha) {
1494  Uint8 lr, lg, lb;
1495 
1496  lr = (*lbeg) >> 16;
1497  lg = (*lbeg) >> 8;
1498  lb = (*lbeg);
1499 
1500  Uint8 r, g, b;
1501  r = (*beg) >> 16;
1502  g = (*beg) >> 8;
1503  b = (*beg);
1504 
1505  int dr = (static_cast<int>(lr) - 128) * 2;
1506  int dg = (static_cast<int>(lg) - 128) * 2;
1507  int db = (static_cast<int>(lb) - 128) * 2;
1508  //note that r + dr will promote r to int (needed to avoid Uint8 math)
1509  r = std::max<int>(0,std::min<int>(255, r + dr));
1510  g = std::max<int>(0,std::min<int>(255, g + dg));
1511  b = std::max<int>(0,std::min<int>(255, b + db));
1512 
1513  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
1514  }
1515  ++beg;
1516  ++lbeg;
1517  }
1518  }
1519 
1520  return optimize ? create_optimized_surface(nsurf) : nsurf;
1521 }
1522 
1523 
1524 surface blur_surface(const surface &surf, int depth, bool optimize)
1525 {
1526  if(surf == nullptr) {
1527  return nullptr;
1528  }
1529 
1531 
1532  if(res == nullptr) {
1533  std::cerr << "could not make neutral surface...\n";
1534  return nullptr;
1535  }
1536 
1537  SDL_Rect rect = sdl::create_rect(0, 0, surf->w, surf->h);
1538  blur_surface(res, rect, depth);
1539 
1540  return optimize ? create_optimized_surface(res) : res;
1541 }
1542 
1543 void blur_surface(surface& surf, SDL_Rect rect, int depth)
1544 {
1545  if(surf == nullptr) {
1546  return;
1547  }
1548 
1549  const int max_blur = 256;
1550  if(depth > max_blur) {
1551  depth = max_blur;
1552  }
1553 
1554  Uint32 queue[max_blur];
1555  const Uint32* end_queue = queue + max_blur;
1556 
1557  const Uint32 ff = 0xff;
1558 
1559  const unsigned pixel_offset = rect.y * surf->w + rect.x;
1560 
1561  surface_lock lock(surf);
1562  for(int y = 0; y < rect.h; ++y) {
1563  const Uint32* front = &queue[0];
1564  Uint32* back = &queue[0];
1565  Uint32 red = 0, green = 0, blue = 0, avg = 0;
1566  Uint32* p = lock.pixels() + pixel_offset + y * surf->w;
1567  for(int x = 0; x <= depth && x < rect.w; ++x, ++p) {
1568  red += ((*p) >> 16)&0xFF;
1569  green += ((*p) >> 8)&0xFF;
1570  blue += (*p)&0xFF;
1571  ++avg;
1572  *back++ = *p;
1573  if(back == end_queue) {
1574  back = &queue[0];
1575  }
1576  }
1577 
1578  p = lock.pixels() + pixel_offset + y * surf->w;
1579  for(int x = 0; x < rect.w; ++x, ++p) {
1580  *p = 0xFF000000
1581  | (std::min(red/avg,ff) << 16)
1582  | (std::min(green/avg,ff) << 8)
1583  | std::min(blue/avg,ff);
1584 
1585  if(x >= depth) {
1586  red -= ((*front) >> 16)&0xFF;
1587  green -= ((*front) >> 8)&0xFF;
1588  blue -= *front&0xFF;
1589  --avg;
1590  ++front;
1591  if(front == end_queue) {
1592  front = &queue[0];
1593  }
1594  }
1595 
1596  if(x + depth+1 < rect.w) {
1597  Uint32* q = p + depth+1;
1598  red += ((*q) >> 16)&0xFF;
1599  green += ((*q) >> 8)&0xFF;
1600  blue += (*q)&0xFF;
1601  ++avg;
1602  *back++ = *q;
1603  if(back == end_queue) {
1604  back = &queue[0];
1605  }
1606  }
1607  }
1608  }
1609 
1610  for(int x = 0; x < rect.w; ++x) {
1611  const Uint32* front = &queue[0];
1612  Uint32* back = &queue[0];
1613  Uint32 red = 0, green = 0, blue = 0, avg = 0;
1614  Uint32* p = lock.pixels() + pixel_offset + x;
1615  for(int y = 0; y <= depth && y < rect.h; ++y, p += surf->w) {
1616  red += ((*p) >> 16)&0xFF;
1617  green += ((*p) >> 8)&0xFF;
1618  blue += *p&0xFF;
1619  ++avg;
1620  *back++ = *p;
1621  if(back == end_queue) {
1622  back = &queue[0];
1623  }
1624  }
1625 
1626  p = lock.pixels() + pixel_offset + x;
1627  for(int y = 0; y < rect.h; ++y, p += surf->w) {
1628  *p = 0xFF000000
1629  | (std::min(red/avg,ff) << 16)
1630  | (std::min(green/avg,ff) << 8)
1631  | std::min(blue/avg,ff);
1632 
1633  if(y >= depth) {
1634  red -= ((*front) >> 16)&0xFF;
1635  green -= ((*front) >> 8)&0xFF;
1636  blue -= *front&0xFF;
1637  --avg;
1638  ++front;
1639  if(front == end_queue) {
1640  front = &queue[0];
1641  }
1642  }
1643 
1644  if(y + depth+1 < rect.h) {
1645  Uint32* q = p + (depth+1)*surf->w;
1646  red += ((*q) >> 16)&0xFF;
1647  green += ((*q) >> 8)&0xFF;
1648  blue += (*q)&0xFF;
1649  ++avg;
1650  *back++ = *q;
1651  if(back == end_queue) {
1652  back = &queue[0];
1653  }
1654  }
1655  }
1656  }
1657 }
1658 
1659 surface blur_alpha_surface(const surface &surf, int depth, bool optimize)
1660 {
1661  if(surf == nullptr) {
1662  return nullptr;
1663  }
1664 
1666 
1667  if(res == nullptr) {
1668  std::cerr << "could not make neutral surface...\n";
1669  return nullptr;
1670  }
1671 
1672  const int max_blur = 256;
1673  if(depth > max_blur) {
1674  depth = max_blur;
1675  }
1676 
1677  Uint32 queue[max_blur];
1678  const Uint32* end_queue = queue + max_blur;
1679 
1680  const Uint32 ff = 0xff;
1681 
1682  surface_lock lock(res);
1683  int x, y;
1684  for(y = 0; y < res->h; ++y) {
1685  const Uint32* front = &queue[0];
1686  Uint32* back = &queue[0];
1687  Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
1688  Uint32* p = lock.pixels() + y*res->w;
1689  for(x = 0; x <= depth && x < res->w; ++x, ++p) {
1690  alpha += ((*p) >> 24)&0xFF;
1691  red += ((*p) >> 16)&0xFF;
1692  green += ((*p) >> 8)&0xFF;
1693  blue += (*p)&0xFF;
1694  ++avg;
1695  *back++ = *p;
1696  if(back == end_queue) {
1697  back = &queue[0];
1698  }
1699  }
1700 
1701  p = lock.pixels() + y*res->w;
1702  for(x = 0; x < res->w; ++x, ++p) {
1703  *p = (std::min(alpha/avg,ff) << 24) | (std::min(red/avg,ff) << 16) | (std::min(green/avg,ff) << 8) | std::min(blue/avg,ff);
1704  if(x >= depth) {
1705  alpha -= ((*front) >> 24)&0xFF;
1706  red -= ((*front) >> 16)&0xFF;
1707  green -= ((*front) >> 8)&0xFF;
1708  blue -= *front&0xFF;
1709  --avg;
1710  ++front;
1711  if(front == end_queue) {
1712  front = &queue[0];
1713  }
1714  }
1715 
1716  if(x + depth+1 < res->w) {
1717  Uint32* q = p + depth+1;
1718  alpha += ((*q) >> 24)&0xFF;
1719  red += ((*q) >> 16)&0xFF;
1720  green += ((*q) >> 8)&0xFF;
1721  blue += (*q)&0xFF;
1722  ++avg;
1723  *back++ = *q;
1724  if(back == end_queue) {
1725  back = &queue[0];
1726  }
1727  }
1728  }
1729  }
1730 
1731  for(x = 0; x < res->w; ++x) {
1732  const Uint32* front = &queue[0];
1733  Uint32* back = &queue[0];
1734  Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
1735  Uint32* p = lock.pixels() + x;
1736  for(y = 0; y <= depth && y < res->h; ++y, p += res->w) {
1737  alpha += ((*p) >> 24)&0xFF;
1738  red += ((*p) >> 16)&0xFF;
1739  green += ((*p) >> 8)&0xFF;
1740  blue += *p&0xFF;
1741  ++avg;
1742  *back++ = *p;
1743  if(back == end_queue) {
1744  back = &queue[0];
1745  }
1746  }
1747 
1748  p = lock.pixels() + x;
1749  for(y = 0; y < res->h; ++y, p += res->w) {
1750  assert(avg);
1751  *p = (std::min(alpha/avg,ff) << 24) | (std::min(red/avg,ff) << 16) | (std::min(green/avg,ff) << 8) | std::min(blue/avg,ff);
1752  if(y >= depth) {
1753  alpha -= ((*front) >> 24)&0xFF;
1754  red -= ((*front) >> 16)&0xFF;
1755  green -= ((*front) >> 8)&0xFF;
1756  blue -= *front&0xFF;
1757  --avg;
1758  ++front;
1759  if(front == end_queue) {
1760  front = &queue[0];
1761  }
1762  }
1763 
1764  if(y + depth+1 < res->h) {
1765  Uint32* q = p + (depth+1)*res->w;
1766  alpha += ((*q) >> 24)&0xFF;
1767  red += ((*q) >> 16)&0xFF;
1768  green += ((*q) >> 8)&0xFF;
1769  blue += (*q)&0xFF;
1770  ++avg;
1771  *back++ = *q;
1772  if(back == end_queue) {
1773  back = &queue[0];
1774  }
1775  }
1776  }
1777  }
1778 
1779  return optimize ? create_optimized_surface(res) : res;
1780 }
1781 
1782 surface cut_surface(const surface &surf, SDL_Rect const &r)
1783 {
1784  if(surf == nullptr)
1785  return nullptr;
1786 
1787  surface res = create_compatible_surface(surf, r.w, r.h);
1788 
1789  if(res == nullptr) {
1790  std::cerr << "Could not create a new surface in cut_surface()\n";
1791  return nullptr;
1792  }
1793 
1794  size_t sbpp = surf->format->BytesPerPixel;
1795  size_t spitch = surf->pitch;
1796  size_t rbpp = res->format->BytesPerPixel;
1797  size_t rpitch = res->pitch;
1798 
1799  // compute the areas to copy
1800  SDL_Rect src_rect = r;
1801  SDL_Rect dst_rect = { 0, 0, r.w, r.h };
1802 
1803  if (src_rect.x < 0) {
1804  if (src_rect.x + src_rect.w <= 0)
1805  return res;
1806  dst_rect.x -= src_rect.x;
1807  dst_rect.w += src_rect.x;
1808  src_rect.w += src_rect.x;
1809  src_rect.x = 0;
1810  }
1811  if (src_rect.y < 0) {
1812  if (src_rect.y + src_rect.h <= 0)
1813  return res;
1814  dst_rect.y -= src_rect.y;
1815  dst_rect.h += src_rect.y;
1816  src_rect.h += src_rect.y;
1817  src_rect.y = 0;
1818  }
1819 
1820  if(src_rect.x >= surf->w || src_rect.y >= surf->h)
1821  return res;
1822 
1823  const_surface_lock slock(surf);
1824  surface_lock rlock(res);
1825 
1826  const Uint8* src = reinterpret_cast<const Uint8 *>(slock.pixels());
1827  Uint8* dest = reinterpret_cast<Uint8 *>(rlock.pixels());
1828 
1829  for(int y = 0; y < src_rect.h && (src_rect.y + y) < surf->h; ++y) {
1830  const Uint8* line_src = src + (src_rect.y + y) * spitch + src_rect.x * sbpp;
1831  Uint8* line_dest = dest + (dst_rect.y + y) * rpitch + dst_rect.x * rbpp;
1832  size_t size = src_rect.w + src_rect.x <= surf->w ? src_rect.w : surf->w - src_rect.x;
1833 
1834  assert(rpitch >= src_rect.w * rbpp);
1835  memcpy(line_dest, line_src, size * rbpp);
1836  }
1837 
1838  return res;
1839 }
1841  const surface &surf
1842  , const double amount
1843  , const Uint32 color
1844  , const bool optimize)
1845 {
1846  if(surf== nullptr) {
1847  return nullptr;
1848  }
1849 
1850  surface nsurf(make_neutral_surface(surf));
1851 
1852  if(nsurf == nullptr) {
1853  std::cerr << "could not make neutral surface...\n";
1854  return nullptr;
1855  }
1856 
1857  {
1858  surface_lock lock(nsurf);
1859  Uint32* beg = lock.pixels();
1860  Uint32* end = beg + nsurf->w*surf->h;
1861 
1862  Uint16 ratio = amount * 256;
1863  const Uint16 red = ratio * static_cast<Uint8>(color >> 16);
1864  const Uint16 green = ratio * static_cast<Uint8>(color >> 8);
1865  const Uint16 blue = ratio * static_cast<Uint8>(color);
1866  ratio = 256 - ratio;
1867 
1868 #ifdef PANDORA
1869  /*
1870  * Use an optimised version of the generic algorithm. The optimised
1871  * version processes 8 pixels a time. If the number of pixels is not an
1872  * exact multiple of 8 it falls back to the generic algorithm to handle
1873  * the last pixels.
1874  */
1875  uint16x8_t vred = vdupq_n_u16(red);
1876  uint16x8_t vgreen = vdupq_n_u16(green);
1877  uint16x8_t vblue = vdupq_n_u16(blue);
1878 
1879  uint8x8_t vratio = vdup_n_u8(ratio);
1880 
1881  const int div = (nsurf->w * surf->h) / 8;
1882  for(int i = 0; i < div; ++i, beg += 8) {
1883  uint8x8x4_t rgba = vld4_u8(reinterpret_cast<Uint8*>(beg));
1884 
1885  uint16x8_t b = vmull_u8(rgba.val[0], vratio);
1886  uint16x8_t g = vmull_u8(rgba.val[1], vratio);
1887  uint16x8_t r = vmull_u8(rgba.val[2], vratio);
1888 
1889  b = vaddq_u16(b, vblue);
1890  g = vaddq_u16(g, vgreen);
1891  r = vaddq_u16(r, vred);
1892 
1893  rgba.val[0] = vshrn_n_u16(b, 8);
1894  rgba.val[1] = vshrn_n_u16(g, 8);
1895  rgba.val[2] = vshrn_n_u16(r, 8);
1896 
1897  vst4_u8(reinterpret_cast<Uint8*>(beg), rgba);
1898  }
1899 #endif
1900  while(beg != end) {
1901  Uint8 a = static_cast<Uint8>(*beg >> 24);
1902  Uint8 r = (ratio * static_cast<Uint8>(*beg >> 16) + red) >> 8;
1903  Uint8 g = (ratio * static_cast<Uint8>(*beg >> 8) + green) >> 8;
1904  Uint8 b = (ratio * static_cast<Uint8>(*beg) + blue) >> 8;
1905 
1906  *beg = (a << 24) | (r << 16) | (g << 8) | b;
1907 
1908  ++beg;
1909  }
1910  }
1911 
1912  return optimize ? create_optimized_surface(nsurf) : nsurf;
1913 }
1914 
1915 /* Simplified RotSprite algorithm.
1916  * http://en.wikipedia.org/wiki/Image_scaling#RotSprite
1917  * Lifted from: http://github.com/salmonmoose/SpriteRotator
1918  * 1) Zoom the source image by a certain factor.
1919  * 2) Scan the zoomed source image at every step=offset and put it in the result. */
1920 surface rotate_any_surface(const surface& surf, float angle, int zoom, int offset, bool optimize)
1921 {
1922  int src_w, src_h, dst_w, dst_h;
1923  float min_x, max_x, min_y, max_y, sine, cosine;
1924  {
1925  // convert angle to radiant (angle * 2 * PI) / 360
1926  const float radians = angle * boost::math::constants::pi<float>() / 180;
1927  cosine = static_cast<float>(cos(radians));
1928  sine = static_cast<float>(sin(radians));
1929  // calculate the size of the dst image
1930  src_w = surf->w * zoom;
1931  src_h = surf->h * zoom;
1932  /* See http://en.wikipedia.org/wiki/Rotation_(mathematics) */
1933  const float point_1x = src_h * -sine;
1934  const float point_1y = src_h * cosine;
1935  const float point_2x = src_w * cosine - src_h * sine;
1936  const float point_2y = src_h * cosine + src_w * sine;
1937  const float point_3x = src_w * cosine;
1938  const float point_3y = src_w * sine;
1939  /* After the rotation, the new image has different dimensions.
1940  * E.g.: The maximum height equals the former diagonal in case the angle is 45, 135, 225 or 315 degree.
1941  * See http://en.wikipedia.org/wiki/File:Rotation_illustration2.svg to get the idea. */
1942  min_x = std::min(0.0F, std::min(point_1x, std::min(point_2x, point_3x)));
1943  min_y = std::min(0.0F, std::min(point_1y, std::min(point_2y, point_3y)));
1944  max_x = (angle > 90 && angle < 180) ? 0 : std::max(point_1x, std::max(point_2x, point_3x));
1945  max_y = (angle > 180 && angle < 270) ? 0 : std::max(point_1y, std::max(point_2y, point_3y));
1946  dst_w = static_cast<int>(ceil(std::abs(max_x) - min_x)) / zoom;
1947  dst_h = static_cast<int>(ceil(std::abs(max_y) - min_y)) / zoom;
1948  }
1949  surface dst(create_neutral_surface(dst_w, dst_h));
1950  {
1951  surface_lock dst_lock(dst);
1952  const surface src = scale_surface(surf, src_w, src_h, false);
1953  const_surface_lock src_lock(src);
1954  const float scale = 1.f / zoom;
1955  const int max_x = dst_w * zoom;
1956  const int max_y = dst_h * zoom;
1957  /* Loop through the zoomed src image,
1958  * take every pixel in steps with offset distance and place it in the dst image. */
1959  for (int x = 0; x < max_x; x += offset)
1960  for (int y = 0; y < max_y; y += offset) {
1961  // calculate the src pixel that fits in the dst
1962  const float source_x = (x + min_x)*cosine + (y + min_y)*sine;
1963  const float source_y = (y + min_y)*cosine - (x + min_x)*sine;
1964  // if the pixel exists on the src surface
1965  if (source_x >= 0 && source_x < src_w
1966  && source_y >= 0 && source_y < src_h)
1967  // get it from the src surface and place it on the dst surface
1968  put_pixel(dst, dst_lock, x*scale , y*scale, // multiply with scale
1969  get_pixel(src, src_lock, source_x, source_y));
1970  }
1971  }
1972  return optimize ? create_optimized_surface(dst) : dst;
1973 }
1974 
1975 void put_pixel(const surface& surf, surface_lock& surf_lock, int x, int y, Uint32 pixel)
1976 {
1977  const int bpp = surf->format->BytesPerPixel;
1978  /* dst is the address to the pixel we want to set */
1979  Uint8* const dst = reinterpret_cast<Uint8*>(surf_lock.pixels()) + y * surf->pitch + x * bpp;
1980  switch (bpp) {
1981  case 1:
1982  *dst = pixel;
1983  break;
1984  case 2:
1985  *reinterpret_cast<Uint16*>(dst) = pixel;
1986  break;
1987  case 3:
1988  if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1989  dst[0] = (pixel >> 16) & 0xff;
1990  dst[1] = (pixel >> 8) & 0xff;
1991  dst[2] = pixel & 0xff;
1992  } else {
1993  dst[0] = pixel & 0xff;
1994  dst[1] = (pixel >> 8) & 0xff;
1995  dst[2] = (pixel >> 16) & 0xff;
1996  }
1997  break;
1998  case 4:
1999  *reinterpret_cast<Uint32*>(dst) = pixel;
2000  break;
2001  default:
2002  break;
2003  }
2004 }
2005 
2006 Uint32 get_pixel(const surface& surf, const const_surface_lock& surf_lock, int x, int y)
2007 {
2008  const int bpp = surf->format->BytesPerPixel;
2009  /* p is the address to the pixel we want to retrieve */
2010  const Uint8* const src = reinterpret_cast<const Uint8*>(surf_lock.pixels()) + y * surf->pitch + x * bpp;
2011  switch (bpp) {
2012  case 1:
2013  return *src;
2014  case 2:
2015  return *reinterpret_cast<const Uint16*>(src);
2016  case 3:
2017  if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
2018  return src[0] << 16 | src[1] << 8 | src[2];
2019  else
2020  return src[0] | src[1] << 8 | src[2] << 16;
2021  break;
2022  case 4:
2023  return *reinterpret_cast<const Uint32*>(src);
2024  }
2025  return 0;
2026 }
2027 
2028 // Rotates a surface 180 degrees.
2029 surface rotate_180_surface(const surface &surf, bool optimize)
2030 {
2031  if ( surf == nullptr )
2032  return nullptr;
2033 
2034  // Work with a "neutral" (unoptimized) surface.
2035  surface nsurf(make_neutral_surface(surf));
2036 
2037  if ( nsurf == nullptr ) {
2038  std::cerr << "could not make neutral surface...\n";
2039  return nullptr;
2040  }
2041 
2042  {// Code block to limit the scope of the surface lock.
2043  surface_lock lock(nsurf);
2044  Uint32* const pixels = lock.pixels();
2045 
2046  // Swap pixels in the upper half of the image with
2047  // those in the lower half.
2048  for (int y=0; y != nsurf->h/2; ++y) {
2049  for(int x=0; x != nsurf->w; ++x) {
2050  const int index1 = y*nsurf->w + x;
2051  const int index2 = (nsurf->h-y)*nsurf->w - x - 1;
2052  std::swap(pixels[index1],pixels[index2]);
2053  }
2054  }
2055 
2056  if ( is_odd(nsurf->h) ) {
2057  // The middle row still needs to be processed.
2058  for (int x=0; x != nsurf->w/2; ++x) {
2059  const int index1 = (nsurf->h/2)*nsurf->w + x;
2060  const int index2 = (nsurf->h/2)*nsurf->w + (nsurf->w - x - 1);
2061  std::swap(pixels[index1],pixels[index2]);
2062  }
2063  }
2064  }
2065 
2066  return optimize ? create_optimized_surface(nsurf) : nsurf;
2067 }
2068 
2069 
2070 // Rotates a surface 90 degrees, either clockwise or counter-clockwise.
2071 surface rotate_90_surface(const surface &surf, bool clockwise, bool optimize)
2072 {
2073  if ( surf == nullptr )
2074  return nullptr;
2075 
2076  // Work with "neutral" (unoptimized) surfaces.
2077  surface dst(create_neutral_surface(surf->h, surf->w)); // Flipped dimensions.
2079 
2080  if ( src == nullptr || dst == nullptr ) {
2081  std::cerr << "could not make neutral surface...\n";
2082  return nullptr;
2083  }
2084 
2085  {// Code block to limit the scope of the surface locks.
2086  const_surface_lock src_lock(src);
2087  surface_lock dst_lock(dst);
2088 
2089  const Uint32* const src_pixels = src_lock.pixels();
2090  Uint32* const dst_pixels = dst_lock.pixels();
2091 
2092  // Copy the pixels.
2093  for ( int y = 0; y != src->h; ++y ) {
2094  for ( int x = 0; x != src->w; ++x ) {
2095  const int src_index = y*src->w + x;
2096  const int dst_index = clockwise ?
2097  x*dst->w + (dst->w-1-y) :
2098  (dst->h-1-x)*dst->w + y;
2099  dst_pixels[dst_index] = src_pixels[src_index];
2100  }
2101  }
2102  }
2103 
2104  return optimize ? create_optimized_surface(dst) : dst;
2105 }
2106 
2107 
2108 surface flip_surface(const surface &surf, bool optimize)
2109 {
2110  if(surf == nullptr) {
2111  return nullptr;
2112  }
2113 
2114  surface nsurf(make_neutral_surface(surf));
2115 
2116  if(nsurf == nullptr) {
2117  std::cerr << "could not make neutral surface...\n";
2118  return nullptr;
2119  }
2120 
2121  {
2122  surface_lock lock(nsurf);
2123  Uint32* const pixels = lock.pixels();
2124 
2125  for(int y = 0; y != nsurf->h; ++y) {
2126  for(int x = 0; x != nsurf->w/2; ++x) {
2127  const int index1 = y*nsurf->w + x;
2128  const int index2 = (y+1)*nsurf->w - x - 1;
2129  std::swap(pixels[index1],pixels[index2]);
2130  }
2131  }
2132  }
2133 
2134  return optimize ? create_optimized_surface(nsurf) : nsurf;
2135 }
2136 
2137 surface flop_surface(const surface &surf, bool optimize)
2138 {
2139  if(surf == nullptr) {
2140  return nullptr;
2141  }
2142 
2143  surface nsurf(make_neutral_surface(surf));
2144 
2145  if(nsurf == nullptr) {
2146  std::cerr << "could not make neutral surface...\n";
2147  return nullptr;
2148  }
2149 
2150  {
2151  surface_lock lock(nsurf);
2152  Uint32* const pixels = lock.pixels();
2153 
2154  for(int x = 0; x != nsurf->w; ++x) {
2155  for(int y = 0; y != nsurf->h/2; ++y) {
2156  const int index1 = y*nsurf->w + x;
2157  const int index2 = (nsurf->h-y-1)*surf->w + x;
2158  std::swap(pixels[index1],pixels[index2]);
2159  }
2160  }
2161  }
2162 
2163  return optimize ? create_optimized_surface(nsurf) : nsurf;
2164 }
2165 
2167 {
2168  if(surf == nullptr)
2169  return nullptr;
2170 
2171  if(width == -1)
2172  width = surf->w;
2173 
2174  if(height == -1)
2175  height = surf->h;
2176 
2177  surface s = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, surf->format->BitsPerPixel,
2178  surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
2179  if (surf->format->palette) {
2180  SDL_SetPaletteColors(s->format->palette, surf->format->palette->colors, 0, surf->format->palette->ncolors);
2181  }
2182  return s;
2183 }
2184 
2186  const SDL_Rect* srcrect, surface& dst, const SDL_Rect* dstrect)
2187 {
2188  assert(surf);
2189  assert(dst);
2190  assert(is_neutral(dst));
2191 
2192  const surface& src = is_neutral(surf) ? surf : make_neutral_surface(surf);
2193 
2194  // Get the areas to blit
2195  SDL_Rect dst_rect = sdl::create_rect(0, 0, dst->w, dst->h);
2196  if(dstrect) {
2197  dst_rect.x = dstrect->x;
2198  dst_rect.w -= dstrect->x;
2199 
2200  dst_rect.y = dstrect->y;
2201  dst_rect.h -= dstrect->y;
2202 
2203  }
2204 
2205  SDL_Rect src_rect = sdl::create_rect(0, 0, src->w, src->h);
2206  if(srcrect && srcrect->w && srcrect->h) {
2207  src_rect.x = srcrect->x;
2208  src_rect.y = srcrect->y;
2209 
2210  src_rect.w = srcrect->w;
2211  src_rect.h = srcrect->h;
2212 
2213  if (src_rect.x < 0) {
2214  if (src_rect.x + src_rect.w <= 0 || src_rect.x + dst_rect.w <= 0 )
2215  return;
2216  dst_rect.x -= src_rect.x;
2217  dst_rect.w += src_rect.x;
2218  src_rect.w += src_rect.x;
2219  src_rect.x = 0;
2220  }
2221  if (src_rect.y < 0) {
2222  if (src_rect.y + src_rect.h <= 0 || src_rect.y + dst_rect.h <= 0 )
2223  return;
2224  dst_rect.y -= src_rect.y;
2225  dst_rect.h += src_rect.y;
2226  src_rect.h += src_rect.y;
2227  src_rect.y = 0;
2228  }
2229  if (src_rect.x + src_rect.w > src->w) {
2230  if (src_rect.x >= src->w)
2231  return;
2232  src_rect.w = src->w - src_rect.x;
2233  }
2234  if (src_rect.y + src_rect.h > src->h) {
2235  if (src_rect.y >= src->h)
2236  return;
2237  src_rect.h = src->h - src_rect.y;
2238  }
2239  }
2240 
2241  assert(dst_rect.x >= 0);
2242  assert(dst_rect.y >= 0);
2243 
2244  // Get the blit size limits.
2245  const unsigned width = std::min(src_rect.w, dst_rect.w);
2246  const unsigned height = std::min(src_rect.h, dst_rect.h);
2247 
2248  {
2249  // Extra scoping used for the surface_lock.
2250  const_surface_lock src_lock(src);
2251  surface_lock dst_lock(dst);
2252 
2253  const Uint32* const src_pixels = src_lock.pixels();
2254  Uint32* dst_pixels = dst_lock.pixels();
2255 
2256  for(unsigned y = 0; y < height; ++y) {
2257  for(unsigned x = 0; x < width; ++x) {
2258 
2259  // We need to do the blitting using some optimizations
2260  // if the src is fully transparent we can ignore this pixel
2261  // if the src is fully opaque we can overwrite the destination with this pixel
2262  // if the destination is fully transparent we replace us with the source
2263  //
2264  // We do these optimizations between the extraction of the variables
2265  // to avoid creating variables not used (it might save us some cycles).
2266 
2267  const int src_offset = (y + src_rect.y) * src->w + (x + src_rect.x);
2268  assert(src_offset < src->w * src->h);
2269  const Uint32 src_pixel = src_pixels[src_offset];
2270  const Uint8 src_a = (src_pixel & 0xFF000000) >> 24;
2271 
2272  if(!src_a) {
2273  // Fully transparent source, ignore
2274  continue;
2275  }
2276 
2277  const ptrdiff_t dst_offset = (y + dst_rect.y) * dst->w + (x + dst_rect.x);
2278  assert(dst_offset < dst->w * dst->h);
2279  if(src_a == 255) {
2280  // Fully opaque source, copy
2281  dst_pixels[dst_offset] = src_pixel;
2282  continue;
2283  }
2284 
2285  const Uint32 dst_pixel = dst_pixels[dst_offset];
2286  Uint8 dst_a = (dst_pixel & 0xFF000000) >> 24;
2287 
2288  if(!dst_a) {
2289  // Fully transparent destination, copy
2290  dst_pixels[dst_offset] = src_pixel;
2291  continue;
2292  }
2293 
2294  const Uint8 src_r = (src_pixel & 0x00FF0000) >> 16;
2295  const Uint8 src_g = (src_pixel & 0x0000FF00) >> 8;
2296  const Uint8 src_b = src_pixel & 0x000000FF;
2297 
2298  Uint8 dst_r = (dst_pixel & 0x00FF0000) >> 16;
2299  Uint8 dst_g = (dst_pixel & 0x0000FF00) >> 8;
2300  Uint8 dst_b = dst_pixel & 0x000000FF;
2301 
2302  if(dst_a == 255) {
2303 
2304  // Destination fully opaque blend the source.
2305  dst_r = (((src_r - dst_r) * src_a) >> 8 ) + dst_r;
2306  dst_g = (((src_g - dst_g) * src_a) >> 8 ) + dst_g;
2307  dst_b = (((src_b - dst_b) * src_a) >> 8 ) + dst_b;
2308 
2309  } else {
2310 
2311  // Destination and source party transparent.
2312 
2313  // acquired the data now do the blitting
2314  const unsigned tmp_a = 255 - src_a;
2315 
2316  const unsigned tmp_r = 1 + (src_r * src_a) + (dst_r * tmp_a);
2317  dst_r = (tmp_r + (tmp_r >> 8)) >> 8;
2318 
2319  const unsigned tmp_g = 1 + (src_g * src_a) + (dst_g * tmp_a);
2320  dst_g = (tmp_g + (tmp_g >> 8)) >> 8;
2321 
2322  const unsigned tmp_b = 1 + (src_b * src_a) + (dst_b * tmp_a);
2323  dst_b = (tmp_b + (tmp_b >> 8)) >> 8;
2324 
2325  dst_a += (((255 - dst_a) * src_a) >> 8);
2326  }
2327 
2328  dst_pixels[dst_offset] = (dst_a << 24) | (dst_r << 16) | (dst_g << 8) | (dst_b);
2329 
2330  }
2331  }
2332  }
2333 }
2334 
2335 surface get_surface_portion(const surface &src, SDL_Rect &area)
2336 {
2337  if (src == nullptr) {
2338  return nullptr;
2339  }
2340 
2341  // Check if there is something in the portion
2342  if(area.x >= src->w || area.y >= src->h || area.x + area.w < 0 || area.y + area.h < 0) {
2343  return nullptr;
2344  }
2345 
2346  if(area.x + area.w > src->w) {
2347  area.w = src->w - area.x;
2348  }
2349  if(area.y + area.h > src->h) {
2350  area.h = src->h - area.y;
2351  }
2352 
2353  // use same format as the source (almost always the screen)
2354  surface dst = create_compatible_surface(src, area.w, area.h);
2355 
2356  if(dst == nullptr) {
2357  std::cerr << "Could not create a new surface in get_surface_portion()\n";
2358  return nullptr;
2359  }
2360 
2361  sdl_copy_portion(src, &area, dst, nullptr);
2362 
2363  return dst;
2364 }
2365 
2366 namespace {
2367 
2368 struct not_alpha
2369 {
2370  not_alpha() {}
2371 
2372  // we assume neutral format
2373  bool operator()(Uint32 pixel) const {
2374  Uint8 alpha = pixel >> 24;
2375  return alpha != 0x00;
2376  }
2377 };
2378 
2379 }
2380 
2382 {
2383  SDL_Rect res = {0,0,0,0};
2384  surface nsurf(make_neutral_surface(surf));
2385  if(nsurf == nullptr) {
2386  std::cerr << "failed to make neutral surface\n";
2387  return res;
2388  }
2389 
2390  const not_alpha calc;
2391 
2392  surface_lock lock(nsurf);
2393  const Uint32* const pixels = lock.pixels();
2394 
2395  int n;
2396  for(n = 0; n != nsurf->h; ++n) {
2397  const Uint32* const start_row = pixels + n*nsurf->w;
2398  const Uint32* const end_row = start_row + nsurf->w;
2399 
2400  if(std::find_if(start_row,end_row,calc) != end_row)
2401  break;
2402  }
2403 
2404  res.y = n;
2405 
2406  for(n = 0; n != nsurf->h-res.y; ++n) {
2407  const Uint32* const start_row = pixels + (nsurf->h-n-1)*surf->w;
2408  const Uint32* const end_row = start_row + nsurf->w;
2409 
2410  if(std::find_if(start_row,end_row,calc) != end_row)
2411  break;
2412  }
2413 
2414  // The height is the height of the surface,
2415  // minus the distance from the top and
2416  // the distance from the bottom.
2417  res.h = nsurf->h - res.y - n;
2418 
2419  for(n = 0; n != nsurf->w; ++n) {
2420  int y;
2421  for(y = 0; y != nsurf->h; ++y) {
2422  const Uint32 pixel = pixels[y*nsurf->w + n];
2423  if(calc(pixel))
2424  break;
2425  }
2426 
2427  if(y != nsurf->h)
2428  break;
2429  }
2430 
2431  res.x = n;
2432 
2433  for(n = 0; n != nsurf->w-res.x; ++n) {
2434  int y;
2435  for(y = 0; y != nsurf->h; ++y) {
2436  const Uint32 pixel = pixels[y*nsurf->w + surf->w - n - 1];
2437  if(calc(pixel))
2438  break;
2439  }
2440 
2441  if(y != nsurf->h)
2442  break;
2443  }
2444 
2445  res.w = nsurf->w - res.x - n;
2446 
2447  return res;
2448 }
2449 
2450 bool operator==(const SDL_Color& a, const SDL_Color& b) {
2451  return a.r == b.r && a.g == b.g && a.b == b.b;
2452 }
2453 
2454 bool operator!=(const SDL_Color& a, const SDL_Color& b) {
2455  return !operator==(a,b);
2456 }
2457 
2458 SDL_Color inverse(const SDL_Color& color) {
2459  SDL_Color inverse;
2460  inverse.r = 255 - color.r;
2461  inverse.g = 255 - color.g;
2462  inverse.b = 255 - color.b;
2463  inverse.a = 0;
2464  return inverse;
2465 }
2466 
2467 surface_restorer::surface_restorer() : target_(nullptr), rect_(sdl::empty_rect), surface_(nullptr)
2468 {
2469 }
2470 
2472 : target_(target), rect_(rect), surface_(nullptr)
2473 {
2474  update();
2475 }
2476 
2478 {
2479  restore();
2480 }
2481 
2482 void surface_restorer::restore(SDL_Rect const &dst) const
2483 {
2484  if (surface_.null())
2485  return;
2486  SDL_Rect dst2 = sdl::intersect_rects(dst, rect_);
2487  if (dst2.w == 0 || dst2.h == 0)
2488  return;
2489  SDL_Rect src = dst2;
2490  src.x -= rect_.x;
2491  src.y -= rect_.y;
2492  sdl_blit(surface_, &src, target_->getSurface(), &dst2);
2493  update_rect(dst2);
2494 }
2495 
2497 {
2498  if (surface_.null())
2499  return;
2500  SDL_Rect dst = rect_;
2501  sdl_blit(surface_, nullptr, target_->getSurface(), &dst);
2502  update_rect(rect_);
2503 }
2504 
2506 {
2507  if(rect_.w <= 0 || rect_.h <= 0)
2508  surface_.assign(nullptr);
2509  else
2511 }
2512 
2514 {
2515  surface_.assign(nullptr);
2516 }
2517 
2518 void draw_centered_on_background(surface surf, const SDL_Rect& rect, const SDL_Color& color, surface target)
2519 {
2520  clip_rect_setter clip_setter(target, &rect);
2521 
2522  Uint32 col = SDL_MapRGBA(target->format, color.r, color.g, color.b, color.a);
2523  //TODO: only draw background outside the image
2524  SDL_Rect r = rect;
2525  sdl::fill_rect(target, &r, col);
2526 
2527  if (surf != nullptr) {
2528  r.x = rect.x + (rect.w-surf->w)/2;
2529  r.y = rect.y + (rect.h-surf->h)/2;
2530  sdl_blit(surf, nullptr, target, &r);
2531  }
2532  update_rect(rect);
2533 }
2534 
2535 std::ostream& operator<<(std::ostream& s, const SDL_Rect& rect)
2536 {
2537  s << rect.x << ',' << rect.y << " x " << rect.w << ',' << rect.h;
2538  return s;
2539 }
uint8x8_t vshrn_n_u16(uint16x8_t m, const unsigned imm)
Definition: neon.hpp:140
surface rotate_any_surface(const surface &surf, float angle, int zoom, int offset, bool optimize)
Rotates a surface by any degrees.
Definition: utils.cpp:1920
Definition: utils.hpp:250
SDL_Rect intersect_rects(SDL_Rect const &rect1, SDL_Rect const &rect2)
Calculates the intersection of two rectangles.
Definition: rect.cpp:58
surface flip_surface(const surface &surf, bool optimize)
Definition: utils.cpp:2108
GLdouble GLdouble z
Definition: glew.h:1527
surface rotate_180_surface(const surface &surf, bool optimize)
Rotates a surface 180 degrees.
Definition: utils.cpp:2029
surface create_neutral_surface(int w, int h)
Definition: utils.cpp:150
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: glew.h:1222
bool null() const
Definition: utils.hpp:104
SDL_Surface * get() const
Definition: utils.hpp:98
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glew.h:1222
surface & surface_
Definition: utils.hpp:446
void fill_rect(surface &dst, SDL_Rect *dst_rect, const Uint32 color)
Fill a rectangle on a given surface.
Definition: rect.hpp:143
GLenum GLenum GLenum GLenum GLenum scale
Definition: glew.h:10669
SDL_Color create_color(const unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
Definition: utils.cpp:89
surface adjust_surface_alpha_add(const surface &surf, int amount, bool optimize)
Definition: utils.cpp:1241
void put_pixel(const surface &surf, surface_lock &surf_lock, int x, int y, Uint32 pixel)
Helper methods for setting/getting a single pixel in an image.
Definition: utils.cpp:1975
surface stretch_surface_vertical(const surface &surf, const unsigned h, const bool optimize)
Stretches a surface in the vertical direction.
Definition: utils.cpp:223
Sint32 fixed_t
Definition: drawer.hpp:40
Helper class for ARM NEON support.
SDL_Color int_to_color(const Uint32 rgb)
Definition: utils.cpp:63
surface create_optimized_surface(const surface &surf)
Definition: utils.cpp:168
Definition: video.hpp:58
#define fxpdiv(x, y)
IN: unsigned and int - OUT: fixed_t.
Definition: util.hpp:509
const SDL_Rect empty_rect
Definition: rect.cpp:26
const Uint32 * pixels() const
Definition: utils.hpp:455
const surface & surface_
Definition: utils.hpp:457
bool string2rgb(const std::string &s, std::vector< Uint32 > &result)
Definition: color_range.cpp:91
surface recolor_image(surface surf, const std::map< Uint32, Uint32 > &map_rgb, bool optimize)
Recolors a surface using a map with source and converted palette values.
Definition: utils.cpp:1126
tvector< T, S > val[D]
Definition: neon.hpp:94
bool is_odd(T num)
Definition: util.hpp:37
surface rotate_90_surface(const surface &surf, bool clockwise, bool optimize)
Rotates a surface 90 degrees.
Definition: utils.cpp:2071
bool in_mask_surface(const surface &surf, const surface &mask)
Check if a surface fit into a mask.
Definition: utils.cpp:1349
surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB, bool optimize)
Definition: utils.cpp:888
#define h
GLboolean GLboolean g
Definition: glew.h:7319
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
GLenum src
Definition: glew.h:2392
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
#define d
surface get_surface_portion(const surface &src, SDL_Rect &area)
Get a portion of the screen.
Definition: utils.cpp:2335
uint16x8_t vdupq_n_u16(uint16_t imm)
Definition: neon.hpp:115
bool locked_
Definition: utils.hpp:447
-file util.hpp
#define SDLKey
Definition: compat.hpp:29
GLsizei samples
Definition: glew.h:3465
surface & getSurface()
Definition: dummy_video.cpp:22
const_surface_lock(const surface &surf)
Definition: utils.cpp:51
SDL_Rect get_non_transparent_portion(const surface &surf)
Definition: utils.cpp:2381
surface surface_
Definition: utils.hpp:489
void blit_surface(const surface &surf, const SDL_Rect *srcrect, surface &dst, const SDL_Rect *dstrect)
Replacement for sdl_blit.
Definition: utils.cpp:2185
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
surface shadow_image(const surface &surf, bool optimize)
create an heavy shadow of the image, by blurring, increasing alpha and darkening
Definition: utils.cpp:987
GLintptr offset
Definition: glew.h:1650
#define fxptoi(x)
IN: fixed_t - OUT: int.
Definition: util.hpp:512
GLdouble GLdouble GLdouble GLdouble q
Definition: glew.h:1382
surface mask_surface(const surface &surf, const surface &mask, bool *empty_result, const std::string &filename)
Applies a mask on a surface.
Definition: utils.cpp:1279
#define fxpmult(x, y)
IN: unsigned and fixed_t - OUT: unsigned.
Definition: util.hpp:506
void restore() const
Definition: utils.cpp:2496
surface wipe_alpha(const surface &surf, bool optimize)
Definition: utils.cpp:959
GLuint GLuint end
Definition: glew.h:1221
GLuint64EXT * result
Definition: glew.h:10727
Contains code for a floating point emulation.
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())
Definition: xbrz.cpp:1196
uint8x8_t vdup_n_u8(uint8_t imm)
Definition: neon.hpp:121
GLclampf GLclampf blue
Definition: glew.h:1488
void draw_centered_on_background(surface surf, const SDL_Rect &rect, const SDL_Color &color, surface target)
Definition: utils.cpp:2518
GLint limit
Definition: glew.h:10112
GLclampf green
Definition: glew.h:1488
SDL_Color string_to_color(const std::string &color_string)
Return the color the string represents.
Definition: utils.cpp:77
SDL_Rect rect_
Definition: utils.hpp:488
Definition: utils.hpp:250
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
surface swap_channels_image(const surface &surf, channel r, channel g, channel b, channel a, bool optimize)
Definition: utils.cpp:1024
GLsizei const GLfloat * value
Definition: glew.h:1817
GLenum GLenum dst
Definition: glew.h:2392
surface adjust_surface_alpha(const surface &surf, fixed_t amount, bool optimize)
Definition: utils.cpp:1202
uint8x8x4_t vld4_u8(uint8_t *base)
Definition: neon.hpp:200
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
surface blend_surface(const surface &surf, const double amount, const Uint32 color, const bool optimize)
Blends a surface with a color.
Definition: utils.cpp:1840
GLclampf GLclampf GLclampf alpha
Definition: glew.h:1488
surface light_surface(const surface &surf, const surface &lightmap, bool optimize)
Light surf using lightmap.
Definition: utils.cpp:1458
GLenum GLint GLuint mask
Definition: glew.h:1813
Helper class for pinning SDL surfaces into memory.
Definition: utils.hpp:439
GLfloat GLfloat p
Definition: glew.h:12766
surface sepia_image(const surface &surf, bool optimize)
Definition: utils.cpp:846
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
surface blur_surface(const surface &surf, int depth, bool optimize)
Cross-fades a surface.
Definition: utils.cpp:1524
surf
Definition: filter.cpp:143
GLuint color
Definition: glew.h:5801
surface scale_surface_nn(const surface &surf, int w, int h)
Scale a surface using the nearest neighbor algorithm (provided by xBRZ lib)
Definition: utils.cpp:404
surface flop_surface(const surface &surf, bool optimize)
Definition: utils.cpp:2137
std::ostream & operator<<(std::ostream &s, const SDL_Rect &rect)
Definition: utils.cpp:2535
const std::string &parameters float amount
Definition: filter.cpp:132
surface submerge_alpha(const surface &surf, int depth, float alpha_base, float alpha_delta, bool optimize)
Progressively reduce alpha of bottom part of the surface.
Definition: utils.cpp:1395
SDLKey sdl_keysym_from_name(std::string const &keyname)
Definition: utils.cpp:103
Definition: pump.hpp:42
surface adjust_surface_color(const surface &surf, int red, int green, int blue, bool optimize)
Definition: utils.cpp:718
GLuint res
Definition: glew.h:9258
Definition: utils.hpp:250
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1222
class CVideo * target_
Definition: utils.hpp:487
void vst4_u8(uint8_t *base, uint8x8x4_t list)
Definition: neon.hpp:217
Template class for the emulation.
SDL_Color inverse(const SDL_Color &color)
Definition: utils.cpp:2458
surface scale_surface_xbrz(const surface &surf, size_t z)
Scale a surface using xBRZ algorithm.
Definition: utils.cpp:366
bool operator==(const SDL_Color &a, const SDL_Color &b)
Definition: utils.cpp:2450
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
size_t i
Definition: function.cpp:1057
surface brighten_image(const surface &surf, fixed_t amount, bool optimize)
Definition: utils.cpp:1160
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
Emulates a vector.
Definition: neon.hpp:64
Definition: utils.hpp:250
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
static SDL_PixelFormat & get_neutral_pixel_format()
Definition: utils.cpp:120
#define SDL_SRCALPHA
Definition: alpha.hpp:28
bool is_neutral(const surface &surf)
Check that the surface is neutral bpp 32.
Definition: utils.cpp:113
static map_location::DIRECTION sw
floating_point_emulation::tfloat< double, 0 > tfloat
surface blur_alpha_surface(const surface &surf, int depth, bool optimize)
Cross-fades a surface with alpha channel.
Definition: utils.cpp:1659
GLint GLint GLint GLint GLint GLint GLsizei GLsizei height
Definition: glew.h:1220
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
GLsizeiptr size
Definition: glew.h:1649
GLclampd n
Definition: glew.h:5903
bool operator<(const surface &a, const surface &b)
Definition: utils.cpp:108
Contains the SDL_Rect helper code.
#define g
Definition: glew.h:12730
surface tile_surface(const surface &surf, int w, int h, bool optimize)
Tile a surface.
Definition: utils.cpp:674
void swap(game_board &one, game_board &other)
Definition: game_board.cpp:56
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:135
GLdouble angle
Definition: glew.h:6979
void assign(const surface &o)
Definition: utils.hpp:83
surface create_compatible_surface(const surface &surf, int width, int height)
Definition: utils.cpp:2166
surface alpha_to_greyscale(const surface &surf, bool optimize)
Definition: utils.cpp:931
surface greyscale_image(const surface &surf, bool optimize)
Definition: utils.cpp:761
bool operator!=(const SDL_Color &a, const SDL_Color &b)
Definition: utils.cpp:2454
Uint32 * pixels()
Definition: utils.hpp:444
GLint GLint GLint GLint GLint GLint GLsizei width
Definition: glew.h:1220
surface_lock(surface &surf)
Definition: utils.cpp:39
#define e
uint16x8_t vaddq_u16(uint16x8_t n, uint16x8_t m)
Definition: neon.hpp:159
void sdl_copy_portion(const surface &screen, SDL_Rect *screen_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:116
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:112
int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha)
Definition: alpha.cpp:18
Compatibility layer for using SDL 1.2 and 2.0.
surface scale_surface_sharp(const surface &surf, int w, int h, bool optimize)
Scale a surface using modified nearest neighbour algorithm.
Definition: utils.cpp:577
GLdouble s
Definition: glew.h:1358
Emulates a matrix.
Definition: neon.hpp:92
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
surface stretch_surface_horizontal(const surface &surf, const unsigned w, const bool optimize)
Stretches a surface in the horizontal direction.
Definition: utils.cpp:178
void nearestNeighborScale(const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight)
Definition: xbrz.hpp:104
GLsizei const GLcharARB ** string
Definition: glew.h:4503
Uint32 blend_rgba(const surface &surf, unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned char drop)
This method blends a RGBA color.
Definition: utils.cpp:356
surface cut_surface(const surface &surf, SDL_Rect const &r)
Cuts a rectangle from a surface.
Definition: utils.cpp:1782
uint16x8_t vmull_u8(uint8x8_t n, uint8x8_t m)
Definition: neon.hpp:179
Uint32 get_pixel(const surface &surf, const const_surface_lock &surf_lock, int x, int y)
Definition: utils.cpp:2006
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: util.hpp:503
GLenum target
Definition: glew.h:5190
~surface_lock()
Definition: utils.cpp:45
surface monochrome_image(const surface &surf, const int threshold, bool optimize)
Definition: utils.cpp:806
channel
Definition: utils.hpp:250