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