Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
/* 8 bit decoding routines */
8
 
9
#include <cstdint>
10
#include <stdio.h>
11
#include <string.h>
12
 
13
#include "decoders.h"
14
#include "console.h"
15
 
16
#include "dxxsconf.h"
17
#include "compiler-range_for.h"
18
#include "d_range.h"
19
#include <array>
20
 
21
static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, const unsigned char **pData, int *pDataRemain, int *curXb, int *curYb);
22
 
23
void decodeFrame8(unsigned char *pFrame, const unsigned char *pMap, int mapRemain, const unsigned char *pData, int dataRemain)
24
{
25
        int xb, yb;
26
 
27
        xb = g_width >> 3;
28
        yb = g_height >> 3;
29
        for (int j=0; j<yb; j++)
30
        {
31
                for (int i=0; i<xb/2; i++)
32
                {
33
                        dispatchDecoder(&pFrame, (*pMap) & 0xf, &pData, &dataRemain, &i, &j);
34
                        if (pFrame < g_vBackBuf1)
35
                                con_printf(CON_CRITICAL, "danger!  pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]", i, j, (*pMap) & 0xf);
36
                        else if (pFrame >= g_vBackBuf1 + g_width*g_height)
37
                                con_printf(CON_CRITICAL, "danger!  pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]", i, j, (*pMap) & 0xf);
38
                        dispatchDecoder(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j);
39
                        if (pFrame < g_vBackBuf1)
40
                                con_printf(CON_CRITICAL, "danger!  pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]", i, j, (*pMap) >> 4);
41
                        else if (pFrame >= g_vBackBuf1 + g_width*g_height)
42
                                con_printf(CON_CRITICAL, "danger!  pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]", i, j, (*pMap) >> 4);
43
 
44
                        ++pMap;
45
                        --mapRemain;
46
                }
47
 
48
                pFrame += 7*g_width;
49
        }
50
}
51
 
52
static void relClose(int i, int *x, int *y)
53
{
54
        int ma, mi;
55
 
56
        ma = i >> 4;
57
        mi = i & 0xf;
58
 
59
        *x = mi - 8;
60
        *y = ma - 8;
61
}
62
 
63
static void relFar(int i, int sign, int *x, int *y)
64
{
65
        if (i < 56)
66
        {
67
                *x = sign * (8 + (i % 7));
68
                *y = sign *      (i / 7);
69
        }
70
        else
71
        {
72
                *x = sign * (-14 + (i - 56) % 29);
73
                *y = sign *   (8 + (i - 56) / 29);
74
        }
75
}
76
 
77
/* copies an 8x8 block from pSrc to pDest.
78
   pDest and pSrc are both g_width bytes wide */
79
static void copyFrame(uint8_t *pDest, const uint8_t *pSrc)
80
{
81
        const auto width = g_width;
82
        range_for (const int i, xrange(8u))
83
        {
84
                (void)i;
85
                memcpy(pDest, pSrc, 8);
86
                pDest += width;
87
                pSrc += width;
88
        }
89
}
90
 
91
// Fill in the next eight bytes with p[0], p[1], p[2], or p[3],
92
// depending on the corresponding two-bit value in pat0 and pat1
93
static void patternRow4Pixels(unsigned char *pFrame,
94
                                                          unsigned char pat0, unsigned char pat1,
95
                                                          const std::array<uint8_t, 4> &p)
96
{
97
        unsigned short mask=0x0003;
98
        unsigned short shift=0;
99
        unsigned short pattern = (pat1 << 8) | pat0;
100
 
101
        while (mask != 0)
102
        {
103
                *pFrame++ = p[(mask & pattern) >> shift];
104
                mask <<= 2;
105
                shift += 2;
106
        }
107
}
108
 
109
// Fill in the next four 2x2 pixel blocks with p[0], p[1], p[2], or p[3],
110
// depending on the corresponding two-bit value in pat0.
111
static void patternRow4Pixels2(unsigned char *pFrame,
112
                                                           unsigned char pat0,
113
                                                           const std::array<uint8_t, 4> &p)
