Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}