Subversion Repositories Games.Descent

Rev

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

  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. }
  924.