123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "client.h"
- typedef struct
- {
- byte *data;
- int count;
- } cblock_t;
- typedef struct
- {
- qboolean restart_sound;
- int s_rate;
- int s_width;
- int s_channels;
- int width;
- int height;
- byte *pic;
- byte *pic_pending;
- // order 1 huffman stuff
- int *hnodes1; // [256][256][2];
- int numhnodes1[256];
- int h_used[512];
- int h_count[512];
- } cinematics_t;
- cinematics_t cin;
- /*
- =================================================================
- PCX LOADING
- =================================================================
- */
- /*
- ==============
- SCR_LoadPCX
- ==============
- */
- void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
- {
- byte *raw;
- pcx_t *pcx;
- int x, y;
- int len;
- int dataByte, runLength;
- byte *out, *pix;
- *pic = NULL;
- //
- // load the file
- //
- len = FS_LoadFile (filename, (void **)&raw);
- if (!raw)
- return; // Com_Printf ("Bad pcx file %s\n", filename);
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
- raw = &pcx->data;
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || pcx->xmax >= 640
- || pcx->ymax >= 480)
- {
- Com_Printf ("Bad pcx file %s\n", filename);
- return;
- }
- out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
- *pic = out;
- pix = out;
- if (palette)
- {
- *palette = Z_Malloc(768);
- memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
- if (width)
- *width = pcx->xmax+1;
- if (height)
- *height = pcx->ymax+1;
- for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
- {
- for (x=0 ; x<=pcx->xmax ; )
- {
- dataByte = *raw++;
- if((dataByte & 0xC0) == 0xC0)
- {
- runLength = dataByte & 0x3F;
- dataByte = *raw++;
- }
- else
- runLength = 1;
- while(runLength-- > 0)
- pix[x++] = dataByte;
- }
- }
- if ( raw - (byte *)pcx > len)
- {
- Com_Printf ("PCX file %s was malformed", filename);
- Z_Free (*pic);
- *pic = NULL;
- }
- FS_FreeFile (pcx);
- }
- //=============================================================
- /*
- ==================
- SCR_StopCinematic
- ==================
- */
- void SCR_StopCinematic (void)
- {
- cl.cinematictime = 0; // done
- if (cin.pic)
- {
- Z_Free (cin.pic);
- cin.pic = NULL;
- }
- if (cin.pic_pending)
- {
- Z_Free (cin.pic_pending);
- cin.pic_pending = NULL;
- }
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- if (cl.cinematic_file)
- {
- fclose (cl.cinematic_file);
- cl.cinematic_file = NULL;
- }
- if (cin.hnodes1)
- {
- Z_Free (cin.hnodes1);
- cin.hnodes1 = NULL;
- }
- // switch back down to 11 khz sound if necessary
- if (cin.restart_sound)
- {
- cin.restart_sound = false;
- CL_Snd_Restart_f ();
- }
- }
- /*
- ====================
- SCR_FinishCinematic
- Called when either the cinematic completes, or it is aborted
- ====================
- */
- void SCR_FinishCinematic (void)
- {
- // tell the server to advance to the next map / cinematic
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
- }
- //==========================================================================
- /*
- ==================
- SmallestNode1
- ==================
- */
- int SmallestNode1 (int numhnodes)
- {
- int i;
- int best, bestnode;
- best = 99999999;
- bestnode = -1;
- for (i=0 ; i<numhnodes ; i++)
- {
- if (cin.h_used[i])
- continue;
- if (!cin.h_count[i])
- continue;
- if (cin.h_count[i] < best)
- {
- best = cin.h_count[i];
- bestnode = i;
- }
- }
- if (bestnode == -1)
- return -1;
- cin.h_used[bestnode] = true;
- return bestnode;
- }
- /*
- ==================
- Huff1TableInit
- Reads the 64k counts table and initializes the node trees
- ==================
- */
- void Huff1TableInit (void)
- {
- int prev;
- int j;
- int *node, *nodebase;
- byte counts[256];
- int numhnodes;
- cin.hnodes1 = Z_Malloc (256*256*2*4);
- memset (cin.hnodes1, 0, 256*256*2*4);
- for (prev=0 ; prev<256 ; prev++)
- {
- memset (cin.h_count,0,sizeof(cin.h_count));
- memset (cin.h_used,0,sizeof(cin.h_used));
- // read a row of counts
- FS_Read (counts, sizeof(counts), cl.cinematic_file);
- for (j=0 ; j<256 ; j++)
- cin.h_count[j] = counts[j];
- // build the nodes
- numhnodes = 256;
- nodebase = cin.hnodes1 + prev*256*2;
- while (numhnodes != 511)
- {
- node = nodebase + (numhnodes-256)*2;
- // pick two lowest counts
- node[0] = SmallestNode1 (numhnodes);
- if (node[0] == -1)
- break; // no more
- node[1] = SmallestNode1 (numhnodes);
- if (node[1] == -1)
- break;
- cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
- numhnodes++;
- }
- cin.numhnodes1[prev] = numhnodes-1;
- }
- }
- /*
- ==================
- Huff1Decompress
- ==================
- */
- cblock_t Huff1Decompress (cblock_t in)
- {
- byte *input;
- byte *out_p;
- int nodenum;
- int count;
- cblock_t out;
- int inbyte;
- int *hnodes, *hnodesbase;
- //int i;
- // get decompressed count
- count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
- input = in.data + 4;
- out_p = out.data = Z_Malloc (count);
- // read bits
- hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
- hnodes = hnodesbase;
- nodenum = cin.numhnodes1[0];
- while (count)
- {
- inbyte = *input++;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- }
- if (input - in.data != in.count && input - in.data != in.count+1)
- {
- Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
- }
- out.count = out_p - out.data;
- return out;
- }
- /*
- ==================
- SCR_ReadNextFrame
- ==================
- */
- byte *SCR_ReadNextFrame (void)
- {
- int r;
- int command;
- byte samples[22050/14*4];
- byte compressed[0x20000];
- int size;
- byte *pic;
- cblock_t in, huf1;
- int start, end, count;
- // read the next frame
- r = fread (&command, 4, 1, cl.cinematic_file);
- if (r == 0) // we'll give it one more chance
- r = fread (&command, 4, 1, cl.cinematic_file);
- if (r != 1)
- return NULL;
- command = LittleLong(command);
- if (command == 2)
- return NULL; // last frame marker
- if (command == 1)
- { // read palette
- FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
- cl.cinematicpalette_active=0; // dubious.... exposes an edge case
- }
- // decompress the next frame
- FS_Read (&size, 4, cl.cinematic_file);
- size = LittleLong(size);
- if (size > sizeof(compressed) || size < 1)
- Com_Error (ERR_DROP, "Bad compressed frame size");
- FS_Read (compressed, size, cl.cinematic_file);
- // read sound
- start = cl.cinematicframe*cin.s_rate/14;
- end = (cl.cinematicframe+1)*cin.s_rate/14;
- count = end - start;
- FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
- S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
- in.data = compressed;
- in.count = size;
- huf1 = Huff1Decompress (in);
- pic = huf1.data;
- cl.cinematicframe++;
- return pic;
- }
- /*
- ==================
- SCR_RunCinematic
- ==================
- */
- void SCR_RunCinematic (void)
- {
- int frame;
- if (cl.cinematictime <= 0)
- {
- SCR_StopCinematic ();
- return;
- }
- if (cl.cinematicframe == -1)
- return; // static image
- if (cls.key_dest != key_game)
- { // pause if menu or console is up
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- return;
- }
- frame = (cls.realtime - cl.cinematictime)*14.0/1000;
- if (frame <= cl.cinematicframe)
- return;
- if (frame > cl.cinematicframe+1)
- {
- Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- }
- if (cin.pic)
- Z_Free (cin.pic);
- cin.pic = cin.pic_pending;
- cin.pic_pending = NULL;
- cin.pic_pending = SCR_ReadNextFrame ();
- if (!cin.pic_pending)
- {
- SCR_StopCinematic ();
- SCR_FinishCinematic ();
- cl.cinematictime = 1; // hack to get the black screen behind loading
- SCR_BeginLoadingPlaque ();
- cl.cinematictime = 0;
- return;
- }
- }
- /*
- ==================
- SCR_DrawCinematic
- Returns true if a cinematic is active, meaning the view rendering
- should be skipped
- ==================
- */
- qboolean SCR_DrawCinematic (void)
- {
- if (cl.cinematictime <= 0)
- {
- return false;
- }
- if (cls.key_dest == key_menu)
- { // blank screen and pause if menu is up
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- return true;
- }
- if (!cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(cl.cinematicpalette);
- cl.cinematicpalette_active = true;
- }
- if (!cin.pic)
- return true;
- re.DrawStretchRaw (0, 0, viddef.width, viddef.height,
- cin.width, cin.height, cin.pic);
- return true;
- }
- /*
- ==================
- SCR_PlayCinematic
- ==================
- */
- void SCR_PlayCinematic (char *arg)
- {
- int width, height;
- byte *palette;
- char name[MAX_OSPATH], *dot;
- int old_khz;
- // make sure CD isn't playing music
- CDAudio_Stop();
- cl.cinematicframe = 0;
- dot = strstr (arg, ".");
- if (dot && !strcmp (dot, ".pcx"))
- { // static pcx image
- Com_sprintf (name, sizeof(name), "pics/%s", arg);
- SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
- cl.cinematicframe = -1;
- cl.cinematictime = 1;
- SCR_EndLoadingPlaque ();
- cls.state = ca_active;
- if (!cin.pic)
- {
- Com_Printf ("%s not found.\n", name);
- cl.cinematictime = 0;
- }
- else
- {
- memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
- Z_Free (palette);
- }
- return;
- }
- Com_sprintf (name, sizeof(name), "video/%s", arg);
- FS_FOpenFile (name, &cl.cinematic_file);
- if (!cl.cinematic_file)
- {
- // Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
- SCR_FinishCinematic ();
- cl.cinematictime = 0; // done
- return;
- }
- SCR_EndLoadingPlaque ();
- cls.state = ca_active;
- FS_Read (&width, 4, cl.cinematic_file);
- FS_Read (&height, 4, cl.cinematic_file);
- cin.width = LittleLong(width);
- cin.height = LittleLong(height);
- FS_Read (&cin.s_rate, 4, cl.cinematic_file);
- cin.s_rate = LittleLong(cin.s_rate);
- FS_Read (&cin.s_width, 4, cl.cinematic_file);
- cin.s_width = LittleLong(cin.s_width);
- FS_Read (&cin.s_channels, 4, cl.cinematic_file);
- cin.s_channels = LittleLong(cin.s_channels);
- Huff1TableInit ();
- // switch up to 22 khz sound if necessary
- old_khz = Cvar_VariableValue ("s_khz");
- if (old_khz != cin.s_rate/1000)
- {
- cin.restart_sound = true;
- Cvar_SetValue ("s_khz", cin.s_rate/1000);
- CL_Snd_Restart_f ();
- Cvar_SetValue ("s_khz", old_khz);
- }
- cl.cinematicframe = 0;
- cin.pic = SCR_ReadNextFrame ();
- cl.cinematictime = Sys_Milliseconds ();
- }
|