Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Routines for bitblt's.
  23.  *
  24.  */
  25.  
  26. #include <algorithm>
  27. #include <utility>
  28. #include <string.h>
  29. #include "u_mem.h"
  30. #include "gr.h"
  31. #include "grdef.h"
  32. #include "rle.h"
  33. #include "dxxerror.h"
  34. #include "byteutil.h"
  35. #if DXX_USE_OGL
  36. #include "ogl_init.h"
  37. #endif
  38.  
  39. #include "compiler-range_for.h"
  40. #include "d_range.h"
  41. #include <array>
  42.  
  43. namespace dcx {
  44.  
  45. static void gr_bm_ubitblt00_rle(unsigned w, unsigned h, int dx, int dy, int sx, int sy, const grs_bitmap &src, grs_bitmap &dest);
  46. #if !DXX_USE_OGL
  47. static void gr_bm_ubitblt00m_rle(unsigned w, unsigned h, int dx, int dy, int sx, int sy, const grs_bitmap &src, grs_bitmap &dest);
  48. static void gr_bm_ubitblt0x_rle(grs_canvas &dest, unsigned w, unsigned h, int dx, int dy, int sx, int sy, const grs_bitmap &src);
  49. #endif
  50.  
  51. #define gr_linear_movsd(S,D,L)  memcpy(D,S,L)
  52.  
  53. #if !DXX_USE_OGL
  54. static void gr_linear_rep_movsdm(uint8_t *const dest, const uint8_t *const src, const uint_fast32_t num_pixels)
  55. {
  56.         auto predicate = [&](uint8_t s, uint8_t d) {
  57.                 return s == 255 ? d : s;
  58.         };
  59.         std::transform(src, src + num_pixels, dest, dest, predicate);
  60. }
  61. #endif
  62.  
  63. template <typename F>
  64. static void gr_for_each_bitmap_line(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm, F f)
  65. {
  66.         const size_t src_width = bm.bm_w;
  67.         const uintptr_t src_rowsize = bm.bm_rowsize;
  68.         const uintptr_t dest_rowsize = canvas.cv_bitmap.bm_rowsize;
  69.         auto dest = &(canvas.cv_bitmap.get_bitmap_data()[ dest_rowsize*y+x ]);
  70.         auto src = bm.get_bitmap_data();
  71.         for (uint_fast32_t y1 = bm.bm_h; y1 --;)
  72.         {
  73.                 f(dest, src, src_width);
  74.                 src += src_rowsize;
  75.                 dest+= dest_rowsize;
  76.         }
  77. }
  78.  
  79. static void gr_ubitmap00(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  80. {
  81. #if defined(WIN32) && defined(__GNUC__) && (__GNUC__ >= 6 && __GNUC__ <= 9)
  82. /*
  83.  * When using memcpy directly, i686-w64-mingw32-g++-6.3.0 fails to
  84.  * deduce the template instantiation correctly, leading to a compiler
  85.  * crash.  i686-w64-mingw32-g++-5.4.0 works correctly.  Other platforms
  86.  * work correctly.  For the affected cases, define a trivial wrapper,
  87.  * which gcc deduces correctly.
  88.  *
  89.  * This appears to be gcc bug #71740.
  90.  * <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71740>
  91.  *
  92.  * Known affected:
  93.  * - i686-w64-mingw32-g++-6.3.0
  94.  * - i686-w64-mingw32-g++-7.3.0
  95.  *
  96.  * Restrict this workaround to known broken versions.
  97.  */
  98.         void *(__attribute__((__cdecl__)) *d_memcpy)(void*, const void*, size_t) = memcpy;
  99. #else
  100. #define d_memcpy memcpy
  101. #endif
  102.         gr_for_each_bitmap_line(canvas, x, y, bm, d_memcpy);
  103. }
  104.  
  105. #if !DXX_USE_OGL
  106. static void gr_ubitmap00m(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  107. {
  108.         gr_for_each_bitmap_line(canvas, x, y, bm, gr_linear_rep_movsdm);
  109. }
  110. #endif
  111.  
  112. template <typename F>
  113. static inline void gr_for_each_bitmap_byte(grs_canvas &canvas, const uint_fast32_t bx, const uint_fast32_t by, const grs_bitmap &bm, F f)
  114. {
  115.         auto src = bm.bm_data;
  116.         const auto ey = by + bm.bm_h;
  117.         const auto ex = bx + bm.bm_w;
  118.         range_for (const auto iy, xrange(by, ey))
  119.                 range_for (const auto ix, xrange(bx, ex))
  120.                         f(canvas, src++, ix, iy);
  121. }
  122.  
  123. static void gr_ubitmap012(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  124. {
  125.         const auto a = [](grs_canvas &cv, const color_palette_index *const src, const uint_fast32_t px, const uint_fast32_t py) {
  126.                 const auto color = *src;
  127.                 gr_upixel(cv.cv_bitmap, px, py, color);
  128.         };
  129.         gr_for_each_bitmap_byte(canvas, x, y, bm, a);
  130. }
  131.  
  132. #if !DXX_USE_OGL
  133. static void gr_ubitmap012m(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  134. {
  135.         const auto a = [](grs_canvas &cv, const color_palette_index *const src, const uint_fast32_t px, const uint_fast32_t py) {
  136.                 const uint8_t c = *src;
  137.                 if (c != 255)
  138.                 {
  139.                         gr_upixel(cv.cv_bitmap, px, py, c);
  140.                 }
  141.         };
  142.         gr_for_each_bitmap_byte(canvas, x, y, bm, a);
  143. }
  144. #endif
  145.  
  146. static void gr_ubitmapGENERIC(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  147. {
  148.         const uint_fast32_t bm_h = bm.bm_h;
  149.         const uint_fast32_t bm_w = bm.bm_w;
  150.         range_for (const uint_fast32_t y1, xrange(bm_h))
  151.         {
  152.                 range_for (const uint_fast32_t x1, xrange(bm_w))
  153.                 {
  154.                         const auto color = gr_gpixel(bm, x1, y1);
  155.                         gr_upixel(canvas.cv_bitmap, x + x1, y + y1, color);
  156.                 }
  157.         }
  158. }
  159.  
  160. #if !DXX_USE_OGL
  161. static void gr_ubitmapGENERICm(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  162. {
  163.         const uint_fast32_t bm_h = bm.bm_h;
  164.         const uint_fast32_t bm_w = bm.bm_w;
  165.         range_for (const uint_fast32_t y1, xrange(bm_h))
  166.         {
  167.                 range_for (const uint_fast32_t x1, xrange(bm_w))
  168.                 {
  169.                         const auto c = gr_gpixel(bm,x1,y1);
  170.                         if (c != TRANSPARENCY_COLOR)
  171.                         {
  172.                                 gr_upixel(canvas.cv_bitmap, x + x1, y + y1, c);
  173.                         }
  174.                 }
  175.         }
  176. }
  177. #endif
  178.  
  179. void gr_ubitmap(grs_canvas &canvas, grs_bitmap &bm)
  180. {
  181.         const unsigned x = 0;
  182.         const unsigned y = 0;
  183.  
  184.         const auto source = bm.get_type();
  185.         const auto dest = canvas.cv_bitmap.get_type();
  186.  
  187.         if (source==bm_mode::linear) {
  188.                 switch( dest )
  189.                 {
  190.                 case bm_mode::linear:
  191.                         if (bm.get_flag_mask(BM_FLAG_RLE))
  192.                                 gr_bm_ubitblt00_rle(bm.bm_w, bm.bm_h, x, y, 0, 0, bm, canvas.cv_bitmap);
  193.                         else
  194.                                 gr_ubitmap00(canvas, x, y, bm);
  195.                         return;
  196. #if DXX_USE_OGL
  197.                 case bm_mode::ogl:
  198.                         ogl_ubitmapm_cs(canvas, x, y, -1, -1, bm, ogl_colors::white, F1_0);
  199.                         return;
  200. #endif
  201.                 default:
  202.                         gr_ubitmap012(canvas, x, y, bm);
  203.                         return;
  204.                 }
  205.         } else  {
  206.                 gr_ubitmapGENERIC(canvas, x, y, bm);
  207.         }
  208. }
  209.  
  210. #if !DXX_USE_OGL
  211. void gr_ubitmapm(grs_canvas &canvas, const unsigned x, const unsigned y, grs_bitmap &bm)
  212. {
  213.         const auto source = bm.get_type();
  214.         if (source==bm_mode::linear) {
  215.                 switch(canvas.cv_bitmap.get_type())
  216.                 {
  217.                 case bm_mode::linear:
  218.                         if (bm.get_flag_mask(BM_FLAG_RLE))
  219.                                 gr_bm_ubitblt00m_rle(bm.bm_w, bm.bm_h, x, y, 0, 0, bm, canvas.cv_bitmap);
  220.                         else
  221.                                 gr_ubitmap00m(canvas, x, y, bm);
  222.                         return;
  223.                 default:
  224.                         gr_ubitmap012m(canvas, x, y, bm);
  225.                         return;
  226.                 }
  227.         } else  {
  228.                 gr_ubitmapGENERICm(canvas, x, y, bm);
  229.         }
  230. }
  231.  
  232. // From Linear to Linear
  233. static void gr_bm_ubitblt00(const unsigned w, const unsigned h, const unsigned dx, const unsigned dy, const unsigned sx, const unsigned sy, const grs_bitmap &src, grs_bitmap &dest)
  234. {
  235.         //int   src_bm_rowsize_2, dest_bm_rowsize_2;
  236.         auto sbits = &src.get_bitmap_data()[(src.bm_rowsize * sy) + sx];
  237.         auto dbits = &dest.get_bitmap_data()[(dest.bm_rowsize * dy) + dx];
  238.         const auto dstep = dest.bm_rowsize;
  239.         // No interlacing, copy the whole buffer.
  240.         for (uint_fast32_t i = h; i --;)
  241.         {
  242.                 gr_linear_movsd( sbits, dbits, w );
  243.                 //memcpy(dbits, sbits, w);
  244.                 sbits += src.bm_rowsize;
  245.                 dbits += dstep;
  246.             }
  247. }
  248.  
  249. // From Linear to Linear Masked
  250. static void gr_bm_ubitblt00m(const unsigned w, const uint_fast32_t h, const unsigned dx, const unsigned dy, const unsigned sx, const unsigned sy, const grs_bitmap &src, grs_bitmap &dest)
  251. {
  252.         //int   src_bm_rowsize_2, dest_bm_rowsize_2;
  253.         auto sbits = &src.get_bitmap_data()[(src.bm_rowsize * sy) + sx];
  254.         auto dbits = &dest.get_bitmap_data()[(dest.bm_rowsize * dy) + dx];
  255.  
  256.         // No interlacing, copy the whole buffer.
  257.  
  258.         {
  259.                 for (auto i = h; i; --i)
  260.                 {
  261.                         gr_linear_rep_movsdm(dbits, sbits, w);
  262.                         sbits += src.bm_rowsize;
  263.                         dbits += dest.bm_rowsize;
  264.                 }
  265.         }
  266. }
  267.  
  268. void gr_bm_ubitblt(grs_canvas &canvas, const unsigned w, const unsigned h, const int dx, const int dy, const int sx, const int sy, const grs_bitmap &src)
  269. {
  270.         auto &dest = canvas.cv_bitmap;
  271.         if (src.get_type() == bm_mode::linear && dest.get_type() == bm_mode::linear)
  272.         {
  273.                 if (src.get_flag_mask(BM_FLAG_RLE))
  274.                         gr_bm_ubitblt00_rle( w, h, dx, dy, sx, sy, src, dest );
  275.                 else
  276.                         gr_bm_ubitblt00( w, h, dx, dy, sx, sy, src, dest );
  277.                 return;
  278.         }
  279.  
  280.         if (src.get_flag_mask(BM_FLAG_RLE) && src.get_type() == bm_mode::linear)
  281.         {
  282.                 gr_bm_ubitblt0x_rle(canvas, w, h, dx, dy, sx, sy, src);
  283.                 return;
  284.         }
  285.  
  286.         range_for (const uint_fast32_t y1, xrange(h))
  287.                 range_for (const uint_fast32_t x1, xrange(w))
  288.                         gr_bm_pixel(canvas, dest, dx + x1, dy + y1, gr_gpixel(src, sx + x1, sy + y1));
  289. }
  290. #endif
  291.  
  292. // Clipped bitmap ...
  293. void gr_bitmap(grs_canvas &canvas, const unsigned x, const unsigned y, grs_bitmap &bm)
  294. {
  295.         int dx1=x, dx2=x+bm.bm_w-1;
  296.         int dy1=y, dy2=y+bm.bm_h-1;
  297.  
  298.         if (dx1 >= canvas.cv_bitmap.bm_w || dx2 < 0)
  299.                 return;
  300.         if (dy1 >= canvas.cv_bitmap.bm_h || dy2 < 0)
  301.                 return;
  302.         // Draw bitmap bm[x,y] into (dx1,dy1)-(dx2,dy2)
  303. #if DXX_USE_OGL
  304.         ogl_ubitmapm_cs(canvas, x, y, 0, 0, bm, ogl_colors::white, F1_0);
  305. #else
  306.         int sx = 0, sy = 0;
  307.         if ( dx1 < 0 )
  308.         {
  309.                 sx = -dx1;
  310.                 dx1 = 0;
  311.         }
  312.         if ( dy1 < 0 )
  313.         {
  314.                 sy = -dy1;
  315.                 dy1 = 0;
  316.         }
  317.         if (dx2 >= canvas.cv_bitmap.bm_w)
  318.                 dx2 = canvas.cv_bitmap.bm_w - 1;
  319.         if (dy2 >= canvas.cv_bitmap.bm_h)
  320.                 dy2 = canvas.cv_bitmap.bm_h - 1;
  321.  
  322.         gr_bm_ubitblt(canvas, dx2 - dx1 + 1, dy2 - dy1 + 1, dx1, dy1, sx, sy, bm);
  323. #endif
  324. }
  325.  
  326. #if !DXX_USE_OGL
  327. void gr_bitmapm(grs_canvas &canvas, const unsigned x, const unsigned y, const grs_bitmap &bm)
  328. {
  329.         int dx1=x, dx2=x+bm.bm_w-1;
  330.         int dy1=y, dy2=y+bm.bm_h-1;
  331.         int sx=0, sy=0;
  332.  
  333.         if (dx1 >= canvas.cv_bitmap.bm_w || dx2 < 0)
  334.                 return;
  335.         if (dy1 >= canvas.cv_bitmap.bm_h || dy2 < 0)
  336.                 return;
  337.         if ( dx1 < 0 ) { sx = -dx1; dx1 = 0; }
  338.         if ( dy1 < 0 ) { sy = -dy1; dy1 = 0; }
  339.         if (dx2 >= canvas.cv_bitmap.bm_w)
  340.                 dx2 = canvas.cv_bitmap.bm_w - 1;
  341.         if (dy2 >= canvas.cv_bitmap.bm_h)
  342.                 dy2 = canvas.cv_bitmap.bm_h - 1;
  343.  
  344.         // Draw bitmap bm[x,y] into (dx1,dy1)-(dx2,dy2)
  345.  
  346.         if (bm.get_type() == bm_mode::linear && canvas.cv_bitmap.get_type() == bm_mode::linear)
  347.         {
  348.                 if (bm.get_flag_mask(BM_FLAG_RLE))
  349.                         gr_bm_ubitblt00m_rle(dx2 - dx1 + 1, dy2 - dy1 + 1, dx1, dy1, sx, sy, bm, canvas.cv_bitmap );
  350.                 else
  351.                         gr_bm_ubitblt00m(dx2 - dx1 + 1, dy2 - dy1 + 1, dx1, dy1, sx, sy, bm, canvas.cv_bitmap );
  352.                 return;
  353.         }
  354.         gr_bm_ubitbltm(canvas, dx2 - dx1 + 1, dy2 - dy1 + 1, dx1, dy1, sx, sy, bm);
  355. }
  356.  
  357. void gr_bm_ubitbltm(grs_canvas &canvas, const unsigned w, const unsigned h, const unsigned dx, const unsigned dy, const unsigned sx, const unsigned sy, const grs_bitmap &src)
  358. {
  359.         ubyte c;
  360.  
  361.         auto &dest = canvas.cv_bitmap;
  362.         range_for (const uint_fast32_t y1, xrange(h))
  363.                 range_for (const uint_fast32_t x1, xrange(w))
  364.                         if ((c=gr_gpixel(src,sx+x1,sy+y1))!=255)
  365.                                 gr_bm_pixel(canvas, dest, dx + x1, dy + y1, c);
  366. }
  367. #endif
  368.  
  369. namespace {
  370.  
  371. class bm_rle_window : bm_rle_src_stride
  372. {
  373. public:
  374.         bm_rle_window(const grs_bitmap &src) :
  375.                 bm_rle_src_stride(src, src.get_flag_mask(BM_FLAG_RLE_BIG))
  376.         {
  377.         }
  378.         void skip_upper_rows(uint_fast32_t);
  379.         uint8_t *init(uint_fast32_t dx, uint_fast32_t dy, uint_fast32_t sy, grs_bitmap &dest);
  380.         template <typename F>
  381.                 void apply(uint_fast32_t w, uint_fast32_t h, uint_fast32_t sx, uint8_t *dbits, uint_fast32_t bm_rowsize, F &&f);
  382. #if !DXX_USE_OGL
  383.         using bm_rle_src_stride::src_bits;
  384.         using bm_rle_src_stride::advance_src_bits;
  385. #endif
  386. };
  387.  
  388. void bm_rle_window::skip_upper_rows(const uint_fast32_t sy)
  389. {
  390.         for (uint_fast32_t i = sy; i; --i)
  391.                 advance_src_bits();
  392. }
  393.  
  394. uint8_t *bm_rle_window::init(const uint_fast32_t dx, const uint_fast32_t dy, const uint_fast32_t sy, grs_bitmap &dest)
  395. {
  396.         skip_upper_rows(sy);
  397.         return &dest.get_bitmap_data()[(dest.bm_rowsize * dy) + dx];
  398. }
  399.  
  400. template <typename F>
  401. void bm_rle_window::apply(const uint_fast32_t w, const uint_fast32_t h, const uint_fast32_t sx, uint8_t *dbits, const uint_fast32_t bm_rowsize, F &&f)
  402. {
  403.         // No interlacing, copy the whole buffer.
  404.         for (uint_fast32_t i = h; i; --i)
  405.         {
  406.                 f(std::exchange(dbits, dbits + bm_rowsize), src_bits, sx, w);
  407.                 advance_src_bits();
  408.         }
  409. }
  410.  
  411. }
  412.  
  413. static void gr_bm_ubitblt00_rle(const unsigned w, const unsigned h, const int dx, const int dy, const int sx, const int sy, const grs_bitmap &src, grs_bitmap &dest)
  414. {
  415.         bm_rle_window bw(src);
  416.         bw.apply(sx + w - 1, h, sx, bw.init(dx, dy, sy, dest), dest.bm_rowsize, gr_rle_expand_scanline);
  417. }
  418.  
  419. #if !DXX_USE_OGL
  420. static void gr_bm_ubitblt00m_rle(const unsigned w, const unsigned h, const int dx, const int dy, const int sx, const int sy, const grs_bitmap &src, grs_bitmap &dest)
  421. {
  422.         bm_rle_window bw(src);
  423.         bw.apply(sx + w - 1, h, sx, bw.init(dx, dy, sy, dest), dest.bm_rowsize, gr_rle_expand_scanline_masked);
  424. }
  425.  
  426. // in rle.c
  427.  
  428. static void gr_bm_ubitblt0x_rle(grs_canvas &canvas, const unsigned w, const unsigned h, const int dx, const int dy, const int sx, const int sy, const grs_bitmap &src)
  429. {
  430.         bm_rle_window bw(src);
  431.         bw.skip_upper_rows(sy);
  432.         range_for (const uint_fast32_t y1, xrange(h))
  433.         {
  434.                 const auto sbits = bw.src_bits;
  435.                 gr_rle_expand_scanline_generic(canvas, canvas.cv_bitmap, dx, dy + y1, sbits, sx, sx + w-1);
  436.                 bw.advance_src_bits();
  437.         }
  438. }
  439. #endif
  440.  
  441. // rescalling bitmaps, 10/14/99 Jan Bobrowski jb@wizard.ae.krakow.pl
  442.  
  443. static void scale_line(const uint8_t *in, uint8_t *out, const uint_fast32_t ilen, const uint_fast32_t olen)
  444. {
  445.         uint_fast32_t a = olen / ilen, b = olen % ilen, c = 0;
  446.         for (uint8_t *const end = out + olen; out != end;)
  447.         {
  448.                 uint_fast32_t i = a;
  449.                 c += b;
  450.                 if(c >= ilen) {
  451.                         c -= ilen;
  452.                         ++i;
  453.                 }
  454.                 auto e = out + i;
  455.                 std::fill(std::exchange(out, e), e, *in++);
  456.         }
  457. }
  458.  
  459. static void gr_bitmap_scale_to(const grs_bitmap &src, grs_bitmap &dst)
  460. {
  461.         auto s = src.get_bitmap_data();
  462.         auto d = dst.get_bitmap_data();
  463.         int h = src.bm_h;
  464.         int a = dst.bm_h/h, b = dst.bm_h%h;
  465.         int c = 0, i;
  466.  
  467.         for (uint_fast32_t y = src.bm_h; y; --y) {
  468.                 i = a;
  469.                 c += b;
  470.                 if(c >= h) {
  471.                         c -= h;
  472.                         goto inside;
  473.                 }
  474.                 while(--i>=0) {
  475. inside:
  476.                         scale_line(s, d, src.bm_w, dst.bm_w);
  477.                         d += dst.bm_rowsize;
  478.                 }
  479.                 s += src.bm_rowsize;
  480.         }
  481. }
  482.  
  483. void show_fullscr(grs_canvas &canvas, grs_bitmap &bm)
  484. {
  485.         auto &scr = canvas.cv_bitmap;
  486. #if DXX_USE_OGL
  487.         if (bm.get_type() == bm_mode::linear && scr.get_type() == bm_mode::ogl &&
  488.                 bm.bm_w <= grd_curscreen->get_screen_width() && bm.bm_h <= grd_curscreen->get_screen_height()) // only scale with OGL if bitmap is not bigger than screen size
  489.         {
  490.                 ogl_ubitmapm_cs(canvas, 0, 0, -1, -1, bm, ogl_colors::white, F1_0);//use opengl to scale, faster and saves ram. -MPM
  491.                 return;
  492.         }
  493. #endif
  494.         if (scr.get_type() != bm_mode::linear)
  495.         {
  496.                 grs_bitmap_ptr p = gr_create_bitmap(scr.bm_w, scr.bm_h);
  497.                 auto &tmp = *p.get();
  498.                 gr_bitmap_scale_to(bm, tmp);
  499.                 gr_bitmap(canvas, 0, 0, tmp);
  500.                 return;
  501.         }
  502.         gr_bitmap_scale_to(bm, scr);
  503. }
  504.  
  505. // Find transparent area in bitmap
  506. void gr_bitblt_find_transparent_area(const grs_bitmap &bm, unsigned &minx, unsigned &miny, unsigned &maxx, unsigned &maxy)
  507. {
  508.         using std::advance;
  509.         using std::min;
  510.         using std::max;
  511.  
  512.         if (!bm.get_flag_mask(BM_FLAG_TRANSPARENT))
  513.                 return;
  514.  
  515.         minx = bm.bm_w - 1;
  516.         maxx = 0;
  517.         miny = bm.bm_h - 1;
  518.         maxy = 0;
  519.  
  520.         unsigned i = 0, count = 0;
  521.         auto check = [&](unsigned x, unsigned y, const color_palette_index c) {
  522.                 if (c == TRANSPARENCY_COLOR) {                          // don't look for transparancy color here.
  523.                         count++;
  524.                         minx = min(x, minx);
  525.                         miny = min(y, miny);
  526.                         maxx = max(x, maxx);
  527.                         maxy = max(y, maxy);
  528.                 }
  529.         };
  530.         // decode the bitmap
  531.         const uint_fast32_t bm_h = bm.bm_h;
  532.         const uint_fast32_t bm_w = bm.bm_w;
  533.         if (bm.get_flag_mask(BM_FLAG_RLE))
  534.         {
  535.                 bm_rle_expand expander(bm);
  536.                 for (uint_fast32_t y = 0;; ++y)
  537.                 {
  538.                         std::array<uint8_t, 4096> buf;
  539.                         if (expander.step(bm_rle_expand_range(buf)) != bm_rle_expand::again)
  540.                                 break;
  541.                         range_for (const uint_fast32_t x, xrange(bm_w))
  542.                                 check(x, y, buf[x]);
  543.                 }
  544.         }
  545.         else
  546.         {
  547.                 range_for (const uint_fast32_t y, xrange(bm_h))
  548.                         range_for (const uint_fast32_t x, xrange(bm_w))
  549.                                 check(x, y, bm.bm_data[i++]);
  550.         }
  551.         Assert (count);
  552. }
  553.  
  554. }
  555.