114
{
115
        unsigned char mask=0x03;
116
        unsigned char shift=0;
117
        unsigned char pel;
118
 
119
        const auto width = g_width;
120
        while (mask != 0)
121
        {
122
                pel = p[(mask & pat0) >> shift];
123
                pFrame[0] = pel;
124
                pFrame[1] = pel;
125
                pFrame[width + 0] = pel;
126
                pFrame[width + 1] = pel;
127
                pFrame += 2;
128
                mask <<= 2;
129
                shift += 2;
130
        }
131
}
132
 
133
// Fill in the next four 2x1 pixel blocks with p[0], p[1], p[2], or p[3],
134
// depending on the corresponding two-bit value in pat.
135
static void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, const std::array<uint8_t, 4> &p)
136
{
137
        unsigned char mask=0x03;
138
        unsigned char shift=0;
139
        unsigned char pel;
140
 
141
        while (mask != 0)
142
        {
143
                pel = p[(mask & pat) >> shift];
144
                pFrame[0] = pel;
145
                pFrame[1] = pel;
146
                pFrame += 2;
147
                mask <<= 2;
148
                shift += 2;
149
        }
150
}
151
 
152
// Fill in the next 4x4 pixel block with p[0], p[1], p[2], or p[3],
153
// depending on the corresponding two-bit value in pat0, pat1, pat2, and pat3.
154
static void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, const std::array<uint8_t, 4> &p)
155
{
156
        unsigned long mask = 0x00000003UL;
157
        int shift=0;
158
        unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
159
 
160
        const auto width = g_width;
161
        range_for (const int i, xrange(16u))
162
        {
163
                pFrame[i&3] = p[(pat & mask) >> shift];
164
 
165
                if ((i&3) == 3)
166
                        pFrame += width;
167
 
168
                mask <<= 2;
169
                shift += 2;
170
        }
171
}
172
 
173
// fills the next 8 pixels with either p[0] or p[1], depending on pattern
174
static void patternRow2Pixels(unsigned char *pFrame, unsigned char pat, const std::array<uint8_t, 4> &p)
175
{
176
        unsigned char mask=0x01;
177
 
178
        while (mask != 0)
179
        {
180
                *pFrame++ = p[(mask & pat) ? 1 : 0];
181
                mask <<= 1;
182
        }
183
}
184
 
185
// fills the next four 2 x 2 pixel boxes with either p[0] or p[1], depending on pattern
186
static void patternRow2Pixels2(unsigned char *pFrame, unsigned char pat, const std::array<uint8_t, 4> &p)
187
{
188
        unsigned char pel;
189
        unsigned char mask=0x1;
190
 
191
        const auto width = g_width;
192
        while (mask != 0x10)
193
        {
194
                pel = p[(mask & pat) ? 1 : 0];
195
 
196
                pFrame[0] = pel;              // upper-left
197
                pFrame[1] = pel;              // upper-right
198
                pFrame[width + 0] = pel;    // lower-left
199
                pFrame[width + 1] = pel;    // lower-right
200
                pFrame += 2;
201
 
202
                mask <<= 1;
203
        }
204
}
205
 
206
// fills pixels in the next 4 x 4 pixel boxes with either p[0] or p[1], depending on pat0 and pat1.
207
static void patternQuadrant2Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, const std::array<uint8_t, 4> &p)
208
{
209
        unsigned char pel;
210
        unsigned short mask = 0x0001;
211
        unsigned short pat = (pat1 << 8) | pat0;
212
 
213
        const auto width = g_width;
214
        range_for (const int i, xrange(4u))
215
        {
216
                range_for (const int j, xrange(4u))
217
                {
218
                        pel = p[(pat & mask) ? 1 : 0];
219
 
220
                        pFrame[j + i * width] = pel;
221
 
222
                        mask <<= 1;
223
                }
224
        }
225
}
226
 
227
static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, const unsigned char **pData, int *pDataRemain, int *curXb, int *curYb)
228
{
229
        std::array<uint8_t, 4> p, pat;
230
        int x, y;
231
 
232
        /* Data is processed in 8x8 pixel blocks.
233
           There are 16 ways to encode each block.
234
        */
235
 
236
        switch(codeType)
237
        {
238
        case 0x0:
239
                /* block is copied from block in current frame */
240
                copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1));
241
                DXX_BOOST_FALLTHROUGH;
242
        case 0x1:
243
                /* block is unchanged from two frames ago */
244
                *pFrame += 8;
245
                break;
246
 
247
        case 0x2:
