From 8b342d1346f32b6c40e9f4ae8ff6024428d18536 Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Tue, 29 Mar 2005 07:50:34 +0000 Subject: [PATCH] Update to newest movie code with much better video support and audio support from Pierre Willenbrock. Movies are enabled always now (no longer a build option) and but can be skipped with the "--nomovies" or "-n" cmdline options. --- Makefile | 15 +- include/mvelib.h | 148 ++--- include/unix.h | 1 + src/movie/decoder16.cpp | 1168 +++++++++++++++++++------------------- src/movie/movie.cpp | 119 ++-- src/movie/mve_audio.cpp | 20 + src/movie/mvelib.cpp | 712 +++++++++++------------ src/movie/mveplayer.cpp | 1190 +++++++++++++++++++++------------------ src/platform/unix.cpp | 5 + src/sound/ds.cpp | 10 +- 10 files changed, 1730 insertions(+), 1658 deletions(-) diff --git a/Makefile b/Makefile index f33d437..504e588 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ MACOSX=false FS1=false DEMO=false -MVE=false CC=g++ AR=ar @@ -146,6 +145,11 @@ CODE_SOURCES =./src/anim/animplay.cpp \ ./src/model/modelinterp.cpp \ ./src/model/modeloctant.cpp \ ./src/model/modelread.cpp \ + ./src/movie/movie.cpp \ + ./src/movie/mveplayer.cpp \ + ./src/movie/mvelib.cpp \ + ./src/movie/decoder16.cpp \ + ./src/movie/mve_audio.cpp \ ./src/object/collidedebrisship.cpp \ ./src/object/collidedebrisweapon.cpp \ ./src/object/collideshipship.cpp \ @@ -261,17 +265,8 @@ CODE_SOURCES =./src/anim/animplay.cpp \ ./src/network/psnet.cpp \ ./src/network/psnet2.cpp \ ./src/network/stand_gui-unix.cpp \ - ./src/movie/movie.cpp \ ./src/platform/unix.cpp -ifeq ($(strip $(MVE)),true) -CODE_SOURCES += \ - ./src/movie/mveplayer.cpp \ - ./src/movie/mvelib.cpp \ - ./src/movie/decoder16.cpp \ - ./src/movie/mve_audio.cpp -endif - ## Only used for software rendering ##CODE_SOURCES += \ ## ./src/graphics/aaline.cpp \ diff --git a/include/mvelib.h b/include/mvelib.h index 829991a..c77f2d1 100644 --- a/include/mvelib.h +++ b/include/mvelib.h @@ -1,100 +1,108 @@ +/* + * $Logfile: /Freespace2/include/mvelib.h $ + * $Revision$ + * $Date$ + * $Author$ + * + * Lib functions for MVE player + * + * $Log$ + * Revision 1.2 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * + * $NoKeywords: $ + * + */ + #ifndef INCLUDED_MVELIB_H #define INCLUDED_MVELIB_H -#include -#include +#include "pstypes.h" -/* - * structure for maintaining info on a MVEFILE stream - */ +struct CFILE; + +// structure for maintaining info on a MVEFILE stream typedef struct MVEFILE { - FILE *stream; - unsigned char *cur_chunk; - int buf_size; - int cur_fill; - int next_segment; + CFILE *stream; + ubyte *cur_chunk; + int buf_size; + int cur_fill; + int next_segment; } MVEFILE; -/* - * open a .MVE file - */ -MVEFILE *mvefile_open(const char *filename); +// open a .MVE file +MVEFILE *mvefile_open(char *filename); -/* - * close a .MVE file - */ +// close a .MVE file void mvefile_close(MVEFILE *movie); -/* - * get size of next segment in chunk (-1 if no more segments in chunk) - */ +// get size of next segment in chunk (-1 if no more segments in chunk) int mvefile_get_next_segment_size(MVEFILE *movie); -/* - * get type of next segment in chunk (0xff if no more segments in chunk) - */ -unsigned char mvefile_get_next_segment_major(MVEFILE *movie); +// get type of next segment in chunk (0xff if no more segments in chunk) +ubyte mvefile_get_next_segment_major(MVEFILE *movie); -/* - * get subtype (version) of next segment in chunk (0xff if no more segments in - * chunk) - */ -unsigned char mvefile_get_next_segment_minor(MVEFILE *movie); +// get subtype (version) of next segment in chunk (0xff if no more segments in chunk) +ubyte mvefile_get_next_segment_minor(MVEFILE *movie); -/* - * see next segment (return NULL if no next segment) - */ -unsigned char *mvefile_get_next_segment(MVEFILE *movie); +// see next segment (return NULL if no next segment) +ubyte *mvefile_get_next_segment(MVEFILE *movie); -/* - * advance to next segment - */ +// advance to next segment void mvefile_advance_segment(MVEFILE *movie); -/* - * fetch the next chunk (return 0 if at end of stream) - */ +// fetch the next chunk (return 0 if at end of stream) int mvefile_fetch_next_chunk(MVEFILE *movie); -/* - * callback for segment type - */ -typedef int (*MVESEGMENTHANDLER)(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context); - -/* - * structure for maintaining an MVE stream - */ +// structure for maintaining an MVE stream typedef struct MVESTREAM { - MVEFILE *movie; - void *context; - MVESEGMENTHANDLER handlers[32]; + MVEFILE *movie; } MVESTREAM; -/* - * open an MVE stream - */ -MVESTREAM *mve_open(const char *filename); +// open an MVE stream +MVESTREAM *mve_open(char *filename); -/* - * close an MVE stream - */ +// close an MVE stream void mve_close(MVESTREAM *movie); -/* - * set segment type handler - */ -void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler); - -/* - * set segment handler context - */ -void mve_set_handler_context(MVESTREAM *movie, void *context); - -/* - * play next chunk - */ +// play next chunk int mve_play_next_chunk(MVESTREAM *movie); +// basic movie playing functions +void mve_init(MVESTREAM *mve); +void mve_play(MVESTREAM *mve); +void mve_shutdown(); + +// utility functions +short mve_get_short(ubyte *data); +ushort mve_get_ushort(ubyte *data); +int mve_get_int(ubyte *data); + +// callbacks for data handling +// audio +void mve_audio_createbuf(ubyte minor, ubyte *data); +int mve_audio_data(ubyte major, ubyte *data); +void mve_audio_play(); +// video +int mve_video_createbuf(ubyte minor, ubyte *data); +int mve_video_init(ubyte *data); +void mve_video_palette(ubyte *data); +void mve_video_data(ubyte *data, int len); +void mve_video_codemap(ubyte *data, int len); +void mve_video_display(); +// misc +void mve_end_movie(); +void mve_end_chunk(); +int mve_timer_create(ubyte *data); + +// special audio functions +void mveaudio_uncompress(short *buffer, unsigned char *data, int length); +typedef short mves; + #endif /* INCLUDED_MVELIB_H */ diff --git a/include/unix.h b/include/unix.h index 473a36c..94f595d 100644 --- a/include/unix.h +++ b/include/unix.h @@ -47,6 +47,7 @@ typedef unsigned long DWORD; typedef unsigned short WORD; extern void strlwr (char *str); +extern void strupr (char *str); extern int filelength (int fd); extern int MulDiv (int, int, int); diff --git a/src/movie/decoder16.cpp b/src/movie/decoder16.cpp index 0b0bae6..cd15b4b 100644 --- a/src/movie/decoder16.cpp +++ b/src/movie/decoder16.cpp @@ -1,120 +1,133 @@ -#include -#include -#include +/* + * $Logfile: /Freespace2/src/movie/decoder16.cpp $ + * $Revision$ + * $Date$ + * $Author$ + * + * 16-bit frame decoder for MVEs + * + * $Log$ + * Revision 1.2 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * + * $NoKeywords: $ + * + */ + +#include "pstypes.h" extern int g_width, g_height; extern void *g_vBackBuf1, *g_vBackBuf2; /* 16 bit decoding routines */ -static unsigned short *backBuf1, *backBuf2; +static ushort *backBuf1, *backBuf2; static int lookup_initialized; -static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb); +static void dispatchDecoder16(ushort **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb); static void genLoopkupTable(); void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain) { - unsigned char *pOrig; - unsigned char *pOffData, *pEnd; - unsigned short offset; - int length; - int op; - int i, j; - int xb, yb; + unsigned char *pOrig; + unsigned char *pOffData, *pEnd; + ushort offset; + int length; + int op; + int i, j; + int xb, yb; if (!lookup_initialized) { genLoopkupTable(); } - - backBuf1 = (unsigned short *)g_vBackBuf1; - backBuf2 = (unsigned short *)g_vBackBuf2; - - xb = g_width >> 3; - yb = g_height >> 3; - - offset = pData[0]|(pData[1]<<8); - - pOffData = pData + offset; - pEnd = pData + offset; - - pData += 2; - - pOrig = pData; - length = offset - 2; /*dataRemain-2;*/ - - for (j=0; j> 3; + yb = g_height >> 3; + + offset = pData[0]|(pData[1]<<8); + + pOffData = pData + offset; + pEnd = pData + offset; + + pData += 2; + + pOrig = pData; + length = offset - 2; /*dataRemain-2;*/ + + for (j=0; j= backBuf1 + g_width*g_height) - fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); + if ((ushort *)pFrame < backBuf1) + fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); + else if ((ushort *)pFrame >= backBuf1 + g_width*g_height) + fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); */ - op = ((*pMap) >> 4) & 0xf; - dispatchDecoder16((unsigned short **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j); + op = ((*pMap) >> 4) & 0xf; + dispatchDecoder16((ushort **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j); /* - if ((unsigned short *)pFrame < backBuf1) - fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); - else if ((unsigned short *)pFrame >= backBuf1 + g_width*g_height) - fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); + if ((ushort *)pFrame < backBuf1) + fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); + else if ((ushort *)pFrame >= backBuf1 + g_width*g_height) + fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); */ - ++pMap; - --mapRemain; - } + pMap++; + mapRemain--; + } + + pFrame += 7*g_width*2; + } - pFrame += 7*g_width*2; - } - - if ((length-(pData-pOrig)) != 0) { - fprintf(stderr, "DEBUG: junk left over: %d,%d,%d\n", (pData-pOrig), length, (length-(pData-pOrig))); - } + if ((length-(pData-pOrig)) != 0) { + nprintf(("MVE", "DEBUG: junk left over: %d,%d,%d\n", (pData-pOrig), length, (length-(pData-pOrig)))); + } } -static unsigned short GETPIXEL(unsigned char **buf, int off) +static ushort GETPIXEL(unsigned char **buf, int off) { - unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8); + ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8); return val; } -static unsigned short GETPIXELI(unsigned char **buf, int off) +static ushort GETPIXELI(unsigned char **buf, int off) { - unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8); + ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8); (*buf) += 2; return val; } static void relClose(int i, int *x, int *y) { - int ma, mi; + int ma, mi; - ma = i >> 4; - mi = i & 0xf; + ma = i >> 4; + mi = i & 0xf; - *x = mi - 8; - *y = ma - 8; + *x = mi - 8; + *y = ma - 8; } static void relFar(int i, int sign, int *x, int *y) { - if (i < 56) - { - *x = sign * (8 + (i % 7)); - *y = sign * (i / 7); - } - else - { - *x = sign * (-14 + (i - 56) % 29); - *y = sign * (8 + (i - 56) / 29); - } + if (i < 56) { + *x = sign * (8 + (i % 7)); + *y = sign * (i / 7); + } else { + *x = sign * (-14 + (i - 56) % 29); + *y = sign * (8 + (i - 56) / 29); + } } static int close_table[512]; @@ -125,593 +138,544 @@ static void genLoopkupTable() { int i; int x, y; - + for (i = 0; i < 256; i++) { relClose(i, &x, &y); - + close_table[i*2+0] = x; close_table[i*2+1] = y; - + relFar(i, 1, &x, &y); - + far_p_table[i*2+0] = x; far_p_table[i*2+1] = y; - + relFar(i, -1, &x, &y); - + far_n_table[i*2+0] = x; far_n_table[i*2+1] = y; } - + lookup_initialized = 1; } -static void copyFrame(unsigned short *pDest, unsigned short *pSrc) +static void copyFrame(ushort *pDest, ushort *pSrc) { - int i; - - for (i=0; i<8; i++) - { - memcpy(pDest, pSrc, 16); - pDest += g_width; - pSrc += g_width; - } + int i; + + for (i=0; i<8; i++) { + memcpy(pDest, pSrc, 16); + pDest += g_width; + pSrc += g_width; + } } -static void patternRow4Pixels(unsigned short *pFrame, - unsigned char pat0, unsigned char pat1, - unsigned short *p) +static void patternRow4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p) { - unsigned short mask=0x0003; - unsigned short shift=0; - unsigned short pattern = (pat1 << 8) | pat0; - - while (mask != 0) - { - *pFrame++ = p[(mask & pattern) >> shift]; - mask <<= 2; - shift += 2; - } + ushort mask=0x0003; + ushort shift=0; + ushort pattern = (pat1 << 8) | pat0; + + while (mask != 0) { + *pFrame++ = p[(mask & pattern) >> shift]; + mask <<= 2; + shift += 2; + } } -static void patternRow4Pixels2(unsigned short *pFrame, - unsigned char pat0, - unsigned short *p) +static void patternRow4Pixels2(ushort *pFrame, unsigned char pat0, ushort *p) { - unsigned char mask=0x03; - unsigned char shift=0; - unsigned short pel; + unsigned char mask=0x03; + unsigned char shift=0; + ushort pel; /* ORIGINAL VERSION IS BUGGY - int skip=1; - - while (mask != 0) - { - pel = p[(mask & pat0) >> shift]; - pFrame[0] = pel; - pFrame[2] = pel; - pFrame[g_width + 0] = pel; - pFrame[g_width + 2] = pel; - pFrame += skip; - skip = 4 - skip; - mask <<= 2; - shift += 2; - } + int skip=1; + + while (mask != 0) { + pel = p[(mask & pat0) >> shift]; + pFrame[0] = pel; + pFrame[2] = pel; + pFrame[g_width + 0] = pel; + pFrame[g_width + 2] = pel; + pFrame += skip; + skip = 4 - skip; + mask <<= 2; + shift += 2; + } */ - while (mask != 0) - { - pel = p[(mask & pat0) >> shift]; - pFrame[0] = pel; - pFrame[1] = pel; - pFrame[g_width + 0] = pel; - pFrame[g_width + 1] = pel; - pFrame += 2; - mask <<= 2; - shift += 2; - } + while (mask != 0) { + pel = p[(mask & pat0) >> shift]; + pFrame[0] = pel; + pFrame[1] = pel; + pFrame[g_width + 0] = pel; + pFrame[g_width + 1] = pel; + pFrame += 2; + mask <<= 2; + shift += 2; + } } -static void patternRow4Pixels2x1(unsigned short *pFrame, unsigned char pat, - unsigned short *p) +static void patternRow4Pixels2x1(ushort *pFrame, unsigned char pat, ushort *p) { - unsigned char mask=0x03; - unsigned char shift=0; - unsigned short pel; - - while (mask != 0) - { - pel = p[(mask & pat) >> shift]; - pFrame[0] = pel; - pFrame[1] = pel; - pFrame += 2; - mask <<= 2; - shift += 2; - } + unsigned char mask=0x03; + unsigned char shift=0; + ushort pel; + + while (mask != 0) { + pel = p[(mask & pat) >> shift]; + pFrame[0] = pel; + pFrame[1] = pel; + pFrame += 2; + mask <<= 2; + shift += 2; + } } -static void patternQuadrant4Pixels(unsigned short *pFrame, - unsigned char pat0, unsigned char pat1, unsigned char pat2, - unsigned char pat3, unsigned short *p) +static void patternQuadrant4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, ushort *p) { - unsigned long mask = 0x00000003UL; - int shift=0; - int i; - unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0; + unsigned long mask = 0x00000003UL; + int shift=0; + int i; + unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0; - for (i=0; i<16; i++) - { - pFrame[i&3] = p[(pat & mask) >> shift]; + for (i=0; i<16; i++) { + pFrame[i&3] = p[(pat & mask) >> shift]; - if ((i&3) == 3) - pFrame += g_width; + if ((i&3) == 3) + pFrame += g_width; - mask <<= 2; - shift += 2; - } + mask <<= 2; + shift += 2; + } } - -static void patternRow2Pixels(unsigned short *pFrame, unsigned char pat, - unsigned short *p) +static void patternRow2Pixels(ushort *pFrame, unsigned char pat, ushort *p) { - unsigned char mask=0x01; + unsigned char mask=0x01; - while (mask != 0) - { - *pFrame++ = p[(mask & pat) ? 1 : 0]; - mask <<= 1; - } + while (mask != 0) { + *pFrame++ = p[(mask & pat) ? 1 : 0]; + mask <<= 1; + } } -static void patternRow2Pixels2(unsigned short *pFrame, unsigned char pat, - unsigned short *p) +static void patternRow2Pixels2(ushort *pFrame, unsigned char pat, ushort *p) { - unsigned short pel; - unsigned char mask=0x1; - -/* ORIGINAL VERSION IS BUGGY - int skip=1; - while (mask != 0x10) - { - pel = p[(mask & pat) ? 1 : 0]; - pFrame[0] = pel; - pFrame[2] = pel; - pFrame[g_width + 0] = pel; - pFrame[g_width + 2] = pel; - pFrame += skip; - skip = 4 - skip; - mask <<= 1; - } + ushort pel; + unsigned char mask=0x1; + +/* ORIGINAL VERSION IS BUGGY + int skip=1; + while (mask != 0x10) { + pel = p[(mask & pat) ? 1 : 0]; + pFrame[0] = pel; + pFrame[2] = pel; + pFrame[g_width + 0] = pel; + pFrame[g_width + 2] = pel; + pFrame += skip; + skip = 4 - skip; + mask <<= 1; + } */ while (mask != 0x10) { pel = p[(mask & pat) ? 1 : 0]; - + pFrame[0] = pel; pFrame[1] = pel; pFrame[g_width + 0] = pel; pFrame[g_width + 1] = pel; pFrame += 2; - + mask <<= 1; } } -static void patternQuadrant2Pixels(unsigned short *pFrame, unsigned char pat0, - unsigned char pat1, unsigned short *p) +static void patternQuadrant2Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p) { - unsigned short mask = 0x0001; - int i; - unsigned short pat = (pat1 << 8) | pat0; + ushort mask = 0x0001; + int i; + ushort pat = (pat1 << 8) | pat0; - for (i=0; i<16; i++) - { - pFrame[i&3] = p[(pat & mask) ? 1 : 0]; + for (i=0; i<16; i++) { + pFrame[i&3] = p[(pat & mask) ? 1 : 0]; - if ((i&3) == 3) - pFrame += g_width; + if ((i&3) == 3) + pFrame += g_width; + + mask <<= 1; + } - mask <<= 1; - } } -static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb) +static void dispatchDecoder16(ushort **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb) { - unsigned short p[4]; - unsigned char pat[16]; - int i, j, k; - int x, y; - unsigned short *pDstBak; - - pDstBak = *pFrame; - - switch(codeType) - { - case 0x0: - copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1)); - case 0x1: - break; - case 0x2: /* - relFar(*(*pOffData)++, 1, &x, &y); - */ - - k = *(*pOffData)++; - x = far_p_table[k*2+0]; - y = far_p_table[k*2+1]; - - copyFrame(*pFrame, *pFrame + x + y*g_width); - --*pDataRemain; - break; - case 0x3: /* - relFar(*(*pOffData)++, -1, &x, &y); - */ - - k = *(*pOffData)++; - x = far_n_table[k*2+0]; - y = far_n_table[k*2+1]; - - copyFrame(*pFrame, *pFrame + x + y*g_width); - --*pDataRemain; - break; - case 0x4: /* - relClose(*(*pOffData)++, &x, &y); - */ - - k = *(*pOffData)++; - x = close_table[k*2+0]; - y = close_table[k*2+1]; - - copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width); - --*pDataRemain; - break; - case 0x5: - x = (char)*(*pData)++; - y = (char)*(*pData)++; - copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width); - *pDataRemain -= 2; - break; - case 0x6: - fprintf(stderr, "STUB: encoding 6 not tested\n"); - for (i=0; i<2; i++) - { - *pFrame += 16; - if (++*curXb == (g_width >> 3)) - { - *pFrame += 7*g_width; - *curXb = 0; - if (++*curYb == (g_height >> 3)) - return; - } - } - break; - - case 0x7: - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - - if (!((p[0]/*|p[1]*/)&0x8000)) - { - for (i=0; i<8; i++) - { - patternRow2Pixels(*pFrame, *(*pData), p); - (*pData)++; - - *pFrame += g_width; - } - } - else - { - for (i=0; i<2; i++) - { - patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p); - *pFrame += 2*g_width; - patternRow2Pixels2(*pFrame, *(*pData) >> 4, p); - (*pData)++; - - *pFrame += 2*g_width; - } - } - break; - - case 0x8: - p[0] = GETPIXEL(pData, 0); - - if (!(p[0] & 0x8000)) - { - for (i=0; i<4; i++) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - (*pData) += 2; - - patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p); - - if (i & 1) - *pFrame -= (4*g_width - 4); - else - *pFrame += 4*g_width; - } - - - } else { - p[2] = GETPIXEL(pData, 8); - - if (!(p[2]&0x8000)) { - for (i=0; i<4; i++) - { - if ((i & 1) == 0) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - } - pat[0] = *(*pData)++; - pat[1] = *(*pData)++; - patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p); - - if (i & 1) - *pFrame -= (4*g_width - 4); - else - *pFrame += 4*g_width; - } - } else { - for (i=0; i<8; i++) - { - if ((i & 3) == 0) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - } - patternRow2Pixels(*pFrame, *(*pData), p); - (*pData)++; - - *pFrame += g_width; - } - } - } - break; - - case 0x9: - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - p[2] = GETPIXELI(pData, 0); - p[3] = GETPIXELI(pData, 0); - - *pDataRemain -= 8; - - if (!(p[0] & 0x8000)) - { - if (!(p[2] & 0x8000)) - { - - for (i=0; i<8; i++) - { - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - (*pData) += 2; - patternRow4Pixels(*pFrame, pat[0], pat[1], p); - *pFrame += g_width; - } - *pDataRemain -= 16; - - } - else - { - patternRow4Pixels2(*pFrame, (*pData)[0], p); - *pFrame += 2*g_width; - patternRow4Pixels2(*pFrame, (*pData)[1], p); - *pFrame += 2*g_width; - patternRow4Pixels2(*pFrame, (*pData)[2], p); - *pFrame += 2*g_width; - patternRow4Pixels2(*pFrame, (*pData)[3], p); - - (*pData) += 4; - *pDataRemain -= 4; + ushort p[4]; + unsigned char pat[16]; + int i, j, k; + int x, y; + ushort *pDstBak; + + pDstBak = *pFrame; + + switch(codeType) { + case 0x0: + copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1)); + break; // ADDED + + case 0x1: + break; + + case 0x2: + /* relFar(*(*pOffData)++, 1, &x, &y); */ + + k = *(*pOffData)++; + x = far_p_table[k*2+0]; + y = far_p_table[k*2+1]; + + copyFrame(*pFrame, *pFrame + x + y*g_width); + *pDataRemain--; + break; + + case 0x3: + /* relFar(*(*pOffData)++, -1, &x, &y); */ + + k = *(*pOffData)++; + x = far_n_table[k*2+0]; + y = far_n_table[k*2+1]; + + copyFrame(*pFrame, *pFrame + x + y*g_width); + *pDataRemain--; + break; + + case 0x4: + /* relClose(*(*pOffData)++, &x, &y); */ + + k = *(*pOffData)++; + x = close_table[k*2+0]; + y = close_table[k*2+1]; + + copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width); + *pDataRemain--; + break; + + case 0x5: + x = (char)*(*pData)++; + y = (char)*(*pData)++; + copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width); + *pDataRemain -= 2; + break; + + case 0x6: + nprintf(("MVE", "STUB: encoding 6 not tested\n")); + + for (i=0; i<2; i++) { + *pFrame += 16; + + if (++*curXb == (g_width >> 3)) { + *pFrame += 7*g_width; + *curXb = 0; + if (++*curYb == (g_height >> 3)) + return; + } } - } - else - { - if (!(p[2] & 0x8000)) - { - for (i=0; i<8; i++) - { - pat[0] = (*pData)[0]; - (*pData) += 1; - patternRow4Pixels2x1(*pFrame, pat[0], p); - *pFrame += g_width; - } - *pDataRemain -= 8; - } - else - { - for (i=0; i<4; i++) - { - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - - (*pData) += 2; - - patternRow4Pixels(*pFrame, pat[0], pat[1], p); - *pFrame += g_width; - patternRow4Pixels(*pFrame, pat[0], pat[1], p); - *pFrame += g_width; - } - *pDataRemain -= 8; - } - } - break; - - case 0xa: - p[0] = GETPIXEL(pData, 0); - - if (!(p[0] & 0x8000)) - { - for (i=0; i<4; i++) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - p[2] = GETPIXELI(pData, 0); - p[3] = GETPIXELI(pData, 0); - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - pat[2] = (*pData)[2]; - pat[3] = (*pData)[3]; - - (*pData) += 4; - - patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p); - - if (i & 1) - *pFrame -= (4*g_width - 4); - else - *pFrame += 4*g_width; - } - } - else - { - p[0] = GETPIXEL(pData, 16); - - if (!(p[0] & 0x8000)) - { - for (i=0; i<4; i++) - { - if ((i&1) == 0) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - p[2] = GETPIXELI(pData, 0); - p[3] = GETPIXELI(pData, 0); - } - - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - pat[2] = (*pData)[2]; - pat[3] = (*pData)[3]; - - (*pData) += 4; - - patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p); - - if (i & 1) - *pFrame -= (4*g_width - 4); - else - *pFrame += 4*g_width; - } - } - else - { - for (i=0; i<8; i++) - { - if ((i&3) == 0) - { - p[0] = GETPIXELI(pData, 0); - p[1] = GETPIXELI(pData, 0); - p[2] = GETPIXELI(pData, 0); - p[3] = GETPIXELI(pData, 0); - } - - pat[0] = (*pData)[0]; - pat[1] = (*pData)[1]; - patternRow4Pixels(*pFrame, pat[0], pat[1], p); - *pFrame += g_width; - - (*pData) += 2; - } - } - } - break; - - case 0xb: - for (i=0; i<8; i++) - { - memcpy(*pFrame, *pData, 16); - *pFrame += g_width; - *pData += 16; - *pDataRemain -= 16; - } - break; - - case 0xc: - for (i=0; i<4; i++) - { - p[0] = GETPIXEL(pData, 0); - p[1] = GETPIXEL(pData, 2); - p[2] = GETPIXEL(pData, 4); - p[3] = GETPIXEL(pData, 6); - - for (j=0; j<2; j++) - { - for (k=0; k<4; k++) - { - (*pFrame)[j+2*k] = p[k]; - (*pFrame)[g_width+j+2*k] = p[k]; - } - *pFrame += g_width; - } - *pData += 8; - *pDataRemain -= 8; - } - break; - - case 0xd: - for (i=0; i<2; i++) - { - p[0] = GETPIXEL(pData, 0); - p[1] = GETPIXEL(pData, 2); - - for (j=0; j<4; j++) - { - for (k=0; k<4; k++) - { - (*pFrame)[k*g_width+j] = p[0]; - (*pFrame)[k*g_width+j+4] = p[1]; - } - } - - *pFrame += 4*g_width; - - *pData += 4; - *pDataRemain -= 4; - } - break; - - case 0xe: - p[0] = GETPIXEL(pData, 0); - - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - (*pFrame)[j] = p[0]; - } - - *pFrame += g_width; - } - - *pData += 2; - *pDataRemain -= 2; - - break; - - case 0xf: - p[0] = GETPIXEL(pData, 0); - p[1] = GETPIXEL(pData, 1); - - for (i=0; i<8; i++) - { - for (j=0; j<8; j++) - { - (*pFrame)[j] = p[(i+j)&1]; - } - *pFrame += g_width; - } - - *pData += 4; - *pDataRemain -= 4; - break; - - default: - break; - } - - *pFrame = pDstBak+8; + break; + + case 0x7: + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + + if (!((p[0]/*|p[1]*/)&0x8000)) { + for (i=0; i<8; i++) { + patternRow2Pixels(*pFrame, *(*pData), p); + (*pData)++; + + *pFrame += g_width; + } + } else { + for (i=0; i<2; i++) { + patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p); + *pFrame += 2*g_width; + patternRow2Pixels2(*pFrame, *(*pData) >> 4, p); + (*pData)++; + + *pFrame += 2*g_width; + } + } + break; + + case 0x8: + p[0] = GETPIXEL(pData, 0); + + if (!(p[0] & 0x8000)) { + for (i=0; i<4; i++) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + (*pData) += 2; + + patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p); + + if (i & 1) { + *pFrame -= (4*g_width - 4); + } else { + *pFrame += 4*g_width; + } + } + } else { + p[2] = GETPIXEL(pData, 8); + + if (!(p[2]&0x8000)) { + for (i=0; i<4; i++) { + if ((i & 1) == 0) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + } + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p); + + if (i & 1) { + *pFrame -= (4*g_width - 4); + } else { + *pFrame += 4*g_width; + } + } + } else { + for (i=0; i<8; i++) { + if ((i & 3) == 0) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + } + patternRow2Pixels(*pFrame, *(*pData), p); + (*pData)++; + + *pFrame += g_width; + } + } + } + break; + + case 0x9: + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + p[2] = GETPIXELI(pData, 0); + p[3] = GETPIXELI(pData, 0); + + *pDataRemain -= 8; + + if (!(p[0] & 0x8000)) { + if (!(p[2] & 0x8000)) { + for (i=0; i<8; i++) { + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + (*pData) += 2; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + } + *pDataRemain -= 16; + } else { + patternRow4Pixels2(*pFrame, (*pData)[0], p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, (*pData)[1], p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, (*pData)[2], p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, (*pData)[3], p); + + (*pData) += 4; + *pDataRemain -= 4; + } + } else { + if (!(p[2] & 0x8000)) { + for (i=0; i<8; i++) { + pat[0] = (*pData)[0]; + (*pData) += 1; + patternRow4Pixels2x1(*pFrame, pat[0], p); + *pFrame += g_width; + } + *pDataRemain -= 8; + } else { + for (i=0; i<4; i++) { + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + + (*pData) += 2; + + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + } + *pDataRemain -= 8; + } + } + break; + + case 0xa: + p[0] = GETPIXEL(pData, 0); + + if (!(p[0] & 0x8000)) { + for (i=0; i<4; i++) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + p[2] = GETPIXELI(pData, 0); + p[3] = GETPIXELI(pData, 0); + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + pat[2] = (*pData)[2]; + pat[3] = (*pData)[3]; + + (*pData) += 4; + + patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p); + + if (i & 1) { + *pFrame -= (4*g_width - 4); + } else { + *pFrame += 4*g_width; + } + } + } else { + p[0] = GETPIXEL(pData, 16); + + if (!(p[0] & 0x8000)) { + for (i=0; i<4; i++) { + if ((i&1) == 0) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + p[2] = GETPIXELI(pData, 0); + p[3] = GETPIXELI(pData, 0); + } + + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + pat[2] = (*pData)[2]; + pat[3] = (*pData)[3]; + + (*pData) += 4; + + patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p); + + if (i & 1) { + *pFrame -= (4*g_width - 4); + } else { + *pFrame += 4*g_width; + } + } + } else { + for (i=0; i<8; i++) { + if ((i&3) == 0) { + p[0] = GETPIXELI(pData, 0); + p[1] = GETPIXELI(pData, 0); + p[2] = GETPIXELI(pData, 0); + p[3] = GETPIXELI(pData, 0); + } + + pat[0] = (*pData)[0]; + pat[1] = (*pData)[1]; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + + (*pData) += 2; + } + } + } + break; + + case 0xb: + for (i=0; i<8; i++) { + memcpy(*pFrame, *pData, 16); + *pFrame += g_width; + *pData += 16; + *pDataRemain -= 16; + } + break; + + case 0xc: + for (i=0; i<4; i++) { + p[0] = GETPIXEL(pData, 0); + p[1] = GETPIXEL(pData, 2); + p[2] = GETPIXEL(pData, 4); + p[3] = GETPIXEL(pData, 6); + + /* for (j=0; j<2; j++) { + for (k=0; k<4; k++) { + (*pFrame)[2*k] = p[k]; + (*pFrame)[2*k+1] = p[k]; + } + *pFrame += g_width; + } */ + + for (k=0; k<4; k++) { + (*pFrame)[0+2*k] = p[k]; + (*pFrame)[g_width+0+2*k] = p[k]; + (*pFrame)[1+2*k] = p[k]; + (*pFrame)[g_width+1+2*k] = p[k]; + } + + *pFrame += 2*g_width; + + *pData += 8; + *pDataRemain -= 8; + } + break; + + case 0xd: + for (i=0; i<2; i++) { + p[0] = GETPIXEL(pData, 0); + p[1] = GETPIXEL(pData, 2); + + for (j=0; j<4; j++) { + for (k=0; k<4; k++) { + (*pFrame)[k*g_width+j] = p[0]; + (*pFrame)[k*g_width+j+4] = p[1]; + } + } + + *pFrame += 4*g_width; + + *pData += 4; + *pDataRemain -= 4; + } + break; + + case 0xe: + p[0] = GETPIXEL(pData, 0); + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + (*pFrame)[j] = p[0]; + } + + *pFrame += g_width; + } + + *pData += 2; + *pDataRemain -= 2; + + break; + + case 0xf: + p[0] = GETPIXEL(pData, 0); + p[1] = GETPIXEL(pData, 1); + + for (i=0; i<8; i++) { + for (j=0; j<8; j++) { + (*pFrame)[j] = p[(i+j)&1]; + } + *pFrame += g_width; + } + + *pData += 4; + *pDataRemain -= 4; + break; + + default: + break; + } + + *pFrame = pDstBak+8; } diff --git a/src/movie/movie.cpp b/src/movie/movie.cpp index c360090..575cdd8 100644 --- a/src/movie/movie.cpp +++ b/src/movie/movie.cpp @@ -1,57 +1,104 @@ -#include -#include +/* + * $Logfile: /Freespace2/src/movie/movie.cpp $ + * $Revision$ + * $Date$ + * $Author$ + * + * Frontend for MVE playing + * + * $Log$ + * Revision 1.4 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * + * $NoKeywords: $ + * + */ + +#include "pstypes.h" #include "mvelib.h" -#include "mve_audio.h" +#include "movie.h" #include "cutscenes.h" #include "freespace.h" +#include "mouse.h" +#include "sound.h" +#include "cmdline.h" +#include "gamesequence.h" +#include "mainhallmenu.h" -extern void initializeMovie(MVESTREAM *mve); -extern void playMovie(MVESTREAM *mve); -extern void shutdownMovie(MVESTREAM *mve); - -int movie_play(char *filename, int unknown) +int movie_play(char *filename, int cd_prompt) { - fprintf (stderr, "Playing MVE file %s\n",filename); - - // mark the mve as viewable in the techroom if in a campaign + // mark the movie as viewable in the techroom if in a campaign if (Game_mode & GM_CAMPAIGN_MODE) { cutscene_mark_viewable(filename); } -#ifdef MVE - int i; - char lower_name[MAX_FILENAME_LEN] = ""; + if (Cmdline_play_movies) { + MVESTREAM *movie; - // lowercase filename to avoid loading problems from mixed case calls - strcpy( lower_name, filename ); - for (i=0; i<(int)strlen(lower_name); i++ ){ - lower_name[i] = char(tolower(lower_name[i])); - } + printf("Playing movie: %s\n", filename); - char file[200]; -// snprintf (file, 200, "movies/%s", filename); - snprintf (file, 200, "Data/Movies/%s", lower_name); - MVESTREAM *mve = mve_open(file); - if (mve == NULL) - { - fprintf(stderr, "can't open MVE file '%s'\n", file); - return -1; - } + // umm, yeah + // if ( cd_prompt == -1 ) + // cd_prompt = require_cd; + + // look for correct CD when viewing movies in the tech room + // if (gameseq_get_state() == GS_STATE_VIEW_CUTSCENES) { + // cutscenes_validate_cd(filename, cd_prompt); + // } + + movie = mve_open(filename); - initializeMovie(mve); - playMovie(mve); - shutdownMovie(mve); + if (movie) { + // kill all background sounds + game_stop_looped_sounds(); + main_hall_stop_music(); + main_hall_stop_ambient(); + + // clear the screen and hide the mouse cursor + Mouse_hidden++; + gr_reset_clip(); + gr_clear(); + gr_flip(); + gr_zbuffer_clear(1); // G400, blah + + // ready to play... + mve_init(movie); + mve_play(movie); + + // ...done playing, close the mve and show the cursor again + mve_shutdown(); + mve_close(movie); + + Mouse_hidden--; + main_hall_start_ambient(); + } else { + printf("Can't open movie file: '%s'\n", filename); + return 0; + } + + } else { + mprintf(("Movies are disabled, skipping...\n")); + } - mve_close(mve); -#else - fprintf(stderr, "STUB: if movie support existed, you'd be watching %s\n", filename); -#endif return 1; } int movie_play_two(char *filename1, char *filename2) { - fprintf(stderr, "STUB: if movie support existed, you'd be watching %s, followed by %s\n", filename1, filename2); + // FIXME: part of the CD code which isn't included yet + int require_cd = 0; + + // make sure the first movie played correctly, then play the second one + if (movie_play(filename1, require_cd)) { + movie_play(filename2, require_cd); + } else { + printf("Not playing second movie: %s\n", filename2); + return 0; + } return 1; } diff --git a/src/movie/mve_audio.cpp b/src/movie/mve_audio.cpp index 4495a03..5958d48 100644 --- a/src/movie/mve_audio.cpp +++ b/src/movie/mve_audio.cpp @@ -1,3 +1,23 @@ +/* + * $Logfile: /Freespace2/src/movie/mve_audio.cpp $ + * $Revision$ + * $Date$ + * $Author$ + * + * Handles compressed audio data in MVE files + * + * $Log$ + * Revision 1.2 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * + * $NoKeywords: $ + * + */ + static int audio_exp_table[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, diff --git a/src/movie/mvelib.cpp b/src/movie/mvelib.cpp index ca1132f..ff9f877 100644 --- a/src/movie/mvelib.cpp +++ b/src/movie/mvelib.cpp @@ -1,449 +1,407 @@ -#include +/* + * $Logfile: /Freespace2/src/movie/mvelib.cpp $ + * $Revision$ + * $Date$ + * $Author$ + * + * Lib functions for MVE player + * + * $Log$ + * Revision 1.2 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * + * $NoKeywords: $ + * + */ + +#include "pstypes.h" #include "mvelib.h" +#include "cfile.h" + -static const char MVE_HEADER[] = "Interplay MVE File\x1A"; +static const char MVE_HEADER[] = "Interplay MVE File\x1A"; static const short MVE_HDRCONST1 = 0x001A; static const short MVE_HDRCONST2 = 0x0100; static const short MVE_HDRCONST3 = 0x1133; -/* - * private utility functions - */ -static short _mve_get_short(unsigned char *data); -static unsigned short _mve_get_ushort(unsigned char *data); - -/* - * private functions for mvefile - */ -static MVEFILE *_mvefile_alloc(void); -static void _mvefile_free(MVEFILE *movie); -static int _mvefile_open(MVEFILE *movie, const char *filename); -static int _mvefile_read_header(MVEFILE *movie); -static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size); -static int _mvefile_fetch_next_chunk(MVEFILE *movie); - -/* - * private functions for mvestream - */ -static MVESTREAM *_mvestream_alloc(void); -static void _mvestream_free(MVESTREAM *movie); -static int _mvestream_open(MVESTREAM *movie, const char *filename); -/************************************************************ - * public MVEFILE functions - ************************************************************/ +// ----------------------------------------------------------- +// public MVEFILE functions +// ----------------------------------------------------------- -/* - * open an MVE file - */ -MVEFILE *mvefile_open(const char *filename) +// utility functions for mvefile and mveplayer +short mve_get_short(ubyte *data) { - MVEFILE *file; - - /* create the file */ - file = _mvefile_alloc(); - if (! _mvefile_open(file, filename)) - { - _mvefile_free(file); - return NULL; - } - - /* initialize the file */ - _mvefile_set_buffer_size(file, 1024); - - /* verify the file's header */ - if (! _mvefile_read_header(file)) - { - _mvefile_free(file); - return NULL; - } - - /* now, prefetch the next chunk */ - _mvefile_fetch_next_chunk(file); - - return file; + short value; + value = data[0] | (data[1] << 8); + return value; } -/* - * close a MVE file - */ -void mvefile_close(MVEFILE *movie) +ushort mve_get_ushort(ubyte *data) { - _mvefile_free(movie); + ushort value; + value = data[0] | (data[1] << 8); + return value; } -/* - * get the size of the next segment - */ -int mvefile_get_next_segment_size(MVEFILE *movie) +int mve_get_int(ubyte *data) { - /* if nothing is cached, fail */ - if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) - return -1; - - /* if we don't have enough data to get a segment, fail */ - if (movie->cur_fill - movie->next_segment < 4) - return -1; - - /* otherwise, get the data length */ - return _mve_get_short(movie->cur_chunk + movie->next_segment); + int value; + value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + return value; } -/* - * get type of next segment in chunk (0xff if no more segments in chunk) - */ -unsigned char mvefile_get_next_segment_major(MVEFILE *movie) +// open an MVE file +MVEFILE *mvefile_open(char *filename) { - /* if nothing is cached, fail */ - if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) - return 0xff; - - /* if we don't have enough data to get a segment, fail */ - if (movie->cur_fill - movie->next_segment < 4) - return 0xff; - - /* otherwise, get the data length */ - return movie->cur_chunk[movie->next_segment + 2]; + int cf_opened = 0; + int mve_valid = 1; + char lower_name[MAX_FILENAME_LEN]; + char upper_name[MAX_FILENAME_LEN]; + char buffer[20]; + MVEFILE *file; + + // create the file + file = (MVEFILE *)malloc(sizeof(MVEFILE)); + + // set defaults + file->stream = NULL; + file->cur_chunk = NULL; + file->buf_size = 0; + file->cur_fill = 0; + file->next_segment = 0; + + // lower case filename for checking + strncpy(lower_name, filename, strlen(filename)+1); + strlwr(lower_name); + // upper case filename for checking + strncpy(upper_name, filename, strlen(filename)+1); + strupr(upper_name); + + // NOTE: CF_TYPE *must* be ANY to get movies off of the CDs + while (1) { + // lower case filename check - off of HD/CD-ROM + if ( (file->stream = cfopen(lower_name, "rb", CFILE_NORMAL, CF_TYPE_MOVIES)) ) { + cf_opened = 1; + break; + } + + // upper case filename check - off of CD-ROM (or HD if case not changed) + if ( (file->stream = cfopen(upper_name, "rb", CFILE_NORMAL, CF_TYPE_ANY)) ) { + cf_opened = 1; + break; + } + + // passed filename check - just because + if ( (file->stream = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_ANY)) ) { + cf_opened = 1; + break; + } + + // uh-oh, couldn't open + cf_opened = 0; + break; + } + + if (!cf_opened) { + mvefile_close(file); + return NULL; + } + + // initialize the buffer + file->cur_chunk = (ubyte *)malloc(100 + 1024); + file->buf_size = 100 + 1024; + + // verify the file's header + cfread_string(buffer, 20, file->stream); + + if (strcmp(buffer, MVE_HEADER)) + mve_valid = 0; + + if (cfread_short(file->stream) != MVE_HDRCONST1) + mve_valid = 0; + + if (cfread_short(file->stream) != MVE_HDRCONST2) + mve_valid = 0; + + if (cfread_short(file->stream) != MVE_HDRCONST3) + mve_valid = 0; + + if (!mve_valid) { + mvefile_close(file); + return NULL; + } + + // now, prefetch the next chunk + mvefile_fetch_next_chunk(file); + + return file; } -/* - * get subtype (version) of next segment in chunk (0xff if no more segments in - * chunk) - */ -unsigned char mvefile_get_next_segment_minor(MVEFILE *movie) +// close a MVE file +void mvefile_close(MVEFILE *file) { - /* if nothing is cached, fail */ - if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) - return 0xff; + // free the stream + if (file->stream) + cfclose(file->stream); - /* if we don't have enough data to get a segment, fail */ - if (movie->cur_fill - movie->next_segment < 4) - return 0xff; + file->stream = NULL; - /* otherwise, get the data length */ - return movie->cur_chunk[movie->next_segment + 3]; -} + // free the buffer + if (file->cur_chunk) + free(file->cur_chunk); -/* - * see next segment (return NULL if no next segment) - */ -unsigned char *mvefile_get_next_segment(MVEFILE *movie) -{ - /* if nothing is cached, fail */ - if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) - return NULL; + file->cur_chunk = NULL; - /* if we don't have enough data to get a segment, fail */ - if (movie->cur_fill - movie->next_segment < 4) - return NULL; + // not strictly necessary + file->buf_size = 0; + file->cur_fill = 0; + file->next_segment = 0; - /* otherwise, get the data length */ - return movie->cur_chunk + movie->next_segment + 4; + // free the struct + free(file); } -/* - * advance to next segment - */ -void mvefile_advance_segment(MVEFILE *movie) +// get the size of the next segment +int mvefile_get_next_segment_size(MVEFILE *file) { - /* if nothing is cached, fail */ - if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) - return; + // if nothing is cached, fail + if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill) + return -1; - /* if we don't have enough data to get a segment, fail */ - if (movie->cur_fill - movie->next_segment < 4) - return; - - /* else, advance to next segment */ - movie->next_segment += - (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment)); -} + // if we don't have enough data to get a segment, fail + if (file->cur_fill - file->next_segment < 4) + return -1; -/* - * fetch the next chunk (return 0 if at end of stream) - */ -int mvefile_fetch_next_chunk(MVEFILE *movie) -{ - return _mvefile_fetch_next_chunk(movie); + // otherwise, get the data length + return mve_get_short(file->cur_chunk + file->next_segment); } -/************************************************************ - * public MVESTREAM functions - ************************************************************/ - -/* - * open an MVE stream - */ -MVESTREAM *mve_open(const char *filename) +// get type of next segment in chunk (0xff if no more segments in chunk) +ubyte mvefile_get_next_segment_major(MVEFILE *file) { - MVESTREAM *movie; + // if nothing is cached, fail + if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill) + return 0xff; - /* allocate */ - movie = _mvestream_alloc(); + // if we don't have enough data to get a segment, fail + if (file->cur_fill - file->next_segment < 4) + return 0xff; - /* open */ - if (! _mvestream_open(movie, filename)) - { - _mvestream_free(movie); - return NULL; - } - - return movie; + // otherwise, get the data length + return file->cur_chunk[file->next_segment + 2]; } -/* - * close an MVE stream - */ -void mve_close(MVESTREAM *movie) +// get subtype (version) of next segment in chunk (0xff if no more segments in chunk) +ubyte mvefile_get_next_segment_minor(MVEFILE *file) { - _mvestream_free(movie); -} + // if nothing is cached, fail + if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill) + return 0xff; -/* - * set segment type handler - */ -void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler) -{ - if (major < 32) - movie->handlers[major] = handler; -} + // if we don't have enough data to get a segment, fail + if (file->cur_fill - file->next_segment < 4) + return 0xff; -/* - * set segment handler context - */ -void mve_set_handler_context(MVESTREAM *movie, void *context) -{ - movie->context = context; + // otherwise, get the data length + return file->cur_chunk[file->next_segment + 3]; } -/* - * play next chunk - */ -int mve_play_next_chunk(MVESTREAM *movie) +// see next segment (return NULL if no next segment) +ubyte *mvefile_get_next_segment(MVEFILE *file) { - unsigned char major, minor; - unsigned char *data; - int len; - - /* loop over segments */ - major = mvefile_get_next_segment_major(movie->movie); - while (major != 0xff) - { - /* check whether to handle the segment */ - if (major < 32 && movie->handlers[major] != NULL) - { - minor = mvefile_get_next_segment_minor(movie->movie); - len = mvefile_get_next_segment_size(movie->movie); - data = mvefile_get_next_segment(movie->movie); - - if (! movie->handlers[major](major, minor, data, len, movie->context)) - return 0; - } - - /* advance to next segment */ - mvefile_advance_segment(movie->movie); - major = mvefile_get_next_segment_major(movie->movie); - } - - if (! mvefile_fetch_next_chunk(movie->movie)) - return 0; - - /* return status */ - return 1; -} + // if nothing is cached, fail + if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill) + return NULL; -/************************************************************ - * private functions - ************************************************************/ + // if we don't have enough data to get a segment, fail + if (file->cur_fill - file->next_segment < 4) + return NULL; -/* - * allocate an MVEFILE - */ -static MVEFILE *_mvefile_alloc(void) -{ - MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE)); - file->stream = NULL; - file->cur_chunk = NULL; - file->buf_size = 0; - file->cur_fill = 0; - file->next_segment = 0; - - return file; + // otherwise, get the data length + return file->cur_chunk + file->next_segment + 4; } -/* - * free an MVE file - */ -static void _mvefile_free(MVEFILE *movie) +// advance to next segment +void mvefile_advance_segment(MVEFILE *file) { - /* free the stream */ - if (movie->stream) - fclose(movie->stream); - movie->stream = NULL; - - /* free the buffer */ - if (movie->cur_chunk) - free(movie->cur_chunk); - movie->cur_chunk = NULL; - - /* not strictly necessary */ - movie->buf_size = 0; - movie->cur_fill = 0; - movie->next_segment = 0; - - /* free the struct */ - free(movie); -} + // if nothing is cached, fail + if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill) + return; -/* - * open the file stream in thie object - */ -static int _mvefile_open(MVEFILE *file, const char *filename) -{ - if (! (file->stream = fopen(filename, "rb"))) - return 0; + // if we don't have enough data to get a segment, fail + if (file->cur_fill - file->next_segment < 4) + return; - return 1; + // else, advance to next segment + file->next_segment += (4 + mve_get_ushort(file->cur_chunk + file->next_segment)); } -/* - * read and verify the header of the recently opened file - */ -static int _mvefile_read_header(MVEFILE *movie) +// fetch the next chunk (return 0 if at end of stream) +int mvefile_fetch_next_chunk(MVEFILE *file) { - unsigned char buffer[26]; - - /* check the file is open */ - if (movie->stream == NULL) - return 0; - - /* check the file is long enough */ - if (fread(buffer, 1, 26, movie->stream) < 26) - return 0; - - /* check the signature */ - if (memcmp(buffer, MVE_HEADER, 20)) - return 0; - - /* check the hard-coded constants */ - if (_mve_get_short(buffer+20) != MVE_HDRCONST1) - return 0; - if (_mve_get_short(buffer+22) != MVE_HDRCONST2) - return 0; - if (_mve_get_short(buffer+24) != MVE_HDRCONST3) - return 0; - - return 1; + ubyte buffer[4]; + ubyte *new_buffer; + ushort length; + + // fail if not open + if (file->stream == NULL) + return 0; + + // fail if we can't read the next segment descriptor + if (cfread(buffer, 1, 4, file->stream) != 4) + return 0; + + // pull out the next length + length = mve_get_ushort(buffer); + + // setup a new buffer if needed -- + // only allocate new buffer is old one is too small + if (length > file->buf_size) { + // allocate new buffer + new_buffer = (ubyte *)malloc(100 + length); + + // copy old data + if (file->cur_chunk && file->cur_fill) + memcpy(new_buffer, file->cur_chunk, file->cur_fill); + + // free old buffer + if (file->cur_chunk) { + free(file->cur_chunk); + file->cur_chunk = NULL; + } + + // install new buffer + file->cur_chunk = new_buffer; + file->buf_size = 100 + length; + } + + // read the chunk + if (length > 0) { + if (cfread(file->cur_chunk, 1, length, file->stream) != length) + return 0; + } + + file->cur_fill = length; + file->next_segment = 0; + + return 1; } -static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size) -{ - unsigned char *new_buffer; - int new_len; - - /* check if this would be a redundant operation */ - if (buf_size <= movie->buf_size) - return; - - /* allocate new buffer */ - new_len = 100 + buf_size; - new_buffer = (unsigned char *)malloc(new_len); - - /* copy old data */ - if (movie->cur_chunk && movie->cur_fill) - memcpy(new_buffer, movie->cur_chunk, movie->cur_fill); - - /* free old buffer */ - if (movie->cur_chunk) - { - free(movie->cur_chunk); - movie->cur_chunk = 0; - } - - /* install new buffer */ - movie->cur_chunk = new_buffer; - movie->buf_size = new_len; -} +// ----------------------------------------------------------- +// public MVESTREAM functions +// ----------------------------------------------------------- -static int _mvefile_fetch_next_chunk(MVEFILE *movie) +// open an MVE stream +MVESTREAM *mve_open(char *filename) { - unsigned char buffer[4]; - unsigned short length; - - /* fail if not open */ - if (movie->stream == NULL) - return 0; + MVESTREAM *stream; - /* fail if we can't read the next segment descriptor */ - if (fread(buffer, 1, 4, movie->stream) < 4) - return 0; + // allocate + stream = (MVESTREAM *)malloc(sizeof(MVESTREAM)); - /* pull out the next length */ - length = _mve_get_short(buffer); + // defaults + stream->movie = NULL; - /* make sure we've got sufficient space */ - _mvefile_set_buffer_size(movie, length); + // open + stream->movie = mvefile_open(filename); - /* read the chunk */ - if (fread(movie->cur_chunk, 1, length, movie->stream) < length) - return 0; - movie->cur_fill = length; - movie->next_segment = 0; - - return 1; -} - -static short _mve_get_short(unsigned char *data) -{ - short value; - value = data[0] | (data[1] << 8); - return value; -} + if (stream->movie == NULL) { + mve_close(stream); + return NULL; + } -static unsigned short _mve_get_ushort(unsigned char *data) -{ - unsigned short value; - value = data[0] | (data[1] << 8); - return value; + return stream; } -/* - * allocate an MVESTREAM - */ -static MVESTREAM *_mvestream_alloc(void) +// close an MVE stream +void mve_close(MVESTREAM *stream) { - MVESTREAM *movie; + // close MVEFILE + if (stream->movie) + mvefile_close(stream->movie); - /* allocate and zero-initialize everything */ - movie = (MVESTREAM *)malloc(sizeof(MVESTREAM)); - movie->movie = NULL; - movie->context = 0; - memset(movie->handlers, 0, sizeof(movie->handlers)); + stream->movie = NULL; - return movie; + free(stream); } -/* - * free an MVESTREAM - */ -static void _mvestream_free(MVESTREAM *movie) +// play next chunk +int mve_play_next_chunk(MVESTREAM *stream) { - /* close MVEFILE */ - if (movie->movie) - mvefile_close(movie->movie); - movie->movie = NULL; - - /* clear context and handlers */ - movie->context = NULL; - memset(movie->handlers, 0, sizeof(movie->handlers)); -} - -/* - * open an MVESTREAM object - */ -static int _mvestream_open(MVESTREAM *movie, const char *filename) -{ - movie->movie = mvefile_open(filename); - - return (movie->movie == NULL) ? 0 : 1; + ubyte major, minor; + ubyte *data; + int len; + + // loop over segments + major = mvefile_get_next_segment_major(stream->movie); + + while (major != 0xff) { + // check whether to handle the segment + if (major < 32) { + minor = mvefile_get_next_segment_minor(stream->movie); + len = mvefile_get_next_segment_size(stream->movie); + data = mvefile_get_next_segment(stream->movie); + + switch (major) { + case 0x00: + mve_end_movie(); + break; + case 0x01: + mve_end_chunk(); + break; + case 0x02: + mve_timer_create(data); + break; + case 0x03: + mve_audio_createbuf(minor, data); + break; + case 0x04: + mve_audio_play(); + break; + case 0x05: + if (!mve_video_createbuf(minor, data)) + return 0; + break; + case 0x07: + mve_video_display(); + break; + case 0x08: + mve_audio_data(major, data); + break; + case 0x09: + mve_audio_data(major, data); + break; + case 0x0a: + if (!mve_video_init(data)) + return 0; + break; + case 0x0c: + mve_video_palette(data); + break; + case 0x0f: + mve_video_codemap(data, len); + break; + case 0x11: + mve_video_data(data, len); + break; + default: + break; + } + } + + // advance to next segment + mvefile_advance_segment(stream->movie); + major = mvefile_get_next_segment_major(stream->movie); + } + + if (!mvefile_fetch_next_chunk(stream->movie)) + return 0; + + // return status + return 1; } diff --git a/src/movie/mveplayer.cpp b/src/movie/mveplayer.cpp index bd55b81..a3d1c61 100644 --- a/src/movie/mveplayer.cpp +++ b/src/movie/mveplayer.cpp @@ -1,487 +1,460 @@ -#include -#include -#include -#include -#include - +/* + * $Logfile: /Freespace2/code/movie/mveplayer.cpp $ + * $Revision$ + * $Date$ + * $Author$ + * + * MVE movie playing routines + * + * $Log$ + * Revision 1.3 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * + * + * $NoKeywords: $ + */ + +#ifdef PLAT_UNIX +#ifdef __APPLE__ +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif // __APPLE__ +#endif // PLAT_UNIX + +#include "pstypes.h" #include "mvelib.h" -#include "bmpman.h" +#include "movie.h" #include "2d.h" -#include "mve_audio.h" #include "key.h" #include "osapi.h" +#include "timer.h" +#include "sound.h" +#include "bmpman.h" -#ifndef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) -#endif - - -static int g_spdFactorNum=0; -static int g_spdFactorDenom=10; -static int playing = 1; -void initializeMovie(MVESTREAM *mve); -void playMovie(MVESTREAM *mve); -void shutdownMovie(MVESTREAM *mve); +static int mve_playing; -#if 0 -static int doPlay(const char *filename) -{ - MVESTREAM *mve = mve_open(filename); - if (mve == NULL) - { - fprintf(stderr, "can't open MVE file '%s'\n", filename); - return 1; - } +// timer variables +static int g_spdFactorNum = 0; +static int g_spdFactorDenom = 10; +static int micro_frame_delay = 0; +static int timer_started = 0; +static fix timer_expire; - initializeMovie(mve); - playMovie(mve); - shutdownMovie(mve); +// audio variables +#define MVE_AUDIO_BUFFERS 64 // total buffers to interact with stream +static int mve_audio_curbuf_curpos = 0; +static int mve_audio_bufhead = 0; +static int mve_audio_buftail = 0; +static int mve_audio_playing = 0; +static int mve_audio_canplay = 0; +static int mve_audio_compressed = 0; +static int audiobuf_created; - mve_close(mve); +#ifdef PLAT_UNIX - return 0; -} +// struct for the audio stream information +typedef struct MVE_AUDIO_T { + ALenum format; + int sample_rate; + int bytes_per_sec; + int channels; + int bitsize; + ALuint audio_data[MVE_AUDIO_BUFFERS]; + ALuint source_id; + ALuint audio_buffer[MVE_AUDIO_BUFFERS]; +} mve_audio_t; + +mve_audio_t *mas; // mve_audio_stream + +#ifndef NDEBUG +#define OpenAL_ErrorCheck(errcode) do { \ + int i = alGetError(); \ + if (i != AL_NO_ERROR) { \ + while(i != AL_NO_ERROR) { \ + fprintf(stderr, "%s/%s:%d - OpenAL error %s\n", __FUNCTION__, __FILE__, __LINE__, alGetString(i)); \ + i = alGetError(); \ + } \ + errcode; \ + } \ +} while (0); +#else +#define OpenAL_ErrorCheck(errocode) +#endif // !NDEBUG + +#endif // PLAT_UNIX + + +// video variables +int g_width, g_height; +void *g_vBuffers = NULL; +void *g_vBackBuf1, *g_vBackBuf2; +ushort *pixelbuf = NULL; +static int g_screenWidth, g_screenHeight; +static ubyte g_palette[768]; +static ubyte *g_pCurMap=NULL; +static int g_nMapLength=0; +static int videobuf_created, video_inited; +static int hp2, wp2; +static uint mve_video_skiptimer = 0; +#ifdef PLAT_UNIX +static GLuint tex = 0; #endif -static short get_short(unsigned char *data) -{ - short value; - value = data[0] | (data[1] << 8); - return value; -} - -static unsigned short get_ushort(unsigned char *data) -{ - unsigned short value; - value = data[0] | (data[1] << 8); - return value; -} - -static int get_int(unsigned char *data) -{ - int value; - value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - return value; -} - -static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) -{ -/* fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor); */ - return 1; -} +// the decoder +void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain); /************************* * general handlers *************************/ -static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_end_movie() { - return 0; + mve_playing = 0; } /************************* * timer handlers *************************/ -/* - * timer variables - */ -static int micro_frame_delay=0; -static int timer_started=0; -static struct timeval timer_expire = {0, 0}; - -static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +int mve_timer_create(ubyte *data) { - __extension__ long long temp; - micro_frame_delay = get_int(data) * (int)get_short(data+4); - if (g_spdFactorNum != 0) - { - temp = micro_frame_delay; - temp *= g_spdFactorNum; - temp /= g_spdFactorDenom; - micro_frame_delay = (int)temp; - } + longlong temp; - return 1; + micro_frame_delay = mve_get_int(data) * (int)mve_get_short(data+4); + + if (g_spdFactorNum != 0) { + temp = micro_frame_delay; + temp *= g_spdFactorNum; + temp /= g_spdFactorDenom; + micro_frame_delay = (int)temp; + } + + return 1; } static void timer_start(void) { - int nsec=0; - gettimeofday(&timer_expire, NULL); - timer_expire.tv_usec += micro_frame_delay; - if (timer_expire.tv_usec > 1000000) - { - nsec = timer_expire.tv_usec / 1000000; - timer_expire.tv_sec += nsec; - timer_expire.tv_usec -= nsec*1000000; - } - timer_started=1; + timer_expire = timer_get_microseconds(); + timer_expire += micro_frame_delay; + + timer_started=1; } static void do_timer_wait(void) { - int nsec=0; - struct timespec ts, tsRem; - struct timeval tv; - if (! timer_started) - return; - - gettimeofday(&tv, NULL); - if (tv.tv_sec > timer_expire.tv_sec) - goto end; - else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec) - goto end; - - ts.tv_sec = timer_expire.tv_sec - tv.tv_sec; - ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec); - if (ts.tv_nsec < 0) - { - ts.tv_nsec += 1000000000UL; - --ts.tv_sec; - } - if (nanosleep(&ts, &tsRem) == -1 && errno == EINTR) - exit(1); + fix tv, ts, ts2; + + tv = timer_get_microseconds(); + + if (tv > timer_expire) + goto end; + + ts = timer_expire - tv; + + ts2 = ts/1000; + + Sleep(ts2); end: - timer_expire.tv_usec += micro_frame_delay; - if (timer_expire.tv_usec > 1000000) - { - nsec = timer_expire.tv_usec / 1000000; - timer_expire.tv_sec += nsec; - timer_expire.tv_usec -= nsec*1000000; - } + timer_expire += micro_frame_delay; } /************************* * audio handlers *************************/ -static void mve_audio_callback(void *userdata, unsigned char *stream, int len); -static short *mve_audio_buffers[64]; -static int mve_audio_buflens[64]; -static int mve_audio_curbuf_curpos=0; -static int mve_audio_bufhead=0; -static int mve_audio_buftail=0; -static int mve_audio_playing=0; -static int mve_audio_canplay=0; -#if 0 -static SDL_AudioSpec *mve_audio_spec=NULL; -#endif -static int mve_audio_compressed = 0; -static void mve_audio_callback(void *userdata, unsigned char *stream, int len) +// setup the audio information from the data stream +void mve_audio_createbuf(ubyte minor, ubyte *data) { -#if 0 - int total=0; - int length; - if (mve_audio_bufhead == mve_audio_buftail) - return /* 0 */; - -//fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); - - while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */ - && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */ - { - length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos; - memcpy(stream, /* cur output position */ - ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */ - length); /* cur input length */ - - total += length; - stream += length; /* advance output */ - len -= length; /* decrement avail ospace */ - free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */ - mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */ - mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */ - - if (++mve_audio_bufhead == 64) /* next buffer */ - mve_audio_bufhead = 0; - mve_audio_curbuf_curpos = 0; + if (audiobuf_created) + return; + + // if game sound disabled don't try and play movie audio + if (!Sound_enabled) { + mve_audio_canplay = 0; + return; + } + +#ifdef PLAT_UNIX + int i, flags, desired_buffer, sample_rate; + + mas = (mve_audio_t *) malloc ( sizeof(mve_audio_t) ); + memset(mas, 0, sizeof(mve_audio_t)); + + mas->format = AL_INVALID; + + flags = mve_get_ushort(data + 2); + sample_rate = mve_get_ushort(data + 4); + desired_buffer = mve_get_int(data + 6); + + mas->channels = (flags & 0x0001) ? 2 : 1; + mas->bitsize = (flags & 0x0002) ? 16 : 8; + + mas->sample_rate = sample_rate; + + if (minor > 0) { + mve_audio_compressed = flags & 0x0004 ? 1 : 0; + } else { + mve_audio_compressed = 0; } -//fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total); -/* return total; */ - - if (len != 0 /* ospace remaining */ - && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */ - { - memcpy(stream, /* dest */ - ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */ - len); /* length */ - - mve_audio_curbuf_curpos += len; /* advance input */ - stream += len; /* advance output (unnecessary) */ - len -= len; /* advance output (unnecessary) */ - - if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */ - { - free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */ - mve_audio_buffers[mve_audio_bufhead]=NULL; - mve_audio_buflens[mve_audio_bufhead]=0; - - if (++mve_audio_bufhead == 64) /* next buffer */ - mve_audio_bufhead = 0; - mve_audio_curbuf_curpos = 0; - } + if (mas->bitsize == 16) { + if (mas->channels == 2) { + mas->format = AL_FORMAT_STEREO16; + } else if (mas->channels == 1) { + mas->format = AL_FORMAT_MONO16; + } + } else if (mas->bitsize == 8) { + if (mas->channels == 2) { + mas->format = AL_FORMAT_STEREO8; + } else if (mas->channels == 1) { + mas->format = AL_FORMAT_MONO8; + } + } + + // somethings wrong, bail now + if (mas->format == AL_INVALID) { + mve_audio_canplay = 0; + audiobuf_created = 1; + return; + } + + alGenSources(1, &mas->source_id); + + if ((i = alGetError()) == AL_NO_ERROR) { + mve_audio_canplay = 1; + } else { + mve_audio_canplay = 0; } -//fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); + alSourcef(mas->source_id, AL_GAIN, 1.0f); + alSource3f(mas->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(mas->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alSource3f(mas->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSourcef(mas->source_id, AL_ROLLOFF_FACTOR, 0.0f ); + alSourcei(mas->source_id, AL_SOURCE_RELATIVE, AL_TRUE ); + + memset(mas->audio_buffer, 0, MVE_AUDIO_BUFFERS * sizeof(ALuint)); + + mve_audio_bufhead = 0; + mve_audio_buftail = 0; + + audiobuf_created = 1; #endif } -static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +// play and stream the audio +void mve_audio_play() { -#if 0 - int flags; - int sample_rate; - int desired_buffer; +#ifdef PLAT_UNIX + if (mve_audio_canplay) { + ALint status, bqueued; + + alGetSourceiv(mas->source_id, AL_SOURCE_STATE, &status); + + OpenAL_ErrorCheck(return); - int stereo; - int bitsize; - int compressed; - - int format; - - flags = get_ushort(data + 2); - sample_rate = get_ushort(data + 4); - desired_buffer = get_int(data + 6); - - stereo = (flags & 0x0001) ? 1 : 0; - bitsize = (flags & 0x0002) ? 1 : 0; - - if (minor > 0) { - compressed = flags & 0x0004 ? 1 : 0; - } else { - compressed = 0; - } + alGetSourcei(mas->source_id, AL_BUFFERS_QUEUED, &bqueued); - mve_audio_compressed = compressed; - - if (bitsize == 1) { - format = AUDIO_S16LSB; - } else { - format = AUDIO_U8; - } - - fprintf(stderr, "creating audio buffers:\n"); - fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n", - sample_rate, stereo, bitsize ? 16 : 8, compressed); - - mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec)); - mve_audio_spec->freq = sample_rate; - mve_audio_spec->format = format; - mve_audio_spec->channels = (stereo) ? 2 : 1; - mve_audio_spec->samples = 4096; - mve_audio_spec->callback = mve_audio_callback; - mve_audio_spec->userdata = NULL; - if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0) - { -fprintf(stderr, " success\n"); - mve_audio_canplay = 1; - } - else - { -fprintf(stderr, " failure : %s\n", SDL_GetError()); - mve_audio_canplay = 0; - } + OpenAL_ErrorCheck(return); + + mve_audio_playing = 1; - memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers)); - memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens)); + if (status != AL_PLAYING && bqueued > 0) { + alSourcePlay(mas->source_id); + OpenAL_ErrorCheck(return); + } + } #endif - return 1; } -static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +// call this in shutdown to stop and close audio +static void mve_audio_stop() { -#if 0 - if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail) - { - SDL_PauseAudio(0); - mve_audio_playing = 1; - } + if (!audiobuf_created) + return; + +#ifdef PLAT_UNIX + mve_audio_playing = 0; + + alSourceStop(mas->source_id); + alSourceUnqueueBuffers(mas->source_id, MVE_AUDIO_BUFFERS, mas->audio_buffer); + alDeleteBuffers(MVE_AUDIO_BUFFERS, mas->audio_buffer); + alDeleteSources(1, &mas->source_id); + + if (mas != NULL) { + free(mas); + mas = NULL; + } #endif - return 1; } -static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +int mve_audio_data(ubyte major, ubyte *data) { -#if 0 - static const int selected_chan=1; - int chan; - int nsamp; - if (mve_audio_canplay) - { - if (mve_audio_playing) - SDL_LockAudio(); - - chan = get_ushort(data + 2); - nsamp = get_ushort(data + 4); - if (chan & selected_chan) - { - /* HACK: +4 mveaudio_uncompress adds 4 more bytes */ - if (major == 8) { - if (mve_audio_compressed) { - nsamp += 4; - - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp); - mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */ - } else { - nsamp -= 8; - data += 8; - - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp); - memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp); - } - } else { - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp); - - memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */ - } +#ifdef PLAT_UNIX + static const int selected_chan=1; + int chan; + int nsamp; + + if (mve_audio_canplay) { + chan = mve_get_ushort(data + 2); + nsamp = mve_get_ushort(data + 4); + + if (chan & selected_chan) { + ALint bprocessed, bqueued, status; + ALuint bid; + + alGetSourcei(mas->source_id, AL_BUFFERS_PROCESSED, &bprocessed); + + OpenAL_ErrorCheck(return 0); + + while (bprocessed-- > 2) { + alSourceUnqueueBuffers(mas->source_id, 1, &bid); + // fprintf(stderr,"Unqueued buffer %d(%d)\n", mve_audio_bufhead, bid); + + if (++mve_audio_bufhead == MVE_AUDIO_BUFFERS) + mve_audio_bufhead = 0; + } + + alGetSourcei(mas->source_id, AL_BUFFERS_QUEUED, &bqueued); + + OpenAL_ErrorCheck(return 0); + + if (bqueued == 0) + mprintf(("MVE: Buffer underun (First is normal)\n")); + + alGetSourceiv(mas->source_id, AL_SOURCE_STATE, &status); + + OpenAL_ErrorCheck(return 0); + + if (mve_audio_playing && status != AL_PLAYING && bqueued > 0) { + alSourcePlay(mas->source_id); + + OpenAL_ErrorCheck(return 0); + } + + if (bqueued < MVE_AUDIO_BUFFERS) { + short *buf = NULL; + + /* HACK: +4 mveaudio_uncompress adds 4 more bytes */ + if (major == 8) { + if (mve_audio_compressed) { + nsamp += 4; + + buf = (short *)malloc(nsamp); + mveaudio_uncompress(buf, data, -1); /* XXX */ + } else { + nsamp -= 8; + data += 8; + + buf = (short *)malloc(nsamp); + memcpy(buf, data, nsamp); + } + } else { + buf = (short *)malloc(nsamp); + + memset(buf, 0, nsamp); /* XXX */ + } + + + if (!mas->audio_buffer[mve_audio_buftail]) { + alGenBuffers(1,&mas->audio_buffer[mve_audio_buftail]); + + OpenAL_ErrorCheck( {free(buf); return 0;} ); + } + + alBufferData(mas->audio_buffer[mve_audio_buftail], mas->format, buf, nsamp, mas->sample_rate); + + OpenAL_ErrorCheck( {free(buf); return 0;} ); - if (++mve_audio_buftail == 64) - mve_audio_buftail = 0; + alSourceQueueBuffers(mas->source_id, 1, &mas->audio_buffer[mve_audio_buftail]); - if (mve_audio_buftail == mve_audio_bufhead) - fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead); - } + // fprintf(stderr,"Queued buffer %d(%d)\n", mve_audio_buftail, mas->audio_buffer[mve_audio_buftail]); + OpenAL_ErrorCheck( {free(buf); return 0;} ); - if (mve_audio_playing) - SDL_UnlockAudio(); - } + if (++mve_audio_buftail == MVE_AUDIO_BUFFERS) + mve_audio_buftail = 0; + + bqueued++; + free(buf); + } else { + mprintf(("MVE: Buffer overrun: Queue full\n")); + } + + // fprintf(stderr,"Buffers queued: %d\n", bqueued); + } + } #endif - return 1; + return 1; } /************************* * video handlers *************************/ -int g_width, g_height; -void *g_vBackBuf1, *g_vBackBuf2; -#if 0 -static SDL_Surface *g_screen; -#endif -static int g_screenWidth, g_screenHeight; -static unsigned char g_palette[768]; -static unsigned char *g_pCurMap=NULL; -static int g_nMapLength=0; -static int g_truecolor; - -static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +int mve_video_createbuf(ubyte minor, ubyte *data) { - short w, h; - short count, truecolor; - w = get_short(data); - h = get_short(data+2); - - if (minor > 0) { - count = get_short(data+4); - } else { - count = 1; - } - - if (minor > 1) { - truecolor = get_short(data+6); - } else { - truecolor = 0; - } - - g_width = w << 3; - g_height = h << 3; - - /* TODO: * 4 causes crashes on some files */ - g_vBackBuf1 = malloc(g_width * g_height * 8); - if (truecolor) { - g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height); - } else { - g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height); - } - - memset(g_vBackBuf1, 0, g_width * g_height * 4); - - fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor); - - g_truecolor = truecolor; - - return 1; -} + if (videobuf_created) + return 1; -#if 0 -static int do_sdl_events() -{ - SDL_Event event; - int retr = 0; - while (SDL_PollEvent(&event)) { - switch(event.type) { - case SDL_QUIT: - exit(0); - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) - exit(0); - break; - case SDL_KEYUP: - retr = 1; - break; - case SDL_MOUSEBUTTONDOWN: -/* - if (event.button.button == SDL_BUTTON_LEFT) { - printf("GRID: %d,%d (pix:%d,%d)\n", - event.button.x / 16, event.button.y / 8, - event.button.x, event.button.y); - } -*/ - break; - default: - break; - } + short w, h; + short count, truecolor; + w = mve_get_short(data); + h = mve_get_short(data+2); + + if (minor > 0) { + count = mve_get_short(data+4); + } else { + count = 1; } - return retr; -} -#endif + if (minor > 1) { + truecolor = mve_get_short(data+6); + } else { + truecolor = 0; + } -static unsigned short stab[65536]; -static unsigned int itab[65536]; -static int table_inited; + g_width = w << 3; + g_height = h << 3; -unsigned short *pixelbuf; -static void ConvertAndDraw() -{ - int i; - - unsigned short *pDests; - unsigned int *pDesti; - unsigned short *pSrcs; - unsigned char *pixels = (unsigned char *)g_vBackBuf1; - int x, y; - -if (g_truecolor) { - pSrcs = (unsigned short *)pixels; - - /* - if (table_inited == 0) { - int r, g, b; - - table_inited = 1; - - for (i = 0; i < 65536; i++) { - r = (i & 0x7c00) >> 10; - g = (i & 0x03e0) >> 5; - b = (i & 0x001f) >> 0; - - stab[i] = 1 << 15; - stab[i] |= (r << 10)&0x7c00; - stab[i] |= (g << 5)&0x03e0; - stab[i] |= (b << 0)&0x001f; - } + /* TODO: * 4 causes crashes on some files */ + g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 8); + + if (g_vBackBuf1 == NULL) { + mprintf(("MOVIE", "ERROR: Can't allocate video buffer")); + videobuf_created = 1; + return 0; } - */ - + + g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height); + + memset(g_vBackBuf1, 0, g_width * g_height * 8); + + videobuf_created = 1; + + return 1; +} + +static void mve_convert_and_draw() +{ + ushort *pDests; + ushort *pSrcs; + ushort *pixels = (ushort *)g_vBackBuf1; + int x, y; + + pSrcs = pixels; + pDests = pixelbuf; if (g_screenWidth > g_width) { @@ -493,202 +466,297 @@ if (g_truecolor) { for (y=0; yformat->palette->colors[i].r = (*pal++) << 2; - initSprite->format->palette->colors[i].g = (*pal++) << 2; - initSprite->format->palette->colors[i].b = (*pal++) << 2; - initSprite->format->palette->colors[i].unused = 0; - } - } - - pDest = initSprite->pixels; - for (i=0; ipitch; - } - - screenSprite = SDL_DisplayFormat(initSprite); - SDL_FreeSurface(initSprite); - - if (g_screenWidth > screenSprite->w) x = (g_screenWidth - screenSprite->w) >> 1; - else x=0; - if (g_screenHeight > screenSprite->h) y = (g_screenHeight - screenSprite->h) >> 1; - else y=0; - renderArea.x = x; - renderArea.y = y; - renderArea.w = MIN(g_screenWidth - x, screenSprite->w); - renderArea.h = MIN(g_screenHeight - y, screenSprite->h); - SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea); - - SDL_FreeSurface(screenSprite); -#endif -} - } -static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_video_display() { - ConvertAndDraw(); -#if 0 - - SDL_Flip(g_screen); + fix t1 = timer_get_fixed_seconds(); + mve_convert_and_draw(); - do_sdl_events(); -#endif - /* DDOI - This is probably really fricking slow */ - int bitmap = bm_create (16, g_screenWidth, g_screenHeight, pixelbuf, 0); + // centers on 1024x768, fills on 640x480 + int x = ((gr_screen.max_w - g_screenWidth) / 2); + int y = ((gr_screen.max_h - g_screenHeight) / 2); + int h = g_screenHeight; + int w = g_screenWidth; + +#ifdef PLAT_UNIX + // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch + if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) { + // we are running slow so subtract desired time from actual and skip this frame + mve_video_skiptimer -= (micro_frame_delay/10); + return; + } else { + // zero out so we can get a new count + mve_video_skiptimer = 0; + } + + glBindTexture(GL_TEXTURE_2D, tex); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixelbuf); + + // 0, 0 + glBegin(GL_QUADS); + glTexCoord2f(0,0); glVertex2i(x,y); + glTexCoord2f(0,i2fl(256)/i2fl(hp2)); glVertex2i(x,y+256); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+256,y+256); + glTexCoord2f(i2fl(256)/i2fl(wp2),0); glVertex2i(x+256,y); + glEnd(); + + // 0, 256 + glBegin(GL_QUADS); + glTexCoord2f(0,i2fl(256)/i2fl(hp2)); glVertex2i(x,y+256); + glTexCoord2f(0,i2fl(h)/i2fl(hp2)); glVertex2i(x,y+h); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2)); glVertex2i(x+256,y+h); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+256,y+256); + glEnd(); + + // 256, 0 + glBegin(GL_QUADS); + glTexCoord2f(i2fl(256)/i2fl(wp2),0); glVertex2i(x+256,y); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+256,y+256); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+512,y+256); + glTexCoord2f(i2fl(512)/i2fl(wp2),0); glVertex2i(x+512,y); + glEnd(); + + // 256, 256 + glBegin(GL_QUADS); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+256,y+256); + glTexCoord2f(i2fl(256)/i2fl(wp2),i2fl(h)/i2fl(hp2)); glVertex2i(x+256,y+h); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2)); glVertex2i(x+512,y+h); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+512,y+256); + glEnd(); + + // 512, 0 + glBegin(GL_QUADS); + glTexCoord2f(i2fl(512)/i2fl(wp2),0); glVertex2i(x+512,y); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+512,y+256); + glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+w,y+256); + glTexCoord2f(i2fl(w)/i2fl(wp2),0); glVertex2i(x+w,y); + glEnd(); + + // 512, 256 + glBegin(GL_QUADS); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+512,y+256); + glTexCoord2f(i2fl(512)/i2fl(wp2),i2fl(h)/i2fl(hp2)); glVertex2i(x+512,y+h); + glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(h)/i2fl(hp2)); glVertex2i(x+w,y+h); + glTexCoord2f(i2fl(w)/i2fl(wp2),i2fl(256)/i2fl(hp2)); glVertex2i(x+w,y+256); + glEnd(); +#else + // DDOI - This is probably really fricking slow + int bitmap = bm_create (16, w, h, pixelbuf, 0); gr_set_bitmap (bitmap); - gr_bitmap (0, 0); + gr_bitmap (x, y); bm_release (bitmap); +#endif + gr_flip (); #ifdef PLAT_UNIX os_poll (); /* DDOI - run event loop(s) */ #endif - if (key_check (KEY_ESC)) playing = 0; - - return 1; + + fix t2 = timer_get_fixed_seconds(); + + // only get a new count if we are definitely through with old count + if ( mve_video_skiptimer == 0 ) { + // for a more accurate count convert the frame rate to a float and multiply + // by one-hundred-thousand before converting to an uint. + mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000); + } + + int k = key_inkey(); + if ( k == KEY_ESC ) { + mve_playing = 0; + } + +// fprintf(stderr, "mve frame took this long: %.6f\n", f2fl(t2-t1)); } -static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +int mve_video_init(ubyte *data) { - short width, height; - width = get_short(data); - height = get_short(data+2); -#if 0 - g_screen = SDL_SetVideoMode(width, height, 16, SDL_ANYFORMAT|SDL_DOUBLEBUF); + if (video_inited) + return 1; + + short width, height; + + width = mve_get_short(data); + height = mve_get_short(data+2); + + // DDOI - Allocate RGB565 pixel buffer + pixelbuf = (ushort *)malloc (width * height * 2); + + if (pixelbuf == NULL) { + mprintf(("MOVIE", "ERROR: Can't allocate memory for pixelbuf")); + video_inited = 1; + return 0; + } + + memset(pixelbuf, 0, width * height * 2); + + g_screenWidth = width; + g_screenHeight = height; + +#ifdef PLAT_UNIX + int i, tex_w, tex_h; + + tex_w = g_screenWidth; + tex_h = g_screenHeight; + + // set height and width to a power of 2 + for (i=0; i<16; i++ ) { + if ( (tex_w > (1< (1< 8) + tex_h = tex_w/8; + if (tex_h/tex_w > 8) + tex_w = tex_h/8; + + wp2 = tex_w; + hp2 = tex_h; + + glGenTextures(1, &tex); + + Assert(tex != 0); + + if ( tex == 0 ) { + mprintf(("MOVIE", "ERROR: Can't create a GL texture")); + video_inited = 1; + return 0; + } + + glBindTexture(GL_TEXTURE_2D, tex); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf so less of two evils... + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, wp2, hp2, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); #endif - // DDOI - Allocate RGB565 pixel buffer - pixelbuf = (unsigned short *)malloc (width * height * 2); - g_screenWidth = width; - g_screenHeight = height; - memset(g_palette, 0, 768); - return 1; + + memset(g_palette, 0, 768); + + video_inited = 1; + + return 1; } -static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_video_palette(ubyte *data) { - short start, count; - start = get_short(data); - count = get_short(data+2); - memcpy(g_palette + 3*start, data+4, 3*count); - return 1; + short start, count; + start = mve_get_short(data); + count = mve_get_short(data+2); + memcpy(g_palette + 3*start, data+4, 3*count); } -static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_video_codemap(ubyte *data, int len) { - g_pCurMap = data; - g_nMapLength = len; - return 1; + g_pCurMap = data; + g_nMapLength = len; } -void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain); - -static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_video_data(ubyte *data, int len) { - short nFrameHot, nFrameCold; - short nXoffset, nYoffset; - short nXsize, nYsize; - unsigned short nFlags; - unsigned char *temp; - - nFrameHot = get_short(data); - nFrameCold = get_short(data+2); - nXoffset = get_short(data+4); - nYoffset = get_short(data+6); - nXsize = get_short(data+8); - nYsize = get_short(data+10); - nFlags = get_ushort(data+12); - - if (nFlags & 1) - { - temp = (unsigned char *)g_vBackBuf1; - g_vBackBuf1 = g_vBackBuf2; - g_vBackBuf2 = temp; - } - - /* convert the frame */ - if (g_truecolor) { - decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14); -#if 0 - } else { - decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14); -#endif - } + short nFrameHot, nFrameCold; + short nXoffset, nYoffset; + short nXsize, nYsize; + ushort nFlags; + ubyte *temp; + + nFrameHot = mve_get_short(data); + nFrameCold = mve_get_short(data+2); + nXoffset = mve_get_short(data+4); + nYoffset = mve_get_short(data+6); + nXsize = mve_get_short(data+8); + nYsize = mve_get_short(data+10); + nFlags = mve_get_ushort(data+12); + + if (nFlags & 1) { + temp = (ubyte *)g_vBackBuf1; + g_vBackBuf1 = g_vBackBuf2; + g_vBackBuf2 = temp; + } - return 1; + decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14); } -static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +void mve_end_chunk() { - g_pCurMap=NULL; - return 1; + g_pCurMap = NULL; } -void initializeMovie(MVESTREAM *mve) +void mve_init(MVESTREAM *mve) { - int i; - - for (i = 0; i < 32; i++) { - mve_set_handler(mve, i, default_seg_handler); - } - - mve_set_handler(mve, 0x00, end_movie_handler); - mve_set_handler(mve, 0x01, end_chunk_handler); - mve_set_handler(mve, 0x02, create_timer_handler); - mve_set_handler(mve, 0x03, create_audiobuf_handler); - mve_set_handler(mve, 0x04, play_audio_handler); - mve_set_handler(mve, 0x05, create_videobuf_handler); - mve_set_handler(mve, 0x07, display_video_handler); - mve_set_handler(mve, 0x08, audio_data_handler); - mve_set_handler(mve, 0x09, audio_data_handler); - mve_set_handler(mve, 0x0a, init_video_handler); - mve_set_handler(mve, 0x0c, video_palette_handler); - mve_set_handler(mve, 0x0f, video_codemap_handler); - mve_set_handler(mve, 0x11, video_data_handler); + // reset to default values + mve_audio_curbuf_curpos = 0; + mve_audio_bufhead = 0; + mve_audio_buftail = 0; + mve_audio_playing = 0; + mve_audio_canplay = 0; + mve_audio_compressed = 0; + audiobuf_created = 0; + + videobuf_created = 0; + video_inited = 0; + + mve_playing = 1; } -void playMovie(MVESTREAM *mve) +void mve_play(MVESTREAM *mve) { - int init_timer=0; - int cont=1; - while (cont && playing) - { - cont = mve_play_next_chunk(mve); - if (micro_frame_delay && !init_timer) - { - timer_start(); - init_timer = 1; - } - - do_timer_wait(); - } + int init_timer = 0; + int cont = 1; + + if (micro_frame_delay && !init_timer) { + timer_start(); + init_timer = 1; + } + + while (cont && mve_playing) { + cont = mve_play_next_chunk(mve); + + do_timer_wait(); + } } -void shutdownMovie(MVESTREAM *mve) +void mve_shutdown() { - free (pixelbuf); + mve_audio_stop(); + + if (pixelbuf != NULL) { + free(pixelbuf); + pixelbuf = NULL; + } + + if (g_vBuffers != NULL) { + free(g_vBuffers); + g_vBuffers = NULL; + } + +#ifdef PLAT_UNIX + glDeleteTextures(1, &tex); + tex = 0; + + glEnable(GL_DEPTH_TEST); +#endif } diff --git a/src/platform/unix.cpp b/src/platform/unix.cpp index 611becd..cd2fab2 100644 --- a/src/platform/unix.cpp +++ b/src/platform/unix.cpp @@ -23,6 +23,11 @@ void strlwr (char * str) while (*str) {*str = tolower (*str); str++; } } +void strupr (char * str) +{ + while (*str) {*str = toupper (*str); str++; } +} + int filelength (int fd) { struct stat buf; diff --git a/src/sound/ds.cpp b/src/sound/ds.cpp index e7bdd96..ad9db65 100644 --- a/src/sound/ds.cpp +++ b/src/sound/ds.cpp @@ -15,6 +15,11 @@ * C file for interface to DirectSound * * $Log$ + * Revision 1.20 2005/03/29 07:50:34 taylor + * Update to newest movie code with much better video support and audio support from + * Pierre Willenbrock. Movies are enabled always now (no longer a build option) + * and but can be skipped with the "--nomovies" or "-n" cmdline options. + * * Revision 1.19 2004/07/04 11:39:06 taylor * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT * @@ -1463,8 +1468,9 @@ int ds_init(int use_a3d, int use_eax) { #ifdef PLAT_UNIX // NOTE: A3D and EAX are unused in OpenAL - ALCubyte *initStr = (ubyte *)"\'( (sampling-rate 22050 ))"; - int attr[] = { ALC_FREQUENCY, 22050, ALC_SYNC, AL_FALSE, 0 }; + // changed from 22050 to 44100 so that movies don't sound like crap + ALCubyte *initStr = (ubyte *)"\'( (sampling-rate 44100 ))"; + int attr[] = { ALC_FREQUENCY, 44100, ALC_SYNC, AL_FALSE, 0 }; Ds_use_a3d = 0; Ds_use_eax = 0; -- 2.39.2