]> icculus.org git repositories - btb/d2x.git/blob - libmve/mveplay.c
oops, can't get rid of main INCLUDE yet...
[btb/d2x.git] / libmve / mveplay.c
1 /* $Id: mveplay.c,v 1.7 2003-03-19 19:21:34 btb Exp $ */
2 #ifdef HAVE_CONFIG_H
3 #include <conf.h>
4 #endif
5
6 #ifndef __MSDOS__
7 #define AUDIO
8 #endif
9 //#define DEBUG
10
11 #include <string.h>
12 #include <errno.h>
13 #include <time.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19
20 #if defined(STANDALONE) || defined(AUDIO)
21 #include <SDL.h>
22 #endif
23
24 #include "mvelib.h"
25 #include "mve_audio.h"
26
27 #include "decoders.h"
28
29 #ifndef STANDALONE
30 #include "libmve.h"
31 #include "u_mem.h"
32 #include "gr.h"
33 #include "palette.h"
34 #endif
35
36 #ifdef STANDALONE
37 #define d_malloc(size)      malloc(size)
38 #define d_free(ptr)         free(ptr)
39 #endif
40
41 #ifndef MIN
42 #define MIN(a,b) ((a)<(b)?(a):(b))
43 #endif
44
45 #define MVE_OPCODE_ENDOFSTREAM          0x00
46 #define MVE_OPCODE_ENDOFCHUNK           0x01
47 #define MVE_OPCODE_CREATETIMER          0x02
48 #define MVE_OPCODE_INITAUDIOBUFFERS     0x03
49 #define MVE_OPCODE_STARTSTOPAUDIO       0x04
50 #define MVE_OPCODE_INITVIDEOBUFFERS     0x05
51
52 #define MVE_OPCODE_DISPLAYVIDEO         0x07
53 #define MVE_OPCODE_AUDIOFRAMEDATA       0x08
54 #define MVE_OPCODE_AUDIOFRAMESILENCE    0x09
55 #define MVE_OPCODE_INITVIDEOMODE        0x0A
56
57 #define MVE_OPCODE_SETPALETTE           0x0C
58 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
59
60 #define MVE_OPCODE_SETDECODINGMAP       0x0F
61
62 #define MVE_OPCODE_VIDEODATA            0x11
63
64 #define MVE_AUDIO_FLAGS_STEREO     1
65 #define MVE_AUDIO_FLAGS_16BIT      2
66 #define MVE_AUDIO_FLAGS_COMPRESSED 4
67
68 int g_spdFactorNum=0;
69 static int g_spdFactorDenom=10;
70 static int g_frameUpdated = 0;
71
72 #ifdef STANDALONE
73 static int playing = 1;
74 int g_sdlVidFlags = SDL_ANYFORMAT | SDL_DOUBLEBUF;
75 int g_loop = 0;
76
77 void initializeMovie(MVESTREAM *mve);
78 void playMovie(MVESTREAM *mve);
79 void shutdownMovie(MVESTREAM *mve);
80 #endif
81
82 static short get_short(unsigned char *data)
83 {
84         short value;
85         value = data[0] | (data[1] << 8);
86         return value;
87 }
88
89 static unsigned short get_ushort(unsigned char *data)
90 {
91         unsigned short value;
92         value = data[0] | (data[1] << 8);
93         return value;
94 }
95
96 static int get_int(unsigned char *data)
97 {
98         int value;
99         value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
100         return value;
101 }
102
103 static unsigned int unhandled_chunks[32*256];
104
105 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
106 {
107         unhandled_chunks[major<<8|minor]++;
108         //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
109         return 1;
110 }
111
112
113 /*************************
114  * general handlers
115  *************************/
116 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
117 {
118         return 0;
119 }
120
121 /*************************
122  * timer handlers
123  *************************/
124
125 /*
126  * timer variables
127  */
128 static int timer_created = 0;
129 static int micro_frame_delay=0;
130 static int timer_started=0;
131 static struct timeval timer_expire = {0, 0};
132
133 #ifdef __MACOSX__
134 int nanosleep(struct timespec *ts, void *rem);
135 #endif
136
137 #ifdef __WIN32
138 #include <sys/timeb.h>
139
140 struct timespec
141 {
142         long int tv_sec;            /* Seconds.  */
143         long int tv_nsec;           /* Nanoseconds.  */
144 };
145
146 int gettimeofday(struct timeval *tv, void *tz)
147 {
148         static int counter = 0;
149         struct timeb tm;
150
151         counter++; /* to avoid collisions */
152         ftime(&tm);
153         tv->tv_sec  = tm.time;
154         tv->tv_usec = (tm.millitm * 1000) + counter;
155
156         return 0;
157 }
158
159 int nanosleep(struct timespec *ts, void *rem)
160 {
161         sleep(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
162
163         return 0;
164 }
165 #endif
166
167 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
168 {
169         __extension__ long long temp;
170
171         if (timer_created)
172                 return 1;
173         else
174                 timer_created = 1;
175
176         micro_frame_delay = get_int(data) * (int)get_short(data+4);
177         if (g_spdFactorNum != 0)
178         {
179                 temp = micro_frame_delay;
180                 temp *= g_spdFactorNum;
181                 temp /= g_spdFactorDenom;
182                 micro_frame_delay = (int)temp;
183         }
184
185         return 1;
186 }
187
188 static void timer_stop(void)
189 {
190         timer_expire.tv_sec = 0;
191         timer_expire.tv_usec = 0;
192         timer_started = 0;
193 }
194
195 static void timer_start(void)
196 {
197         int nsec=0;
198         gettimeofday(&timer_expire, NULL);
199         timer_expire.tv_usec += micro_frame_delay;
200         if (timer_expire.tv_usec > 1000000)
201         {
202                 nsec = timer_expire.tv_usec / 1000000;
203                 timer_expire.tv_sec += nsec;
204                 timer_expire.tv_usec -= nsec*1000000;
205         }
206         timer_started=1;
207 }
208
209 static void do_timer_wait(void)
210 {
211         int nsec=0;
212         struct timespec ts;
213         struct timeval tv;
214         if (! timer_started)
215                 return;
216
217         gettimeofday(&tv, NULL);
218         if (tv.tv_sec > timer_expire.tv_sec)
219                 goto end;
220         else if (tv.tv_sec == timer_expire.tv_sec  &&  tv.tv_usec >= timer_expire.tv_usec)
221                 goto end;
222
223         ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
224         ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
225         if (ts.tv_nsec < 0)
226         {
227                 ts.tv_nsec += 1000000000UL;
228                 --ts.tv_sec;
229         }
230 #ifdef __CYGWIN__
231         usleep(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
232 #else
233         if (nanosleep(&ts, NULL) == -1  &&  errno == EINTR)
234                 exit(1);
235 #endif
236
237  end:
238         timer_expire.tv_usec += micro_frame_delay;
239         if (timer_expire.tv_usec > 1000000)
240         {
241                 nsec = timer_expire.tv_usec / 1000000;
242                 timer_expire.tv_sec += nsec;
243                 timer_expire.tv_usec -= nsec*1000000;
244         }
245 }
246
247 /*************************
248  * audio handlers
249  *************************/
250 #ifdef AUDIO
251 #define TOTAL_AUDIO_BUFFERS 64
252
253 static int audiobuf_created = 0;
254 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
255 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
256 static int    mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
257 static int    mve_audio_curbuf_curpos=0;
258 static int mve_audio_bufhead=0;
259 static int mve_audio_buftail=0;
260 static int mve_audio_playing=0;
261 static int mve_audio_canplay=0;
262 static int mve_audio_compressed=0;
263 static int mve_audio_enabled = 1;
264 static SDL_AudioSpec *mve_audio_spec=NULL;
265
266 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
267 {
268         int total=0;
269         int length;
270         if (mve_audio_bufhead == mve_audio_buftail)
271                 return /* 0 */;
272
273         //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
274
275         while (mve_audio_bufhead != mve_audio_buftail                                           /* while we have more buffers  */
276                    &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))        /* and while we need more data */
277         {
278                 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
279                 memcpy(stream,                                                                  /* cur output position */
280                        ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos,           /* cur input position  */
281                        length);                                                                 /* cur input length    */
282
283                 total += length;
284                 stream += length;                                                               /* advance output */
285                 len -= length;                                                                  /* decrement avail ospace */
286                 d_free(mve_audio_buffers[mve_audio_bufhead]);                                   /* free the buffer */
287                 mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
288                 mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
289
290                 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                                 /* next buffer */
291                         mve_audio_bufhead = 0;
292                 mve_audio_curbuf_curpos = 0;
293         }
294
295         //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
296         /*    return total; */
297
298         if (len != 0                                                                        /* ospace remaining  */
299                 &&  mve_audio_bufhead != mve_audio_buftail)                                     /* buffers remaining */
300         {
301                 memcpy(stream,                                                                  /* dest */
302                            ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos,         /* src */
303                            len);                                                                    /* length */
304
305                 mve_audio_curbuf_curpos += len;                                                 /* advance input */
306                 stream += len;                                                                  /* advance output (unnecessary) */
307                 len -= len;                                                                     /* advance output (unnecessary) */
308
309                 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
310                 {
311                         d_free(mve_audio_buffers[mve_audio_bufhead]);                               /* free buffer */
312                         mve_audio_buffers[mve_audio_bufhead]=NULL;
313                         mve_audio_buflens[mve_audio_bufhead]=0;
314
315                         if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                             /* next buffer */
316                                 mve_audio_bufhead = 0;
317                         mve_audio_curbuf_curpos = 0;
318                 }
319         }
320
321         //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
322 }
323 #endif
324
325 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
326 {
327 #ifdef AUDIO
328         int flags;
329         int sample_rate;
330         int desired_buffer;
331
332         int stereo;
333         int bitsize;
334         int compressed;
335
336         int format;
337
338         if (!mve_audio_enabled)
339                 return 1;
340
341         if (audiobuf_created)
342                 return 1;
343         else
344                 audiobuf_created = 1;
345
346         flags = get_ushort(data + 2);
347         sample_rate = get_ushort(data + 4);
348         desired_buffer = get_int(data + 6);
349
350         stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
351         bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
352
353         if (minor > 0) {
354                 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
355         } else {
356                 compressed = 0;
357         }
358
359         mve_audio_compressed = compressed;
360
361         if (bitsize == 1) {
362 #ifdef WORDS_BIGENDIAN
363                 format = AUDIO_S16MSB;
364 #else
365                 format = AUDIO_S16LSB;
366 #endif
367         } else {
368                 format = AUDIO_U8;
369         }
370
371         fprintf(stderr, "creating audio buffers:\n");
372         fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
373                         sample_rate, stereo, bitsize ? 16 : 8, compressed);
374
375         mve_audio_spec = (SDL_AudioSpec *)d_malloc(sizeof(SDL_AudioSpec));
376         mve_audio_spec->freq = sample_rate;
377         mve_audio_spec->format = format;
378         mve_audio_spec->channels = (stereo) ? 2 : 1;
379         mve_audio_spec->samples = 4096;
380         mve_audio_spec->callback = mve_audio_callback;
381         mve_audio_spec->userdata = NULL;
382         if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
383         {
384                 fprintf(stderr, "   success\n");
385                 mve_audio_canplay = 1;
386         }
387         else
388         {
389                 fprintf(stderr, "   failure : %s\n", SDL_GetError());
390                 mve_audio_canplay = 0;
391         }
392
393         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
394         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
395 #endif
396
397         return 1;
398 }
399
400 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
401 {
402 #ifdef AUDIO
403         if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
404         {
405                 SDL_PauseAudio(0);
406                 mve_audio_playing = 1;
407         }
408 #endif
409         return 1;
410 }
411
412 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
413 {
414 #ifdef AUDIO
415         static const int selected_chan=1;
416         int chan;
417         int nsamp;
418         if (mve_audio_canplay)
419         {
420                 if (mve_audio_playing)
421                         SDL_LockAudio();
422
423                 chan = get_ushort(data + 2);
424                 nsamp = get_ushort(data + 4);
425                 if (chan & selected_chan)
426                 {
427                         /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
428                         if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
429                                 if (mve_audio_compressed) {
430                                         nsamp += 4;
431
432                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
433                                         mve_audio_buffers[mve_audio_buftail] = (short *)d_malloc(nsamp);
434                                         mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
435                                 } else {
436                                         nsamp -= 8;
437                                         data += 8;
438
439                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
440                                         mve_audio_buffers[mve_audio_buftail] = (short *)d_malloc(nsamp);
441                                         memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
442                                 }
443                         } else {
444                                 mve_audio_buflens[mve_audio_buftail] = nsamp;
445                                 mve_audio_buffers[mve_audio_buftail] = (short *)d_malloc(nsamp);
446
447                                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
448                         }
449
450                         if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
451                                 mve_audio_buftail = 0;
452
453                         if (mve_audio_buftail == mve_audio_bufhead)
454                                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
455                 }
456
457                 if (mve_audio_playing)
458                         SDL_UnlockAudio();
459         }
460 #endif
461
462         return 1;
463 }
464
465 /*************************
466  * video handlers
467  *************************/
468 static int videobuf_created = 0;
469 static int video_initialized = 0;
470 int g_width, g_height;
471 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
472
473 #ifdef STANDALONE
474 static SDL_Surface *g_screen;
475 #else
476 static int g_destX, g_destY;
477 #endif
478 static int g_screenWidth, g_screenHeight;
479 static unsigned char g_palette[768];
480 static unsigned char *g_pCurMap=NULL;
481 static int g_nMapLength=0;
482 static int g_truecolor;
483
484 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
485 {
486         short w, h;
487         short count, truecolor;
488
489         if (videobuf_created)
490                 return 1;
491         else
492                 videobuf_created = 1;
493
494         w = get_short(data);
495         h = get_short(data+2);
496
497         if (minor > 0) {
498                 count = get_short(data+4);
499         } else {
500                 count = 1;
501         }
502
503         if (minor > 1) {
504                 truecolor = get_short(data+6);
505         } else {
506                 truecolor = 0;
507         }
508
509         g_width = w << 3;
510         g_height = h << 3;
511
512         /* TODO: * 4 causes crashes on some files */
513         g_vBackBuf1 = g_vBuffers = d_malloc(g_width * g_height * 8);
514         if (truecolor) {
515                 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
516         } else {
517                 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
518         }
519
520         memset(g_vBackBuf1, 0, g_width * g_height * 4);
521
522 #ifdef DEBUG
523         fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
524 #endif
525
526         g_truecolor = truecolor;
527
528         return 1;
529 }
530
531 #ifdef STANDALONE
532 static int do_sdl_events()
533 {
534         SDL_Event event;
535         int retr = 0;
536         while (SDL_PollEvent(&event)) {
537                 switch(event.type) {
538                 case SDL_QUIT:
539                         playing=0;
540                         break;
541                 case SDL_KEYDOWN:
542                         if (event.key.keysym.sym == SDLK_ESCAPE)
543                                 playing=0;
544                         break;
545                 case SDL_KEYUP:
546                         retr = 1;
547                         break;
548                 case SDL_MOUSEBUTTONDOWN:
549                         /*
550                           if (event.button.button == SDL_BUTTON_LEFT) {
551                           printf("GRID: %d,%d (pix:%d,%d)\n", 
552                           event.button.x / 16, event.button.y / 8,
553                           event.button.x, event.button.y);
554                           }
555                         */
556                         break;
557                 default:
558                         break;
559                 }
560         }
561
562         return retr;
563 }
564
565 static void ConvertAndDraw()
566 {
567         int i;
568         unsigned char *pal = g_palette;
569         unsigned char *pDest;
570         unsigned char *pixels = g_vBackBuf1;
571         SDL_Surface *screenSprite, *initSprite;
572         SDL_Rect renderArea;
573         int x, y;
574
575         initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, g_truecolor?16:8, 0x7C00, 0x03E0, 0x001F, 0);
576
577         if (!g_truecolor) {
578                 for(i = 0; i < 256; i++) {
579                         initSprite->format->palette->colors[i].r = (*pal++) << 2;
580                         initSprite->format->palette->colors[i].g = (*pal++) << 2;
581                         initSprite->format->palette->colors[i].b = (*pal++) << 2;
582                         initSprite->format->palette->colors[i].unused = 0;
583                 }
584         }
585
586         pDest = initSprite->pixels;
587
588         if (0 /*g_truecolor*/) {
589
590                 unsigned short *pSrcs, *pDests;
591
592                 pSrcs = (unsigned short *)pixels;
593                 pDests = (unsigned short *)pDest;
594
595                 for (y=0; y<g_height; y++) {
596                         for (x = 0; x < g_width; x++) {
597                                 pDests[x] = (1<<15)|*pSrcs;
598                                 pSrcs++;
599                         }
600                         pDests += g_screenWidth;
601                 }
602
603         } else {
604
605                 for (i=0; i<g_height; i++) {
606                         memcpy(pDest, pixels, g_width * (g_truecolor?2:1));
607                         pixels += g_width* (g_truecolor?2:1);
608                         pDest += initSprite->pitch;
609                 }
610         }
611
612         screenSprite = SDL_DisplayFormat(initSprite);
613         SDL_FreeSurface(initSprite);
614
615         if (g_screenWidth > screenSprite->w)
616                 x = (g_screenWidth - screenSprite->w) >> 1;
617         else
618                 x=0;
619         if (g_screenHeight > screenSprite->h)
620                 y = (g_screenHeight - screenSprite->h) >> 1;
621         else
622                 y=0;
623         renderArea.x = x;
624         renderArea.y = y;
625         renderArea.w = MIN(g_screenWidth  - x, screenSprite->w);
626         renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
627         SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
628
629         SDL_FreeSurface(screenSprite);
630 }
631 #endif
632
633 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
634 {
635 #ifdef STANDALONE
636         ConvertAndDraw();
637
638         SDL_Flip(g_screen);
639
640         do_sdl_events();
641 #else
642         grs_bitmap *bitmap;
643
644         bitmap = gr_create_bitmap_raw(g_width, g_height, g_vBackBuf1);
645
646         if (g_destX == -1) // center it
647                 g_destX = (g_screenWidth - g_width) >> 1;
648         if (g_destY == -1) // center it
649                 g_destY = (g_screenHeight - g_height) >> 1;
650
651         gr_palette_load(g_palette);
652
653         gr_bitmap(g_destX, g_destY, bitmap);
654
655         gr_free_sub_bitmap(bitmap);
656 #endif
657         g_frameUpdated = 1;
658
659         return 1;
660 }
661
662 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
663 {
664         short width, height;
665
666         if (video_initialized)
667                 return 1;
668         else
669                 video_initialized = 1;
670
671         width = get_short(data);
672         height = get_short(data+2);
673 #ifdef STANDALONE
674         g_screen = SDL_SetVideoMode(width, height, 16, g_sdlVidFlags);
675 #endif
676         g_screenWidth = width;
677         g_screenHeight = height;
678         memset(g_palette, 0, 765);
679         // 255 needs to default to white, for subtitles, etc
680         memset(g_palette + 765, 63, 3);
681
682         return 1;
683 }
684
685 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
686 {
687         short start, count;
688         start = get_short(data);
689         count = get_short(data+2);
690         memcpy(g_palette + 3*start, data+4, 3*count);
691
692         return 1;
693 }
694
695 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
696 {
697         g_pCurMap = data;
698         g_nMapLength = len;
699         return 1;
700 }
701
702 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
703 {
704         short nFrameHot, nFrameCold;
705         short nXoffset, nYoffset;
706         short nXsize, nYsize;
707         unsigned short nFlags;
708         unsigned char *temp;
709
710         nFrameHot  = get_short(data);
711         nFrameCold = get_short(data+2);
712         nXoffset   = get_short(data+4);
713         nYoffset   = get_short(data+6);
714         nXsize     = get_short(data+8);
715         nYsize     = get_short(data+10);
716         nFlags     = get_ushort(data+12);
717
718         if (nFlags & 1)
719         {
720                 temp = (unsigned char *)g_vBackBuf1;
721                 g_vBackBuf1 = g_vBackBuf2;
722                 g_vBackBuf2 = temp;
723         }
724
725         /* convert the frame */
726         if (g_truecolor) {
727                 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
728         } else {
729                 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
730         }
731
732         return 1;
733 }
734
735 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
736 {
737         g_pCurMap=NULL;
738         return 1;
739 }
740
741
742 #ifdef STANDALONE
743 void initializeMovie(MVESTREAM *mve)
744 {
745         int i;
746
747         for (i = 0; i < 32; i++)
748                 mve_set_handler(mve, i, default_seg_handler);
749
750         memset(unhandled_chunks, 0, 32*256);
751
752         mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
753         mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
754         mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
755         mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
756         mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
757         mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
758
759         mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
760         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
761         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
762         mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
763
764         mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
765         mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, video_palette_handler);
766         mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
767
768         mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
769 }
770
771 void playMovie(MVESTREAM *mve)
772 {
773         int init_timer=0;
774         int cont=1;
775
776         mve_audio_enabled = 1;
777
778         while (cont && playing)
779         {
780                 cont = mve_play_next_chunk(mve);
781                 if (micro_frame_delay  &&  !init_timer)
782                 {
783                         timer_start();
784                         init_timer = 1;
785                 }
786
787                 do_timer_wait();
788
789                 if (g_loop && !cont) {
790                         mve_reset(mve);
791                         cont = 1;
792                 }
793         }
794 }
795
796 void shutdownMovie(MVESTREAM *mve)
797 {
798 #ifdef DEBUG
799         int i;
800 #endif
801
802         timer_stop();
803
804 #ifdef DEBUG
805         for (i = 0; i < 32*256; i++) {
806                 if (unhandled_chunks[i]) {
807                         fprintf(stderr, "unhandled chunks of type %02x/%02x: %d\n", i>>8, i&0xFF, unhandled_chunks[i]);
808                 }
809         }
810 #endif
811 }
812
813 #else
814 static MVESTREAM *mve = NULL;
815
816 int MVE_rmPrepMovie(int filehandle, int x, int y, int track)
817 {
818         int i;
819
820         if (mve) {
821                 mve_reset(mve);
822                 return 0;
823         }
824
825         mve = mve_open_filehandle(filehandle);
826
827         if (!mve)
828                 return 1;
829
830         g_destX = x;
831         g_destY = y;
832
833         for (i = 0; i < 32; i++)
834                 mve_set_handler(mve, i, default_seg_handler);
835
836         mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM,          end_movie_handler);
837         mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK,           end_chunk_handler);
838         mve_set_handler(mve, MVE_OPCODE_CREATETIMER,          create_timer_handler);
839         mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS,     create_audiobuf_handler);
840         mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO,       play_audio_handler);
841         mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS,     create_videobuf_handler);
842
843         mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO,         display_video_handler);
844         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA,       audio_data_handler);
845         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE,    audio_data_handler);
846         mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE,        init_video_handler);
847
848         mve_set_handler(mve, MVE_OPCODE_SETPALETTE,           video_palette_handler);
849         mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
850
851         mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP,       video_codemap_handler);
852
853         mve_set_handler(mve, MVE_OPCODE_VIDEODATA,            video_data_handler);
854
855         return 0;
856 }
857
858 int MVE_rmStepMovie()
859 {
860         static int init_timer=0;
861         int cont=1;
862
863         if (!timer_started)
864                 timer_start();
865
866         while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
867                 cont = mve_play_next_chunk(mve);
868         g_frameUpdated = 0;
869
870         if (micro_frame_delay  && !init_timer) {
871                 timer_start();
872                 init_timer = 1;
873         }
874
875         do_timer_wait();
876
877         if (cont)
878                 return 0;
879         else
880                 return MVE_ERR_EOF;
881 }
882
883 void MVE_rmEndMovie()
884 {
885 #ifdef AUDIO
886         int i;
887 #endif
888
889         timer_stop();
890         timer_created = 0;
891
892 #ifdef AUDIO
893         if (mve_audio_canplay) {
894                 // only close audio if we opened it
895                 SDL_CloseAudio();
896                 mve_audio_canplay = 0;
897         }
898         for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
899                 if (mve_audio_buffers[i] != NULL)
900                         d_free(mve_audio_buffers[i]);
901         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
902         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
903         mve_audio_curbuf_curpos=0;
904         mve_audio_bufhead=0;
905         mve_audio_buftail=0;
906         mve_audio_playing=0;
907         mve_audio_canplay=0;
908         mve_audio_compressed=0;
909         if (mve_audio_spec)
910                 d_free(mve_audio_spec);
911         mve_audio_spec=NULL;
912         audiobuf_created = 0;
913 #endif
914
915         d_free(g_vBuffers);
916         g_vBuffers = NULL;
917         g_pCurMap=NULL;
918         g_nMapLength=0;
919         videobuf_created = 0;
920         video_initialized = 0;
921
922         mve_close_filehandle(mve);
923         mve = NULL;
924 }
925
926
927 void MVE_rmHoldMovie()
928 {
929         timer_started = 0;
930 }
931
932
933 void MVE_sndInit(int x)
934 {
935 #ifdef AUDIO
936         if (x == -1)
937                 mve_audio_enabled = 0;
938         else
939                 mve_audio_enabled = 1;
940 #endif
941 }
942
943 #endif