248
                /* Block is copied from nearby (below and/or to the right) within the
249
                   new frame.  The offset within the buffer from which to grab the
250
                   patch of 8 pixels is given by grabbing a byte B from the data
251
                   stream, which is broken into a positive x and y offset according
252
                   to the following mapping:
253
 
254
                   if B < 56:
255
                   x = 8 + (B % 7)
256
                   y = B / 7
257
                   else
258
                   x = -14 + ((B - 56) % 29)
259
                   y =   8 + ((B - 56) / 29)
260
                */
261
                relFar(*(*pData)++, 1, &x, &y);
262
                copyFrame(*pFrame, *pFrame + x + y*g_width);
263
                *pFrame += 8;
264
                --*pDataRemain;
265
                break;
266
 
267
        case 0x3:
268
                /* Block is copied from nearby (above and/or to the left) within the
269
                   new frame.
270
 
271
                   if B < 56:
272
                   x = -(8 + (B % 7))
273
                   y = -(B / 7)
274
                   else
275
                   x = -(-14 + ((B - 56) % 29))
276
                   y = -(  8 + ((B - 56) / 29))
277
                */
278
                relFar(*(*pData)++, -1, &x, &y);
279
                copyFrame(*pFrame, *pFrame + x + y*g_width);
280
                *pFrame += 8;
281
                --*pDataRemain;
282
                break;
283
 
284
        case 0x4:
285
                /* Similar to 0x2 and 0x3, except this method copies from the
286
                   "current" frame, rather than the "new" frame, and instead of the
287
                   lopsided mapping they use, this one uses one which is symmetric
288
                   and centered around the top-left corner of the block.  This uses
289
                   only 1 byte still, though, so the range is decreased, since we
290
                   have to encode all directions in a single byte.  The byte we pull
291
                   from the data stream, I'll call B.  Call the highest 4 bits of B
292
                   BH and the lowest 4 bytes BL.  Then the offset from which to copy
293
                   the data is:
294
 
295
                   x = -8 + BL
296
                   y = -8 + BH
297
                */
298
                relClose(*(*pData)++, &x, &y);
299
                copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
300
                *pFrame += 8;
301
                --*pDataRemain;
302
                break;
303
 
304
        case 0x5:
305
                /* Similar to 0x4, but instead of one byte for the offset, this uses
306
                   two bytes to encode a larger range, the first being the x offset
307
                   as a signed 8-bit value, and the second being the y offset as a
308
                   signed 8-bit value.
309
                */
310
                x = static_cast<int8_t>(*(*pData)++);
311
                y = static_cast<int8_t>(*(*pData)++);
312
                copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
313
                *pFrame += 8;
314
                *pDataRemain -= 2;
315
                break;
316
 
317
        case 0x6:
318
                /* I can't figure out how any file containing a block of this type
319
                   could still be playable, since it appears that it would leave the
320
                   internal bookkeeping in an inconsistent state in the BG player
321
                   code.  Ahh, well.  Perhaps it was a bug in the BG player code that
322
                   just didn't happen to be exposed by any of the included movies.
323
                   Anyway, this skips the next two blocks, doing nothing to them.
324
                   Note that if you've reached the end of a row, this means going on
325
                   to the next row.
326
                */
327
                {
328
                        const auto width = g_width;
329
                range_for (const int i, xrange(2u))
330
                {
331
                        (void)i;
332
                        *pFrame += 16;
333
                        if (++*curXb == (width >> 3))
334
                        {
335
                                *pFrame += 7 * width;
336
                                *curXb = 0;
337
                                if (++*curYb == (g_height >> 3))
338
                                        return;
339
                        }
340
                }
341
                }
342
                break;
343
 
344
        case 0x7:
