1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 #ifdef CINEMATICS
21 #include "client.h"
22
23 typedef struct
24 {
25 byte *data;
26 int count;
27 } cblock_t;
28
29 typedef struct
30 {
31 qboolean restart_sound;
32 int s_rate;
33 int s_width;
34 int s_channels;
35
36 int width;
37 int height;
38 byte *pic;
39 byte *pic_pending;
40
41 // order 1 huffman stuff
42 int *hnodes1; // [256][256][2];
43 int numhnodes1[256];
44
45 int h_used[512];
46 int h_count[512];
47 } cinematics_t;
48
49 cinematics_t cin;
50
51 /*
52 =================================================================
53
54 PCX LOADING
55
56 =================================================================
57 */
58
59
60 /*
61 ==============
62 SCR_LoadPCX
63 ==============
64 */
SCR_LoadPCX(char * filename,byte ** pic,byte ** palette,int * width,int * height)65 void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
66 {
67 byte *raw;
68 pcx_t *pcx;
69 int x, y;
70 int len;
71 int dataByte, runLength;
72 byte *out, *pix;
73
74 *pic = NULL;
75
76 //
77 // load the file
78 //
79 len = FS_LoadFile (filename, (void **)&raw);
80 if (!raw)
81 return;
82
83 //
84 // parse the PCX file
85 //
86 pcx = (pcx_t *)raw;
87 raw = &pcx->data;
88
89 if (pcx->manufacturer != 0x0a
90 || pcx->version != 5
91 || pcx->encoding != 1
92 || pcx->bits_per_pixel != 8
93 || pcx->xmax >= 640
94 || pcx->ymax >= 480)
95 {
96 Com_Printf ("Bad pcx file %s\n", LOG_CLIENT, filename);
97 return;
98 }
99
100 out = Z_TagMalloc ( (pcx->ymax+1) * (pcx->xmax+1), TAGMALLOC_CLIENT_LOADPCX);
101
102 *pic = out;
103
104 pix = out;
105
106 if (palette)
107 {
108 *palette = Z_TagMalloc(768, TAGMALLOC_CLIENT_LOADPCX);
109 memcpy (*palette, (byte *)pcx + len - 768, 768);
110 }
111
112 if (width)
113 *width = pcx->xmax+1;
114 if (height)
115 *height = pcx->ymax+1;
116
117 for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
118 {
119 for (x=0 ; x<=pcx->xmax ; )
120 {
121 dataByte = *raw++;
122
123 if((dataByte & 0xC0) == 0xC0)
124 {
125 runLength = dataByte & 0x3F;
126 dataByte = *raw++;
127 }
128 else
129 runLength = 1;
130
131 while(runLength-- > 0)
132 pix[x++] = dataByte;
133 }
134
135 }
136
137 if ( raw - (byte *)pcx > len)
138 {
139 Com_Printf ("PCX file %s was malformed", LOG_CLIENT, filename);
140 Z_Free (*pic);
141 *pic = NULL;
142 }
143
144 FS_FreeFile (pcx);
145 }
146
147 //=============================================================
148
149 /*
150 ==================
151 SCR_StopCinematic
152 ==================
153 */
SCR_StopCinematic(void)154 void SCR_StopCinematic (void)
155 {
156 cl.cinematictime = 0; // done
157 if (cin.pic)
158 {
159 Z_Free (cin.pic);
160 cin.pic = NULL;
161 }
162 if (cin.pic_pending)
163 {
164 Z_Free (cin.pic_pending);
165 cin.pic_pending = NULL;
166 }
167 if (cl.cinematicpalette_active)
168 {
169 re.CinematicSetPalette(NULL);
170 cl.cinematicpalette_active = false;
171 }
172 if (cl.cinematic_file)
173 {
174 fclose (cl.cinematic_file);
175 cl.cinematic_file = NULL;
176 }
177 if (cin.hnodes1)
178 {
179 Z_Free (cin.hnodes1);
180 cin.hnodes1 = NULL;
181 }
182
183 // switch back down to 11 khz sound if necessary
184 if (cin.restart_sound)
185 {
186 cin.restart_sound = false;
187 CL_Snd_Restart_f ();
188 }
189
190 }
191
192 /*
193 ====================
194 SCR_FinishCinematic
195
196 Called when either the cinematic completes, or it is aborted
197 ====================
198 */
SCR_FinishCinematic(void)199 void SCR_FinishCinematic (void)
200 {
201 // tell the server to advance to the next map / cinematic
202 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
203 SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
204 }
205
206 //==========================================================================
207
208 /*
209 ==================
210 SmallestNode1
211 ==================
212 */
SmallestNode1(int numhnodes)213 int SmallestNode1 (int numhnodes)
214 {
215 int i;
216 int best, bestnode;
217
218 best = 99999999;
219 bestnode = -1;
220 for (i=0 ; i<numhnodes ; i++)
221 {
222 if (cin.h_used[i])
223 continue;
224 if (!cin.h_count[i])
225 continue;
226 if (cin.h_count[i] < best)
227 {
228 best = cin.h_count[i];
229 bestnode = i;
230 }
231 }
232
233 if (bestnode == -1)
234 return -1;
235
236 cin.h_used[bestnode] = true;
237 return bestnode;
238 }
239
240
241 /*
242 ==================
243 Huff1TableInit
244
245 Reads the 64k counts table and initializes the node trees
246 ==================
247 */
Huff1TableInit(void)248 void Huff1TableInit (void)
249 {
250 int prev;
251 int j;
252 int *node, *nodebase;
253 byte counts[256];
254 int numhnodes;
255
256 cin.hnodes1 = Z_TagMalloc (256*256*2*4, TAGMALLOC_CLIENT_CINEMA);
257 memset (cin.hnodes1, 0, 256*256*2*4);
258
259 for (prev=0 ; prev<256 ; prev++)
260 {
261 memset (cin.h_count,0,sizeof(cin.h_count));
262 memset (cin.h_used,0,sizeof(cin.h_used));
263
264 // read a row of counts
265 FS_Read (counts, sizeof(counts), cl.cinematic_file);
266 for (j=0 ; j<256 ; j++)
267 cin.h_count[j] = counts[j];
268
269 // build the nodes
270 numhnodes = 256;
271 nodebase = cin.hnodes1 + prev*256*2;
272
273 while (numhnodes != 511)
274 {
275 node = nodebase + (numhnodes-256)*2;
276
277 // pick two lowest counts
278 node[0] = SmallestNode1 (numhnodes);
279 if (node[0] == -1)
280 break; // no more
281
282 node[1] = SmallestNode1 (numhnodes);
283 if (node[1] == -1)
284 break;
285
286 cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
287 numhnodes++;
288 }
289
290 cin.numhnodes1[prev] = numhnodes-1;
291 }
292 }
293
294 /*
295 ==================
296 Huff1Decompress
297 ==================
298 */
Huff1Decompress(cblock_t in)299 cblock_t Huff1Decompress (cblock_t in)
300 {
301 byte *input;
302 byte *out_p;
303 int nodenum;
304 int count;
305 cblock_t out;
306 int inbyte;
307 int *hnodes, *hnodesbase;
308 //int i;
309
310 // get decompressed count
311 count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
312 input = in.data + 4;
313 out_p = out.data = Z_TagMalloc (count, TAGMALLOC_CLIENT_CINEMA);
314
315 // read bits
316
317 hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
318
319 hnodes = hnodesbase;
320 nodenum = cin.numhnodes1[0];
321 while (count)
322 {
323 inbyte = *input++;
324 //-----------
325 if (nodenum < 256)
326 {
327 hnodes = hnodesbase + (nodenum<<9);
328 *out_p++ = nodenum;
329 if (!--count)
330 break;
331 nodenum = cin.numhnodes1[nodenum];
332 }
333 nodenum = hnodes[nodenum*2 + (inbyte&1)];
334 inbyte >>=1;
335 //-----------
336 if (nodenum < 256)
337 {
338 hnodes = hnodesbase + (nodenum<<9);
339 *out_p++ = nodenum;
340 if (!--count)
341 break;
342 nodenum = cin.numhnodes1[nodenum];
343 }
344 nodenum = hnodes[nodenum*2 + (inbyte&1)];
345 inbyte >>=1;
346 //-----------
347 if (nodenum < 256)
348 {
349 hnodes = hnodesbase + (nodenum<<9);
350 *out_p++ = nodenum;
351 if (!--count)
352 break;
353 nodenum = cin.numhnodes1[nodenum];
354 }
355 nodenum = hnodes[nodenum*2 + (inbyte&1)];
356 inbyte >>=1;
357 //-----------
358 if (nodenum < 256)
359 {
360 hnodes = hnodesbase + (nodenum<<9);
361 *out_p++ = nodenum;
362 if (!--count)
363 break;
364 nodenum = cin.numhnodes1[nodenum];
365 }
366 nodenum = hnodes[nodenum*2 + (inbyte&1)];
367 inbyte >>=1;
368 //-----------
369 if (nodenum < 256)
370 {
371 hnodes = hnodesbase + (nodenum<<9);
372 *out_p++ = nodenum;
373 if (!--count)
374 break;
375 nodenum = cin.numhnodes1[nodenum];
376 }
377 nodenum = hnodes[nodenum*2 + (inbyte&1)];
378 inbyte >>=1;
379 //-----------
380 if (nodenum < 256)
381 {
382 hnodes = hnodesbase + (nodenum<<9);
383 *out_p++ = nodenum;
384 if (!--count)
385 break;
386 nodenum = cin.numhnodes1[nodenum];
387 }
388 nodenum = hnodes[nodenum*2 + (inbyte&1)];
389 inbyte >>=1;
390 //-----------
391 if (nodenum < 256)
392 {
393 hnodes = hnodesbase + (nodenum<<9);
394 *out_p++ = nodenum;
395 if (!--count)
396 break;
397 nodenum = cin.numhnodes1[nodenum];
398 }
399 nodenum = hnodes[nodenum*2 + (inbyte&1)];
400 inbyte >>=1;
401 //-----------
402 if (nodenum < 256)
403 {
404 hnodes = hnodesbase + (nodenum<<9);
405 *out_p++ = nodenum;
406 if (!--count)
407 break;
408 nodenum = cin.numhnodes1[nodenum];
409 }
410 nodenum = hnodes[nodenum*2 + (inbyte&1)];
411 inbyte >>=1;
412 }
413
414 if (input - in.data != in.count && input - in.data != in.count+1)
415 {
416 Com_Printf ("Decompression overread by %i", LOG_CLIENT, (input - in.data) - in.count);
417 }
418 out.count = out_p - out.data;
419
420 return out;
421 }
422
423 /*
424 ==================
425 SCR_ReadNextFrame
426 ==================
427 */
SCR_ReadNextFrame(void)428 byte *SCR_ReadNextFrame (void)
429 {
430 int r;
431 int command;
432 byte samples[22050/14*4];
433 byte compressed[0x20000];
434 int size;
435 byte *pic;
436 cblock_t in, huf1;
437 int start, end, count;
438
439 // read the next frame
440 r = fread (&command, 4, 1, cl.cinematic_file);
441 if (r == 0) // we'll give it one more chance
442 r = fread (&command, 4, 1, cl.cinematic_file);
443
444 if (r != 1)
445 return NULL;
446 command = LittleLong(command);
447 if (command == 2)
448 return NULL; // last frame marker
449
450 if (command == 1)
451 { // read palette
452 FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
453 cl.cinematicpalette_active=0; // dubious.... exposes an edge case
454 }
455
456 // decompress the next frame
457 FS_Read (&size, 4, cl.cinematic_file);
458 size = LittleLong(size);
459 if (size > sizeof(compressed) || size < 1)
460 Com_Error (ERR_DROP, "Bad compressed frame size");
461 FS_Read (compressed, size, cl.cinematic_file);
462
463 // read sound
464 start = cl.cinematicframe*cin.s_rate/14;
465 end = (cl.cinematicframe+1)*cin.s_rate/14;
466 count = end - start;
467
468 FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
469
470 S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
471
472 in.data = compressed;
473 in.count = size;
474
475 huf1 = Huff1Decompress (in);
476
477 pic = huf1.data;
478
479 cl.cinematicframe++;
480
481 return pic;
482 }
483
484
485 /*
486 ==================
487 SCR_RunCinematic
488
489 ==================
490 */
SCR_RunCinematic(void)491 void SCR_RunCinematic (void)
492 {
493 int frame;
494
495 if (cl.cinematictime <= 0)
496 {
497 SCR_StopCinematic ();
498 return;
499 }
500
501 if (cl.cinematicframe == -1)
502 return; // static image
503
504 if (cls.key_dest != key_game)
505 { // pause if menu or console is up
506 cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
507 return;
508 }
509
510 frame = (cls.realtime - cl.cinematictime)*14.0/1000;
511 if (frame <= cl.cinematicframe)
512 return;
513 if (frame > cl.cinematicframe+1)
514 {
515 Com_Printf ("Dropped frame: %i > %i\n", LOG_CLIENT, frame, cl.cinematicframe+1);
516 cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
517 }
518 if (cin.pic)
519 Z_Free (cin.pic);
520 cin.pic = cin.pic_pending;
521 cin.pic_pending = NULL;
522 cin.pic_pending = SCR_ReadNextFrame ();
523 if (!cin.pic_pending)
524 {
525 SCR_StopCinematic ();
526 SCR_FinishCinematic ();
527 cl.cinematictime = 1; // hack to get the black screen behind loading
528 SCR_BeginLoadingPlaque ();
529 cl.cinematictime = 0;
530 return;
531 }
532 }
533
534 /*
535 ==================
536 SCR_DrawCinematic
537
538 Returns true if a cinematic is active, meaning the view rendering
539 should be skipped
540 ==================
541 */
SCR_DrawCinematic(void)542 qboolean SCR_DrawCinematic (void)
543 {
544 if (cl.cinematictime <= 0)
545 {
546 return false;
547 }
548
549 if (cls.key_dest == key_menu)
550 { // blank screen and pause if menu is up
551 re.CinematicSetPalette(NULL);
552 cl.cinematicpalette_active = false;
553 return true;
554 }
555
556 if (!cl.cinematicpalette_active)
557 {
558 re.CinematicSetPalette(cl.cinematicpalette);
559 cl.cinematicpalette_active = true;
560 }
561
562 if (!cin.pic)
563 return true;
564
565 re.DrawStretchRaw (0, 0, viddef.width, viddef.height,
566 cin.width, cin.height, cin.pic);
567
568 return true;
569 }
570
571 /*
572 ==================
573 SCR_PlayCinematic
574
575 ==================
576 */
SCR_PlayCinematic(char * arg)577 void SCR_PlayCinematic (char *arg)
578 {
579 int width, height;
580 byte *palette;
581 char name[MAX_OSPATH], *dot;
582 int old_khz;
583 qboolean dummy;
584
585 // make sure CD isn't playing music
586 #ifdef CD_AUDIO
587 CDAudio_Stop();
588 #endif
589
590 cl.cinematicframe = 0;
591 dot = strchr (arg, '.');
592 if (dot && !strcmp (dot, ".pcx"))
593 { // static pcx image
594 Com_sprintf (name, sizeof(name), "pics/%s", arg);
595 SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
596 cl.cinematicframe = -1;
597 cl.cinematictime = 1;
598 SCR_EndLoadingPlaque ();
599 cls.state = ca_active;
600 if (!cin.pic)
601 {
602 Com_Printf ("%s not found.\n", LOG_CLIENT, name);
603 cl.cinematictime = 0;
604 }
605 else
606 {
607 memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
608 Z_Free (palette);
609 }
610 return;
611 }
612
613 Com_sprintf (name, sizeof(name), "video/%s", arg);
614 FS_FOpenFile (name, &cl.cinematic_file, HANDLE_DUPE, &dummy);
615 if (!cl.cinematic_file)
616 {
617 // Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
618 SCR_FinishCinematic ();
619 cl.cinematictime = 0; // done
620 return;
621 }
622
623 SCR_EndLoadingPlaque ();
624
625 cls.state = ca_active;
626
627 FS_Read (&width, 4, cl.cinematic_file);
628 FS_Read (&height, 4, cl.cinematic_file);
629 cin.width = LittleLong(width);
630 cin.height = LittleLong(height);
631
632 FS_Read (&cin.s_rate, 4, cl.cinematic_file);
633 cin.s_rate = LittleLong(cin.s_rate);
634 FS_Read (&cin.s_width, 4, cl.cinematic_file);
635 cin.s_width = LittleLong(cin.s_width);
636 FS_Read (&cin.s_channels, 4, cl.cinematic_file);
637 cin.s_channels = LittleLong(cin.s_channels);
638
639 Huff1TableInit ();
640
641 // switch up to 22 khz sound if necessary
642 old_khz = Cvar_IntValue ("s_khz");
643 if (old_khz != cin.s_rate/1000)
644 {
645 cin.restart_sound = true;
646 Cvar_SetValue ("s_khz", cin.s_rate/1000);
647 CL_Snd_Restart_f ();
648 Cvar_SetValue ("s_khz", old_khz);
649 }
650
651 cl.cinematicframe = 0;
652 cin.pic = SCR_ReadNextFrame ();
653 cl.cinematictime = Sys_Milliseconds ();
654 }
655 #endif
656