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