345
                /* Ok, here's where it starts to get really...interesting.  This is,
346
                   incidentally, the part where they started using self-modifying
347
                   code.  So, most of the following encodings are "patterned" blocks,
348
                   where we are given a number of pixel values and then bitmapped
349
                   values to specify which pixel values belong to which squares.  For
350
                   this encoding, we are given the following in the data stream:
351
 
352
                   P0 P1
353
 
354
                   These are pixel values (i.e. 8-bit indices into the palette).  If
355
                   P0 <= P1, we then get 8 more bytes from the data stream, one for
356
                   each row in the block:
357
 
358
                   B0 B1 B2 B3 B4 B5 B6 B7
359
 
360
                   For each row, the leftmost pixel is represented by the low-order
361
                   bit, and the rightmost by the high-order bit.  Use your imagination
362
                   in between.  If a bit is set, the pixel value is P1 and if it is
363
                   unset, the pixel value is P0.
364
 
365
                   So, for example, if we had:
366
 
367
                   11 22 fe 83 83 83 83 83 83 fe
368
 
369
                   This would represent the following layout:
370
 
371
                   11 22 22 22 22 22 22 22     ; fe == 11111110
372
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
373
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
374
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
375
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
376
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
377
                   22 22 11 11 11 11 11 22     ; 83 == 10000011
378
                   11 22 22 22 22 22 22 22     ; fe == 11111110
379
 
380
                   If, on the other hand, P0 > P1, we get two more bytes from the
381
                   data stream:
382
 
383
                   B0 B1
384
 
385
                   Each of these bytes contains two 4-bit patterns. These patterns
386
                   work like the patterns above with 8 bytes, except each bit
387
                   represents a 2x2 pixel region.
388
 
389
                   B0 contains the pattern for the top two rows and B1 contains
390
                   the pattern for the bottom two rows.  Note that the low-order
391
                   nibble of each byte contains the pattern for the upper of the
392
                   two rows that that byte controls.
393
 
394
                   So if we had:
395
 
396
                   22 11 7e 83
397
 
398
                   The output would be:
399
 
400
                   11 11 22 22 22 22 22 22     ; e == 1 1 1 0
401
                   11 11 22 22 22 22 22 22     ;
402
                   22 22 22 22 22 22 11 11     ; 7 == 0 1 1 1
403
                   22 22 22 22 22 22 11 11     ;
404
                   11 11 11 11 11 11 22 22     ; 3 == 1 0 0 0
405
                   11 11 11 11 11 11 22 22     ;
406
                   22 22 22 22 11 11 11 11     ; 8 == 0 0 1 1
407
                   22 22 22 22 11 11 11 11     ;
408
                */
409
                p[0] = *(*pData)++;
410
                p[1] = *(*pData)++;
411
                {
412
                        const auto width = g_width;
413
                if (p[0] <= p[1])
414
                {
415
                        range_for (const int i, xrange(8u))
416
                        {
417
                                (void)i;
418
                                patternRow2Pixels(*pFrame, *(*pData)++, p);
419
                                *pFrame += width;
420
                        }
421
                }
422
                else
423
                {
424
                        const auto width2 = 2 * width;
425
                        range_for (const int i, xrange(2u))
426
                        {
427
                                (void)i;
428
                                patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
429
                                *pFrame += width2;
430
                                patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p);
431
                                *pFrame += width2;
432
                        }
433
                }
434
                *pFrame -= (8 * width - 8);
435
                }
436
                break;
437
 
438
        case 0x8:
