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