]> icculus.org git repositories - btb/d2x.git/blob - main/mveplay.c
-fwritable-strings doesn't work on OS X
[btb/d2x.git] / main / mveplay.c
1 #include "mvelib.h"                                             /* next buffer */
2 #include "mve_audio.h"
3
4 #include <string.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <sys/time.h>
8 #include <SDL/SDL.h>
9 #include <SDL/SDL_thread.h>
10
11 #ifndef MIN
12 #define MIN(a,b) ((a)<(b)?(a):(b))
13 #endif
14
15 int doPlay(const char *filename);
16
17 void usage(void)
18 {
19     fprintf(stderr, "usage: mveplay filename\n");
20     exit(1);
21 }
22
23 int g_spdFactorNum=0;
24 int g_spdFactorDenom=10;
25
26 void initializeMovie(MVESTREAM *mve);
27 void playMovie(MVESTREAM *mve);
28 void shutdownMovie(MVESTREAM *mve);
29
30 short get_short(unsigned char *data)
31 {
32     short value;
33     value = data[0] | (data[1] << 8);
34     return value;
35 }
36
37 int get_int(unsigned char *data)
38 {
39     int value;
40     value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
41     return value;
42 }
43
44 int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
45 {
46     fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
47     return 1;
48 }
49
50 /*************************
51  * general handlers
52  *************************/
53 int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
54 {
55     return 0;
56 }
57
58 /*************************
59  * timer handlers
60  *************************/
61
62 /*
63  * timer variables
64  */
65 int micro_frame_delay=0;
66 int timer_started=0;
67 Uint32 timer_expire = 0;
68
69 int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
70 {
71     long long temp;
72     micro_frame_delay = get_int(data) * (int)get_short(data+4);
73     if (g_spdFactorNum != 0)
74     {
75         temp = micro_frame_delay;
76         temp *= g_spdFactorNum;
77         temp /= g_spdFactorDenom;
78         micro_frame_delay = (int)temp;
79     }
80
81     return 1;
82 }
83
84 void timer_start(void)
85 {
86     timer_expire = SDL_GetTicks();
87     timer_expire += micro_frame_delay / 1000;
88     timer_started=1;
89 }
90
91 void do_timer_wait(void)
92 {
93     Uint32 ts, tv;
94     if (! timer_started)
95         return;
96
97     tv = SDL_GetTicks();
98     if (tv > timer_expire)
99         goto end;
100
101     ts = timer_expire - tv;
102     SDL_Delay(ts);
103
104 end:
105     timer_expire += micro_frame_delay / 1000;
106 }
107
108 /*************************
109  * audio handlers
110  *************************/
111 void mve_audio_callback(void *userdata, Uint8 *stream, int len); 
112 short *mve_audio_buffers[64];
113 int    mve_audio_buflens[64];
114 int    mve_audio_curbuf_curpos=0;
115 int mve_audio_bufhead=0;
116 int mve_audio_buftail=0;
117 int mve_audio_playing=0;
118 int mve_audio_canplay=0;
119 SDL_AudioSpec *mve_audio_spec=NULL;
120 SDL_mutex *mve_audio_mutex=NULL;
121
122 void mve_audio_callback(void *userdata, Uint8 *stream, int len)
123 {
124     int total=0;
125     int length;
126     if (mve_audio_bufhead == mve_audio_buftail)
127         return /* 0 */;
128
129 fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
130
131     if (!mve_audio_mutex) {
132         fprintf(stderr, "mve_audio_callback: creating mutex");
133         mve_audio_mutex = SDL_CreateMutex();
134     }
135     SDL_mutexP(mve_audio_mutex);
136
137     while (mve_audio_bufhead != mve_audio_buftail                                       /* while we have more buffers  */
138             &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))   /* and while we need more data */
139     {
140         length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
141         __builtin_memcpy(stream,                                                        /* cur output position */
142                 mve_audio_buffers[mve_audio_bufhead]+mve_audio_curbuf_curpos,           /* cur input position  */
143                 length);                                                                /* cur input length    */
144
145         total += length;
146         stream += length;                                                               /* advance output */
147         len -= length;                                                                  /* decrement avail ospace */
148         free(mve_audio_buffers[mve_audio_bufhead]);                                     /* free the buffer */
149         mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
150         mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
151
152         if (++mve_audio_bufhead == 64)                                                  /* next buffer */
153             mve_audio_bufhead = 0;
154         mve_audio_curbuf_curpos = 0;
155     }
156
157 fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
158 /*    return total; */
159
160     if (len != 0                                                                        /* ospace remaining  */
161             &&  mve_audio_bufhead != mve_audio_buftail)                                 /* buffers remaining */
162     {
163         __builtin_memcpy(stream,                                                        /* dest */
164                 mve_audio_buffers[mve_audio_bufhead] + mve_audio_curbuf_curpos,         /* src */
165                 len);                                                                   /* length */
166
167         mve_audio_curbuf_curpos += len;                                                 /* advance input */
168         stream += len;                                                                  /* advance output (unnecessary) */
169         len -= len;                                                                     /* advance output (unnecessary) */
170
171         if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
172         {
173             free(mve_audio_buffers[mve_audio_bufhead]);                                 /* free buffer */
174             mve_audio_buffers[mve_audio_bufhead]=NULL;
175             mve_audio_buflens[mve_audio_bufhead]=0;
176
177             if (++mve_audio_bufhead == 64)                                              /* next buffer */
178                 mve_audio_bufhead = 0;
179             mve_audio_curbuf_curpos = 0;
180         }
181     }
182
183 fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
184     SDL_mutexV(mve_audio_mutex);
185 }
186
187 int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
188 {
189     int sample_rate;
190     int desired_buffer;
191
192 fprintf(stderr, "creating audio buffers\n");
193
194     sample_rate = get_short(data + 4);
195     desired_buffer = get_int(data + 6);
196     mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
197     mve_audio_spec->freq = sample_rate;
198     mve_audio_spec->format = AUDIO_S16LSB;
199     mve_audio_spec->channels = 2;
200     mve_audio_spec->samples = 32768;
201     mve_audio_spec->callback = mve_audio_callback;
202     mve_audio_spec->userdata = NULL;
203     if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
204     {
205 fprintf(stderr, "   success\n");
206         mve_audio_canplay = 1;
207     }
208     else
209     {
210 fprintf(stderr, "   failure : %s\n", SDL_GetError());
211         mve_audio_canplay = 0;
212     }
213
214     memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
215     memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
216
217     return 1;
218 }
219
220 int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
221 {
222     if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
223     {
224         SDL_PauseAudio(0);
225         mve_audio_playing = 1;
226     }
227
228     return 1;
229 }
230
231 int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
232 {
233     const int selected_chan=1;
234     int chan;
235     int nsamp;
236     if (mve_audio_canplay)
237     {
238         if (mve_audio_playing)
239             SDL_LockAudio();
240
241         chan = get_short(data + 2);
242         nsamp = get_short(data + 4);
243         if (chan & selected_chan)
244         {
245             if (!mve_audio_mutex) {
246                 fprintf(stderr, "audio_data_handler: creating mutex");
247                 mve_audio_mutex = SDL_CreateMutex();
248             }
249             SDL_mutexP(mve_audio_mutex);
250             mve_audio_buflens[mve_audio_buftail] = nsamp;
251             mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
252             if (major == 8)
253                 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
254             else
255                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
256
257             if (++mve_audio_buftail == 64)
258                 mve_audio_buftail = 0;
259
260             if (mve_audio_buftail == mve_audio_bufhead)
261                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
262             SDL_mutexV(mve_audio_mutex);
263         }
264
265         if (mve_audio_playing)
266             SDL_UnlockAudio();
267     }
268
269     return 1;
270 }
271
272 /*************************
273  * video handlers
274  *************************/
275 SDL_Surface *g_screen;
276 int g_screenWidth, g_screenHeight;
277 int g_width, g_height;
278 unsigned char g_palette[768];
279 unsigned char *g_vBackBuf1, *g_vBackBuf2;
280 unsigned char *g_pCurMap=NULL;
281 int g_nMapLength=0;
282
283 int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
284 {
285     short w, h;
286     w = get_short(data);
287     h = get_short(data+2);
288     g_width = w << 3;
289     g_height = h << 3;
290     g_vBackBuf1 = malloc(g_width * g_height);
291     g_vBackBuf2 = malloc(g_width * g_height);
292     memset(g_vBackBuf1, 0, g_width * g_height);
293     memset(g_vBackBuf2, 0, g_width * g_height);
294     return 1;
295 }
296
297 int stupefaction=0;
298 int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
299 {
300     int i;
301     unsigned char *pal = g_palette;
302     unsigned char *pDest;
303     unsigned char *pixels = g_vBackBuf1;
304     SDL_Surface *screenSprite;
305     SDL_Rect renderArea;
306     int x, y;
307
308     SDL_Surface *initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, 8, 0, 0, 0, 0);
309     for(i = 0; i < 256; i++)
310     {
311         initSprite->format->palette->colors[i].r = (*pal++) << 2;
312         initSprite->format->palette->colors[i].g = (*pal++) << 2;
313         initSprite->format->palette->colors[i].b = (*pal++) << 2;
314         initSprite->format->palette->colors[i].unused = 0;
315     }
316
317     pDest = initSprite->pixels;
318     for (i=0; i<g_height; i++)
319     {
320         memcpy(pDest, pixels, g_width);
321         pixels += g_width;
322         pDest += initSprite->pitch;
323     }
324
325     screenSprite = SDL_DisplayFormat(initSprite);
326     SDL_FreeSurface(initSprite);
327
328     if (g_screenWidth > screenSprite->w) x = (g_screenWidth - screenSprite->w) >> 1;
329     else x=0;
330     if (g_screenHeight > screenSprite->h) y = (g_screenHeight - screenSprite->h) >> 1;
331     else y=0;
332     renderArea.x = x;
333     renderArea.y = y;
334     renderArea.w = MIN(g_screenWidth  - x, screenSprite->w);
335     renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
336     SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
337     if ( (g_screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF )
338         SDL_Flip(g_screen);
339     else
340         SDL_UpdateRects(g_screen, 1, &renderArea);
341     SDL_FreeSurface(screenSprite);
342     return 1;
343 }
344
345 int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
346 {
347     short width, height;
348     width = get_short(data);
349     height = get_short(data+2);
350     g_screen = SDL_SetVideoMode(width, height, 16, SDL_ANYFORMAT);
351     g_screenWidth = width;
352     g_screenHeight = height;
353     memset(g_palette, 0, 768);
354     return 1;
355 }
356
357 int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
358 {
359     short start, count;
360     start = get_short(data);
361     count = get_short(data+2);
362     memcpy(g_palette + 3*start, data+4, 3*count);
363     return 1;
364 }
365
366 int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
367 {
368     g_pCurMap = data;
369     g_nMapLength = len;
370     return 1;
371 }
372
373 void decodeFrame(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
374
375 int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
376 {
377     short nFrameHot, nFrameCold;
378     short nXoffset, nYoffset;
379     short nXsize, nYsize;
380     short nFlags;
381     unsigned char *temp;
382
383     nFrameHot  = get_short(data);
384     nFrameCold = get_short(data+2);
385     nXoffset   = get_short(data+4);
386     nYoffset   = get_short(data+6);
387     nXsize     = get_short(data+8);
388     nYsize     = get_short(data+10);
389     nFlags     = get_short(data+12);
390
391     if (nFlags & 1)
392     {
393         temp = g_vBackBuf1;
394         g_vBackBuf1 = g_vBackBuf2;
395         g_vBackBuf2 = temp;
396     }
397
398     /* convert the frame */
399     decodeFrame(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
400
401     return 1;
402 }
403
404 int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
405 {
406     g_pCurMap=NULL;
407     return 1;
408 }
409
410 void initializeMovie(MVESTREAM *mve)
411 {
412     mve_set_handler(mve, 0x00, end_movie_handler);
413     mve_set_handler(mve, 0x01, end_chunk_handler);
414     mve_set_handler(mve, 0x02, create_timer_handler);
415     mve_set_handler(mve, 0x03, create_audiobuf_handler);
416     mve_set_handler(mve, 0x04, play_audio_handler);
417     mve_set_handler(mve, 0x05, create_videobuf_handler);
418     mve_set_handler(mve, 0x07, display_video_handler);
419     mve_set_handler(mve, 0x08, audio_data_handler);
420     mve_set_handler(mve, 0x09, audio_data_handler);
421     mve_set_handler(mve, 0x0a, init_video_handler);
422     mve_set_handler(mve, 0x0c, video_palette_handler);
423     mve_set_handler(mve, 0x0f, video_codemap_handler);
424     mve_set_handler(mve, 0x11, video_data_handler);
425 }
426
427 void playMovie(MVESTREAM *mve)
428 {
429     int init_timer=0;
430     int cont=1;
431     while (cont)
432     {
433         cont = mve_play_next_chunk(mve);
434         if (micro_frame_delay  &&  !init_timer)
435         {
436             timer_start();
437             init_timer = 1;
438         }
439
440         do_timer_wait();
441     }
442 }
443
444 void shutdownMovie(MVESTREAM *mve)
445 {
446 }
447
448 void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb);
449
450 void decodeFrame(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain)
451 {
452     int i, j;
453     int xb, yb;
454
455     xb = g_width >> 3;
456     yb = g_height >> 3;
457     for (j=0; j<yb; j++)
458     {
459         for (i=0; i<xb/2; i++)
460         {
461             dispatchDecoder(&pFrame, (*pMap) & 0xf, &pData, &dataRemain, &i, &j);
462             if (pFrame < g_vBackBuf1)
463                 fprintf(stderr, "danger!  pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
464             else if (pFrame >= g_vBackBuf1 + g_width*g_height)
465                 fprintf(stderr, "danger!  pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf);
466             dispatchDecoder(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j);
467             if (pFrame < g_vBackBuf1)
468                 fprintf(stderr, "danger!  pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
469             else if (pFrame >= g_vBackBuf1 + g_width*g_height)
470                 fprintf(stderr, "danger!  pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4);
471
472             ++pMap;
473             --mapRemain;
474         }
475
476         pFrame += 7*g_width;
477     }
478 }
479
480 void relClose(int i, int *x, int *y)
481 {
482     int ma, mi;
483
484     ma = i >> 4;
485     mi = i & 0xf;
486
487     *x = mi - 8;
488     *y = ma - 8;
489 }
490
491 void relFar(int i, int sign, int *x, int *y)
492 {
493     if (i < 56)
494     {
495         *x = sign * (8 + (i % 7));
496         *y = sign *      (i / 7);
497     }
498     else
499     {
500         *x = sign * (-14 + (i - 56) % 29);
501         *y = sign *   (8 + (i - 56) / 29);
502     }
503 }
504
505 void copyFrame(unsigned char *pDest, unsigned char *pSrc)
506 {
507     int i;
508
509     for (i=0; i<8; i++)
510     {
511         memcpy(pDest, pSrc, 8);
512         pDest += g_width;
513         pSrc += g_width;
514     }
515 }
516
517 void patternRow4Pixels(unsigned char *pFrame,
518                               unsigned char pat0, unsigned char pat1,
519                               unsigned char *p)
520 {
521     unsigned short mask=0x0003;
522     unsigned short shift=0;
523     unsigned short pattern = (pat1 << 8) | pat0;
524
525     while (mask != 0)
526     {
527         *pFrame++ = p[(mask & pattern) >> shift];
528         mask <<= 2;
529         shift += 2;
530     }
531 }
532
533 void patternRow4Pixels2(unsigned char *pFrame,
534                                unsigned char pat0,
535                                unsigned char *p)
536 {
537     unsigned char mask=0x03;
538     unsigned char shift=0;
539     unsigned char pel;
540     int skip=1;
541
542     while (mask != 0)
543     {
544         pel = p[(mask & pat0) >> shift];
545         pFrame[0] = pel;
546         pFrame[2] = pel;
547         pFrame[g_width + 0] = pel;
548         pFrame[g_width + 2] = pel;
549         pFrame += skip;
550         skip = 4 - skip;
551         mask <<= 2;
552         shift += 2;
553     }
554 }
555
556 void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, unsigned char *p)
557 {
558     unsigned char mask=0x03;
559     unsigned char shift=0;
560     unsigned char pel;
561
562     while (mask != 0)
563     {
564         pel = p[(mask & pat) >> shift];
565         pFrame[0] = pel;
566         pFrame[1] = pel;
567         pFrame += 2;
568         mask <<= 2;
569         shift += 2;
570     }
571 }
572
573 void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, unsigned char *p)
574 {
575     unsigned long mask = 0x00000003UL;
576     int shift=0;
577     int i;
578     unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
579
580     for (i=0; i<16; i++)
581     {
582         pFrame[i&3] = p[(pat & mask) >> shift];
583
584         if ((i&3) == 3)
585             pFrame += g_width;
586
587         mask <<= 2;
588         shift += 2;
589     }
590 }
591
592
593 void patternRow2Pixels(unsigned char *pFrame, unsigned char pat, unsigned char *p)
594 {
595     unsigned char mask=0x01;
596
597     while (mask != 0)
598     {
599         *pFrame++ = p[(mask & pat) ? 1 : 0];
600         mask <<= 1;
601     }
602 }
603
604 void patternRow2Pixels2(unsigned char *pFrame, unsigned char pat, unsigned char *p)
605 {
606     unsigned char pel;
607     unsigned char mask=0x1;
608     int skip=1;
609
610     while (mask != 0x10)
611     {
612         pel = p[(mask & pat) ? 1 : 0];
613         pFrame[0] = pel;
614         pFrame[2] = pel;
615         pFrame[g_width + 0] = pel;
616         pFrame[g_width + 2] = pel;
617         pFrame += skip;
618         skip = 4 - skip;
619         mask <<= 1;
620     }
621 }
622
623 void patternQuadrant2Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char *p)
624 {
625     unsigned short mask = 0x0001;
626     int i;
627     unsigned short pat = (pat1 << 8) | pat0;
628
629     for (i=0; i<16; i++)
630     {
631         pFrame[i&3] = p[(pat & mask) ? 1 : 0];
632
633         if ((i&3) == 3)
634             pFrame += g_width;
635
636         mask <<= 1;
637     }
638 }
639
640 void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb)
641 {
642     unsigned char p[4];
643     unsigned char pat[16];
644     int i, j, k;
645     int x, y;
646
647     switch(codeType)
648     {
649         case 0x0:
650                   copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1));
651         case 0x1:
652                   *pFrame += 8;
653                   break;
654
655         case 0x2:
656                   relFar(*(*pData)++, 1, &x, &y);
657                   copyFrame(*pFrame, *pFrame + x + y*g_width);
658                   *pFrame += 8;
659                   --*pDataRemain;
660                   break;
661
662         case 0x3:
663                   relFar(*(*pData)++, -1, &x, &y);
664                   copyFrame(*pFrame, *pFrame + x + y*g_width);
665                   *pFrame += 8;
666                   --*pDataRemain;
667                   break;
668
669         case 0x4:
670                   relClose(*(*pData)++, &x, &y);
671                   copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
672                   *pFrame += 8;
673                   --*pDataRemain;
674                   break;
675
676         case 0x5:
677                   x = (char)*(*pData)++;
678                   y = (char)*(*pData)++;
679                   copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width);
680                   *pFrame += 8;
681                   *pDataRemain -= 2;
682                   break;
683
684         case 0x6:
685                   for (i=0; i<2; i++)
686                   {
687                       *pFrame += 16;
688                       if (++*curXb == (g_width >> 3))
689                       {
690                           *pFrame += 7*g_width;
691                           *curXb = 0;
692                           if (++*curYb == (g_height >> 3))
693                               return;
694                       }
695                   }
696                   break;
697
698         case 0x7:
699                   p[0] = *(*pData)++;
700                   p[1] = *(*pData)++;
701                   if (p[0] <= p[1])
702                   {
703                       for (i=0; i<8; i++)
704                       {
705                           patternRow2Pixels(*pFrame, *(*pData)++, p);
706                           *pFrame += g_width;
707                       }
708                   }
709                   else
710                   {
711                       for (i=0; i<2; i++)
712                       {
713                           patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
714                           *pFrame += 2*g_width;
715                           patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p);
716                           *pFrame += 2*g_width;
717                       }
718                   }
719                   *pFrame -= (8*g_width - 8);
720                   break;
721
722         case 0x8:
723                   if ( (*pData)[0] <= (*pData)[1])
724                   {
725                       for (i=0; i<4; i++)
726                       {
727                           p[0] = *(*pData)++;
728                           p[1] = *(*pData)++;
729                           pat[0] = *(*pData)++;
730                           pat[1] = *(*pData)++;
731                           patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
732
733                           if (i & 1)
734                               *pFrame -= (4*g_width - 4);
735                           else
736                               *pFrame += 4*g_width;
737                       }
738                   }
739                   else if ( (*pData)[6] <= (*pData)[7])
740                   {
741                       for (i=0; i<4; i++)
742                       {
743                           if ((i & 1) == 0)
744                           {
745                               p[0] = *(*pData)++;
746                               p[1] = *(*pData)++;
747                           }
748                           pat[0] = *(*pData)++;
749                           pat[1] = *(*pData)++;
750                           patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
751
752                           if (i & 1)
753                               *pFrame -= (4*g_width - 4);
754                           else
755                               *pFrame += 4*g_width;
756                       }
757                   }
758                   else
759                   {
760                       for (i=0; i<8; i++)
761                       {
762                           if ((i & 3) == 0)
763                           {
764                               p[0] = *(*pData)++;
765                               p[1] = *(*pData)++;
766                           }
767                           patternRow2Pixels(*pFrame, *(*pData)++, p);
768                           *pFrame += g_width;
769                       }
770                       *pFrame -= (8*g_width - 8);
771                   }
772                   break;
773
774         case 0x9:
775                   if ( (*pData)[0] <= (*pData)[1])
776                   {
777                       if ( (*pData)[2] <= (*pData)[3])
778                       {
779                           p[0] = *(*pData)++;
780                           p[1] = *(*pData)++;
781                           p[2] = *(*pData)++;
782                           p[3] = *(*pData)++;
783
784                           for (i=0; i<8; i++)
785                           {
786                               pat[0] = *(*pData)++;
787                               pat[1] = *(*pData)++;
788                               patternRow4Pixels(*pFrame, pat[0], pat[1], p);
789                               *pFrame += g_width;
790                           }
791
792                           *pFrame -= (8*g_width - 8);
793                       }
794                       else
795                       {
796                           p[0] = *(*pData)++;
797                           p[1] = *(*pData)++;
798                           p[2] = *(*pData)++;
799                           p[3] = *(*pData)++;
800
801                           patternRow4Pixels2(*pFrame, *(*pData)++, p);
802                           *pFrame += 2*g_width;
803                           patternRow4Pixels2(*pFrame, *(*pData)++, p);
804                           *pFrame += 2*g_width;
805                           patternRow4Pixels2(*pFrame, *(*pData)++, p);
806                           *pFrame += 2*g_width;
807                           patternRow4Pixels2(*pFrame, *(*pData)++, p);
808                           *pFrame -= (6*g_width - 8);
809                       }
810                   }
811                   else
812                   {
813                       if ( (*pData)[2] <= (*pData)[3])
814                       {
815                           p[0] = *(*pData)++;
816                           p[1] = *(*pData)++;
817                           p[2] = *(*pData)++;
818                           p[3] = *(*pData)++;
819
820                           for (i=0; i<8; i++)
821                           {
822                               pat[0] = *(*pData)++;
823                               patternRow4Pixels2x1(*pFrame, pat[0], p);
824                               *pFrame += g_width;
825                           }
826
827                           *pFrame -= (8*g_width - 8);
828                       }
829                       else
830                       {
831                           p[0] = *(*pData)++;
832                           p[1] = *(*pData)++;
833                           p[2] = *(*pData)++;
834                           p[3] = *(*pData)++;
835
836                           for (i=0; i<4; i++)
837                           {
838                               pat[0] = *(*pData)++;
839                               pat[1] = *(*pData)++;
840                               patternRow4Pixels(*pFrame, pat[0], pat[1], p);
841                               *pFrame += g_width;
842                               patternRow4Pixels(*pFrame, pat[0], pat[1], p);
843                               *pFrame += g_width;
844                           }
845
846                           *pFrame -= (8*g_width - 8);
847                       }
848                   }
849                   break;
850
851         case 0xa:
852                   if ( (*pData)[0] <= (*pData)[1])
853                   {
854                       for (i=0; i<4; i++)
855                       {
856                           p[0] = *(*pData)++;
857                           p[1] = *(*pData)++;
858                           p[2] = *(*pData)++;
859                           p[3] = *(*pData)++;
860                           pat[0] = *(*pData)++;
861                           pat[1] = *(*pData)++;
862                           pat[2] = *(*pData)++;
863                           pat[3] = *(*pData)++;
864
865                           patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
866
867                           if (i & 1)
868                               *pFrame -= (4*g_width - 4);
869                           else
870                               *pFrame += 4*g_width;
871                       }
872                   }
873                   else
874                   {
875                       if ( (*pData)[12] <= (*pData)[13])
876                       {
877                           for (i=0; i<4; i++)
878                           {
879                               if ((i&1) == 0)
880                               {
881                                   p[0] = *(*pData)++;
882                                   p[1] = *(*pData)++;
883                                   p[2] = *(*pData)++;
884                                   p[3] = *(*pData)++;
885                               }
886
887                               pat[0] = *(*pData)++;
888                               pat[1] = *(*pData)++;
889                               pat[2] = *(*pData)++;
890                               pat[3] = *(*pData)++;
891
892                               patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
893
894                               if (i & 1)
895                                   *pFrame -= (4*g_width - 4);
896                               else
897                                   *pFrame += 4*g_width;
898                           }
899                       }
900                       else
901                       {
902                           for (i=0; i<8; i++)
903                           {
904                               if ((i&3) == 0)
905                               {
906                                   p[0] = *(*pData)++;
907                                   p[1] = *(*pData)++;
908                                   p[2] = *(*pData)++;
909                                   p[3] = *(*pData)++;
910                               }
911
912                               pat[0] = *(*pData)++;
913                               pat[1] = *(*pData)++;
914                               patternRow4Pixels(*pFrame, pat[0], pat[1], p);
915                               *pFrame += g_width;
916                           }
917
918                           *pFrame -= (8*g_width - 8);
919                       }
920                   }
921                   break;
922
923         case 0xb:
924                   for (i=0; i<8; i++)
925                   {
926                       memcpy(*pFrame, *pData, 8);
927                       *pFrame += g_width;
928                       *pData += 8;
929                       *pDataRemain -= 8;
930                   }
931                   *pFrame -= (8*g_width - 8);
932                   break;
933
934         case 0xc:
935                   for (i=0; i<4; i++)
936                   {
937                       for (j=0; j<2; j++)
938                       {
939                           for (k=0; k<4; k++)
940                           {
941                               (*pFrame)[j+2*k] = (*pData)[k];
942                               (*pFrame)[g_width+j+2*k] = (*pData)[k];
943                           }
944                           *pFrame += g_width;
945                       }
946                       *pData += 4;
947                       *pDataRemain -= 4;
948                   }
949                   *pFrame -= (8*g_width - 8);
950                   break;
951
952         case 0xd:
953                   for (i=0; i<2; i++)
954                   {
955                       for (j=0; j<4; j++)
956                       {
957                           for (k=0; k<4; k++)
958                           {
959                               (*pFrame)[k*g_width+j] = (*pData)[0];
960                               (*pFrame)[k*g_width+j+4] = (*pData)[1];
961                           }
962                       }
963                       *pFrame += 4*g_width;
964                       *pData += 2;
965                       *pDataRemain -= 2;
966                   }
967                   *pFrame -= (8*g_width - 8);
968                   break;
969
970         case 0xe:
971                   for (i=0; i<8; i++)
972                   {
973                       memset(*pFrame, **pData, 8);
974                       *pFrame += g_width;
975                   }
976                   ++*pData;
977                   --*pDataRemain;
978                   *pFrame -= (8*g_width - 8);
979                   break;
980
981         case 0xf:
982                   for (i=0; i<8; i++)
983                   {
984                       for (j=0; j<8; j++)
985                       {
986                           (*pFrame)[j] = (*pData)[(i+j)&1];
987                       }
988                       *pFrame += g_width;
989                   }
990                   *pData += 2;
991                   *pDataRemain -= 2;
992                   *pFrame -= (8*g_width - 8);
993                   break;
994
995         default:
996             break;
997     }
998 }