439
                /* Ok, this one is basically like encoding 0x7, only more
440
                   complicated.  Again, we start out by getting two bytes on the data
441
                   stream:
442
 
443
                   P0 P1
444
 
445
                   if P0 <= P1 then we get the following from the data stream:
446
 
447
                   B0 B1
448
                   P2 P3 B2 B3
449
                   P4 P5 B4 B5
450
                   P6 P7 B6 B7
451
 
452
                   P0 P1 and B0 B1 are used for the top-left corner, P2 P3 B2 B3 for
453
                   the bottom-left corner, P4 P5 B4 B5 for the top-right, P6 P7 B6 B7
454
                   for the bottom-right.  (So, each codes for a 4x4 pixel array.)
455
                   Since we have 16 bits in B0 B1, there is one bit for each pixel in
456
                   the array.  The convention for the bit-mapping is, again, left to
457
                   right and top to bottom.
458
 
459
                   So, basically, the top-left quarter of the block is an arbitrary
460
                   pattern with 2 pixels, the bottom-left a different arbitrary
461
                   pattern with 2 different pixels, and so on.
462
 
463
                   For example if the next 16 bytes were:
464
 
465
                   00 22 f9 9f  44 55 aa 55  11 33 cc 33  66 77 01 ef
466
 
467
                   We'd draw:
468
 
469
                   22 22 22 22 | 11 11 33 33     ; f = 1111, c = 1100
470
                   22 00 00 22 | 11 11 33 33     ; 9 = 1001, c = 1100
471
                   22 00 00 22 | 33 33 11 11     ; 9 = 1001, 3 = 0011
472
                   22 22 22 22 | 33 33 11 11     ; f = 1111, 3 = 0011
473
                   ------------+------------
474
                   44 55 44 55 | 66 66 66 66     ; a = 1010, 0 = 0000
475
                   44 55 44 55 | 77 66 66 66     ; a = 1010, 1 = 0001
476
                   55 44 55 44 | 66 77 77 77     ; 5 = 0101, e = 1110
477
                   55 44 55 44 | 77 77 77 77     ; 5 = 0101, f = 1111
478
 
479
                   I've added a dividing line in the above to clearly delineate the
480
                   quadrants.
481
 
482
 
483
                   Now, if P0 > P1 then we get 10 more bytes from the data stream:
484
 
485
                   B0 B1 B2 B3 P2 P3 B4 B5 B6 B7
486
 
487
                   Now, if P2 <= P3, then the first six bytes [P0 P1 B0 B1 B2 B3]
488
                   represent the left half of the block and the latter six bytes
489
                   [P2 P3 B4 B5 B6 B7] represent the right half.
490
 
491
                   For example:
492
 
493
                   22 00 01 37 f7 31   11 66 8c e6 73 31
494
 
495
                   yeilds:
496
 
497
                   22 22 22 22 | 11 11 11 66     ; 0: 0000 | 8: 1000
498
                   00 22 22 22 | 11 11 66 66     ; 1: 0001 | C: 1100
499
                   00 00 22 22 | 11 66 66 66     ; 3: 0011 | e: 1110
500
                   00 00 00 22 | 11 66 11 66     ; 7: 0111 | 6: 0101
501
                   00 00 00 00 | 66 66 66 11     ; f: 1111 | 7: 0111
502
                   00 00 00 22 | 66 66 11 11     ; 7: 0111 | 3: 0011
503
                   00 00 22 22 | 66 66 11 11     ; 3: 0011 | 3: 0011
504
                   00 22 22 22 | 66 11 11 11     ; 1: 0001 | 1: 0001
505
 
506
 
507
                   On the other hand, if P0 > P1 and P2 > P3, then
508
                   [P0 P1 B0 B1 B2 B3] represent the top half of the
509
                   block and [P2 P3 B4 B5 B6 B7] represent the bottom half.
510
 
511
                   For example:
512
 
513
                   22 00 cc 66 33 19   66 11 18 24 42 81
514
 
515
                   yeilds:
516
 
517
                   22 22 00 00 22 22 00 00     ; cc: 11001100
518
                   22 00 00 22 22 00 00 22     ; 66: 01100110
519
                   00 00 22 22 00 00 22 22     ; 33: 00110011
520
                   00 22 22 00 00 22 22 22     ; 19: 00011001
521
                   -----------------------
522
                   66 66 66 11 11 66 66 66     ; 18: 00011000
523
                   66 66 11 66 66 11 66 66     ; 24: 00100100
524
                   66 11 66 66 66 66 11 66     ; 42: 01000010
525
                   11 66 66 66 66 66 66 11     ; 81: 10000001
526
                */
527
                {
528
                        const auto width = g_width;
529
                if ( (*pData)[0] <= (*pData)[1])
530
                {
531
                        // four quadrant case
532
                        range_for (const int i, xrange(4u))
533
                        {
534
                                p[0] = *(*pData)++;
535
                                p[1] = *(*pData)++;
536
                                pat[0] = *(*pData)++;
537
                                pat[1] = *(*pData)++;
538
                                patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
539
 
540
                                // alternate between moving down and moving up and right
541
                                if (i & 1)
542
                                        *pFrame += 4 - 4 * width; // up and right
543
                                else
544
                                        *pFrame += 4 * width;     // down
545
                        }
546
                }
547
                else if ( (*pData)[6] <= (*pData)[7])
548
                {
549
                        // split horizontal
550
                        range_for (const int i, xrange(4u))
551
                        {
552
                                if ((i & 1) == 0)
553
                                {
554
                                        p[0] = *(*pData)++;
555
                                        p[1] = *(*pData)++;
556
                                }
557
                                pat[0] = *(*pData)++;
558
                                pat[1] = *(*pData)++;
559
                                patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
560
 
561
                                if (i & 1)
562
                                        *pFrame -= (4 * width - 4);
563
                                else
564
                                        *pFrame += 4 * width;
565
                        }
566
                }
567
                else
568
                {
569
                        // split vertical
570
                        range_for (const int i, xrange(8u))
571
                        {
572
                                if ((i & 3) == 0)
573
                                {
574
                                        p[0] = *(*pData)++;
575
                                        p[1] = *(*pData)++;
576
                                }
577
                                patternRow2Pixels(*pFrame, *(*pData)++, p);
578
                                *pFrame += width;
579
                        }
580
                        *pFrame -= (8 * width - 8);
581
                }
582
                }
