From 325c4fcf677156f0a76000662327745bb9b4710d Mon Sep 17 00:00:00 2001 From: Bradley Bell Date: Wed, 15 Jan 2003 02:44:31 +0000 Subject: [PATCH] fix several bugs, comments, formatting. courtesy of David Costanzo --- main/mveplay.c | 507 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 423 insertions(+), 84 deletions(-) diff --git a/main/mveplay.c b/main/mveplay.c index 90d69759..beb33eab 100644 --- a/main/mveplay.c +++ b/main/mveplay.c @@ -1,3 +1,5 @@ +/* $Id: mveplay.c,v 1.9 2003-01-15 02:44:31 btb Exp $ */ + #ifdef HAVE_CONFIG_H #include #endif @@ -10,8 +12,8 @@ #include #include #include -#include -#include + +#include #include "mveplay.h" #include "error.h" @@ -27,6 +29,29 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) #endif +#define MVE_OPCODE_ENDOFSTREAM 0x00 +#define MVE_OPCODE_ENDOFCHUNK 0x01 +#define MVE_OPCODE_CREATETIMER 0x02 +#define MVE_OPCODE_INITAUDIOBUFFERS 0x03 +#define MVE_OPCODE_STARTSTOPAUDIO 0x04 +#define MVE_OPCODE_INITVIDEOBUFFERS 0x05 +#define MVE_OPCODE_UNKNOWN 0x06 +#define MVE_OPCODE_DISPLAYVIDEO 0x07 +#define MVE_OPCODE_AUDIOFRAMEDATA 0x08 +#define MVE_OPCODE_AUDIOFRAMESILENCE 0x09 +#define MVE_OPCODE_INITVIDEOMODE 0x0A +#define MVE_OPCODE_CREATEGRADIENT 0x0B +#define MVE_OPCODE_SETPALETTE 0x0C +#define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D +#define MVE_OPCODE_UNKNOWN2 0x0E +#define MVE_OPCODE_SETDECODINGMAP 0x0F +#define MVE_OPCODE_UNKNOWN3 0x10 +#define MVE_OPCODE_VIDEODATA 0x11 +#define MVE_OPCODE_UNKNOWN4 0x12 +#define MVE_OPCODE_UNKNOWN5 0x13 +#define MVE_OPCODE_UNKNOWN6 0x14 +#define MVE_OPCODE_UNKNOWN7 0x15 + //#define DEBUG static int g_spdFactorNum=0; @@ -57,7 +82,7 @@ static int default_seg_handler(unsigned char major, unsigned char minor, unsigne *************************/ static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) { - return 0; + return 0; } /************************* @@ -126,9 +151,11 @@ end: /************************* * audio handlers *************************/ +#define TOTAL_AUDIO_BUFFERS 64 + static void mve_audio_callback(void *userdata, Uint8 *stream, int len); -static short *mve_audio_buffers[64]; -static int mve_audio_buflens[64]; +static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS]; +static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS]; static int mve_audio_curbuf_curpos=0; static int mve_audio_bufhead=0; static int mve_audio_buftail=0; @@ -136,7 +163,6 @@ static int mve_audio_playing=0; static int mve_audio_canplay=0; static int mve_audio_compressed=0; static SDL_AudioSpec *mve_audio_spec=NULL; -static SDL_mutex *mve_audio_mutex = NULL; static void mve_audio_callback(void *userdata, Uint8 *stream, int len) { @@ -149,15 +175,13 @@ static void mve_audio_callback(void *userdata, Uint8 *stream, int len) fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); #endif - SDL_mutexP(mve_audio_mutex); - while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */ && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */ { length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos; - __builtin_memcpy(stream, /* cur output position */ - mve_audio_buffers[mve_audio_bufhead]+mve_audio_curbuf_curpos, /* cur input position */ - length); /* cur input length */ + __builtin_memcpy(stream, /* cur output position */ + (unsigned char *)(mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */ + length); /* cur input length */ total += length; stream += length; /* advance output */ @@ -166,7 +190,7 @@ static void mve_audio_callback(void *userdata, Uint8 *stream, int len) mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */ mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */ - if (++mve_audio_bufhead == 64) /* next buffer */ + if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */ mve_audio_bufhead = 0; mve_audio_curbuf_curpos = 0; } @@ -179,9 +203,9 @@ static void mve_audio_callback(void *userdata, Uint8 *stream, int len) if (len != 0 /* ospace remaining */ && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */ { - __builtin_memcpy(stream, /* dest */ - mve_audio_buffers[mve_audio_bufhead] + mve_audio_curbuf_curpos, /* src */ - len); /* length */ + __builtin_memcpy(stream, /* dest */ + (unsigned char *)(mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */ + len); /* length */ mve_audio_curbuf_curpos += len; /* advance input */ stream += len; /* advance output (unnecessary) */ @@ -193,7 +217,7 @@ static void mve_audio_callback(void *userdata, Uint8 *stream, int len) mve_audio_buffers[mve_audio_bufhead]=NULL; mve_audio_buflens[mve_audio_bufhead]=0; - if (++mve_audio_bufhead == 64) /* next buffer */ + if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */ mve_audio_bufhead = 0; mve_audio_curbuf_curpos = 0; } @@ -202,7 +226,6 @@ static void mve_audio_callback(void *userdata, Uint8 *stream, int len) #ifdef DEBUG fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); #endif - SDL_mutexV(mve_audio_mutex); } static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) @@ -215,8 +238,6 @@ static int create_audiobuf_handler(unsigned char major, unsigned char minor, uns fprintf(stderr, "creating audio buffers\n"); #endif - mve_audio_mutex = SDL_CreateMutex(); - flags = get_short(data + 2); sample_rate = get_short(data + 4); desired_buffer = get_int(data + 6); @@ -286,25 +307,24 @@ static int audio_data_handler(unsigned char major, unsigned char minor, unsigned nsamp = get_short(data + 4); if (chan & selected_chan) { - SDL_mutexP(mve_audio_mutex); mve_audio_buflens[mve_audio_buftail] = nsamp; - if (mve_audio_buffers[mve_audio_buftail]) - d_free(mve_audio_buffers[mve_audio_buftail]); + if (mve_audio_buffers[mve_audio_buftail]) + d_free(mve_audio_buffers[mve_audio_buftail]); mve_audio_buffers[mve_audio_buftail] = (short *)d_malloc(nsamp+4); - if (major == 8) + if (major == MVE_OPCODE_AUDIOFRAMEDATA) if (mve_audio_compressed) mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */ else memcpy(mve_audio_buffers[mve_audio_buftail], data + 6, nsamp); else + // silence memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */ - if (++mve_audio_buftail == 64) + if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS) mve_audio_buftail = 0; - + if (mve_audio_buftail == mve_audio_bufhead) Warning("mveplay: d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead); - SDL_mutexV(mve_audio_mutex); } if (mve_audio_playing) @@ -428,28 +448,28 @@ void mveplay_initializeMovie(MVESTREAM *mve, grs_bitmap *mve_bitmap) { g_screen = mve_bitmap; - mve_set_handler(mve, 0x00, end_movie_handler); - mve_set_handler(mve, 0x01, end_chunk_handler); - mve_set_handler(mve, 0x02, create_timer_handler); - mve_set_handler(mve, 0x03, create_audiobuf_handler); - mve_set_handler(mve, 0x04, play_audio_handler); - mve_set_handler(mve, 0x05, create_videobuf_handler); - mve_set_handler(mve, 0x06, default_seg_handler); - mve_set_handler(mve, 0x07, display_video_handler); - mve_set_handler(mve, 0x08, audio_data_handler); - mve_set_handler(mve, 0x09, audio_data_handler); - mve_set_handler(mve, 0x0a, init_video_handler); - mve_set_handler(mve, 0x0b, default_seg_handler); - mve_set_handler(mve, 0x0c, video_palette_handler); - mve_set_handler(mve, 0x0d, default_seg_handler); - mve_set_handler(mve, 0x0e, default_seg_handler); - mve_set_handler(mve, 0x0f, video_codemap_handler); - mve_set_handler(mve, 0x10, default_seg_handler); - mve_set_handler(mve, 0x11, video_data_handler); - mve_set_handler(mve, 0x12, default_seg_handler); - //mve_set_handler(mve, 0x13, default_seg_handler); - mve_set_handler(mve, 0x14, default_seg_handler); - //mve_set_handler(mve, 0x15, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler); + mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler); + mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler); + mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler); + mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler); + mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler); + mve_set_handler(mve, MVE_OPCODE_UNKNOWN, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler); + mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler); + mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler); + mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler); + mve_set_handler(mve, MVE_OPCODE_CREATEGRADIENT, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler); + mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_UNKNOWN2, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler); + mve_set_handler(mve, MVE_OPCODE_UNKNOWN3, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler); + mve_set_handler(mve, MVE_OPCODE_UNKNOWN4, default_seg_handler); + //mve_set_handler(mve, MVE_OPCODE_UNKNOWN5, default_seg_handler); + mve_set_handler(mve, MVE_OPCODE_UNKNOWN6, default_seg_handler); + //mve_set_handler(mve, MVE_OPCODE_UNKNOWN7, default_seg_handler); } int mveplay_stepMovie(MVESTREAM *mve) @@ -481,8 +501,13 @@ void mveplay_shutdownMovie(MVESTREAM *mve) int i; timer_stop(); - SDL_CloseAudio(); - for (i = 0; i < 64; i++) + + if (mve_audio_canplay) { + // only close audio if we opened it + SDL_CloseAudio(); + mve_audio_canplay = 0; + } + for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++) if (mve_audio_buffers[i] != NULL) d_free(mve_audio_buffers[i]); memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers)); @@ -493,7 +518,6 @@ void mveplay_shutdownMovie(MVESTREAM *mve) mve_audio_playing=0; mve_audio_canplay=0; mve_audio_compressed=0; - mve_audio_mutex = NULL; if (mve_audio_spec) d_free(mve_audio_spec); mve_audio_spec=NULL; @@ -529,6 +553,7 @@ static void decodeFrame(unsigned char *pFrame, unsigned char *pMap, int mapRemai Warning("mveplay: danger! pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); else if (pFrame >= g_vBackBuf1 + g_width*g_height) Warning("mveplay: danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); + dispatchDecoder(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j); if (pFrame < g_vBackBuf1) Warning("mveplay: danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); @@ -564,10 +589,12 @@ static void relFar(int i, int sign, int *x, int *y) else { *x = sign * (-14 + (i - 56) % 29); - *y = sign * (8 + (i - 56) / 29); + *y = sign * (8 + (i - 56) / 29); } } +/* copies an 8x8 block from pSrc to pDest. + pDest and pSrc are both g_width bytes wide */ static void copyFrame(unsigned char *pDest, unsigned char *pSrc) { int i; @@ -580,6 +607,8 @@ static void copyFrame(unsigned char *pDest, unsigned char *pSrc) } } +// Fill in the next eight bytes with p[0], p[1], p[2], or p[3], +// depending on the corresponding two-bit value in pat0 and pat1 static void patternRow4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char *p) @@ -596,6 +625,8 @@ static void patternRow4Pixels(unsigned char *pFrame, } } +// Fill in the next four 2x2 pixel blocks with p[0], p[1], p[2], or p[3], +// depending on the corresponding two-bit value in pat0. static void patternRow4Pixels2(unsigned char *pFrame, unsigned char pat0, unsigned char *p) @@ -603,22 +634,22 @@ static void patternRow4Pixels2(unsigned char *pFrame, unsigned char mask=0x03; unsigned char shift=0; unsigned char pel; - int skip=1; while (mask != 0) { pel = p[(mask & pat0) >> shift]; pFrame[0] = pel; - pFrame[2] = pel; + pFrame[1] = pel; pFrame[g_width + 0] = pel; - pFrame[g_width + 2] = pel; - pFrame += skip; - skip = 4 - skip; + pFrame[g_width + 1] = pel; + pFrame += 2; mask <<= 2; shift += 2; } } +// Fill in the next four 2x1 pixel blocks with p[0], p[1], p[2], or p[3], +// depending on the corresponding two-bit value in pat. static void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, unsigned char *p) { unsigned char mask=0x03; @@ -636,6 +667,8 @@ static void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, unsig } } +// Fill in the next 4x4 pixel block with p[0], p[1], p[2], or p[3], +// depending on the corresponding two-bit value in pat0, pat1, pat2, and pat3. static void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, unsigned char *p) { unsigned long mask = 0x00000003UL; @@ -655,51 +688,57 @@ static void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, un } } - -static void patternRow2Pixels(unsigned char *pFrame, unsigned char pat, unsigned char *p) +// fills the next 8 pixels with either p[0] or p[1], depending on pattern +static void patternRow2Pixels(unsigned char *pFrame, unsigned char pattern, unsigned char *p) { unsigned char mask=0x01; - + while (mask != 0) { - *pFrame++ = p[(mask & pat) ? 1 : 0]; + *pFrame++ = p[(mask & pattern) ? 1 : 0]; mask <<= 1; } } -static void patternRow2Pixels2(unsigned char *pFrame, unsigned char pat, unsigned char *p) +// fills the next four 2 x 2 pixel boxes with either p[0] or p[1], depending on pattern +static void patternRow2Pixels2(unsigned char *pFrame, unsigned char pattern, unsigned char *p) { unsigned char pel; unsigned char mask=0x1; - int skip=1; while (mask != 0x10) { - pel = p[(mask & pat) ? 1 : 0]; - pFrame[0] = pel; - pFrame[2] = pel; - pFrame[g_width + 0] = pel; - pFrame[g_width + 2] = pel; - pFrame += skip; - skip = 4 - skip; + pel = p[(mask & pattern) ? 1 : 0]; + + pFrame[0] = pel; // upper-left + pFrame[1] = pel; // upper-right + pFrame[g_width + 0] = pel; // lower-left + pFrame[g_width + 1] = pel; // lower-right + pFrame += 2; + mask <<= 1; } } +// fills pixels in the next 4 x 4 pixel boxes with either p[0] or p[1], depending on pat0 and pat1. static void patternQuadrant2Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char *p) { + unsigned char pel; unsigned short mask = 0x0001; int i; + int j; unsigned short pat = (pat1 << 8) | pat0; - for (i=0; i<16; i++) + for (i=0; i<4; i++) { - pFrame[i&3] = p[(pat & mask) ? 1 : 0]; + for (j=0; j<4; j++) + { + pel = p[(pat & mask) ? 1 : 0]; - if ((i&3) == 3) - pFrame += g_width; + pFrame[j + i * g_width] = pel; - mask <<= 1; + mask <<= 1; + } } } @@ -710,22 +749,51 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi int i, j, k; int x, y; + /* Data is processed in 8x8 pixel blocks. + There are 16 ways to encode each block. + */ + switch(codeType) { case 0x0: + /* block is copied from block in current frame */ copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1)); case 0x1: + /* block is unchanged from two frames ago */ *pFrame += 8; break; case 0x2: + /* Block is copied from nearby (below and/or to the right) within the + new frame. The offset within the buffer from which to grab the + patch of 8 pixels is given by grabbing a byte B from the data + stream, which is broken into a positive x and y offset according + to the following mapping: + + if B < 56: + x = 8 + (B % 7) + y = B / 7 + else + x = -14 + ((B - 56) % 29) + y = 8 + ((B - 56) / 29) + */ relFar(*(*pData)++, 1, &x, &y); copyFrame(*pFrame, *pFrame + x + y*g_width); *pFrame += 8; --*pDataRemain; break; - case 0x3: + case 0x3: + /* Block is copied from nearby (above and/or to the left) within the + new frame. + + if B < 56: + x = -(8 + (B % 7)) + y = -(B / 7) + else + x = -(-14 + ((B - 56) % 29)) + y = -( 8 + ((B - 56) / 29)) + */ relFar(*(*pData)++, -1, &x, &y); copyFrame(*pFrame, *pFrame + x + y*g_width); *pFrame += 8; @@ -733,6 +801,19 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0x4: + /* Similar to 0x2 and 0x3, except this method copies from the + "current" frame, rather than the "new" frame, and instead of the + lopsided mapping they use, this one uses one which is symmetric + and centered around the top-left corner of the block. This uses + only 1 byte still, though, so the range is decreased, since we + have to encode all directions in a single byte. The byte we pull + from the data stream, I'll call B. Call the highest 4 bits of B + BH and the lowest 4 bytes BL. Then the offset from which to copy + the data is: + + x = -8 + BL + y = -8 + BH + */ relClose(*(*pData)++, &x, &y); copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width); *pFrame += 8; @@ -740,14 +821,28 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0x5: - x = (char)*(*pData)++; - y = (char)*(*pData)++; + /* Similar to 0x4, but instead of one byte for the offset, this uses + two bytes to encode a larger range, the first being the x offset + as a signed 8-bit value, and the second being the y offset as a + signed 8-bit value. + */ + x = (signed char)*(*pData)++; + y = (signed char)*(*pData)++; copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width); *pFrame += 8; *pDataRemain -= 2; break; case 0x6: + /* I can't figure out how any file containing a block of this type + could still be playable, since it appears that it would leave the + internal bookkeeping in an inconsistent state in the BG player + code. Ahh, well. Perhaps it was a bug in the BG player code that + just didn't happen to be exposed by any of the included movies. + Anyway, this skips the next two blocks, doing nothing to them. + Note that if you've reached the end of a row, this means going on + to the next row. + */ for (i=0; i<2; i++) { *pFrame += 16; @@ -762,6 +857,70 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0x7: + /* Ok, here's where it starts to get really...interesting. This is, + incidentally, the part where they started using self-modifying + code. So, most of the following encodings are "patterned" blocks, + where we are given a number of pixel values and then bitmapped + values to specify which pixel values belong to which squares. For + this encoding, we are given the following in the data stream: + + P0 P1 + + These are pixel values (i.e. 8-bit indices into the palette). If + P0 <= P1, we then get 8 more bytes from the data stream, one for + each row in the block: + + B0 B1 B2 B3 B4 B5 B6 B7 + + For each row, the leftmost pixel is represented by the low-order + bit, and the rightmost by the high-order bit. Use your imagination + in between. If a bit is set, the pixel value is P1 and if it is + unset, the pixel value is P0. + + So, for example, if we had: + + 11 22 fe 83 83 83 83 83 83 fe + + This would represent the following layout: + + 11 22 22 22 22 22 22 22 ; fe == 11111110 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 22 22 11 11 11 11 11 22 ; 83 == 10000011 + 11 22 22 22 22 22 22 22 ; fe == 11111110 + + If, on the other hand, P0 > P1, we get two more bytes from the + data stream: + + B0 B1 + + Each of these bytes contains two 4-bit patterns. These patterns + work like the patterns above with 8 bytes, except each bit + represents a 2x2 pixel region. + + B0 contains the pattern for the top two rows and B1 contains + the pattern for the bottom two rows. Note that the low-order + nibble of each byte contains the pattern for the upper of the + two rows that that byte controls. + + So if we had: + + 22 11 7e 83 + + The output would be: + + 11 11 22 22 22 22 22 22 ; e == 1 1 1 0 + 11 11 22 22 22 22 22 22 ; + 22 22 22 22 22 22 11 11 ; 7 == 0 1 1 1 + 22 22 22 22 22 22 11 11 ; + 11 11 11 11 11 11 22 22 ; 3 == 1 0 0 0 + 11 11 11 11 11 11 22 22 ; + 22 22 22 22 11 11 11 11 ; 8 == 0 0 1 1 + 22 22 22 22 11 11 11 11 ; + */ p[0] = *(*pData)++; p[1] = *(*pData)++; if (p[0] <= p[1]) @@ -785,9 +944,98 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi *pFrame -= (8*g_width - 8); break; - case 0x8: + case 0x8: + /* Ok, this one is basically like encoding 0x7, only more + complicated. Again, we start out by getting two bytes on the data + stream: + + P0 P1 + + if P0 <= P1 then we get the following from the data stream: + + B0 B1 + P2 P3 B2 B3 + P4 P5 B4 B5 + P6 P7 B6 B7 + + P0 P1 and B0 B1 are used for the top-left corner, P2 P3 B2 B3 for + the bottom-left corner, P4 P5 B4 B5 for the top-right, P6 P7 B6 B7 + for the bottom-right. (So, each codes for a 4x4 pixel array.) + Since we have 16 bits in B0 B1, there is one bit for each pixel in + the array. The convention for the bit-mapping is, again, left to + right and top to bottom. + + So, basically, the top-left quarter of the block is an arbitrary + pattern with 2 pixels, the bottom-left a different arbitrary + pattern with 2 different pixels, and so on. + + For example if the next 16 bytes were: + + 00 22 f9 9f 44 55 aa 55 11 33 cc 33 66 77 01 ef + + We'd draw: + + 22 22 22 22 | 11 11 33 33 ; f = 1111, c = 1100 + 22 00 00 22 | 11 11 33 33 ; 9 = 1001, c = 1100 + 22 00 00 22 | 33 33 11 11 ; 9 = 1001, 3 = 0011 + 22 22 22 22 | 33 33 11 11 ; f = 1111, 3 = 0011 + ------------+------------ + 44 55 44 55 | 66 66 66 66 ; a = 1010, 0 = 0000 + 44 55 44 55 | 77 66 66 66 ; a = 1010, 1 = 0001 + 55 44 55 44 | 66 77 77 77 ; 5 = 0101, e = 1110 + 55 44 55 44 | 77 77 77 77 ; 5 = 0101, f = 1111 + + I've added a dividing line in the above to clearly delineate the + quadrants. + + + Now, if P0 > P1 then we get 10 more bytes from the data stream: + + B0 B1 B2 B3 P2 P3 B4 B5 B6 B7 + + Now, if P2 <= P3, then the first six bytes [P0 P1 B0 B1 B2 B3] + represent the left half of the block and the latter six bytes + [P2 P3 B4 B5 B6 B7] represent the right half. + + For example: + + 22 00 01 37 f7 31 11 66 8c e6 73 31 + + yeilds: + + 22 22 22 22 | 11 11 11 66 ; 0: 0000 | 8: 1000 + 00 22 22 22 | 11 11 66 66 ; 1: 0001 | C: 1100 + 00 00 22 22 | 11 66 66 66 ; 3: 0011 | e: 1110 + 00 00 00 22 | 11 66 11 66 ; 7: 0111 | 6: 0101 + 00 00 00 00 | 66 66 66 11 ; f: 1111 | 7: 0111 + 00 00 00 22 | 66 66 11 11 ; 7: 0111 | 3: 0011 + 00 00 22 22 | 66 66 11 11 ; 3: 0011 | 3: 0011 + 00 22 22 22 | 66 11 11 11 ; 1: 0001 | 1: 0001 + + + On the other hand, if P0 > P1 and P2 > P3, then + [P0 P1 B0 B1 B2 B3] represent the top half of the + block and [P2 P3 B4 B5 B6 B7] represent the bottom half. + + For example: + + 22 00 cc 66 33 19 66 11 18 24 42 81 + + yeilds: + + 22 22 00 00 22 22 00 00 ; cc: 11001100 + 22 00 00 22 22 00 00 22 ; 66: 01100110 + 00 00 22 22 00 00 22 22 ; 33: 00110011 + 00 22 22 00 00 22 22 22 ; 19: 00011001 + ----------------------- + 66 66 66 11 11 66 66 66 ; 18: 00011000 + 66 66 11 66 66 11 66 66 ; 24: 00100100 + 66 11 66 66 66 66 11 66 ; 42: 01000010 + 11 66 66 66 66 66 66 11 ; 81: 10000001 + */ if ( (*pData)[0] <= (*pData)[1]) { + // four quadrant case for (i=0; i<4; i++) { p[0] = *(*pData)++; @@ -795,15 +1043,17 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi pat[0] = *(*pData)++; pat[1] = *(*pData)++; patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p); - + + // alternate between moving down and moving up and right if (i & 1) - *pFrame -= (4*g_width - 4); + *pFrame += 4 - 4*g_width; // up and right else - *pFrame += 4*g_width; + *pFrame += 4*g_width; // down } } else if ( (*pData)[6] <= (*pData)[7]) { + // split horizontal for (i=0; i<4; i++) { if ((i & 1) == 0) @@ -823,6 +1073,7 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi } else { + // split vertical for (i=0; i<8; i++) { if ((i & 3) == 0) @@ -838,6 +1089,31 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0x9: + /* Similar to the previous 2 encodings, only more complicated. And + it will get worse before it gets better. No longer are we dealing + with patterns over two pixel values. Now we are dealing with + patterns over 4 pixel values with 2 bits assigned to each pixel + (or block of pixels). + + So, first on the data stream are our 4 pixel values: + + P0 P1 P2 P3 + + Now, if P0 <= P1 AND P2 <= P3, we get 16 bytes of pattern, each + 2 bits representing a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3). The + ordering is again left to right and top to bottom. The most + significant bits represent the left side at the top, and so on. + + If P0 <= P1 AND P2 > P3, we get 4 bytes of pattern, each 2 bits + representing a 2x2 pixel. Ordering is left to right and top to + bottom. + + if P0 > P1 AND P2 <= P3, we get 8 bytes of pattern, each 2 bits + representing a 2x1 pixel (i.e. 2 pixels wide, and 1 high). + + if P0 > P1 AND P2 > P3, we get 8 bytes of pattern, each 2 bits + representing a 1x2 pixel (i.e. 1 pixel wide, and 2 high). + */ if ( (*pData)[0] <= (*pData)[1]) { if ( (*pData)[2] <= (*pData)[3]) @@ -878,6 +1154,7 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi { if ( (*pData)[2] <= (*pData)[3]) { + // draw 2x1 strips p[0] = *(*pData)++; p[1] = *(*pData)++; p[2] = *(*pData)++; @@ -894,6 +1171,7 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi } else { + // draw 1x2 strips p[0] = *(*pData)++; p[1] = *(*pData)++; p[2] = *(*pData)++; @@ -915,6 +1193,39 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xa: + /* Similar to the previous, only a little more complicated. + + We are still dealing with patterns over 4 pixel values with 2 bits + assigned to each pixel (or block of pixels). + + So, first on the data stream are our 4 pixel values: + + P0 P1 P2 P3 + + Now, if P0 <= P1, the block is divided into 4 quadrants, ordered + (as with opcode 0x8) TL, BL, TR, BR. In this case the next data + in the data stream should be: + + B0 B1 B2 B3 + P4 P5 P6 P7 B4 B5 B6 B7 + P8 P9 P10 P11 B8 B9 B10 B11 + P12 P13 P14 P15 B12 B13 B14 B15 + + Each 2 bits represent a 1x1 pixel (00=P0, 01=P1, 10=P2, 11=P3). + The ordering is again left to right and top to bottom. The most + significant bits represent the right side at the top, and so on. + + If P0 > P1 then the next data on the data stream is: + + B0 B1 B2 B3 B4 B5 B6 B7 + P4 P5 P6 P7 B8 B9 B10 B11 B12 B13 B14 B15 + + Now, in this case, if P4 <= P5, + [P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the left half of + the block and the other bytes represent the right half. If P4 > + P5, then [P0 P1 P2 P3 B0 B1 B2 B3 B4 B5 B6 B7] represent the top + half of the block and the other bytes represent the bottom half. + */ if ( (*pData)[0] <= (*pData)[1]) { for (i=0; i<4; i++) @@ -940,6 +1251,7 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi { if ( (*pData)[12] <= (*pData)[13]) { + // split vertical for (i=0; i<4; i++) { if ((i&1) == 0) @@ -965,6 +1277,7 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi } else { + // split horizontal for (i=0; i<8; i++) { if ((i&3) == 0) @@ -987,6 +1300,10 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xb: + /* In this encoding we get raw pixel data in the data stream -- 64 + bytes of pixel data. 1 byte for each pixel, and in the standard + order (l->r, t->b). + */ for (i=0; i<8; i++) { memcpy(*pFrame, *pData, 8); @@ -998,14 +1315,18 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xc: + /* In this encoding we get raw pixel data in the data stream -- 16 + bytes of pixel data. 1 byte for each block of 2x2 pixels, and in + the standard order (l->r, t->b). + */ for (i=0; i<4; i++) { for (j=0; j<2; j++) { for (k=0; k<4; k++) { - (*pFrame)[j+2*k] = (*pData)[k]; - (*pFrame)[g_width+j+2*k] = (*pData)[k]; + (*pFrame)[2*k] = (*pData)[k]; + (*pFrame)[2*k+1] = (*pData)[k]; } *pFrame += g_width; } @@ -1016,6 +1337,10 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xd: + /* In this encoding we get raw pixel data in the data stream -- 4 + bytes of pixel data. 1 byte for each block of 4x4 pixels, and in + the standard order (l->r, t->b). + */ for (i=0; i<2; i++) { for (j=0; j<4; j++) @@ -1034,6 +1359,9 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xe: + /* This encoding represents a solid 8x8 frame. We get 1 byte of pixel + data from the data stream. + */ for (i=0; i<8; i++) { memset(*pFrame, **pData, 8); @@ -1045,6 +1373,17 @@ static void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsi break; case 0xf: + /* This encoding represents a "dithered" frame, which is + checkerboarded with alternate pixels of two colors. We get 2 + bytes of pixel data from the data stream, and these bytes are + alternated: + + P0 P1 P0 P1 P0 P1 P0 P1 + P1 P0 P1 P0 P1 P0 P1 P0 + ... + P0 P1 P0 P1 P0 P1 P0 P1 + P1 P0 P1 P0 P1 P0 P1 P0 + */ for (i=0; i<8; i++) { for (j=0; j<8; j++) -- 2.39.2