From 44f0c0d870a97187e6abbb8cf58b4a6f325193c9 Mon Sep 17 00:00:00 2001 From: Bradley Bell Date: Mon, 22 Jul 2002 02:20:05 +0000 Subject: [PATCH] initial movie support --- include/mve_audio.h | 6 + include/mvelib.h | 100 +++++ main/Makefile.am | 4 +- main/inferno.c | 4 +- main/kludge.c | 66 +-- main/movie.c | 513 ++++++++++++---------- main/mve_audio.c | 55 +++ main/mvelib.c | 440 +++++++++++++++++++ main/mveplay.c | 1014 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1907 insertions(+), 295 deletions(-) create mode 100644 include/mve_audio.h create mode 100644 include/mvelib.h create mode 100644 main/mve_audio.c create mode 100644 main/mvelib.c create mode 100644 main/mveplay.c diff --git a/include/mve_audio.h b/include/mve_audio.h new file mode 100644 index 00000000..a42b60fe --- /dev/null +++ b/include/mve_audio.h @@ -0,0 +1,6 @@ +#ifndef INCLUDED_MVE_AUDIO_H +#define INCLUDED_MVE_AUDIO_H + +void mveaudio_uncompress(short *buffer, unsigned char *data, int length); + +#endif /* INCLUDED_MVE_AUDIO_H */ diff --git a/include/mvelib.h b/include/mvelib.h new file mode 100644 index 00000000..84b0b7a8 --- /dev/null +++ b/include/mvelib.h @@ -0,0 +1,100 @@ +#ifndef INCLUDED_MVELIB_H +#define INCLUDED_MVELIB_H + +#include +#include + +/* + * structure for maintaining info on a MVEFILE stream + */ +typedef struct MVEFILE +{ + int stream; + unsigned char *cur_chunk; + int buf_size; + int cur_fill; + int next_segment; +} MVEFILE; + +/* + * open a .MVE file + */ +MVEFILE *mvefile_open(int filehandle); + +/* + * close a .MVE file + */ +void mvefile_close(MVEFILE *movie); + +/* + * 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 subtype (version) of next segment in chunk (0xff if no more segments in + * chunk) + */ +unsigned char mvefile_get_next_segment_minor(MVEFILE *movie); + +/* + * see next segment (return NULL if no next segment) + */ +unsigned char *mvefile_get_next_segment(MVEFILE *movie); + +/* + * advance to next segment + */ +void mvefile_advance_segment(MVEFILE *movie); + +/* + * 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 + */ +typedef struct MVESTREAM +{ + MVEFILE *movie; + void *context; + MVESEGMENTHANDLER handlers[32]; +} MVESTREAM; + +/* + * open an MVE stream + */ +MVESTREAM *mve_open(int filehandle); + +/* + * 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 + */ +int mve_play_next_chunk(MVESTREAM *movie); + +#endif /* INCLUDED_MVELIB_H */ diff --git a/main/Makefile.am b/main/Makefile.am index 93a8fba6..218f0714 100644 --- a/main/Makefile.am +++ b/main/Makefile.am @@ -23,9 +23,7 @@ if SHAREWARE SHAREWARE_SRCS = terrain.c endif -if MOVIE_TRICK -MOVIE_SRCS = movie.c -endif +MOVIE_SRCS = movie.c mvelib.c mve_audio.c mveplay.c libmain_a_SOURCES = \ ${EDITOR_SRCS} ${NETWORK_SRCS} ${SHAREWARE_SRCS} ${MOVIE_SRCS} \ diff --git a/main/inferno.c b/main/inferno.c index eed52872..7ea9462a 100644 --- a/main/inferno.c +++ b/main/inferno.c @@ -1,4 +1,4 @@ -/* $Id: inferno.c,v 1.31 2002-07-18 08:35:58 bradleyb Exp $ */ +/* $Id: inferno.c,v 1.32 2002-07-22 02:20:05 btb Exp $ */ /* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO @@ -293,7 +293,7 @@ void print_commandline_help() printf( " -stickmag %s\n","FIXME: Undocumented"); #endif // printf( " -stopwatch %s\n","FIXME: Undocumented"); -// printf( " -subtitles %s\n","Turn on movie subtitles (English-only)"); + printf( " -subtitles %s\n","Turn on movie subtitles (English-only)"); // printf( " -sysram %s\n","FIXME: Undocumented"); printf( " -text %s\n","Specify alternate .tex file"); // printf( " -tsengdebug1 %s\n","FIXME: Undocumented"); diff --git a/main/kludge.c b/main/kludge.c index ca557c8e..dc36d03f 100644 --- a/main/kludge.c +++ b/main/kludge.c @@ -12,15 +12,11 @@ int gr_renderstats = 0; int gr_badtexture = 0; extern int VGA_current_mode; -#ifndef MOVIE_TRICK -int MovieHires = 1; -int MVEPaletteCalls = 0; -int robot_movies = 0; -#endif int Dont_start_sound_objects = 1; int Window_clip_left,Window_clip_top,Window_clip_right,Window_clip_bot; -#ifndef MOVIE_TRICK + +#if 0 char CDROM_dir[40] = "."; #else char CDROM_dir[40] = "/cdrom/d2data/"; @@ -48,13 +44,6 @@ void joy_set_btn_values( int btn, int state, int time_down, int downcount, int u } #endif -#ifndef MOVIE_TRICK -int request_cd(void) -{ - return 0; -} -#endif - void key_putkey(char i) { @@ -80,38 +69,6 @@ void g3_remap_interp_colors() } */ -#ifndef MOVIE_TRICK -void init_movies() -{ - -} - -int InitMovieBriefing() -{ - return 0; -} - -void RotateRobot() -{ - -} - -int InitRobotMovie(char *a) -{ - return 0; -} - -void DeInitRobotMovie(void) -{ - -} - -void init_extra_robot_movie(char *f) -{ - -} -#endif - int com_init(void) { return 0; @@ -183,13 +140,6 @@ void digi_play_midi_song(void) } -#ifndef MOVIE_TRICK -int PlayMovie(const char *a, int b) -{ - return 0; -} -#endif - void digi_pause_digi_sounds() { @@ -217,15 +167,3 @@ void digi_start_sound_queued( short soundnum, fix volume ) { } - -#ifndef MOVIE_TRICK -void init_subtitles() -{ - -} - -void close_subtitles() -{ - -} -#endif diff --git a/main/movie.c b/main/movie.c index 3f33a1d5..e66f9e10 100644 --- a/main/movie.c +++ b/main/movie.c @@ -1,3 +1,4 @@ +/* $ Id: $ */ /* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO @@ -11,49 +12,50 @@ AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ -/* - * $Source: /cvs/cvsroot/d2x/main/movie.c,v $ - * $Revision: 1.1 $ - * $Author: bradleyb $ - * $Date: 2002-01-18 07:26:54 $ - * - * Movie stuff (converts mve's to exe files, and plays them externally (e.g. with wine) - * - * $Log: not supported by cvs2svn $ - * - */ - #ifdef HAVE_CONFIG_H #include #endif +#ifdef RCS +static char rcsid[] = "$Id: movie.c,v 1.2 2002-07-22 02:20:05 btb Exp $"; +#endif + +#define DEBUG_LEVEL CON_NORMAL + #include -#include +#include +#include #include +#include #include -#include -#include -#include "inferno.h" -#include "args.h" #include "movie.h" +#include "console.h" +#include "args.h" #include "key.h" +#include "digi.h" #include "songs.h" +#include "inferno.h" +#include "palette.h" #include "strutil.h" -#include "mono.h" #include "error.h" -#include "digi.h" #include "u_mem.h" #include "byteswap.h" -#include "cfile.h" #include "gr.h" -#include "palette.h" -#include "newmenu.h" +#include "gamefont.h" +#include "cfile.h" +#include "menu.h" +#include "mvelib.h" +#include "text.h" -int RoboFile=0,MVEPaletteCalls=0; +extern int MenuHiresAvailable; +extern char CDROM_dir[]; + +#define VID_PLAY 0 +#define VID_PAUSE 1 + +int Vid_State; -// Function Prototypes -int RunMovie(char *filename, int highres_flag, int allow_abort,int dx,int dy); // Subtitle data typedef struct { @@ -61,14 +63,56 @@ typedef struct { char *msg; } subtitle; - -// #define BUFFER_MOVIE - #define MAX_SUBTITLES 500 +#define MAX_ACTIVE_SUBTITLES 3 subtitle Subtitles[MAX_SUBTITLES]; int Num_subtitles; -int MovieHires = 0; //default for now is lores + +typedef struct { + char name[FILENAME_LEN]; + int offset,len; +} ml_entry; + +#define MLF_ON_CD 1 +#define MAX_MOVIES_PER_LIB 50 //determines size of malloc + + +typedef struct { + char name[100]; //[FILENAME_LEN]; + int n_movies; + ubyte flags,pad[3]; + ml_entry *movies; +} movielib; + +#ifdef D2_OEM +char *movielib_files[] = {"intro-l.mvl","other-l.mvl","robots-l.mvl","oem-l.mvl"}; +#else +char *movielib_files[] = {"intro-l.mvl","other-l.mvl","robots-l.mvl"}; +#endif + +#define N_BUILTIN_MOVIE_LIBS (sizeof(movielib_files)/sizeof(*movielib_files)) +#define N_MOVIE_LIBS (N_BUILTIN_MOVIE_LIBS+1) +#define EXTRA_ROBOT_LIB N_BUILTIN_MOVIE_LIBS +movielib *movie_libs[N_MOVIE_LIBS]; + +int MVEPaletteCalls = 0; + +//do we have the robot movies available +int robot_movies = 0; //0 means none, 1 means lowres, 2 means hires + +int MovieHires = 0; //default for now is lores + + +// Function Prototypes +int RunMovie(char *filename, int highres_flag, int allow_abort,int dx,int dy); + +int open_movie_file(char *filename,int must_have); + +void change_filename_ext( char *dest, char *src, char *ext ); +void decode_text_line(char *p); +void draw_subtitles(int frame_num); + //filename will actually get modified to be either low-res or high-res //returns status. see values in movie.h @@ -76,6 +120,9 @@ int PlayMovie(const char *filename, int must_have) { char name[FILENAME_LEN],*p; int c, ret; + int save_sample_rate; + + con_printf(DEBUG_LEVEL, "movie: PlayMovie: %s %d\n", filename, must_have); #ifndef RELEASE if (FindArg("-nomovies")) @@ -98,31 +145,45 @@ int PlayMovie(const char *filename, int must_have) // Stop all songs songs_stop_all(); + save_sample_rate = digi_sample_rate; + digi_sample_rate = SAMPLE_RATE_22K; //always 22K for movies + digi_reset(); digi_reset(); + ret = RunMovie(name,MovieHires,must_have,-1,-1); + //gr_palette_clear(); //clear out palette in case movie aborted + + digi_sample_rate = save_sample_rate; //restore rate for game + digi_reset(); digi_reset(); + + //Screen_mode = -1; //force screen reset + return ret; } - -int open_movie_file(char *filename,int must_have, int *lenp); + +void initializeMovie(MVESTREAM *mve); +void shutdownMovie(MVESTREAM *mve); //returns status. see movie.h int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy) { - int filehndl, size; - int aborted=0; + int filehndl; + int result=1,aborted=0; + int frame_num; + MVESTREAM *mve; + + con_printf(DEBUG_LEVEL, "movie: RunMovie: %s, %d, %d, %d\n", filename, hires_flag, must_have, dx, dy); // Open Movie file. If it doesn't exist, no movie, just return. - filehndl = open_movie_file(filename,must_have, &size); + filehndl = open_movie_file(filename,must_have); if (filehndl == -1) { #ifndef EDITOR - if (must_have) - { - strupr(filename); - Error("Cannot open movie file <%s>",filename); - } - else + if (must_have) { + strupr(filename); + Error("movie: RunMovie: Cannot open movie file <%s>",filename); + } else return MOVIE_NOT_PLAYED; #else return MOVIE_NOT_PLAYED; @@ -131,110 +192,109 @@ int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy) #if 0 if (hires_flag) - gr_set_mode(SM_640x480V); + gr_set_mode(SM(640,480)); else - gr_set_mode(SM_320x200C); + gr_set_mode(SM(320,200)); #endif - // play! - { - char *buf; - int len; - FILE *fil; - struct stat stats; - char *stubfile; - char *execcmd; - - strcpy(filename+strlen(filename)-4,".exe"); //change extension - if (stat(filename, &stats)) { - stubfile = "fstrailw.stub"; - if (stat(stubfile, &stats)) { - con_printf(CON_NORMAL, "Error loading %s, aborting movie.\n", stubfile); - return MOVIE_NOT_PLAYED; - } - - len = stats.st_size; - buf = d_malloc(len); - fil = fopen(stubfile, "r"); - fread(buf, len, 1, fil); - fclose(fil); - - fil = fopen(filename, "w"); - fwrite(buf, len, 1, fil); - d_free(buf); - - len = size; - buf = d_malloc(len); - read(filehndl, buf, len); - fwrite(buf, len, 1, fil); - d_free(buf); - fclose(fil); + frame_num = 0; + + FontHires = hires_flag; + + mve = mve_open(filehndl); + if (mve == NULL) + { + fprintf(stderr, "can't open MVE file '%s'\n", filename); + return 1; + } + + initializeMovie(mve); + + while((result = mve_play_next_chunk(mve))) { + int key; + + draw_subtitles(frame_num); + + key = key_inkey(); + + // If ESCAPE pressed, then quit movie. + if (key == KEY_ESC) { + result = aborted = 1; + break; } - sprintf(execcmd, "wine %s", filename); - if(system(execcmd) == -1) { - con_printf(CON_NORMAL, "Error executing %s, movie aborted.\n", filename); - return MOVIE_NOT_PLAYED; + + // If PAUSE pressed, then pause movie + if (key == KEY_PAUSE) { + //MVE_rmHoldMovie(); + //show_pause_message(TXT_PAUSE); + while (!key_inkey()) ; + //clear_pause_message(); } - + frame_num++; } + Assert(aborted || !result); ///movie should be over + + shutdownMovie(mve); + mve_close(mve); + close(filehndl); // Close Movie File - Screen_mode=-1; //force reset of screen mode - + // Restore old graphic state + + //Screen_mode=-1; //force reset of screen mode + return (aborted?MOVIE_ABORTED:MOVIE_PLAYED_FULL); } -int InitMovieBriefing () -{ - return 1; -} -//returns 1 if frame updated ok -int RotateRobot () +int InitMovieBriefing() { + con_printf(DEBUG_LEVEL, "movie: InitMovieBriefing\n"); + +#if 0 + if (MenuHires) + gr_set_mode(SM(640,480)); + else + gr_set_mode(SM(320,200)); +#endif return 1; } -void DeInitRobotMovie() -{ - close(RoboFile); // Close Movie File -} -int InitRobotMovie (char *filename) +void RotateRobot() { - int len; + con_printf(DEBUG_LEVEL, "STUB: movie: RotateRobot\n"); +} - if (FindArg("-nomovies")) - return MOVIE_NOT_PLAYED; -// digi_stop_all(); +void DeInitRobotMovie(void) +{ + con_printf(DEBUG_LEVEL, "STUB: movie: DeInitRobotMovie\n"); +} - mprintf ((0,"RoboFile=%s\n",filename)); - RoboFile = open_movie_file(filename,1, &len); +int InitRobotMovie(char *a) +{ + con_printf(DEBUG_LEVEL, "STUB: movie: InitRobotMovie: %s\n", a); - if (RoboFile == -1) { - #ifdef RELEASE - Error("Cannot open movie file <%s>",filename); - #else - return MOVIE_NOT_PLAYED; - #endif - } - - return 1; + return 0; } + /* * Subtitle system code */ ubyte *subtitle_raw_data; + //search for next field following whitespace ubyte *next_field(ubyte *p) { + con_printf(DEBUG_LEVEL, "movie: next_field: %c\n", *p); + while (*p && !isspace(*p)) p++; @@ -250,8 +310,6 @@ ubyte *next_field(ubyte *p) return p; } -void change_filename_ext( char *dest, char *src, char *ext ); -void decode_text_line(char *p); int init_subtitles(char *filename) { @@ -260,6 +318,8 @@ int init_subtitles(char *filename) ubyte *p; int have_binary = 0; + con_printf(DEBUG_LEVEL, "movie: init_subtitles: %s\n", filename); + Num_subtitles = 0; if (! FindArg("-subtitles")) @@ -278,16 +338,16 @@ int init_subtitles(char *filename) size = cfilelength(ifile); - MALLOC (subtitle_raw_data, ubyte, size+1); + MALLOC (subtitle_raw_data, ubyte, size+1); - read_count = cfread(subtitle_raw_data, 1, size, ifile); + read_count = cfread(subtitle_raw_data, 1, size, ifile); cfclose(ifile); subtitle_raw_data[size] = 0; if (read_count != size) { - free(subtitle_raw_data); + d_free(subtitle_raw_data); return 0; } @@ -324,32 +384,83 @@ int init_subtitles(char *filename) } return 1; - } + void close_subtitles() { + con_printf(DEBUG_LEVEL, "movie: close_subtitles\n"); + if (subtitle_raw_data) - free(subtitle_raw_data); + d_free(subtitle_raw_data); subtitle_raw_data = NULL; Num_subtitles = 0; } -typedef struct { - char name[FILENAME_LEN]; - int offset,len; -} ml_entry; -#define MLF_ON_CD 0 +//draw the subtitles for this frame +void draw_subtitles(int frame_num) +{ + static int active_subtitles[MAX_ACTIVE_SUBTITLES]; + static int num_active_subtitles,next_subtitle,line_spacing; + int t,y; + int must_erase=0; + + con_printf(DEBUG_LEVEL, "movie: draw_subtitles: %d\n", frame_num); + + if (frame_num == 0) { + num_active_subtitles = 0; + next_subtitle = 0; + gr_set_curfont( GAME_FONT ); + line_spacing = grd_curcanv->cv_font->ft_h + (grd_curcanv->cv_font->ft_h >> 2); + gr_set_fontcolor(255,-1); + } -typedef struct { - char name[100]; //[FILENAME_LEN]; - int n_movies; - ubyte flags,pad[3]; - ml_entry movies[1]; -} movielib; + //get rid of any subtitles that have expired + for (t=0;t Subtitles[active_subtitles[t]].last_frame) { + int t2; + for (t2=t;t2= Subtitles[next_subtitle].first_frame) { + if (num_active_subtitles >= MAX_ACTIVE_SUBTITLES) + Error("Too many active subtitles!"); + active_subtitles[num_active_subtitles++] = next_subtitle; + next_subtitle++; + } + + //find y coordinate for first line of subtitles + y = grd_curcanv->cv_bitmap.bm_h-((line_spacing+1)*MAX_ACTIVE_SUBTITLES+2); + + //erase old subtitles if necessary + if (must_erase) { + gr_setcolor(0); + gr_rect(0,y,grd_curcanv->cv_bitmap.bm_w-1,grd_curcanv->cv_bitmap.bm_h-1); + } + + //now draw the current subtitles + for (t=0;tmovies, ml_entry, nfiles); strcpy(table->name,filename); table->n_movies = nfiles; @@ -394,16 +509,19 @@ movielib *init_new_movie_lib(char *filename,FILE *fp) } + movielib *init_old_movie_lib(char *filename,FILE *fp) { int nfiles,size; int i; movielib *table,*table2; + con_printf(DEBUG_LEVEL, "movie: init_old_movie_lib: %s\n", filename); + nfiles = 0; //allocate big table - table = malloc(sizeof(*table) + sizeof(ml_entry)*MAX_MOVIES_PER_LIB); + table = d_malloc(sizeof(*table) + sizeof(ml_entry)*MAX_MOVIES_PER_LIB); while( 1 ) { int len; @@ -426,9 +544,9 @@ movielib *init_old_movie_lib(char *filename,FILE *fp) //allocate correct-sized table size = sizeof(*table) + sizeof(ml_entry)*nfiles; - table2 = malloc(size); + table2 = d_malloc(size); memcpy(table2,table,size); - free(table); + d_free(table); table = table2; strcpy(table->name,filename); @@ -443,6 +561,7 @@ movielib *init_old_movie_lib(char *filename,FILE *fp) } + //find the specified movie library, and read in list of movies in it movielib *init_movie_lib(char *filename) { @@ -451,6 +570,8 @@ movielib *init_movie_lib(char *filename) char id[4]; FILE * fp; + con_printf(DEBUG_LEVEL, "movie: init_movie_lib: %s\n", filename); + fp = fopen( filename, "rb" ); if ( fp == NULL ) return NULL; @@ -468,106 +589,41 @@ movielib *init_movie_lib(char *filename) } } -#ifdef D2_OEM -char *movielib_files[] = {"intro-l.mvl","other-l.mvl","robots-l.mvl","oem-l.mvl"}; -#else -char *movielib_files[] = {"intro-l.mvl","other-l.mvl","robots-l.mvl"}; -#endif - -#define N_BUILTIN_MOVIE_LIBS (sizeof(movielib_files)/sizeof(*movielib_files)) -#define N_MOVIE_LIBS (N_BUILTIN_MOVIE_LIBS+1) -#define EXTRA_ROBOT_LIB N_BUILTIN_MOVIE_LIBS -movielib *movie_libs[N_MOVIE_LIBS]; void close_movie(int i) { - if (movie_libs[i]) - free(movie_libs[i]); + con_printf(DEBUG_LEVEL, "movie: close_movie\n"); + + if (movie_libs[i]) { + d_free(movie_libs[i]->movies); + d_free(movie_libs[i]); + } } + void close_movies() { int i; + con_printf(DEBUG_LEVEL, "movie: close_movies\n"); + for (i=0;icv_w,grd_curcanv->cv_h); - - gr_set_current_canvas(tcanv); - gr_ubitmap(0,0,&save_canv->cv_bitmap); - gr_set_current_canvas(save_canv); - - gr_clear_canvas(BM_XRGB(0,0,0)); - - memcpy(save_pal,gr_palette,sizeof(save_pal)); - - memcpy(gr_palette,last_palette_for_color_fonts,sizeof(gr_palette)); - -try_again:; - - ret = nm_messagebox( "CD ERROR", 1, "Ok", "Please insert your Descent II CD"); - - if (ret == -1) { - int ret2; - - ret2 = nm_messagebox( "CD ERROR", 2, "Try Again", "Leave Game", "You must insert your\nDescent II CD to Continue"); - - if (ret2 == -1 || ret2 == 0) - goto try_again; - } - - force_rb_register = 1; //disc has changed; force register new CD - - gr_palette_clear(); - - memcpy(gr_palette,save_pal,sizeof(save_pal)); - - gr_ubitmap(0,0,&tcanv->cv_bitmap); - - if (!was_faded) - gr_palette_load(gr_palette); - - gr_free_canvas(tcanv); - - return ret; -} - -//do we have the robot movies available -int robot_movies=0; //0 means none, 1 means lowres, 2 means hires void init_movie(char *filename,int libnum,int is_robots,int required) { int high_res; - #ifndef RELEASE + con_printf(DEBUG_LEVEL, "movie: init_movie: %s, %d, %d, %d\n", filename, libnum, is_robots, required); + +#ifndef RELEASE if (FindArg("-nomovies")) { movie_libs[libnum] = NULL; return; } - #endif +#endif //for robots, load highres versions if highres menus set if (is_robots) @@ -593,12 +649,12 @@ try_again:; movie_libs[libnum]->flags |= MLF_ON_CD; else { if (required) { - #if defined(RELEASE) && !defined(D2_OEM) //allow no movies if not release +#if defined(RELEASE) && !defined(D2_OEM) //allow no movies if not release strupr(filename); Error("Cannot open movie file <%s>",filename); - #endif +#endif } - #if defined(D2_OEM) //if couldn't get higres, try low +#if defined(D2_OEM) //if couldn't get higres, try low if (is_robots == 1) { //first try, try again with lowres strchr(filename,'.')[-1] = 'l'; high_res = 0; @@ -609,7 +665,7 @@ try_again:; strupr(filename); Error("Cannot open movie file <%s>",filename); } - #endif +#endif } } @@ -617,12 +673,15 @@ try_again:; robot_movies = high_res?2:1; } + //find and initialize the movie libraries void init_movies() { int i; int is_robots; + con_printf(DEBUG_LEVEL, "movie: init_movies\n"); + for (i=0;iname, filename, must_have); + if (lib == NULL) return -1; @@ -661,8 +720,6 @@ int search_movie_lib(movielib *lib,char *filename,int must_have, int *lenp) if (!stricmp(filename,lib->movies[i].name)) { //found the movie in a library int from_cd; - *lenp = lib->movies[i].len; - from_cd = (lib->flags & MLF_ON_CD); if (from_cd) @@ -670,7 +727,7 @@ int search_movie_lib(movielib *lib,char *filename,int must_have, int *lenp) do { //keep trying until we get the file handle - movie_handle = filehandle = open(lib->name, O_RDONLY); + /* movie_handle = */ filehandle = open(lib->name, O_RDONLY); if (must_have && from_cd && filehandle == -1) { //didn't get file! @@ -681,7 +738,7 @@ int search_movie_lib(movielib *lib,char *filename,int must_have, int *lenp) } while (must_have && from_cd && filehandle == -1); if (filehandle != -1) - lseek(filehandle,(movie_start=lib->movies[i].offset),SEEK_SET); + lseek(filehandle,(/* movie_start = */ lib->movies[i].offset),SEEK_SET); return filehandle; } @@ -689,16 +746,20 @@ int search_movie_lib(movielib *lib,char *filename,int must_have, int *lenp) return -1; } + //returns file handle -int open_movie_file(char *filename,int must_have, int *lenp) +int open_movie_file(char *filename,int must_have) { int filehandle,i; - for (i=0;i + +#include "mvelib.h" + +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); + +/* + * private functions for mvefile + */ +static MVEFILE *_mvefile_alloc(void); +static void _mvefile_free(MVEFILE *movie); +static int _mvefile_open(MVEFILE *movie, int filehandle); +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, int filehandle); + +/************************************************************ + * public MVEFILE functions + ************************************************************/ + +/* + * open an MVE file + */ +MVEFILE *mvefile_open(filehandle) +{ + MVEFILE *file; + + /* create the file */ + file = _mvefile_alloc(); + if (! _mvefile_open(file, filehandle)) + { + _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; +} + +/* + * close a MVE file + */ +void mvefile_close(MVEFILE *movie) +{ + _mvefile_free(movie); +} + +/* + * get the size of the next segment + */ +int mvefile_get_next_segment_size(MVEFILE *movie) +{ + /* 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); +} + +/* + * get type of next segment in chunk (0xff if no more segments in chunk) + */ +unsigned char mvefile_get_next_segment_major(MVEFILE *movie) +{ + /* 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]; +} + +/* + * get subtype (version) of next segment in chunk (0xff if no more segments in + * chunk) + */ +unsigned char mvefile_get_next_segment_minor(MVEFILE *movie) +{ + /* 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 + 3]; +} + +/* + * 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; + + /* if we don't have enough data to get a segment, fail */ + if (movie->cur_fill - movie->next_segment < 4) + return NULL; + + /* otherwise, get the data length */ + return movie->cur_chunk + movie->next_segment + 4; +} + +/* + * advance to next segment + */ +void mvefile_advance_segment(MVEFILE *movie) +{ + /* if nothing is cached, fail */ + if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill) + return; + + /* 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_short(movie->cur_chunk + movie->next_segment)); +} + +/* + * fetch the next chunk (return 0 if at end of stream) + */ +int mvefile_fetch_next_chunk(MVEFILE *movie) +{ + return _mvefile_fetch_next_chunk(movie); +} + +/************************************************************ + * public MVESTREAM functions + ************************************************************/ + +/* + * open an MVE stream + */ +MVESTREAM *mve_open(int filehandle) +{ + MVESTREAM *movie; + + /* allocate */ + movie = _mvestream_alloc(); + + /* open */ + if (! _mvestream_open(movie, filehandle)) + { + _mvestream_free(movie); + return NULL; + } + + return movie; +} + +/* + * close an MVE stream + */ +void mve_close(MVESTREAM *movie) +{ + _mvestream_free(movie); +} + +/* + * set segment type handler + */ +void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler) +{ + if (major < 32) + movie->handlers[major] = handler; +} + +/* + * set segment handler context + */ +void mve_set_handler_context(MVESTREAM *movie, void *context) +{ + movie->context = context; +} + +/* + * play next chunk + */ +int mve_play_next_chunk(MVESTREAM *movie) +{ + 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; +} + +/************************************************************ + * private functions + ************************************************************/ + +/* + * allocate an MVEFILE + */ +static MVEFILE *_mvefile_alloc(void) +{ + MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE)); + file->stream = 0; + file->cur_chunk = NULL; + file->buf_size = 0; + file->cur_fill = 0; + file->next_segment = 0; + + return file; +} + +/* + * free an MVE file + */ +static void _mvefile_free(MVEFILE *movie) +{ + /* free the stream */ + movie->stream = 0; + + /* 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); +} + +/* + * open the file stream in thie object + */ +static int _mvefile_open(MVEFILE *file, int filehandle) +{ + if (! (file->stream = filehandle)) + return 0; + + return 1; +} + +/* + * read and verify the header of the recently opened file + */ +static int _mvefile_read_header(MVEFILE *movie) +{ + unsigned char buffer[26]; + + /* check the file is open */ + if (movie->stream == 0) + return 0; + + /* check the file is long enough */ + if (read(movie->stream, buffer, 26) < 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; +} + +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 = 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; +} + +static int _mvefile_fetch_next_chunk(MVEFILE *movie) +{ + unsigned char buffer[4]; + unsigned short length; + + /* fail if not open */ + if (movie->stream == 0) + return 0; + + /* fail if we can't read the next segment descriptor */ + if (read(movie->stream, buffer, 4) < 4) + return 0; + + /* pull out the next length */ + length = _mve_get_short(buffer); + + /* make sure we've got sufficient space */ + _mvefile_set_buffer_size(movie, length); + + /* read the chunk */ + if (read(movie->stream, movie->cur_chunk, length) < 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; +} + +/* + * allocate an MVESTREAM + */ +static MVESTREAM *_mvestream_alloc(void) +{ + MVESTREAM *movie; + + /* allocate and zero-initialize everything */ + movie = (MVESTREAM *)malloc(sizeof(MVESTREAM)); + movie->movie = NULL; + movie->context = 0; + memset(movie->handlers, 0, sizeof(movie->handlers)); + + return movie; +} + +/* + * free an MVESTREAM + */ +static void _mvestream_free(MVESTREAM *movie) +{ + /* 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, int filehandle) +{ + movie->movie = mvefile_open(filehandle); + + return (movie->movie == NULL) ? 0 : 1; +} diff --git a/main/mveplay.c b/main/mveplay.c new file mode 100644 index 00000000..6cb4af2e --- /dev/null +++ b/main/mveplay.c @@ -0,0 +1,1014 @@ +#include "mvelib.h" /* next buffer */ +#include "mve_audio.h" + +#include +#include +#include +#include +#include +#include + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +int doPlay(const char *filename); + +void usage(void) +{ + fprintf(stderr, "usage: mveplay filename\n"); + exit(1); +} + +int g_spdFactorNum=0; +int g_spdFactorDenom=10; + +void initializeMovie(MVESTREAM *mve); +void playMovie(MVESTREAM *mve); +void shutdownMovie(MVESTREAM *mve); + +short get_short(unsigned char *data) +{ + short value; + value = data[0] | (data[1] << 8); + return value; +} + +int get_int(unsigned char *data) +{ + int value; + value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + return value; +} + +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; +} + +/************************* + * general handlers + *************************/ +int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + return 0; +} + +/************************* + * timer handlers + *************************/ + +/* + * timer variables + */ +int micro_frame_delay=0; +int timer_started=0; +struct timeval timer_expire = {0, 0}; + +int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + 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; + } + + return 1; +} + +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; +} + +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); + +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; + } +} + +/************************* + * audio handlers + *************************/ +void mve_audio_callback(void *userdata, Uint8 *stream, int len); +short *mve_audio_buffers[64]; +int mve_audio_buflens[64]; +int mve_audio_curbuf_curpos=0; +int mve_audio_bufhead=0; +int mve_audio_buftail=0; +int mve_audio_playing=0; +int mve_audio_canplay=0; +SDL_AudioSpec *mve_audio_spec=NULL; +pthread_mutex_t mve_audio_mutex = PTHREAD_MUTEX_INITIALIZER; + +void mve_audio_callback(void *userdata, Uint8 *stream, int len) +{ + 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); + + pthread_mutex_lock(&mve_audio_mutex); + + 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; + __builtin_memcpy(stream, /* cur output position */ + 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; + } + +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 */ + { + __builtin_memcpy(stream, /* dest */ + 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; + } + } + +fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); + pthread_mutex_unlock(&mve_audio_mutex); +} + +int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + int sample_rate; + int desired_buffer; + +fprintf(stderr, "creating audio buffers\n"); + + sample_rate = get_short(data + 4); + desired_buffer = get_int(data + 6); + mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec)); + mve_audio_spec->freq = sample_rate; + mve_audio_spec->format = AUDIO_S16LSB; + mve_audio_spec->channels = 2; + mve_audio_spec->samples = 32768; + 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; + } + + memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers)); + memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens)); + + return 1; +} + +int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail) + { + SDL_PauseAudio(0); + mve_audio_playing = 1; + } + + return 1; +} + +int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + const int selected_chan=1; + int chan; + int nsamp; + if (mve_audio_canplay) + { + if (mve_audio_playing) + SDL_LockAudio(); + + chan = get_short(data + 2); + nsamp = get_short(data + 4); + if (chan & selected_chan) + { + pthread_mutex_lock(&mve_audio_mutex); + mve_audio_buflens[mve_audio_buftail] = nsamp; + mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp); + if (major == 8) + mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */ + else + memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */ + + if (++mve_audio_buftail == 64) + mve_audio_buftail = 0; + + if (mve_audio_buftail == mve_audio_bufhead) + fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead); + pthread_mutex_unlock(&mve_audio_mutex); + } + + if (mve_audio_playing) + SDL_UnlockAudio(); + } + + return 1; +} + +/************************* + * video handlers + *************************/ +SDL_Surface *g_screen; +int g_screenWidth, g_screenHeight; +int g_width, g_height; +unsigned char g_palette[768]; +unsigned char *g_vBackBuf1, *g_vBackBuf2; +unsigned char *g_pCurMap=NULL; +int g_nMapLength=0; + +int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + short w, h; + w = get_short(data); + h = get_short(data+2); + g_width = w << 3; + g_height = h << 3; + g_vBackBuf1 = malloc(g_width * g_height); + g_vBackBuf2 = malloc(g_width * g_height); + memset(g_vBackBuf1, 0, g_width * g_height); + memset(g_vBackBuf2, 0, g_width * g_height); + return 1; +} + +int stupefaction=0; +int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + int i; + unsigned char *pal = g_palette; + unsigned char *pDest; + unsigned char *pixels = g_vBackBuf1; + SDL_Surface *screenSprite; + SDL_Rect renderArea; + int x, y; + + SDL_Surface *initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, 8, 0, 0, 0, 0); + for(i = 0; i < 256; i++) + { + initSprite->format->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); + if ( (g_screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) + SDL_Flip(g_screen); + else + SDL_UpdateRects(g_screen, 1, &renderArea); + SDL_FreeSurface(screenSprite); + return 1; +} + +int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + short width, height; + width = get_short(data); + height = get_short(data+2); + g_screen = SDL_SetVideoMode(width, height, 16, SDL_ANYFORMAT); + g_screenWidth = width; + g_screenHeight = height; + memset(g_palette, 0, 768); + return 1; +} + +int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + short start, count; + start = get_short(data); + count = get_short(data+2); + memcpy(g_palette + 3*start, data+4, 3*count); + return 1; +} + +int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + g_pCurMap = data; + g_nMapLength = len; + return 1; +} + +void decodeFrame(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain); + +int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + short nFrameHot, nFrameCold; + short nXoffset, nYoffset; + short nXsize, nYsize; + 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_short(data+12); + + if (nFlags & 1) + { + temp = g_vBackBuf1; + g_vBackBuf1 = g_vBackBuf2; + g_vBackBuf2 = temp; + } + + /* convert the frame */ + decodeFrame(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14); + + return 1; +} + +int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) +{ + g_pCurMap=NULL; + return 1; +} + +void initializeMovie(MVESTREAM *mve) +{ + 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); +} + +void playMovie(MVESTREAM *mve) +{ + int init_timer=0; + int cont=1; + while (cont) + { + cont = mve_play_next_chunk(mve); + if (micro_frame_delay && !init_timer) + { + timer_start(); + init_timer = 1; + } + + do_timer_wait(); + } +} + +void shutdownMovie(MVESTREAM *mve) +{ +} + +void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb); + +void decodeFrame(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain) +{ + int i, j; + int xb, yb; + + xb = g_width >> 3; + yb = g_height >> 3; + for (j=0; j= g_vBackBuf1 + g_width*g_height) + fprintf(stderr, "danger! pointing out of bounds above after dispatch decoder: %d, %d (1) [%x]\n", i, j, (*pMap) & 0xf); + dispatchDecoder(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j); + if (pFrame < g_vBackBuf1) + fprintf(stderr, "danger! pointing out of bounds below after dispatch decoder: %d, %d (2) [%x]\n", i, j, (*pMap) >> 4); + else if (pFrame >= g_vBackBuf1 + 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; + } + + pFrame += 7*g_width; + } +} + +void relClose(int i, int *x, int *y) +{ + int ma, mi; + + ma = i >> 4; + mi = i & 0xf; + + *x = mi - 8; + *y = ma - 8; +} + +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); + } +} + +void copyFrame(unsigned char *pDest, unsigned char *pSrc) +{ + int i; + + for (i=0; i<8; i++) + { + memcpy(pDest, pSrc, 8); + pDest += g_width; + pSrc += g_width; + } +} + +void patternRow4Pixels(unsigned char *pFrame, + unsigned char pat0, unsigned char pat1, + unsigned char *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; + } +} + +void patternRow4Pixels2(unsigned char *pFrame, + unsigned char pat0, + unsigned char *p) +{ + unsigned char mask=0x03; + unsigned char shift=0; + unsigned char pel; + 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; + } +} + +void patternRow4Pixels2x1(unsigned char *pFrame, unsigned char pat, unsigned char *p) +{ + unsigned char mask=0x03; + unsigned char shift=0; + unsigned char pel; + + while (mask != 0) + { + pel = p[(mask & pat) >> shift]; + pFrame[0] = pel; + pFrame[1] = pel; + pFrame += 2; + mask <<= 2; + shift += 2; + } +} + +void patternQuadrant4Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, unsigned char *p) +{ + 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]; + + if ((i&3) == 3) + pFrame += g_width; + + mask <<= 2; + shift += 2; + } +} + + +void patternRow2Pixels(unsigned char *pFrame, unsigned char pat, unsigned char *p) +{ + unsigned char mask=0x01; + + while (mask != 0) + { + *pFrame++ = p[(mask & pat) ? 1 : 0]; + mask <<= 1; + } +} + +void patternRow2Pixels2(unsigned char *pFrame, unsigned char pat, unsigned char *p) +{ + unsigned char pel; + unsigned char mask=0x1; + 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; + } +} + +void patternQuadrant2Pixels(unsigned char *pFrame, unsigned char pat0, unsigned char pat1, unsigned char *p) +{ + unsigned short mask = 0x0001; + int i; + unsigned short pat = (pat1 << 8) | pat0; + + for (i=0; i<16; i++) + { + pFrame[i&3] = p[(pat & mask) ? 1 : 0]; + + if ((i&3) == 3) + pFrame += g_width; + + mask <<= 1; + } +} + +void dispatchDecoder(unsigned char **pFrame, unsigned char codeType, unsigned char **pData, int *pDataRemain, int *curXb, int *curYb) +{ + unsigned char p[4]; + unsigned char pat[16]; + int i, j, k; + int x, y; + + switch(codeType) + { + case 0x0: + copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1)); + case 0x1: + *pFrame += 8; + break; + + case 0x2: + relFar(*(*pData)++, 1, &x, &y); + copyFrame(*pFrame, *pFrame + x + y*g_width); + *pFrame += 8; + --*pDataRemain; + break; + + case 0x3: + relFar(*(*pData)++, -1, &x, &y); + copyFrame(*pFrame, *pFrame + x + y*g_width); + *pFrame += 8; + --*pDataRemain; + break; + + case 0x4: + relClose(*(*pData)++, &x, &y); + copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width); + *pFrame += 8; + --*pDataRemain; + break; + + case 0x5: + x = (char)*(*pData)++; + y = (char)*(*pData)++; + copyFrame(*pFrame, *pFrame + (g_vBackBuf2 - g_vBackBuf1) + x + y*g_width); + *pFrame += 8; + *pDataRemain -= 2; + break; + + case 0x6: + 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] = *(*pData)++; + p[1] = *(*pData)++; + if (p[0] <= p[1]) + { + for (i=0; i<8; i++) + { + patternRow2Pixels(*pFrame, *(*pData)++, p); + *pFrame += g_width; + } + } + else + { + for (i=0; i<2; i++) + { + patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p); + *pFrame += 2*g_width; + patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p); + *pFrame += 2*g_width; + } + } + *pFrame -= (8*g_width - 8); + break; + + case 0x8: + if ( (*pData)[0] <= (*pData)[1]) + { + for (i=0; i<4; i++) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + 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 if ( (*pData)[6] <= (*pData)[7]) + { + for (i=0; i<4; i++) + { + if ((i & 1) == 0) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + } + 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] = *(*pData)++; + p[1] = *(*pData)++; + } + patternRow2Pixels(*pFrame, *(*pData)++, p); + *pFrame += g_width; + } + *pFrame -= (8*g_width - 8); + } + break; + + case 0x9: + if ( (*pData)[0] <= (*pData)[1]) + { + if ( (*pData)[2] <= (*pData)[3]) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + + for (i=0; i<8; i++) + { + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + } + + *pFrame -= (8*g_width - 8); + } + else + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + + patternRow4Pixels2(*pFrame, *(*pData)++, p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, *(*pData)++, p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, *(*pData)++, p); + *pFrame += 2*g_width; + patternRow4Pixels2(*pFrame, *(*pData)++, p); + *pFrame -= (6*g_width - 8); + } + } + else + { + if ( (*pData)[2] <= (*pData)[3]) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + + for (i=0; i<8; i++) + { + pat[0] = *(*pData)++; + patternRow4Pixels2x1(*pFrame, pat[0], p); + *pFrame += g_width; + } + + *pFrame -= (8*g_width - 8); + } + else + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + + for (i=0; i<4; i++) + { + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + } + + *pFrame -= (8*g_width - 8); + } + } + break; + + case 0xa: + if ( (*pData)[0] <= (*pData)[1]) + { + for (i=0; i<4; i++) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + pat[2] = *(*pData)++; + pat[3] = *(*pData)++; + + 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 + { + if ( (*pData)[12] <= (*pData)[13]) + { + for (i=0; i<4; i++) + { + if ((i&1) == 0) + { + p[0] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + } + + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + pat[2] = *(*pData)++; + pat[3] = *(*pData)++; + + 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] = *(*pData)++; + p[1] = *(*pData)++; + p[2] = *(*pData)++; + p[3] = *(*pData)++; + } + + pat[0] = *(*pData)++; + pat[1] = *(*pData)++; + patternRow4Pixels(*pFrame, pat[0], pat[1], p); + *pFrame += g_width; + } + + *pFrame -= (8*g_width - 8); + } + } + break; + + case 0xb: + for (i=0; i<8; i++) + { + memcpy(*pFrame, *pData, 8); + *pFrame += g_width; + *pData += 8; + *pDataRemain -= 8; + } + *pFrame -= (8*g_width - 8); + break; + + case 0xc: + for (i=0; i<4; i++) + { + for (j=0; j<2; j++) + { + for (k=0; k<4; k++) + { + (*pFrame)[j+2*k] = (*pData)[k]; + (*pFrame)[g_width+j+2*k] = (*pData)[k]; + } + *pFrame += g_width; + } + *pData += 4; + *pDataRemain -= 4; + } + *pFrame -= (8*g_width - 8); + break; + + case 0xd: + for (i=0; i<2; i++) + { + for (j=0; j<4; j++) + { + for (k=0; k<4; k++) + { + (*pFrame)[k*g_width+j] = (*pData)[0]; + (*pFrame)[k*g_width+j+4] = (*pData)[1]; + } + } + *pFrame += 4*g_width; + *pData += 2; + *pDataRemain -= 2; + } + *pFrame -= (8*g_width - 8); + break; + + case 0xe: + for (i=0; i<8; i++) + { + memset(*pFrame, **pData, 8); + *pFrame += g_width; + } + ++*pData; + --*pDataRemain; + *pFrame -= (8*g_width - 8); + break; + + case 0xf: + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + (*pFrame)[j] = (*pData)[(i+j)&1]; + } + *pFrame += g_width; + } + *pData += 2; + *pDataRemain -= 2; + *pFrame -= (8*g_width - 8); + break; + + default: + break; + } +} -- 2.39.2