583
                break;
584
 
585
        case 0x9:
586
                /* Similar to the previous 2 encodings, only more complicated.  And
587
                   it will get worse before it gets better.  No longer are we dealing
588
                   with patterns over two pixel values.  Now we are dealing with
589
                   patterns over 4 pixel values with 2 bits assigned to each pixel
590
                   (or block of pixels).
591
 
592
                   So, first on the data stream are our 4 pixel values:
593
 
594
                   P0 P1 P2 P3
595
 
596
                   Now, if P0 <= P1  AND  P2 <= P3, we get 16 bytes of pattern, each
597
                   2 bits representing a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3).  The
598
                   ordering is again left to right and top to bottom.  The most
599
                   significant bits represent the left side at the top, and so on.
600
 
601
                   If P0 <= P1  AND  P2 > P3, we get 4 bytes of pattern, each 2 bits
602
                   representing a 2x2 pixel.  Ordering is left to right and top to
603
                   bottom.
604
 
605
                   if P0 > P1  AND  P2 <= P3, we get 8 bytes of pattern, each 2 bits
606
                   representing a 2x1 pixel (i.e. 2 pixels wide, and 1 high).
607
 
608
                   if P0 > P1  AND  P2 > P3, we get 8 bytes of pattern, each 2 bits
609
                   representing a 1x2 pixel (i.e. 1 pixel wide, and 2 high).
610
                */
611
                {
612
                const auto width = g_width;
613
                if ( (*pData)[0] <= (*pData)[1])
614
                {
615
                        if ( (*pData)[2] <= (*pData)[3])
616
                        {
617
                                p[0] = *(*pData)++;
618
                                p[1] = *(*pData)++;
619
                                p[2] = *(*pData)++;
620
                                p[3] = *(*pData)++;
621
 
622
                                range_for (const int i, xrange(8u))
623
                                {
624
                                        (void)i;
625
                                        pat[0] = *(*pData)++;
626
                                        pat[1] = *(*pData)++;
627
                                        patternRow4Pixels(*pFrame, pat[0], pat[1], p);
628
                                        *pFrame += width;
629
                                }
630
 
631
                                *pFrame -= (8 * width - 8);
632
                        }
633
                        else
634
                        {
635
                                p[0] = *(*pData)++;
636
                                p[1] = *(*pData)++;
637
                                p[2] = *(*pData)++;
638
                                p[3] = *(*pData)++;
639
 
640
                                patternRow4Pixels2(*pFrame, *(*pData)++, p);
641
                                *pFrame += 2 * width;
642
                                patternRow4Pixels2(*pFrame, *(*pData)++, p);
643
                                *pFrame += 2 * width;
644
                                patternRow4Pixels2(*pFrame, *(*pData)++, p);
645
                                *pFrame += 2 * width;
646
                                patternRow4Pixels2(*pFrame, *(*pData)++, p);
647
                                *pFrame -= (6 * width - 8);
648
                        }
649
                }
650
                else
651
                {
652
                        if ( (*pData)[2] <= (*pData)[3])
653
                        {
654
                                // draw 2x1 strips
655
                                p[0] = *(*pData)++;
656
                                p[1] = *(*pData)++;
657
                                p[2] = *(*pData)++;
658
                                p[3] = *(*pData)++;
659
 
660
                                range_for (const int i, xrange(8u))
661
                                {
662
                                        (void)i;
663
                                        pat[0] = *(*pData)++;
664
                                        patternRow4Pixels2x1(*pFrame, pat[0], p);
665
                                        *pFrame += width;
666
                                }
667
                        }
668
                        else
669
                        {
670
                                // draw 1x2 strips
671
                                p[0] = *(*pData)++;
672
                                p[1] = *(*pData)++;
673
                                p[2] = *(*pData)++;
674
                                p[3] = *(*pData)++;
675
 
676
                                range_for (const int i, xrange(4u))
677
                                {
678
                                        (void)i;
679
                                        pat[0] = *(*pData)++;
680
                                        pat[1] = *(*pData)++;
681
                                        patternRow4Pixels(*pFrame, pat[0], pat[1], p);
682
                                        *pFrame += width;
683
                                        patternRow4Pixels(*pFrame, pat[0], pat[1], p);
684
                                        *pFrame += width;
685
                                }
686
                        }
687
                        *pFrame -= (8 * width - 8);
688
                }
689
                }
