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
21 /*
22 gl_cin.c
23
24 CIN File Decoder for cinematic textures
25
26 Adapted from executable source by Robert 'Heffo' Heffernan
27 1/1/2002, 1:34pm AEDST
28 */
29
30 #include "gl_local.h"
31 #include "gl_cin.h"
32
33 typedef struct
34 {
35 byte *data;
36 int count;
37 } cblock_t;
38
39 void CIN_StopCinematic (void);
40 int SmallestNode1 (int numhnodes);
41 void Huff1TableInit (void);
42 cblock_t Huff1Decompress (cblock_t in);
43 byte *CIN_ReadNextFrame (void);
44 void CIN_RunCinematic (void);
45 qboolean CIN_DrawCinematic (void);
46 void CIN_PlayCinematic (char *arg);
47 void CIN_StartCinematic (void);
48
49 cinematics_t *cin;
50
51 //=============================================================
52
GetInteger(byte * data)53 long GetInteger (byte *data)
54 {
55 long b0, b1, b2, b3;
56
57 b0 = (data[0] & 0xFF);
58 b1 = (data[1] & 0xFF) << 8;
59 b2 = (data[2] & 0xFF) << 16;
60 b3 = (data[3] & 0xFF) << 24;
61
62 return b0 + b1 + b2 + b3;
63 }
64
65 /*
66 ==================
67 CIN_StopCinematic
68 ==================
69 */
CIN_StopCinematic(void)70 void CIN_StopCinematic (void)
71 {
72 cin->time = 0; // done
73 if (cin->pic)
74 {
75 free(cin->pic);
76 cin->pic = NULL;
77 }
78 if (cin->pic_pending)
79 {
80 free(cin->pic_pending);
81 cin->pic_pending = NULL;
82 }
83 if (cin->cinematic_file)
84 {
85 ri.FS_FreeFile(cin->cinematic_file);
86 cin->cinematic_file = NULL;
87 cin->offset = NULL;
88 }
89 if (cin->hnodes1)
90 {
91 free(cin->hnodes1);
92 cin->hnodes1 = NULL;
93 }
94 }
95
96 //==========================================================================
97
98 /*
99 ==================
100 SmallestNode1
101 ==================
102 */
SmallestNode1(int numhnodes)103 int SmallestNode1 (int numhnodes)
104 {
105 int i;
106 int best, bestnode;
107
108 best = 99999999;
109 bestnode = -1;
110 for (i=0 ; i<numhnodes ; i++)
111 {
112 if (cin->h_used[i])
113 continue;
114 if (!cin->h_count[i])
115 continue;
116 if (cin->h_count[i] < best)
117 {
118 best = cin->h_count[i];
119 bestnode = i;
120 }
121 }
122
123 if (bestnode == -1)
124 return -1;
125
126 cin->h_used[bestnode] = true;
127 return bestnode;
128 }
129
130
131 /*
132 ==================
133 Huff1TableInit
134
135 Reads the 64k counts table and initializes the node trees
136 ==================
137 */
Huff1TableInit(void)138 void Huff1TableInit (void)
139 {
140 int prev;
141 int j;
142 int *node, *nodebase;
143 byte counts[256];
144 int numhnodes;
145
146 cin->hnodes1 = malloc(256*256*2*4);
147 memset (cin->hnodes1, 0, 256*256*2*4);
148
149 for (prev=0 ; prev<256 ; prev++)
150 {
151 memset (cin->h_count,0,sizeof(cin->h_count));
152 memset (cin->h_used,0,sizeof(cin->h_used));
153
154 // read a row of counts
155 memcpy(counts, cin->offset, sizeof(counts)); cin->offset += sizeof(counts);
156 for (j=0 ; j<256 ; j++)
157 cin->h_count[j] = counts[j];
158
159 // build the nodes
160 numhnodes = 256;
161 nodebase = cin->hnodes1 + prev*256*2;
162
163 while (numhnodes != 511)
164 {
165 node = nodebase + (numhnodes-256)*2;
166
167 // pick two lowest counts
168 node[0] = SmallestNode1 (numhnodes);
169 if (node[0] == -1)
170 break; // no more
171
172 node[1] = SmallestNode1 (numhnodes);
173 if (node[1] == -1)
174 break;
175
176 cin->h_count[numhnodes] = cin->h_count[node[0]] + cin->h_count[node[1]];
177 numhnodes++;
178 }
179
180 cin->numhnodes1[prev] = numhnodes-1;
181 }
182
183 cin->framestart = cin->offset;
184 }
185
186 /*
187 ==================
188 Huff1Decompress
189 ==================
190 */
Huff1Decompress(cblock_t in)191 cblock_t Huff1Decompress (cblock_t in)
192 {
193 byte *input;
194 byte *out_p;
195 int nodenum;
196 int count;
197 cblock_t out;
198 int inbyte;
199 int *hnodes, *hnodesbase;
200 //int i;
201
202 // get decompressed count
203 count = GetInteger(in.data);
204 input = in.data + 4;
205 out_p = out.data = malloc(count);
206
207 // read bits
208
209 hnodesbase = cin->hnodes1 - 256*2; // nodes 0-255 aren't stored
210
211 hnodes = hnodesbase;
212 nodenum = cin->numhnodes1[0];
213 while (count)
214 {
215 inbyte = *input++;
216 //-----------
217 if (nodenum < 256)
218 {
219 hnodes = hnodesbase + (nodenum<<9);
220 *out_p++ = nodenum;
221 if (!--count)
222 break;
223 nodenum = cin->numhnodes1[nodenum];
224 }
225 nodenum = hnodes[nodenum*2 + (inbyte&1)];
226 inbyte >>=1;
227 //-----------
228 if (nodenum < 256)
229 {
230 hnodes = hnodesbase + (nodenum<<9);
231 *out_p++ = nodenum;
232 if (!--count)
233 break;
234 nodenum = cin->numhnodes1[nodenum];
235 }
236 nodenum = hnodes[nodenum*2 + (inbyte&1)];
237 inbyte >>=1;
238 //-----------
239 if (nodenum < 256)
240 {
241 hnodes = hnodesbase + (nodenum<<9);
242 *out_p++ = nodenum;
243 if (!--count)
244 break;
245 nodenum = cin->numhnodes1[nodenum];
246 }
247 nodenum = hnodes[nodenum*2 + (inbyte&1)];
248 inbyte >>=1;
249 //-----------
250 if (nodenum < 256)
251 {
252 hnodes = hnodesbase + (nodenum<<9);
253 *out_p++ = nodenum;
254 if (!--count)
255 break;
256 nodenum = cin->numhnodes1[nodenum];
257 }
258 nodenum = hnodes[nodenum*2 + (inbyte&1)];
259 inbyte >>=1;
260 //-----------
261 if (nodenum < 256)
262 {
263 hnodes = hnodesbase + (nodenum<<9);
264 *out_p++ = nodenum;
265 if (!--count)
266 break;
267 nodenum = cin->numhnodes1[nodenum];
268 }
269 nodenum = hnodes[nodenum*2 + (inbyte&1)];
270 inbyte >>=1;
271 //-----------
272 if (nodenum < 256)
273 {
274 hnodes = hnodesbase + (nodenum<<9);
275 *out_p++ = nodenum;
276 if (!--count)
277 break;
278 nodenum = cin->numhnodes1[nodenum];
279 }
280 nodenum = hnodes[nodenum*2 + (inbyte&1)];
281 inbyte >>=1;
282 //-----------
283 if (nodenum < 256)
284 {
285 hnodes = hnodesbase + (nodenum<<9);
286 *out_p++ = nodenum;
287 if (!--count)
288 break;
289 nodenum = cin->numhnodes1[nodenum];
290 }
291 nodenum = hnodes[nodenum*2 + (inbyte&1)];
292 inbyte >>=1;
293 //-----------
294 if (nodenum < 256)
295 {
296 hnodes = hnodesbase + (nodenum<<9);
297 *out_p++ = nodenum;
298 if (!--count)
299 break;
300 nodenum = cin->numhnodes1[nodenum];
301 }
302 nodenum = hnodes[nodenum*2 + (inbyte&1)];
303 inbyte >>=1;
304 }
305
306 /*if (input - in.data != in.count && input - in.data != in.count+1)
307 {
308 Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
309 }*/
310 out.count = out_p - out.data;
311
312 return out;
313 }
314
315 /*
316 ==================
317 CIN_ReadNextFrame
318 ==================
319 */
CIN_ReadNextFrame(void)320 byte *CIN_ReadNextFrame (void)
321 {
322 int command;
323 byte compressed[0x20000];
324 int size;
325 byte *pic;
326 cblock_t in, huf1;
327 int start, end, count, i;
328 byte *rp = ( byte * ) cin->palette;
329
330 // read the next frame
331 command = GetInteger(cin->offset); cin->offset += 4;
332 command = LittleLong(command);
333
334 if (command == 2)
335 return NULL; // last frame marker
336
337 if (command == 1)
338 { // read palette
339 memcpy(cin->rawpalette, cin->offset, sizeof(cin->rawpalette));
340 cin->offset += sizeof(cin->rawpalette);
341
342 for ( i = 0; i < 256; i++ )
343 {
344 rp[i*4+0] = cin->rawpalette[i*3+0];
345 rp[i*4+1] = cin->rawpalette[i*3+1];
346 rp[i*4+2] = cin->rawpalette[i*3+2];
347 rp[i*4+3] = 0xff;
348 }
349 }
350
351 // decompress the next frame
352 size = GetInteger(cin->offset); cin->offset += 4;
353 if (size > sizeof(compressed) || size < 1)
354 ri.Sys_Error (ERR_DROP, "Bad compressed frame size");
355 memcpy(compressed, cin->offset, size);
356 cin->offset += size;
357
358 // read sound
359 start = cin->frame*cin->s_rate*0.071428571428571428571428571428571;
360 end = (cin->frame+1)*cin->s_rate*0.071428571428571428571428571428571;
361 count = end - start;
362
363 cin->offset += (count*cin->s_width*cin->s_channels);
364
365 in.data = compressed;
366 in.count = size;
367
368 huf1 = Huff1Decompress (in);
369
370 pic = huf1.data;
371
372 cin->frame++;
373
374 return pic;
375 }
376
377
378 /*
379 ==================
380 CIN_RunCinematic
381
382 ==================
383 */
CIN_RunCinematic(void)384 void CIN_RunCinematic (void)
385 {
386 int frame;
387
388 if(!cin && !cin->cinematic_file)
389 return;
390
391 frame = (Sys_Milliseconds() - cin->time)*14.0*0.001;
392 if (frame <= cin->frame)
393 return;
394
395 if (frame > cin->frame+1)
396 {
397 //Com_Printf ("Dropped frame: %i > %i\n", frame, cin->frame+1);
398 cin->time = Sys_Milliseconds() - cin->frame*1000*0.071428571428571428571428571428571;
399 }
400 if (cin->pic)
401 free(cin->pic);
402 cin->pic = cin->pic_pending;
403 cin->pic_pending = NULL;
404 cin->pic_pending = CIN_ReadNextFrame ();
405 if (!cin->pic_pending)
406 {
407 CIN_StartCinematic ();
408 cin->pic_pending = CIN_ReadNextFrame ();
409 }
410
411 CIN_DrawCinematic();
412 }
413
414 /*
415 ==================
416 CIN_DrawCinematic
417
418 Returns true if a cinematic is active, meaning the view rendering
419 should be skipped
420 ==================
421 */
CIN_DrawCinematic(void)422 qboolean CIN_DrawCinematic (void)
423 {
424 int i, j;
425 byte *inrow;
426 unsigned frac, fracstep;
427 static unsigned image[MAX_SCALE_SIZE*MAX_SCALE_SIZE];
428 unsigned *out;
429
430 if (cin->time <= 0)
431 {
432 return false;
433 }
434
435 if (!cin->pic)
436 {
437 return true;
438 }
439
440 GL_Bind (cin->texnum);
441
442 out = image;
443 fracstep = cin->width*0x10000/cin->p2_width;
444 for (i=0 ; i<cin->p2_height ; i++, out += cin->p2_width)
445 {
446 inrow = cin->pic + cin->width*(i*cin->height/cin->p2_height);
447 frac = fracstep >> 1;
448 for (j=0 ; j<cin->p2_width ; j+=4)
449 {
450 out[j] = cin->palette[inrow[frac>>16]];
451 frac += fracstep;
452 out[j+1] = cin->palette[inrow[frac>>16]];
453 frac += fracstep;
454 out[j+2] = cin->palette[inrow[frac>>16]];
455 frac += fracstep;
456 out[j+3] = cin->palette[inrow[frac>>16]];
457 frac += fracstep;
458 }
459 }
460
461 qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, cin->p2_width, cin->p2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
462
463 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
464 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
465
466 return true;
467 }
468
469 /*
470 ==================
471 CIN_PlayCinematic
472
473 ==================
474 */
CIN_PlayCinematic(char * arg)475 void CIN_PlayCinematic (char *arg)
476 {
477 int size;
478
479 cin->frame = 0;
480
481 size = ri.FS_LoadFile(arg, (void **)&cin->cinematic_file);
482 if(size == -1)
483 {
484 ri.Sys_Error (ERR_DROP, "Cinematic %s not found.\n", arg);
485 cin->time = 0; // done
486 return;
487 }
488
489 cin->offset = cin->cinematic_file;
490
491 cin->width = GetInteger(cin->offset); cin->offset += 4;
492 cin->height = GetInteger(cin->offset); cin->offset += 4;
493 cin->s_rate = GetInteger(cin->offset); cin->offset += 4;
494 cin->s_width = GetInteger(cin->offset); cin->offset += 4;
495 cin->s_channels = GetInteger(cin->offset); cin->offset += 4;
496
497 for( cin->p2_width = 2 ; cin->p2_width <= cin->width ; cin->p2_width <<= 1 );
498 cin->p2_width >>= 1;
499
500 if(cin->p2_width >= MAX_SCALE_SIZE)
501 {
502 cin->p2_width = MAX_SCALE_SIZE;
503 }
504
505 for( cin->p2_height = 2 ; cin->p2_height <= cin->height ; cin->p2_height <<= 1 );
506 cin->p2_height >>= 1;
507
508 if(cin->p2_height >= MAX_SCALE_SIZE)
509 {
510 cin->p2_height = MAX_SCALE_SIZE;
511 }
512
513 Huff1TableInit ();
514
515 cin->frame = 0;
516 cin->pic = CIN_ReadNextFrame ();
517 cin->time = Sys_Milliseconds();
518 }
519
520 /*
521 ==================
522 CIN_StartCinematic
523 ==================
524 */
CIN_StartCinematic(void)525 void CIN_StartCinematic (void)
526 {
527 cin->offset = cin->framestart;
528
529 cin->frame = 0;
530 cin->time = Sys_Milliseconds();
531
532 cin->pic = CIN_ReadNextFrame ();
533 }
534
535
536 /*
537 ==================
538 CIN_OpenCin
539 ==================
540 */
541 #define MAX_CINS 8
542 cinematics_t cinpool[MAX_CINS];
543
CIN_OpenCin(char * name)544 cinematics_t *CIN_OpenCin (char *name)
545 {
546 int i;
547
548 //return nothing if there is no file!
549 if (!ri.FS_LoadFile(name, NULL))
550 return NULL;
551
552 for(i=0; i<MAX_CINS; i++)
553 {
554 if(cinpool[i].texnum)
555 continue;
556
557 cin = &cinpool[i];
558 CIN_PlayCinematic(name);
559
560 return &cinpool[i];
561 }
562
563 return NULL;
564 }
565
CIN_ProcessCins(void)566 void CIN_ProcessCins (void)
567 {
568 int i;
569
570 for(i=0; i<MAX_CINS; i++)
571 {
572 if(cinpool[i].texnum)
573 {
574 cin = &cinpool[i];
575
576 CIN_RunCinematic();
577 }
578 }
579 }
580
CIN_FreeCin(int texnum)581 void CIN_FreeCin (int texnum)
582 {
583 int i;
584
585 for(i=0; i<MAX_CINS; i++)
586 {
587 if(cinpool[i].texnum == texnum)
588 {
589 cin = &cinpool[i];
590 CIN_StopCinematic();
591 cinpool[i].texnum = 0;
592
593 return;
594 }
595 }
596 }
597
598