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