690
                break;
691
 
692
        case 0xa:
693
                /* Similar to the previous, only a little more complicated.
694
 
695
                We are still dealing with patterns over 4 pixel values with 2 bits
696
                assigned to each pixel (or block of pixels).
697
 
698
                So, first on the data stream are our 4 pixel values:
699
 
700
                P0 P1 P2 P3
701
 
702
                Now, if P0 <= P1, the block is divided into 4 quadrants, ordered
703
                (as with opcode 0x8) TL, BL, TR, BR.  In this case the next data
704
                in the data stream should be:
705
 
706
                B0  B1  B2  B3
707
                P4  P5  P6  P7  B4  B5  B6  B7
708
                P8  P9  P10 P11 B8  B9  B10 B11
709
                P12 P13 P14 P15 B12 B13 B14 B15
710
 
711
                Each 2 bits represent a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3).
712
                The ordering is again left to right and top to bottom.  The most
713
                significant bits represent the right side at the top, and so on.
714
 
715
                If P0 > P1 then the next data on the data stream is:
716
 
717
                B0 B1 B2  B3  B4  B5  B6  B7
718
                P4 P5 P6 P7 B8 B9 B10 B11 B12 B13 B14 B15
719
 
720
                Now, in this case, if P4 <= P5,
721
                [P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the left half of
722
                the block and the other bytes represent the right half.  If P4 >
723
                P5, then [P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the top
724
                half of the block and the other bytes represent the bottom half.
725
                */
726
                {
727
                        const auto width = g_width;
728
                if ( (*pData)[0] <= (*pData)[1])
729
                {
730
                        range_for (const int i, xrange(4u))
731
                        {
732
                                p[0] = *(*pData)++;
733
                                p[1] = *(*pData)++;
734
                                p[2] = *(*pData)++;
735
                                p[3] = *(*pData)++;
736
                                pat[0] = *(*pData)++;
737
                                pat[1] = *(*pData)++;
738
                                pat[2] = *(*pData)++;
739
                                pat[3] = *(*pData)++;
740
 
741
                                patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
742
 
743
                                if (i & 1)
744
                                        *pFrame -= (4 * width - 4);
745
                                else
746
                                        *pFrame += 4 * width;
747
                        }
748
                }
749
                else
750
                {
751
                        if ( (*pData)[12] <= (*pData)[13])
752
                        {
753
                                // split vertical
754
                                range_for (const int i, xrange(4u))
755
                                {
756
                                        if ((i&1) == 0)
757
                                        {
758
                                                p[0] = *(*pData)++;
759
                                                p[1] = *(*pData)++;
760
                                                p[2] = *(*pData)++;
761
                                                p[3] = *(*pData)++;
762
                                        }
763
 
764
                                        pat[0] = *(*pData)++;
765
                                        pat[1] = *(*pData)++;
766
                                        pat[2] = *(*pData)++;
767
                                        pat[3] = *(*pData)++;
768
 
769
                                        patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
770
 
771
                                        if (i & 1)
772
                                                *pFrame -= (4 * width - 4);
773
                                        else
774
                                                *pFrame += 4 * width;
775
                                }
776
                        }
777
                        else
778
                        {
779
                                // split horizontal
780
                                range_for (const int i, xrange(8u))
781
                                {
782
                                        if ((i&3) == 0)
783
                                        {
784
                                                p[0] = *(*pData)++;
785
                                                p[1] = *(*pData)++;
786
                                                p[2] = *(*pData)++;
787
                                                p[3] = *(*pData)++;
788
                                        }
789
 
790
                                        pat[0] = *(*pData)++;
791
                                        pat[1] = *(*pData)++;
792
                                        patternRow4Pixels(*pFrame, pat[0], pat[1], p);
793
                                        *pFrame += width;
794
                                }
795
 
796
                                *pFrame -= (8 * width - 8);
797
                        }
798
                }
799
                }
