]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
first pass at updated sound 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 "oal.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         sound_channel *chan;
77         ALenum format;
78         int sample_rate;
79         int bytes_per_sec;
80         int channels;
81         int bitsize;
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         mas->chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
283
284         if (mas->chan == NULL) {
285                 mve_audio_canplay = 0;
286                 audiobuf_created = 1;
287                 return;
288         }
289
290         alSourcef(mas->chan->source_id, AL_GAIN, 1.0f);
291         alSource3f(mas->chan->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
292         alSource3f(mas->chan->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
293         alSource3f(mas->chan->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
294         alSourcef(mas->chan->source_id, AL_ROLLOFF_FACTOR, 0.0f);
295         alSourcei(mas->chan->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->chan->source_id, AL_BUFFERS_QUEUED, &queued);
315                 alGetSourcei(mas->chan->source_id, AL_SOURCE_STATE, &status);
316
317                 if ( (status != AL_PLAYING) && (queued > 0) ) {
318                         alSourcePlay(mas->chan->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->chan->source_id) {
339                 alSourceStop(mas->chan->source_id);
340
341                 alGetSourcei(mas->chan->source_id, AL_BUFFERS_PROCESSED, &processed);
342
343                 while (processed > 0) {
344                         alSourceUnqueueBuffers(mas->chan->source_id, 1, &bid);
345                         --processed;
346                 }
347
348                 alDeleteBuffers(MVE_AUDIO_BUFFERS, mas->buffers);
349         }
350
351         if (mas != NULL) {
352                 free(mas);
353                 mas = NULL;
354         }
355
356         if (mve_audio_buf != NULL) {
357                 free(mve_audio_buf);
358                 mve_audio_buf = NULL;
359         }
360
361         mve_audio_buf_size = 0;
362         mve_audio_buf_offset = 0;
363 }
364
365 int mve_audio_data(ubyte major, ubyte *data)
366 {
367         static const int selected_chan = 1;
368         int chan;
369         int nsamp;
370         ALint processed = 0;
371         ALuint bid;
372
373         if (mve_audio_canplay) {
374                 chan = mve_get_ushort(data + 2);
375                 nsamp = mve_get_ushort(data + 4);
376
377                 if (chan & selected_chan) {
378                         if ( (mve_audio_buf_offset+nsamp+4) <= mve_audio_buf_size ) {
379                                 if (major == 8) {
380                                         if (mve_audio_compressed) {
381                                                 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
382                                                 nsamp += 4;
383
384                                                 mveaudio_uncompress(mve_audio_buf+mve_audio_buf_offset, data, -1);
385                                         } else {
386                                                 nsamp -= 8;
387                                                 data += 8;
388
389                                                 memcpy(mve_audio_buf+mve_audio_buf_offset, data, nsamp);
390                                         }
391                                 } else {
392                                         // silence
393                                         memset(mve_audio_buf+mve_audio_buf_offset, 0, nsamp);
394                                 }
395
396                                 mve_audio_buf_offset += nsamp;
397                         } else {
398                                 mprintf(("MVE audio_buf overrun!!\n"));
399                         }
400
401                         alGetSourcei(mas->chan->source_id, AL_BUFFERS_PROCESSED, &processed);
402
403                         while (processed) {
404                                 alSourceUnqueueBuffers(mas->chan->source_id, 1, &bid);
405                                 mve_audio_bufl_free.push_back(bid);
406                                 --processed;
407                         }
408
409                         if ( !mve_audio_bufl_free.empty() ) {
410                                 bid = mve_audio_bufl_free.back();
411
412                                 alBufferData(bid, mas->format, mve_audio_buf, mve_audio_buf_offset, mas->sample_rate);
413                                 alSourceQueueBuffers(mas->chan->source_id, 1, &bid);
414
415                                 mve_audio_buf_offset = 0;
416                                 mve_audio_bufl_free.pop_back();
417                         }
418
419                         if ( !mve_audio_playing ) {
420                                 mve_audio_play();
421                         }
422                 }
423         }
424
425         return 1;
426 }
427
428 /*************************
429  * video handlers
430  *************************/
431
432 int mve_video_createbuf(ubyte minor, ubyte *data)
433 {
434         if (videobuf_created)
435                 return 1;
436
437         short w, h;
438         short count, truecolor;
439         w = mve_get_short(data);
440         h = mve_get_short(data+2);
441         
442         if (minor > 0) {
443                 count = mve_get_short(data+4);
444         } else {
445                 count = 1;
446         }
447         
448         if (minor > 1) {
449                 truecolor = mve_get_short(data+6);
450         } else {
451                 truecolor = 0;
452         }
453
454         g_width = w << 3;
455         g_height = h << 3;
456
457         // with Pierre's decoder16 fix in opcode 0xc, 8 should no longer be needed
458         g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 4);
459
460         if (g_vBackBuf1 == NULL) {
461                 mprintf(("MOVIE", "ERROR: Can't allocate video buffer"));
462                 videobuf_created = 1;
463                 return 0;
464         }
465
466         g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height);
467                 
468         memset(g_vBackBuf1, 0, g_width * g_height * 4);
469
470         videobuf_created = 1;
471
472         return 1;
473 }
474
475 static void mve_convert_and_draw()
476 {
477         ushort *pDests;
478         ushort *pSrcs;
479         ushort *pixels = (ushort *)g_vBackBuf1;
480         int x, y;
481
482         pSrcs = pixels;
483
484         pDests = pixelbuf;
485
486         if (g_screenWidth > g_width) {
487                 pDests += ((g_screenWidth - g_width) / 2) / 2;
488         }
489         if (g_screenHeight > g_height) {
490                 pDests += ((g_screenHeight - g_height) / 2) * g_screenWidth;
491         }
492
493         for (y=0; y<g_height; y++) {
494                 for (x = 0; x < g_width; x++) {
495                         pDests[x] = (1<<15)|*pSrcs;
496
497                         pSrcs++;
498                 }
499                 pDests += g_screenWidth;
500         }
501 }
502
503 void mve_video_display()
504 {
505         fix t1 = timer_get_fixed_seconds();
506         mve_convert_and_draw();
507
508         int x, y;
509         int h = g_screenHeight;
510         int w = g_screenWidth;
511
512 #ifdef PLAT_UNIX
513         if (mve_scale_video) {
514                 x = y = 0;
515         } else {
516                 // centers on 1024x768, fills on 640x480
517                 x = ((gr_screen.max_w - g_screenWidth) / 2);
518                 y = ((gr_screen.max_h - g_screenHeight) / 2);
519         }
520
521         // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch
522         if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) {
523                 // we are running slow so subtract desired time from actual and skip this frame
524                 mve_video_skiptimer -= (micro_frame_delay/10);
525                 return;
526         } else {
527                 // zero out so we can get a new count
528                 mve_video_skiptimer = 0;
529         }
530
531         glBindTexture(GL_TEXTURE_2D, tex);
532         
533         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixelbuf);
534
535         // 0, 0
536         glBegin(GL_QUADS);
537                 glTexCoord2f(0,0);                                                                              glVertex2i(x,y);
538                 glTexCoord2f(0,i2fl(256)/i2fl(hp2));                                    glVertex2i(x,y+256);
539                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
540                 glTexCoord2f(i2fl(256)/i2fl(wp2),0);                                    glVertex2i(x+256,y);
541         glEnd();
542
543         // 0, 256
544         glBegin(GL_QUADS);
545                 glTexCoord2f(0,i2fl(256)/i2fl(hp2));                                    glVertex2i(x,y+256);
546                 glTexCoord2f(0,i2fl(h)/i2fl(hp2));                                              glVertex2i(x,y+h);
547                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+256,y+h);
548                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
549         glEnd();
550
551         // 256, 0
552         glBegin(GL_QUADS);
553                 glTexCoord2f(i2fl(256)/i2fl(wp2),0);                                    glVertex2i(x+256,y);
554                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
555                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
556                 glTexCoord2f(i2fl(512)/i2fl(wp2),0);                                    glVertex2i(x+512,y);
557         glEnd();
558
559         // 256, 256
560         glBegin(GL_QUADS);
561                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+256,y+256);
562                 glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+256,y+h);
563                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+512,y+h);
564                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
565         glEnd();
566
567         // 512, 0
568         glBegin(GL_QUADS);
569                 glTexCoord2f(i2fl(512)/i2fl(wp2),0);                                    glVertex2i(x+512,y);
570                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
571                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2));    glVertex2i(x+w,y+256);
572                 glTexCoord2f(i2fl(w)/i2fl(wp2),0);                                              glVertex2i(x+w,y);
573         glEnd();
574
575         // 512, 256
576         glBegin(GL_QUADS);
577                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2));  glVertex2i(x+512,y+256);
578                 glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2));    glVertex2i(x+512,y+h);
579                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(h)/i2fl(hp2));              glVertex2i(x+w,y+h);
580                 glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2));    glVertex2i(x+w,y+256);
581         glEnd();
582 #else
583         // centers on 1024x768, fills on 640x480
584         x = ((gr_screen.max_w - g_screenWidth) / 2);
585         y = ((gr_screen.max_h - g_screenHeight) / 2);
586
587         // DDOI - This is probably really fricking slow
588         int bitmap = bm_create (16, w, h, pixelbuf, 0);
589         gr_set_bitmap (bitmap);
590         gr_bitmap (x, y);
591         bm_release (bitmap);
592 #endif
593
594         gr_flip ();
595 #ifdef PLAT_UNIX
596         os_poll ();     /* DDOI - run event loop(s) */
597 #endif
598
599         fix t2 = timer_get_fixed_seconds();
600
601         // only get a new count if we are definitely through with old count
602         if ( mve_video_skiptimer == 0 ) {
603                 // for a more accurate count convert the frame rate to a float and multiply
604                 // by one-hundred-thousand before converting to an uint.
605                 mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000);
606         }
607
608         int k = key_inkey();
609         if ( k == SDLK_ESCAPE ) {
610                 mve_playing = 0;
611         }
612
613 //      fprintf(stderr, "mve frame took this long: %.6f\n", f2fl(t2-t1));
614 }
615
616 int mve_video_init(ubyte *data)
617 {
618         if (video_inited)
619                 return 1;
620
621         short width, height;
622
623         width = mve_get_short(data);
624         height = mve_get_short(data+2);
625
626         // DDOI - Allocate RGB565 pixel buffer
627         pixelbuf = (ushort *)malloc (width * height * 2);
628
629         if (pixelbuf == NULL) {
630                 mprintf(("MOVIE", "ERROR: Can't allocate memory for pixelbuf"));
631                 video_inited = 1;
632                 return 0;
633         }
634
635         memset(pixelbuf, 0, width * height * 2);
636
637         g_screenWidth = width;
638         g_screenHeight = height;
639
640 #ifdef PLAT_UNIX
641         int i, tex_w, tex_h;
642
643         tex_w = g_screenWidth;
644         tex_h = g_screenHeight;
645
646         // set height and width to a power of 2
647         for (i=0; i<16; i++ )   {
648                 if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) )        {
649                         tex_w = 1 << (i+1);
650                         break;
651                 }
652         }
653
654         for (i=0; i<16; i++ )   {
655                 if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) )        {
656                         tex_h = 1 << (i+1);
657                         break;
658                 }
659         }
660
661         // try to keep an 8:1 size ratio
662         if (tex_w/tex_h > 8)
663                 tex_h = tex_w/8;
664         if (tex_h/tex_w > 8)
665                 tex_w = tex_h/8;
666
667         wp2 = tex_w;
668         hp2 = tex_h;
669
670         glGenTextures(1, &tex);
671
672         Assert(tex != 0);
673
674         if ( tex == 0 ) {
675                 mprintf(("MOVIE", "ERROR: Can't create a GL texture"));
676                 video_inited = 1;
677                 return 0;
678         }
679
680         glBindTexture(GL_TEXTURE_2D, tex);
681         
682         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
683         glDepthFunc(GL_ALWAYS);
684         glDepthMask(GL_FALSE);
685         glDisable(GL_DEPTH_TEST);
686         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
687         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
688
689         if ( os_config_read_uint(NULL, NOX("ScaleMovies"), 0) == 1 ) {
690                 float scale_by = (float)gr_screen.max_w / (float)g_screenWidth;
691
692                 // don't bother setting anything if we aren't going to need it
693                 if (scale_by != 1.0f) {
694                         glMatrixMode(GL_MODELVIEW);
695                         glPushMatrix();
696                         glLoadIdentity();
697
698                         glScalef( scale_by, scale_by, 1.0f );
699                         mve_scale_video = 1;
700                 }
701         }
702
703         // NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf so less of two evils...
704         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, wp2, hp2, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
705 #endif
706
707         memset(g_palette, 0, 768);
708         
709         video_inited = 1;
710         
711         return 1;
712 }
713
714 void mve_video_palette(ubyte *data)
715 {
716         short start, count;
717         start = mve_get_short(data);
718         count = mve_get_short(data+2);
719         memcpy(g_palette + 3*start, data+4, 3*count);
720 }
721
722 void mve_video_codemap(ubyte *data, int len)
723 {
724         g_pCurMap = data;
725         g_nMapLength = len;
726 }
727
728 void mve_video_data(ubyte *data, int len)
729 {
730         short nFrameHot, nFrameCold;
731         short nXoffset, nYoffset;
732         short nXsize, nYsize;
733         ushort nFlags;
734         ubyte *temp;
735
736         nFrameHot = mve_get_short(data);
737         nFrameCold = mve_get_short(data+2);
738         nXoffset = mve_get_short(data+4);
739         nYoffset = mve_get_short(data+6);
740         nXsize = mve_get_short(data+8);
741         nYsize = mve_get_short(data+10);
742         nFlags = mve_get_ushort(data+12);
743
744         if (nFlags & 1) {
745                 temp = (ubyte *)g_vBackBuf1;
746                 g_vBackBuf1 = g_vBackBuf2;
747                 g_vBackBuf2 = temp;
748         }
749
750         decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
751 }
752
753 void mve_end_chunk()
754 {
755         g_pCurMap = NULL;
756 }
757
758 void mve_init(MVESTREAM *mve)
759 {
760         // reset to default values
761         mve_audio_playing = 0;
762         mve_audio_canplay = 0;
763         mve_audio_compressed = 0;
764         mve_audio_buf_offset = 0;
765         audiobuf_created = 0;
766
767         videobuf_created = 0;
768         video_inited = 0;
769         mve_scale_video = 0;
770
771         mve_playing = 1;
772 }
773
774 void mve_play(MVESTREAM *mve)
775 {
776         int init_timer = 0, timer_error = 0;
777         int cont = 1;
778
779         if (!timer_started)
780                 mve_timer_start();
781
782         while (cont && mve_playing && !timer_error) {
783                 cont = mve_play_next_chunk(mve);
784
785                 if (micro_frame_delay && !init_timer) {
786                         mve_timer_start();
787                         init_timer = 1;
788                 }
789
790                 timer_error = mve_do_timer_wait();
791         }
792 }
793
794 void mve_shutdown()
795 {
796         mve_audio_stop();
797
798         mve_timer_stop();
799
800         if (pixelbuf != NULL) {
801                 free(pixelbuf);
802                 pixelbuf = NULL;
803         }
804
805         if (g_vBuffers != NULL) {
806                 free(g_vBuffers);
807                 g_vBuffers = NULL;
808         }
809
810 #ifdef PLAT_UNIX
811         if (mve_scale_video) {
812                 glMatrixMode(GL_MODELVIEW);
813                 glPopMatrix();
814                 glLoadIdentity();
815         }
816
817         glDeleteTextures(1, &tex);
818         tex = 0;
819
820         glEnable(GL_DEPTH_TEST);
821 #endif
822 }