]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
update/cleanup MVE audio code
[taylor/freespace2.git] / src / movie / mveplayer.cpp
1 /*
2  * $Logfile: /Freespace2/code/movie/mveplayer.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * MVE movie playing routines
8  *
9  * $Log$
10  * Revision 1.7  2005/10/01 21:48:01  taylor
11  * various cleanups
12  * fix decoder to swap opcode 0xb since it screws up on PPC
13  * the previous opcode 0xc change was wrong since we had already determined that it messes up FS1 movies
14  *
15  * Revision 1.6  2005/08/12 08:47:24  taylor
16  * use new audiostr code rather than old windows/unix version
17  * update all OpenAL commands with new error checking macros
18  * fix play_position to properly account for real position, fixes the talking heads and message text cutting out early
19  * movies will now use better filtering when scaled
20  *
21  * Revision 1.5  2005/03/31 21:26:02  taylor
22  * s/alGetSourceiv/alGetSourcei/
23  *
24  * Revision 1.4  2005/03/31 00:06:20  taylor
25  * go back to more accurate timer and allow video scaling for movies
26  *
27  * Revision 1.3  2005/03/29 07:50:34  taylor
28  * Update to newest movie code with much better video support and audio support from
29  *   Pierre Willenbrock.  Movies are enabled always now (no longer a build option)
30  *   and but can be skipped with the "--nomovies" or "-n" cmdline options.
31  *
32  *
33  * $NoKeywords: $
34  */
35  
36 #include "pstypes.h"
37 #include "mvelib.h"
38 #include "movie.h"
39 #include "2d.h"
40 #include "key.h"
41 #include "osapi.h"
42 #include "timer.h"
43 #include "sound.h"
44 #include "bmpman.h"
45 #include "osregistry.h"
46 #include "ds.h"
47 #include "gropengl.h"
48 #include <vector>
49
50 static int mve_playing;
51
52
53 // timer variables
54 static int micro_frame_delay = 0;
55 static int timer_started = 0;
56 static int timer_created = 0;
57 static int timer_expire;
58 static Uint64 micro_timer_start = 0;
59 static Uint64 micro_timer_freq = 0;
60
61 // audio variables
62 #define MVE_AUDIO_BUFFERS 8  // total buffers to interact with stream
63
64 static std::vector<ALuint> mve_audio_bufl_free;
65 static ubyte *mve_audio_buf = NULL;
66 static size_t mve_audio_buf_size = 0;
67 static size_t mve_audio_buf_offset = 0;
68
69 static int mve_audio_playing = 0;
70 static int mve_audio_canplay = 0;
71 static int mve_audio_compressed = 0;
72 static int audiobuf_created;
73
74 // struct for the audio stream information
75 struct mve_audio_t {
76         ALenum format;
77         int sample_rate;
78         int bytes_per_sec;
79         int channels;
80         int bitsize;
81         ALuint source_id;
82         ALuint buffers[MVE_AUDIO_BUFFERS];
83 };
84
85 mve_audio_t *mas = NULL;  // mve_audio_stream
86
87
88
89 // video variables
90 int g_width, g_height;
91 void *g_vBuffers = NULL;
92 void *g_vBackBuf1, *g_vBackBuf2;
93 ushort *pixelbuf = NULL;
94 static int g_screenWidth, g_screenHeight;
95 static ubyte g_palette[768];
96 static ubyte *g_pCurMap=NULL;
97 static int g_nMapLength=0;
98 static int videobuf_created, video_inited;
99 static int hp2, wp2;
100 static uint mve_video_skiptimer = 0;
101 static int mve_scale_video = 0;
102 static GLuint tex = 0;
103
104 // the decoder
105 void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain);
106
107 /*************************
108  * general handlers
109  *************************/
110 void mve_end_movie()
111 {
112         mve_playing = 0;
113 }
114
115 /*************************
116  * timer handlers
117  *************************/
118
119 int mve_timer_create(ubyte *data)
120 {
121         micro_frame_delay = mve_get_int(data) * (int)mve_get_short(data+4);
122
123         micro_timer_start = SDL_GetPerformanceCounter();
124         micro_timer_freq = SDL_GetPerformanceFrequency();
125
126         if (micro_timer_freq < 1000) {
127                 micro_timer_freq = 1000;
128         }
129
130         timer_created = 1;
131
132         return 1;
133 }
134
135 static int mve_timer_get_microseconds()
136 {
137
138         Uint64 us = SDL_GetPerformanceCounter() - micro_timer_start;
139
140         if (micro_timer_freq >= 1000000) {
141                 us /= (micro_timer_freq / 1000000);
142         } else {
143                 us *= (1000000 / micro_timer_freq);
144         }
145
146         return (int)us;
147 }
148
149 static void mve_timer_start(void)
150 {
151         if (!timer_created)
152                 return;
153
154         timer_expire = mve_timer_get_microseconds();
155         timer_expire += micro_frame_delay;
156
157         timer_started = 1;
158 }
159
160 static int mve_do_timer_wait(void)
161 {
162         if (!timer_started)
163                 return 0;
164
165         int tv, ts;
166
167         tv = mve_timer_get_microseconds();
168
169         if (tv > timer_expire)
170                 goto end;
171
172         ts = timer_expire - tv;
173
174         Sleep(ts / 1000);
175
176         // try and burn off excess in attempt to keep sync
177         if (ts % 1000) {
178                 for (int i = 0; i < 10; i++) {
179                         Sleep(0);
180                 }
181         }
182 end:
183         timer_expire += micro_frame_delay;
184
185         return 0;
186 }
187
188 static void mve_timer_stop()
189 {
190         timer_expire = 0;
191         timer_started = 0;
192         timer_created = 0;
193
194         micro_timer_start = 0;
195         micro_timer_freq = 0;
196 }
197
198 /*************************
199  * audio handlers
200  *************************/
201
202 // setup the audio information from the data stream
203 void mve_audio_createbuf(ubyte minor, ubyte *data)
204 {
205         if (audiobuf_created)
206                 return;
207
208         // if game sound disabled don't try and play movie audio
209         if (!Sound_enabled) {
210                 mve_audio_canplay = 0;
211                 audiobuf_created = 1;
212                 return;
213         }
214
215         int flags, desired_buffer, sample_rate;
216
217         mas = (mve_audio_t *) malloc ( sizeof(mve_audio_t) );
218
219         if (mas == NULL) {
220                 mve_audio_canplay = 0;
221                 audiobuf_created = 1;
222                 return;
223         }
224
225         memset(mas, 0, sizeof(mve_audio_t));
226
227         mas->format = AL_INVALID;
228
229         flags = mve_get_ushort(data + 2);
230         sample_rate = mve_get_ushort(data + 4);
231         desired_buffer = mve_get_int(data + 6);
232
233         if (desired_buffer > 0) {
234                 mve_audio_buf = (ubyte*) malloc (desired_buffer);
235
236                 if (mve_audio_buf == NULL) {
237                         mve_audio_canplay = 0;
238                         audiobuf_created = 1;
239                         return;
240                 }
241
242                 mve_audio_buf_size = desired_buffer;
243                 mve_audio_buf_offset = 0;
244         } else {
245                 mve_audio_canplay = 0;
246                 audiobuf_created = 1;
247                 return;
248         }
249
250         mas->channels = (flags & 0x0001) ? 2 : 1;
251         mas->bitsize = (flags & 0x0002) ? 16 : 8;
252
253         mas->sample_rate = sample_rate;
254
255         if (minor > 0) {
256                 mve_audio_compressed = flags & 0x0004 ? 1 : 0;
257         } else {
258                 mve_audio_compressed = 0;
259         }
260
261         if (mas->bitsize == 16) {
262                 if (mas->channels == 2) {
263                         mas->format = AL_FORMAT_STEREO16;
264                 } else if (mas->channels == 1) {
265                         mas->format = AL_FORMAT_MONO16;
266                 }
267         } else if (mas->bitsize == 8) {
268                 if (mas->channels == 2) {
269                         mas->format = AL_FORMAT_STEREO8;
270                 } else if (mas->channels == 1) {
271                         mas->format = AL_FORMAT_MONO8;
272                 }
273         }
274
275         // somethings wrong, bail now
276         if (mas->format == AL_INVALID) {
277                 mve_audio_canplay = 0;
278                 audiobuf_created = 1;
279                 return;
280         }
281
282         alGenSources(1, &mas->source_id);
283
284         if (mas->source_id == 0) {
285                 mve_audio_canplay = 0;
286                 audiobuf_created = 1;
287                 return;
288         }
289
290         alSourcef(mas->source_id, AL_GAIN, 1.0f);
291         alSource3f(mas->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
292         alSource3f(mas->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
293         alSource3f(mas->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
294         alSourcef(mas->source_id, AL_ROLLOFF_FACTOR, 0.0f);
295         alSourcei(mas->source_id, AL_SOURCE_RELATIVE, AL_TRUE);
296
297         for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
298                 alGenBuffers(1, &mas->buffers[i]);
299         }
300
301         mve_audio_bufl_free.assign(mas->buffers, mas->buffers+MVE_AUDIO_BUFFERS);
302
303         audiobuf_created = 1;
304         mve_audio_canplay = 1;
305 }
306
307 // play and stream the audio
308 void mve_audio_play()
309 {
310         if (mve_audio_canplay) {
311                 ALint queued = 0;
312                 ALint status = AL_INVALID;
313
314                 alGetSourcei(mas->source_id, AL_BUFFERS_QUEUED, &queued);
315                 alGetSourcei(mas->source_id, AL_SOURCE_STATE, &status);
316
317                 if ( (status != AL_PLAYING) && (queued > 0) ) {
318                         alSourcePlay(mas->source_id);
319                         mve_audio_playing = 1;
320                 }
321         }
322 }
323
324 // call this in shutdown to stop and close audio
325 static void mve_audio_stop()
326 {
327         if (!audiobuf_created)
328                 return;
329
330         ALint processed = 0;
331         ALuint bid = 0;
332
333         mve_audio_playing = 0;
334         audiobuf_created = 0;
335
336         mve_audio_bufl_free.clear();
337
338         if (mas && mas->source_id) {
339                 alSourceStop(mas->source_id);
340
341                 alGetSourcei(mas->source_id, AL_BUFFERS_PROCESSED, &processed);
342
343                 while (processed > 0) {
344                         alSourceUnqueueBuffers(mas->source_id, 1, &bid);
345                         --processed;
346                 }
347
348                 alDeleteBuffers(MVE_AUDIO_BUFFERS, mas->buffers);
349                 alDeleteSources(1, &mas->source_id);
350         }
351
352         if (mas != NULL) {
353                 free(mas);
354                 mas = NULL;
355         }
356
357         if (mve_audio_buf != NULL) {
358                 free(mve_audio_buf);
359                 mve_audio_buf = NULL;
360         }
361
362         mve_audio_buf_size = 0;
363         mve_audio_buf_offset = 0;
364 }
365
366 int mve_audio_data(ubyte major, ubyte *data)
367 {
368         static const int selected_chan = 1;
369         int chan;
370         int nsamp;
371         ALint processed = 0;
372         ALuint bid;
373
374         if (mve_audio_canplay) {
375                 chan = mve_get_ushort(data + 2);
376                 nsamp = mve_get_ushort(data + 4);
377
378                 if (chan & selected_chan) {
379                         if ( (mve_audio_buf_offset+nsamp+4) <= mve_audio_buf_size ) {
380                                 if (major == 8) {
381                                         if (mve_audio_compressed) {
382                                                 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
383                                                 nsamp += 4;
384
385                                                 mveaudio_uncompress(mve_audio_buf+mve_audio_buf_offset, data, -1);
386                                         } else {
387                                                 nsamp -= 8;
388                                                 data += 8;
389
390                                                 memcpy(mve_audio_buf+mve_audio_buf_offset, data, nsamp);
391                                         }
392                                 } else {
393                                         // silence
394                                         memset(mve_audio_buf+mve_audio_buf_offset, 0, nsamp);
395                                 }
396
397                                 mve_audio_buf_offset += nsamp;
398                         } else {
399                                 mprintf(("MVE audio_buf overrun!!\n"));
400                         }
401
402                         alGetSourcei(mas->source_id, AL_BUFFERS_PROCESSED, &processed);
403
404                         while (processed) {
405                                 alSourceUnqueueBuffers(mas->source_id, 1, &bid);
406                                 mve_audio_bufl_free.push_back(bid);
407                                 --processed;
408                         }
409
410                         if ( !mve_audio_bufl_free.empty() ) {
411                                 bid = mve_audio_bufl_free.back();
412
413                                 alBufferData(bid, mas->format, mve_audio_buf, mve_audio_buf_offset, mas->sample_rate);
414                                 alSourceQueueBuffers(mas->source_id, 1, &bid);
415
416                                 mve_audio_buf_offset = 0;
417                                 mve_audio_bufl_free.pop_back();
418                         }
419
420                         if ( !mve_audio_playing ) {
421                                 mve_audio_play();
422                         }
423                 }
424         }
425
426         return 1;
427 }
428
429 /*************************
430  * video handlers
431  *************************/
432
433 int mve_video_createbuf(ubyte minor, ubyte *data)
434 {
435         if (videobuf_created)
436                 return 1;
437
438         short w, h;
439         short count, truecolor;
440         w = mve_get_short(data);
441         h = mve_get_short(data+2);
442         
443         if (minor > 0) {
444                 count = mve_get_short(data+4);
445         } else {
446                 count = 1;
447         }
448         
449         if (minor > 1) {
450                 truecolor = mve_get_short(data+6);
451         } else {
452                 truecolor = 0;
453         }
454
455         g_width = w << 3;
456         g_height = h << 3;
457
458         // with Pierre's decoder16 fix in opcode 0xc, 8 should no longer be needed
459         g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 4);
460
461         if (g_vBackBuf1 == NULL) {
462                 mprintf(("MOVIE", "ERROR: Can't allocate video buffer"));
463                 videobuf_created = 1;
464                 return 0;
465         }
466
467         g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height);
468                 
469         memset(g_vBackBuf1, 0, g_width * g_height * 4);
470
471         videobuf_created = 1;
472
473         return 1;
474 }
475
476 static void mve_convert_and_draw()
477 {
478         ushort *pDests;
479         ushort *pSrcs;
480         ushort *pixels = (ushort *)g_vBackBuf1;
481         int x, y;
482
483         pSrcs = pixels;
484
485         pDests = pixelbuf;
486
487         if (g_screenWidth > g_width) {
488                 pDests += ((g_screenWidth - g_width) / 2) / 2;
489         }
490         if (g_screenHeight > g_height) {
491                 pDests += ((g_screenHeight - g_height) / 2) * g_screenWidth;
492         }
493
494         for (y=0; y<g_height; y++) {
495                 for (x = 0; x < g_width; x++) {
496                         pDests[x] = (1<<15)|*pSrcs;
497
498                         pSrcs++;
499                 }
500                 pDests += g_screenWidth;
501         }
502 }
503
504 void mve_video_display()
505 {
506         fix t1 = timer_get_fixed_seconds();
507         mve_convert_and_draw();
508
509         int x, y;
510         int h = g_screenHeight;
511         int w = g_screenWidth;
512
513 #ifdef PLAT_UNIX
514         if (mve_scale_video) {
515                 x = y = 0;
516         } else {
517                 // centers on 1024x768, fills on 640x480
518                 x = ((gr_screen.max_w - g_screenWidth) / 2);
519                 y = ((gr_screen.max_h - g_screenHeight) / 2);
520         }
521
522         // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch
523         if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) {
524                 // we are running slow so subtract desired time from actual and skip this frame
525                 mve_video_skiptimer -= (micro_frame_delay/10);
526                 return;
527         } else {
528                 // zero out so we can get a new count
529                 mve_video_skiptimer = 0;
530         }
531
532         glBindTexture(GL_TEXTURE_2D, tex);
533         
534         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixelbuf);
535
536         // 0, 0
537         glBegin(GL_QUADS);
538                 glTexCoord2f(0,0);                                                                              glVertex2i(x,y);
539                 glTexCoord2f(0,i2fl(256)/i2fl(hp2));                                    glVertex2i(x,y+256);
540                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
541                 glTexCoord2f(i2fl(256)/i2fl(wp2),0);                                    glVertex2i(x+256,y);
542         glEnd();
543
544         // 0, 256
545         glBegin(GL_QUADS);
546                 glTexCoord2f(0,i2fl(256)/i2fl(hp2));                                    glVertex2i(x,y+256);
547                 glTexCoord2f(0,i2fl(h)/i2fl(hp2));                                              glVertex2i(x,y+h);
548                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+256,y+h);
549                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
550         glEnd();
551
552         // 256, 0
553         glBegin(GL_QUADS);
554                 glTexCoord2f(i2fl(256)/i2fl(wp2),0);                                    glVertex2i(x+256,y);
555                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
556                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
557                 glTexCoord2f(i2fl(512)/i2fl(wp2),0);                                    glVertex2i(x+512,y);
558         glEnd();
559
560         // 256, 256
561         glBegin(GL_QUADS);
562                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
563                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+256,y+h);
564                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+512,y+h);
565                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
566         glEnd();
567
568         // 512, 0
569         glBegin(GL_QUADS);
570                 glTexCoord2f(i2fl(512)/i2fl(wp2),0);                                    glVertex2i(x+512,y);
571                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
572                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2));    glVertex2i(x+w,y+256);
573                 glTexCoord2f(i2fl(w)/i2fl(wp2),0);                                              glVertex2i(x+w,y);
574         glEnd();
575
576         // 512, 256
577         glBegin(GL_QUADS);
578                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
579                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+512,y+h);
580                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(h)/i2fl(hp2));              glVertex2i(x+w,y+h);
581                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2));    glVertex2i(x+w,y+256);
582         glEnd();
583 #else
584         // centers on 1024x768, fills on 640x480
585         x = ((gr_screen.max_w - g_screenWidth) / 2);
586         y = ((gr_screen.max_h - g_screenHeight) / 2);
587
588         // DDOI - This is probably really fricking slow
589         int bitmap = bm_create (16, w, h, pixelbuf, 0);
590         gr_set_bitmap (bitmap);
591         gr_bitmap (x, y);
592         bm_release (bitmap);
593 #endif
594
595         gr_flip ();
596 #ifdef PLAT_UNIX
597         os_poll ();     /* DDOI - run event loop(s) */
598 #endif
599
600         fix t2 = timer_get_fixed_seconds();
601
602         // only get a new count if we are definitely through with old count
603         if ( mve_video_skiptimer == 0 ) {
604                 // for a more accurate count convert the frame rate to a float and multiply
605                 // by one-hundred-thousand before converting to an uint.
606                 mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000);
607         }
608
609         int k = key_inkey();
610         if ( k == SDLK_ESCAPE ) {
611                 mve_playing = 0;
612         }
613
614 //      fprintf(stderr, "mve frame took this long: %.6f\n", f2fl(t2-t1));
615 }
616
617 int mve_video_init(ubyte *data)
618 {
619         if (video_inited)
620                 return 1;
621
622         short width, height;
623
624         width = mve_get_short(data);
625         height = mve_get_short(data+2);
626
627         // DDOI - Allocate RGB565 pixel buffer
628         pixelbuf = (ushort *)malloc (width * height * 2);
629
630         if (pixelbuf == NULL) {
631                 mprintf(("MOVIE", "ERROR: Can't allocate memory for pixelbuf"));
632                 video_inited = 1;
633                 return 0;
634         }
635
636         memset(pixelbuf, 0, width * height * 2);
637
638         g_screenWidth = width;
639         g_screenHeight = height;
640
641 #ifdef PLAT_UNIX
642         int i, tex_w, tex_h;
643
644         tex_w = g_screenWidth;
645         tex_h = g_screenHeight;
646
647         // set height and width to a power of 2
648         for (i=0; i<16; i++ )   {
649                 if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) )        {
650                         tex_w = 1 << (i+1);
651                         break;
652                 }
653         }
654
655         for (i=0; i<16; i++ )   {
656                 if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) )        {
657                         tex_h = 1 << (i+1);
658                         break;
659                 }
660         }
661
662         // try to keep an 8:1 size ratio
663         if (tex_w/tex_h > 8)
664                 tex_h = tex_w/8;
665         if (tex_h/tex_w > 8)
666                 tex_w = tex_h/8;
667
668         wp2 = tex_w;
669         hp2 = tex_h;
670
671         glGenTextures(1, &tex);
672
673         Assert(tex != 0);
674
675         if ( tex == 0 ) {
676                 mprintf(("MOVIE", "ERROR: Can't create a GL texture"));
677                 video_inited = 1;
678                 return 0;
679         }
680
681         glBindTexture(GL_TEXTURE_2D, tex);
682         
683         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
684         glDepthFunc(GL_ALWAYS);
685         glDepthMask(GL_FALSE);
686         glDisable(GL_DEPTH_TEST);
687         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
688         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
689
690         if ( os_config_read_uint(NULL, NOX("ScaleMovies"), 0) == 1 ) {
691                 float scale_by = (float)gr_screen.max_w / (float)g_screenWidth;
692
693                 // don't bother setting anything if we aren't going to need it
694                 if (scale_by != 1.0f) {
695                         glMatrixMode(GL_MODELVIEW);
696                         glPushMatrix();
697                         glLoadIdentity();
698
699                         glScalef( scale_by, scale_by, 1.0f );
700                         mve_scale_video = 1;
701                 }
702         }
703
704         // NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf so less of two evils...
705         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, wp2, hp2, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
706 #endif
707
708         memset(g_palette, 0, 768);
709         
710         video_inited = 1;
711         
712         return 1;
713 }
714
715 void mve_video_palette(ubyte *data)
716 {
717         short start, count;
718         start = mve_get_short(data);
719         count = mve_get_short(data+2);
720         memcpy(g_palette + 3*start, data+4, 3*count);
721 }
722
723 void mve_video_codemap(ubyte *data, int len)
724 {
725         g_pCurMap = data;
726         g_nMapLength = len;
727 }
728
729 void mve_video_data(ubyte *data, int len)
730 {
731         short nFrameHot, nFrameCold;
732         short nXoffset, nYoffset;
733         short nXsize, nYsize;
734         ushort nFlags;
735         ubyte *temp;
736
737         nFrameHot = mve_get_short(data);
738         nFrameCold = mve_get_short(data+2);
739         nXoffset = mve_get_short(data+4);
740         nYoffset = mve_get_short(data+6);
741         nXsize = mve_get_short(data+8);
742         nYsize = mve_get_short(data+10);
743         nFlags = mve_get_ushort(data+12);
744
745         if (nFlags & 1) {
746                 temp = (ubyte *)g_vBackBuf1;
747                 g_vBackBuf1 = g_vBackBuf2;
748                 g_vBackBuf2 = temp;
749         }
750
751         decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
752 }
753
754 void mve_end_chunk()
755 {
756         g_pCurMap = NULL;
757 }
758
759 void mve_init(MVESTREAM *mve)
760 {
761         // reset to default values
762         mve_audio_playing = 0;
763         mve_audio_canplay = 0;
764         mve_audio_compressed = 0;
765         mve_audio_buf_offset = 0;
766         audiobuf_created = 0;
767
768         videobuf_created = 0;
769         video_inited = 0;
770         mve_scale_video = 0;
771
772         mve_playing = 1;
773 }
774
775 void mve_play(MVESTREAM *mve)
776 {
777         int init_timer = 0, timer_error = 0;
778         int cont = 1;
779
780         if (!timer_started)
781                 mve_timer_start();
782
783         while (cont && mve_playing && !timer_error) {
784                 cont = mve_play_next_chunk(mve);
785
786                 if (micro_frame_delay && !init_timer) {
787                         mve_timer_start();
788                         init_timer = 1;
789                 }
790
791                 timer_error = mve_do_timer_wait();
792         }
793 }
794
795 void mve_shutdown()
796 {
797         mve_audio_stop();
798
799         mve_timer_stop();
800
801         if (pixelbuf != NULL) {
802                 free(pixelbuf);
803                 pixelbuf = NULL;
804         }
805
806         if (g_vBuffers != NULL) {
807                 free(g_vBuffers);
808                 g_vBuffers = NULL;
809         }
810
811 #ifdef PLAT_UNIX
812         if (mve_scale_video) {
813                 glMatrixMode(GL_MODELVIEW);
814                 glPopMatrix();
815                 glLoadIdentity();
816         }
817
818         glDeleteTextures(1, &tex);
819         tex = 0;
820
821         glEnable(GL_DEPTH_TEST);
822 #endif
823 }