800
                break;
801
 
802
        case 0xb:
803
                /* In this encoding we get raw pixel data in the data stream -- 64
804
                   bytes of pixel data.  1 byte for each pixel, and in the standard
805
                   order (l->r, t->b).
806
                */
807
                {
808
                        const auto width = g_width;
809
                range_for (const int i, xrange(8u))
810
                {
811
                        (void)i;
812
                        memcpy(*pFrame, *pData, 8);
813
                        *pFrame += width;
814
                        *pData += 8;
815
                        *pDataRemain -= 8;
816
                }
817
                *pFrame -= (8 * width - 8);
818
                }
819
                break;
820
 
821
        case 0xc:
822
                /* In this encoding we get raw pixel data in the data stream -- 16
823
                   bytes of pixel data.  1 byte for each block of 2x2 pixels, and in
824
                   the standard order (l->r, t->b).
825
                */
826
                {
827
                        const auto width = g_width;
828
                range_for (const int i, xrange(4u))
829
                {
830
                        (void)i;
831
                        range_for (const int j, xrange(2u))
832
                        {
833
                                (void)j;
834
                                range_for (const int k, xrange(4u))
835
                                {
836
                                        (*pFrame)[2*k]   = (*pData)[k];
837
                                        (*pFrame)[2*k+1] = (*pData)[k];
838
                                }
839
                                *pFrame += width;
840
                        }
841
                        *pData += 4;
842
                        *pDataRemain -= 4;
843
                }
844
                *pFrame -= (8 * width - 8);
845
                }
846
                break;
847
 
848
        case 0xd:
849
                /* In this encoding we get raw pixel data in the data stream -- 4
850
                   bytes of pixel data.  1 byte for each block of 4x4 pixels, and in
851
                   the standard order (l->r, t->b).
852
                */
853
                {
854
                        const auto width = g_width;
855
                range_for (const int i, xrange(2u))
856
                {
857
                        (void)i;
858
                        range_for (const int j, xrange(4u))
859
                        {
860
                                range_for (const int k, xrange(4u))
861
                                {
862
                                        (*pFrame)[k * width+j] = (*pData)[0];
863
                                        (*pFrame)[k * width+j+4] = (*pData)[1];
864
                                }
865
                        }
866
                        *pFrame += 4 * width;
867
                        *pData += 2;
868
                        *pDataRemain -= 2;
869
                }
870
                *pFrame -= (8 * width - 8);
871
                }
872
                break;
873
 
874
        case 0xe:
875
                /* This encoding represents a solid 8x8 frame.  We get 1 byte of pixel
876
                   data from the data stream.
877
                */
878
                {
879
                        const auto width = g_width;
880
                range_for (const int i, xrange(8u))
881
                {
882
                        (void)i;
883
                        memset(*pFrame, **pData, 8);
884
                        *pFrame += width;
885
                }
886
                ++*pData;
887
                --*pDataRemain;
888
                *pFrame -= (8 * width - 8);
889
                }
890
                break;
891
 
892
        case 0xf:
893
                /* This encoding represents a "dithered" frame, which is
894
                   checkerboarded with alternate pixels of two colors.  We get 2
895
                   bytes of pixel data from the data stream, and these bytes are
896
                   alternated:
897
 
898
                   P0 P1 P0 P1 P0 P1 P0 P1
899
                   P1 P0 P1 P0 P1 P0 P1 P0
900
                   ...
901
                   P0 P1 P0 P1 P0 P1 P0 P1
902
                   P1 P0 P1 P0 P1 P0 P1 P0
903
                */
904
                {
905
                        const auto width = g_width;
906
                range_for (const int i, xrange(8u))
907
                {
908
                        range_for (const int j, xrange(8u))
909
                        {
910
                                (*pFrame)[j] = (*pData)[(i+j)&1];
911
                        }
912
                        *pFrame += width;
913
                }
914
                *pData += 2;
915
                *pDataRemain -= 2;
916
                *pFrame -= (8 * width - 8);
917
                }
918
                break;
919
 
920
        default:
921
                break;
922
        }
923
}