]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
more MVE graphics code cleanup and simplification
[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 = 0;
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 ubyte *g_pCurMap=NULL;
95 static int g_nMapLength=0;
96 static int videobuf_created;
97 static int mve_scale_video = 0;
98 static GLuint tex = 0;
99
100 struct g_coords_t {
101         int x, y;
102         float u, v;
103 };
104
105 static g_coords_t g_coords[4];
106
107
108 // the decoder
109 void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain);
110
111 /*************************
112  * general handlers
113  *************************/
114 void mve_end_movie()
115 {
116         mve_playing = 0;
117 }
118
119 /*************************
120  * timer handlers
121  *************************/
122
123 int mve_timer_create(ubyte *data)
124 {
125         micro_frame_delay = mve_get_int(data) * (int)mve_get_short(data+4);
126
127         micro_timer_start = SDL_GetPerformanceCounter();
128         micro_timer_freq = SDL_GetPerformanceFrequency();
129
130         if (micro_timer_freq < 1000) {
131                 micro_timer_freq = 1000;
132         }
133
134         timer_created = 1;
135
136         return 1;
137 }
138
139 static int mve_timer_get_microseconds()
140 {
141
142         Uint64 us = SDL_GetPerformanceCounter() - micro_timer_start;
143
144         if (micro_timer_freq >= 1000000) {
145                 us /= (micro_timer_freq / 1000000);
146         } else {
147                 us *= (1000000 / micro_timer_freq);
148         }
149
150         return (int)us;
151 }
152
153 static void mve_timer_start(void)
154 {
155         if (!timer_created)
156                 return;
157
158         timer_expire = mve_timer_get_microseconds();
159         timer_expire += micro_frame_delay;
160
161         timer_started = 1;
162 }
163
164 static int mve_do_timer_wait(void)
165 {
166         if (!timer_started)
167                 return 0;
168
169         int tv, ts;
170
171         tv = mve_timer_get_microseconds();
172
173         if (tv > timer_expire)
174                 goto end;
175
176         ts = timer_expire - tv;
177
178         SDL_Delay(ts / 1000);
179
180         // try and burn off excess in attempt to keep sync
181         if (ts % 1000) {
182                 for (int i = 0; i < 10; i++) {
183                         SDL_Delay(0);
184                 }
185         }
186 end:
187         timer_expire += micro_frame_delay;
188
189         return 0;
190 }
191
192 static void mve_timer_stop()
193 {
194         timer_expire = 0;
195         timer_started = 0;
196         timer_created = 0;
197
198         micro_frame_delay = 0;
199
200         micro_timer_start = 0;
201         micro_timer_freq = 0;
202 }
203
204 /*************************
205  * audio handlers
206  *************************/
207
208 // setup the audio information from the data stream
209 void mve_audio_createbuf(ubyte minor, ubyte *data)
210 {
211         if (audiobuf_created)
212                 return;
213
214         // if game sound disabled don't try and play movie audio
215         if ( !Sound_enabled ) {
216                 mve_audio_canplay = 0;
217                 audiobuf_created = 1;
218                 return;
219         }
220
221         int flags, desired_buffer, sample_rate;
222
223         mas = (mve_audio_t *) malloc ( sizeof(mve_audio_t) );
224
225         if (mas == NULL) {
226                 mve_audio_canplay = 0;
227                 audiobuf_created = 1;
228                 return;
229         }
230
231         memset(mas, 0, sizeof(mve_audio_t));
232
233         mas->format = AL_INVALID;
234
235         flags = mve_get_ushort(data + 2);
236         sample_rate = mve_get_ushort(data + 4);
237         desired_buffer = mve_get_int(data + 6);
238
239         if (desired_buffer > 0) {
240                 mve_audio_buf = (ubyte*) malloc (desired_buffer);
241
242                 if (mve_audio_buf == NULL) {
243                         mve_audio_canplay = 0;
244                         audiobuf_created = 1;
245                         return;
246                 }
247
248                 mve_audio_buf_size = desired_buffer;
249                 mve_audio_buf_offset = 0;
250         } else {
251                 mve_audio_canplay = 0;
252                 audiobuf_created = 1;
253                 return;
254         }
255
256         mas->channels = (flags & 0x0001) ? 2 : 1;
257         mas->bitsize = (flags & 0x0002) ? 16 : 8;
258
259         mas->sample_rate = sample_rate;
260
261         if (minor > 0) {
262                 mve_audio_compressed = flags & 0x0004 ? 1 : 0;
263         } else {
264                 mve_audio_compressed = 0;
265         }
266
267         if (mas->bitsize == 16) {
268                 if (mas->channels == 2) {
269                         mas->format = AL_FORMAT_STEREO16;
270                 } else if (mas->channels == 1) {
271                         mas->format = AL_FORMAT_MONO16;
272                 }
273         } else if (mas->bitsize == 8) {
274                 if (mas->channels == 2) {
275                         mas->format = AL_FORMAT_STEREO8;
276                 } else if (mas->channels == 1) {
277                         mas->format = AL_FORMAT_MONO8;
278                 }
279         }
280
281         // somethings wrong, bail now
282         if (mas->format == AL_INVALID) {
283                 mve_audio_canplay = 0;
284                 audiobuf_created = 1;
285                 return;
286         }
287
288         oal_check_for_errors("mve_audio_createbuf() begin");
289
290         for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
291                 alGenBuffers(1, &mas->buffers[i]);
292
293                 if ( !mas->buffers[i] ) {
294                         mve_audio_canplay = 0;
295                         audiobuf_created = 1;
296                         return;
297                 }
298         }
299
300         mve_audio_bufl_free.assign(mas->buffers, mas->buffers+MVE_AUDIO_BUFFERS);
301
302         mas->chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
303
304         if (mas->chan == NULL) {
305                 mve_audio_canplay = 0;
306                 audiobuf_created = 1;
307                 return;
308         }
309
310         alSourcef(mas->chan->source_id, AL_GAIN, 1.0f);
311         alSource3f(mas->chan->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
312         alSource3f(mas->chan->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
313         alSource3f(mas->chan->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
314         alSourcef(mas->chan->source_id, AL_ROLLOFF_FACTOR, 0.0f);
315         alSourcei(mas->chan->source_id, AL_SOURCE_RELATIVE, AL_TRUE);
316
317         oal_check_for_errors("mve_audio_createbuf() end");
318
319         audiobuf_created = 1;
320         mve_audio_canplay = 1;
321 }
322
323 // play and stream the audio
324 void mve_audio_play()
325 {
326         if (mve_audio_canplay) {
327                 ALint queued = 0;
328                 ALint status = AL_INVALID;
329
330                 oal_check_for_errors("mve_audio_play() begin");
331
332                 alGetSourcei(mas->chan->source_id, AL_BUFFERS_QUEUED, &queued);
333                 alGetSourcei(mas->chan->source_id, AL_SOURCE_STATE, &status);
334
335                 if ( (status != AL_PLAYING) && (queued > 0) ) {
336                         alSourcePlay(mas->chan->source_id);
337                         mve_audio_playing = 1;
338                 }
339
340                 oal_check_for_errors("mve_audio_play() end");
341         }
342 }
343
344 // call this in shutdown to stop and close audio
345 static void mve_audio_stop()
346 {
347         if (!audiobuf_created)
348                 return;
349
350         oal_check_for_errors("mve_audio_stop() begin");
351
352         mve_audio_playing = 0;
353         mve_audio_canplay = 0;
354         mve_audio_compressed = 0;
355
356         audiobuf_created = 0;
357
358         mve_audio_bufl_free.clear();
359
360         if (mas) {
361                 if (mas->chan) {
362                         alSourceStop(mas->chan->source_id);
363
364                         // detach buffers from source so that we can delete them
365                         alSourcei(mas->chan->source_id, AL_BUFFER, 0);
366                 }
367
368                 for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
369                         if ( alIsBuffer(mas->buffers[i]) ) {
370                                 alDeleteBuffers(1, &mas->buffers[i]);
371                         }
372                 }
373         }
374
375         if (mas != NULL) {
376                 free(mas);
377                 mas = NULL;
378         }
379
380         if (mve_audio_buf != NULL) {
381                 free(mve_audio_buf);
382                 mve_audio_buf = NULL;
383         }
384
385         mve_audio_buf_size = 0;
386         mve_audio_buf_offset = 0;
387
388         oal_check_for_errors("mve_audio_stop() end");
389 }
390
391 int mve_audio_data(ubyte major, ubyte *data)
392 {
393         static const int selected_chan = 1;
394         int chan;
395         int nsamp;
396         ALint processed = 0;
397         ALuint bid;
398
399         if (mve_audio_canplay) {
400                 chan = mve_get_ushort(data + 2);
401                 nsamp = mve_get_ushort(data + 4);
402
403                 if (chan & selected_chan) {
404                         oal_check_for_errors("mve_audio_data() begin");
405
406                         if ( (mve_audio_buf_offset+nsamp+4) <= mve_audio_buf_size ) {
407                                 if (major == 8) {
408                                         if (mve_audio_compressed) {
409                                                 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
410                                                 nsamp += 4;
411
412                                                 mveaudio_uncompress(mve_audio_buf+mve_audio_buf_offset, data, -1);
413                                         } else {
414                                                 nsamp -= 8;
415                                                 data += 8;
416
417                                                 memcpy(mve_audio_buf+mve_audio_buf_offset, data, nsamp);
418                                         }
419                                 } else {
420                                         // silence
421                                         memset(mve_audio_buf+mve_audio_buf_offset, 0, nsamp);
422                                 }
423
424                                 mve_audio_buf_offset += nsamp;
425                         } else {
426                                 mprintf(("MVE audio_buf overrun!!\n"));
427                         }
428
429                         alGetSourcei(mas->chan->source_id, AL_BUFFERS_PROCESSED, &processed);
430
431                         while (processed) {
432                                 alSourceUnqueueBuffers(mas->chan->source_id, 1, &bid);
433
434                                 mve_audio_bufl_free.push_back(bid);
435                                 --processed;
436                         }
437
438                         if ( !mve_audio_bufl_free.empty() ) {
439                                 bid = mve_audio_bufl_free.back();
440
441                                 alBufferData(bid, mas->format, mve_audio_buf, mve_audio_buf_offset, mas->sample_rate);
442                                 alSourceQueueBuffers(mas->chan->source_id, 1, &bid);
443
444                                 mve_audio_buf_offset = 0;
445                                 mve_audio_bufl_free.pop_back();
446                         }
447
448                         if ( !mve_audio_playing ) {
449                                 mve_audio_play();
450                         }
451
452                         oal_check_for_errors("mve_audio_data() end");
453                 }
454         }
455
456         return 1;
457 }
458
459 /*************************
460  * video handlers
461  *************************/
462
463 int mve_video_createbuf(ubyte minor, ubyte *data)
464 {
465         if (videobuf_created)
466                 return 1;
467
468         if (gr_screen.mode != GR_OPENGL) {
469                 mprintf(("MVE-ERROR: Movie playback requires OpenGL renderer\n"));
470                 videobuf_created = 1;
471                 return 0;
472         }
473
474         if (gr_screen.use_sections) {
475                 mprintf(("MVE-ERROR: Bitmap sections not supported\n"));
476                 videobuf_created = 1;
477                 return 0;
478         }
479
480         int tex_w, tex_h;
481         short w, h;
482
483         w = mve_get_short(data);
484         h = mve_get_short(data+2);
485
486         g_width = w << 3;
487         g_height = h << 3;
488
489         // with Pierre's decoder16 fix in opcode 0xc, 8 should no longer be needed
490         g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 4);
491
492         if (g_vBackBuf1 == NULL) {
493                 mprintf(("MVE-ERROR: Can't allocate video buffer\n"));
494                 videobuf_created = 1;
495                 return 0;
496         }
497
498         g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height);
499
500         memset(g_vBackBuf1, 0, g_width * g_height * 4);
501
502         // DDOI - Allocate RGB565 pixel buffer
503         pixelbuf = (ushort *)malloc (g_width * g_height * 2);
504
505         if (pixelbuf == NULL) {
506                 mprintf(("MVE-ERROR: Can't allocate memory for pixelbuf\n"));
507                 videobuf_created = 1;
508                 return 0;
509         }
510
511         memset(pixelbuf, 0, g_width * g_height * 2);
512
513         // set height and width to a power of 2
514         tex_w = next_pow2(g_width);
515         tex_h = next_pow2(g_height);
516
517         SDL_assert(tex_w > 0);
518         SDL_assert(tex_h > 0);
519
520         glGenTextures(1, &tex);
521
522         if (tex == 0) {
523                 mprintf(("MVE-ERROR: Can't create a GL texture\n"));
524                 videobuf_created = 1;
525                 return 0;
526         }
527
528         glBindTexture(GL_TEXTURE_2D, tex);
529
530         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
531         glDepthFunc(GL_ALWAYS);
532         glDepthMask(GL_FALSE);
533         glDisable(GL_DEPTH_TEST);
534         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
535         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
536
537         int x, y;
538
539         // centers
540         x = ((gr_screen.max_w - g_width) / 2);
541         y = ((gr_screen.max_h - g_height) / 2);
542
543         if ( os_config_read_uint(NULL, NOX("ScaleMovies"), 1) == 1 ) {
544                 float scale_by = (float)gr_screen.max_w / (float)g_width;
545
546                 // don't bother setting anything if we aren't going to need it
547                 if (scale_by != 1.0f) {
548                         glMatrixMode(GL_MODELVIEW);
549                         glPushMatrix();
550                         glLoadIdentity();
551
552                         glScalef( scale_by, scale_by, 1.0f );
553                         mve_scale_video = 1;
554
555                         x = 0;
556                         y = ((480 - g_height) / 2);
557                 }
558         }
559
560         g_coords[0].x = x;
561         g_coords[0].y = y;
562         g_coords[0].u = 0.0f;
563         g_coords[0].v = 0.0f;
564
565         g_coords[1].x = x;
566         g_coords[1].y = y + g_height;
567         g_coords[1].u = 0.0f;
568         g_coords[1].v = i2fl(g_height) / i2fl(tex_h);
569
570         g_coords[2].x = x + g_width;
571         g_coords[2].y = y;
572         g_coords[2].u = i2fl(g_width) / i2fl(tex_w);
573         g_coords[2].v = 0.0f;
574
575         g_coords[3].x = x + g_width;
576         g_coords[3].y = y + g_height;
577         g_coords[3].u = i2fl(g_width) / i2fl(tex_w);
578         g_coords[3].v = i2fl(g_height) / i2fl(tex_h);
579
580         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
581         glEnableClientState(GL_VERTEX_ARRAY);
582
583         glTexCoordPointer(2, GL_FLOAT, sizeof(g_coords_t), &g_coords[0].u);
584         glVertexPointer(2, GL_INT, sizeof(g_coords_t), &g_coords[0].x);
585
586         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, tex_w, tex_h, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
587
588         videobuf_created = 1;
589
590         return 1;
591 }
592
593 static void mve_convert_and_draw()
594 {
595         ushort *pDests;
596         ushort *pSrcs;
597         ushort *pixels = (ushort *)g_vBackBuf1;
598         int x, y;
599
600         pSrcs = pixels;
601
602         pDests = pixelbuf;
603
604         for (y=0; y<g_height; y++) {
605                 for (x = 0; x < g_width; x++) {
606                         pDests[x] = (1<<15)|*pSrcs;
607
608                         pSrcs++;
609                 }
610                 pDests += g_width;
611         }
612 }
613
614 void mve_video_display()
615 {
616         static uint mve_video_skiptimer = 0;
617
618         fix t1 = timer_get_fixed_seconds();
619
620         // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch
621         if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) {
622                 // we are running slow so subtract desired time from actual and skip this frame
623                 mve_video_skiptimer -= (micro_frame_delay/10);
624                 return;
625         } else {
626                 // zero out so we can get a new count
627                 mve_video_skiptimer = 0;
628         }
629
630         mve_convert_and_draw();
631
632         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_width, g_height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixelbuf);
633
634         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
635
636         gr_flip();
637
638         fix t2 = timer_get_fixed_seconds();
639
640         // only get a new count if we are definitely through with old count
641         if ( mve_video_skiptimer == 0 ) {
642                 // for a more accurate count convert the frame rate to a float and multiply
643                 // by one-hundred-thousand before converting to an uint.
644                 mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000);
645         }
646 }
647
648 void mve_video_codemap(ubyte *data, int len)
649 {
650         g_pCurMap = data;
651         g_nMapLength = len;
652 }
653
654 void mve_video_data(ubyte *data, int len)
655 {
656         ushort nFlags;
657         ubyte *temp;
658
659         nFlags = mve_get_ushort(data+12);
660
661         if (nFlags & 1) {
662                 temp = (ubyte *)g_vBackBuf1;
663                 g_vBackBuf1 = g_vBackBuf2;
664                 g_vBackBuf2 = temp;
665         }
666
667         decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
668 }
669
670 void mve_end_chunk()
671 {
672         g_pCurMap = NULL;
673 }
674
675 void mve_init(MVESTREAM *mve)
676 {
677         // reset to default values
678         mve_audio_playing = 0;
679         mve_audio_canplay = 0;
680         mve_audio_compressed = 0;
681         mve_audio_buf_offset = 0;
682         audiobuf_created = 0;
683
684         videobuf_created = 0;
685         mve_scale_video = 0;
686
687         mve_playing = 1;
688 }
689
690 void mve_play(MVESTREAM *mve)
691 {
692         int init_timer = 0, timer_error = 0;
693         int cont = 1;
694
695         if (!timer_started)
696                 mve_timer_start();
697
698         while (cont && mve_playing && !timer_error) {
699                 cont = mve_play_next_chunk(mve);
700
701                 if (micro_frame_delay && !init_timer) {
702                         mve_timer_start();
703                         init_timer = 1;
704                 }
705
706                 timer_error = mve_do_timer_wait();
707
708                 os_poll();
709
710                 if (key_inkey() == SDLK_ESCAPE) {
711                         mve_playing = 0;
712                 }
713         }
714 }
715
716 void mve_shutdown()
717 {
718         mve_audio_stop();
719
720         mve_timer_stop();
721
722         if (pixelbuf != NULL) {
723                 free(pixelbuf);
724                 pixelbuf = NULL;
725         }
726
727         if (g_vBuffers != NULL) {
728                 free(g_vBuffers);
729                 g_vBuffers = NULL;
730         }
731
732         if (gr_screen.mode == GR_OPENGL) {
733                 if (tex > 0) {
734                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
735                         glDisableClientState(GL_VERTEX_ARRAY);
736
737                         glBindTexture(GL_TEXTURE_2D, 0);
738                         glDeleteTextures(1, &tex);
739                         tex = 0;
740                 }
741
742                 if (mve_scale_video) {
743                         glMatrixMode(GL_MODELVIEW);
744                         glPopMatrix();
745                         glLoadIdentity();
746                 }
747
748                 glEnable(GL_DEPTH_TEST);
749         }
750 }