1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 /*****************************************************************************
31  * name:		cl_cin.c
32  *
33  * desc:		video and cinematic playback
34  *
35  *
36  * cl_glconfig.hwtype trtypes 3dfx/ragepro need 256x256
37  *
38  *****************************************************************************/
39 
40 //#define ADAPTED_TO_STREAMING_SOUND
41 //	(SA) MISSIONPACK MERGE
42 //	s_rawend for wolf is [] and for q3 is just a single value
43 //  I need to ask Ryan if it's as simple as a constant index or
44 // if some more coding needs to be done.
45 
46 
47 #include "client.h"
48 #include "snd_local.h"
49 
50 #define MAXSIZE             8
51 #define MINSIZE             4
52 
53 #define DEFAULT_CIN_WIDTH   512
54 #define DEFAULT_CIN_HEIGHT  512
55 
56 #define ROQ_QUAD            0x1000
57 #define ROQ_QUAD_INFO       0x1001
58 #define ROQ_CODEBOOK        0x1002
59 #define ROQ_QUAD_VQ         0x1011
60 #define ROQ_QUAD_JPEG       0x1012
61 #define ROQ_QUAD_HANG       0x1013
62 #define ROQ_PACKET          0x1030
63 #define ZA_SOUND_MONO       0x1020
64 #define ZA_SOUND_STEREO     0x1021
65 
66 #define MAX_VIDEO_HANDLES   16
67 
68 extern int s_soundtime;
69 
70 static void RoQ_init( void );
71 
72 /******************************************************************************
73 *
74 * Class:		trFMV
75 *
76 * Description:	RoQ/RnR manipulation routines
77 *				not entirely complete for first run
78 *
79 ******************************************************************************/
80 
81 static long ROQ_YY_tab[256];
82 static long ROQ_UB_tab[256];
83 static long ROQ_UG_tab[256];
84 static long ROQ_VG_tab[256];
85 static long ROQ_VR_tab[256];
86 static unsigned short vq2[256 * 16 * 4];
87 static unsigned short vq4[256 * 64 * 4];
88 static unsigned short vq8[256 * 256 * 4];
89 
90 
91 typedef struct {
92 	byte linbuf[DEFAULT_CIN_WIDTH * DEFAULT_CIN_HEIGHT * 4 * 2];
93 	byte file[65536];
94 	short sqrTable[256];
95 
96 	int	mcomp[256];
97 	byte                *qStatus[2][32768];
98 
99 	long oldXOff, oldYOff, oldysize, oldxsize;
100 
101 	int currentHandle;
102 } cinematics_t;
103 
104 typedef struct {
105 	char fileName[MAX_OSPATH];
106 	int CIN_WIDTH, CIN_HEIGHT;
107 	int xpos, ypos, width, height;
108 	qboolean looping, holdAtEnd, dirty, alterGameState, silent, shader;
109 	fileHandle_t iFile;
110 	e_status status;
111 	int startTime;
112 	int lastTime;
113 	long tfps;
114 	long RoQPlayed;
115 	long ROQSize;
116 	unsigned int RoQFrameSize;
117 	long onQuad;
118 	long numQuads;
119 	long samplesPerLine;
120 	unsigned int roq_id;
121 	long screenDelta;
122 
123 	void ( *VQ0 )( byte *status, void *qdata );
124 	void ( *VQ1 )( byte *status, void *qdata );
125 	void ( *VQNormal )( byte *status, void *qdata );
126 	void ( *VQBuffer )( byte *status, void *qdata );
127 
128 	long samplesPerPixel;                               // defaults to 2
129 	byte*               gray;
130 	unsigned int xsize, ysize, maxsize, minsize;
131 
132 	qboolean half, smootheddouble, inMemory;
133 	long normalBuffer0;
134 	long roq_flags;
135 	long roqF0;
136 	long roqF1;
137 	long t[2];
138 	long roqFPS;
139 	int playonwalls;
140 	byte*               buf;
141 	long drawX, drawY;
142 } cin_cache;
143 
144 static cinematics_t cin;
145 static cin_cache cinTable[MAX_VIDEO_HANDLES];
146 static int currentHandle = -1;
147 static int CL_handle = -1;
148 
CIN_CloseAllVideos(void)149 void CIN_CloseAllVideos( void ) {
150 	int i;
151 
152 	for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
153 		if ( cinTable[i].fileName[0] != 0 ) {
154 			CIN_StopCinematic( i );
155 		}
156 	}
157 }
158 
159 
CIN_HandleForVideo(void)160 static int CIN_HandleForVideo( void ) {
161 	int i;
162 
163 	for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
164 		if ( cinTable[i].fileName[0] == 0 ) {
165 			return i;
166 		}
167 	}
168 	Com_Error( ERR_DROP, "CIN_HandleForVideo: none free" );
169 	return -1;
170 }
171 
172 
173 extern int CL_ScaledMilliseconds( void );
174 
175 //-----------------------------------------------------------------------------
176 // RllSetupTable
177 //
178 // Allocates and initializes the square table.
179 //
180 // Parameters:	None
181 //
182 // Returns:		Nothing
183 //-----------------------------------------------------------------------------
RllSetupTable(void)184 static void RllSetupTable( void ) {
185 	int z;
186 
187 	for ( z = 0; z < 128; z++ ) {
188 		cin.sqrTable[z] = (short)( z * z );
189 		cin.sqrTable[z + 128] = (short)( -cin.sqrTable[z] );
190 	}
191 }
192 
193 
194 
195 //-----------------------------------------------------------------------------
196 // RllDecodeMonoToMono
197 //
198 // Decode mono source data into a mono buffer.
199 //
200 // Parameters:	from -> buffer holding encoded data
201 //				to ->	buffer to hold decoded data
202 //				size =	number of bytes of input (= # of shorts of output)
203 //				signedOutput = 0 for unsigned output, non-zero for signed output
204 //				flag = flags from asset header
205 //
206 // Returns:		Number of samples placed in output buffer
207 //-----------------------------------------------------------------------------
RllDecodeMonoToMono(unsigned char * from,short * to,unsigned int size,char signedOutput,unsigned short flag)208 long RllDecodeMonoToMono( unsigned char *from,short *to,unsigned int size,char signedOutput,unsigned short flag ) {
209 	unsigned int z;
210 	int prev;
211 
212 	if ( signedOutput ) {
213 		prev =  flag - 0x8000;
214 	} else {
215 		prev = flag;
216 	}
217 
218 	for ( z = 0; z < size; z++ ) {
219 		prev = to[z] = (short)( prev + cin.sqrTable[from[z]] );
220 	}
221 	return size;    //*sizeof(short));
222 }
223 
224 
225 //-----------------------------------------------------------------------------
226 // RllDecodeMonoToStereo
227 //
228 // Decode mono source data into a stereo buffer. Output is 4 times the number
229 // of bytes in the input.
230 //
231 // Parameters:	from -> buffer holding encoded data
232 //				to ->	buffer to hold decoded data
233 //				size =	number of bytes of input (= 1/4 # of bytes of output)
234 //				signedOutput = 0 for unsigned output, non-zero for signed output
235 //				flag = flags from asset header
236 //
237 // Returns:		Number of samples placed in output buffer
238 //-----------------------------------------------------------------------------
RllDecodeMonoToStereo(unsigned char * from,short * to,unsigned int size,char signedOutput,unsigned short flag)239 long RllDecodeMonoToStereo( unsigned char *from,short *to,unsigned int size,char signedOutput,unsigned short flag ) {
240 	unsigned int z;
241 	int prev;
242 
243 	if ( signedOutput ) {
244 		prev =  flag - 0x8000;
245 	} else {
246 		prev = flag;
247 	}
248 
249 	for ( z = 0; z < size; z++ ) {
250 		prev = (short)( prev + cin.sqrTable[from[z]] );
251 		to[z * 2 + 0] = to[z * 2 + 1] = (short)( prev );
252 	}
253 
254 	return size;    // * 2 * sizeof(short));
255 }
256 
257 
258 //-----------------------------------------------------------------------------
259 // RllDecodeStereoToStereo
260 //
261 // Decode stereo source data into a stereo buffer.
262 //
263 // Parameters:	from -> buffer holding encoded data
264 //				to ->	buffer to hold decoded data
265 //				size =	number of bytes of input (= 1/2 # of bytes of output)
266 //				signedOutput = 0 for unsigned output, non-zero for signed output
267 //				flag = flags from asset header
268 //
269 // Returns:		Number of samples placed in output buffer
270 //-----------------------------------------------------------------------------
RllDecodeStereoToStereo(unsigned char * from,short * to,unsigned int size,char signedOutput,unsigned short flag)271 long RllDecodeStereoToStereo( unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag ) {
272 	unsigned int z;
273 	unsigned char *zz = from;
274 	int prevL, prevR;
275 
276 	if ( signedOutput ) {
277 		prevL = ( flag & 0xff00 ) - 0x8000;
278 		prevR = ( ( flag & 0x00ff ) << 8 ) - 0x8000;
279 	} else {
280 		prevL = flag & 0xff00;
281 		prevR = ( flag & 0x00ff ) << 8;
282 	}
283 
284 	for ( z = 0; z < size; z += 2 ) {
285 		prevL = (short)( prevL + cin.sqrTable[*zz++] );
286 		prevR = (short)( prevR + cin.sqrTable[*zz++] );
287 		to[z + 0] = (short)( prevL );
288 		to[z + 1] = (short)( prevR );
289 	}
290 
291 	return ( size >> 1 );   //*sizeof(short));
292 }
293 
294 
295 //-----------------------------------------------------------------------------
296 // RllDecodeStereoToMono
297 //
298 // Decode stereo source data into a mono buffer.
299 //
300 // Parameters:	from -> buffer holding encoded data
301 //				to ->	buffer to hold decoded data
302 //				size =	number of bytes of input (= # of bytes of output)
303 //				signedOutput = 0 for unsigned output, non-zero for signed output
304 //				flag = flags from asset header
305 //
306 // Returns:		Number of samples placed in output buffer
307 //-----------------------------------------------------------------------------
RllDecodeStereoToMono(unsigned char * from,short * to,unsigned int size,char signedOutput,unsigned short flag)308 long RllDecodeStereoToMono( unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag ) {
309 	unsigned int z;
310 	int prevL,prevR;
311 
312 	if ( signedOutput ) {
313 		prevL = ( flag & 0xff00 ) - 0x8000;
314 		prevR = ( ( flag & 0x00ff ) << 8 ) - 0x8000;
315 	} else {
316 		prevL = flag & 0xff00;
317 		prevR = ( flag & 0x00ff ) << 8;
318 	}
319 
320 	for ( z = 0; z < size; z += 1 ) {
321 		prevL = prevL + cin.sqrTable[from[z * 2]];
322 		prevR = prevR + cin.sqrTable[from[z * 2 + 1]];
323 		to[z] = (short)( ( prevL + prevR ) / 2 );
324 	}
325 
326 	return size;
327 }
328 
329 /******************************************************************************
330 *
331 * Function:
332 *
333 * Description:
334 *
335 ******************************************************************************/
336 
move8_32(byte * src,byte * dst,int spl)337 static void move8_32( byte *src, byte *dst, int spl ) {
338 	int i;
339 
340 	for(i = 0; i < 8; ++i)
341 	{
342 		memcpy(dst, src, 32);
343 		src += spl;
344 		dst += spl;
345 	}
346 }
347 
348 /******************************************************************************
349 *
350 * Function:
351 *
352 * Description:
353 *
354 ******************************************************************************/
355 
move4_32(byte * src,byte * dst,int spl)356 static void move4_32( byte *src, byte *dst, int spl  ) {
357 	int i;
358 
359 	for(i = 0; i < 4; ++i)
360 	{
361 		memcpy(dst, src, 16);
362 		src += spl;
363 		dst += spl;
364 	}
365 }
366 
367 /******************************************************************************
368 *
369 * Function:
370 *
371 * Description:
372 *
373 ******************************************************************************/
374 
blit8_32(byte * src,byte * dst,int spl)375 static void blit8_32( byte *src, byte *dst, int spl  ) {
376 	int i;
377 
378 	for(i = 0; i < 8; ++i)
379 	{
380 		memcpy(dst, src, 32);
381 		src += 32;
382 		dst += spl;
383 	}
384 }
385 
386 /******************************************************************************
387 *
388 * Function:
389 *
390 * Description:
391 *
392 ******************************************************************************/
blit4_32(byte * src,byte * dst,int spl)393 static void blit4_32( byte *src, byte *dst, int spl  ) {
394 	int i;
395 
396 	for(i = 0; i < 4; ++i)
397 	{
398 		memmove(dst, src, 16);
399 		src += 16;
400 		dst += spl;
401 	}
402 }
403 
404 /******************************************************************************
405 *
406 * Function:
407 *
408 * Description:
409 *
410 ******************************************************************************/
411 
blit2_32(byte * src,byte * dst,int spl)412 static void blit2_32( byte *src, byte *dst, int spl  ) {
413 	memcpy(dst, src, 8);
414 	memcpy(dst+spl, src+8, 8);
415 }
416 
417 /******************************************************************************
418 *
419 * Function:
420 *
421 * Description:
422 *
423 ******************************************************************************/
424 
blitVQQuad32fs(byte ** status,unsigned char * data)425 static void blitVQQuad32fs( byte **status, unsigned char *data ) {
426 	unsigned short newd, celdata, code;
427 	unsigned int index, i;
428 	int spl;
429 
430 	newd    = 0;
431 	celdata = 0;
432 	index   = 0;
433 
434 	spl = cinTable[currentHandle].samplesPerLine;
435 
436 	do {
437 		if ( !newd ) {
438 			newd = 7;
439 			celdata = data[0] + data[1] * 256;
440 			data += 2;
441 		} else {
442 			newd--;
443 		}
444 
445 		code = ( unsigned short )( celdata & 0xc000 );
446 		celdata <<= 2;
447 
448 		switch ( code ) {
449 		case    0x8000:                                                     // vq code
450 			blit8_32( (byte *)&vq8[( *data ) * 128], status[index], spl );
451 			data++;
452 			index += 5;
453 			break;
454 		case    0xc000:                                                     // drop
455 			index++;                                                        // skip 8x8
456 			for ( i = 0; i < 4; i++ ) {
457 				if ( !newd ) {
458 					newd = 7;
459 					celdata = data[0] + data[1] * 256;
460 					data += 2;
461 				} else {
462 					newd--;
463 				}
464 
465 				code = ( unsigned short )( celdata & 0xc000 ); celdata <<= 2;
466 
467 				switch ( code ) {                                           // code in top two bits of code
468 				case    0x8000:                                             // 4x4 vq code
469 					blit4_32( (byte *)&vq4[( *data ) * 32], status[index], spl );
470 					data++;
471 					break;
472 				case    0xc000:                                             // 2x2 vq code
473 					blit2_32( (byte *)&vq2[( *data ) * 8], status[index], spl );
474 					data++;
475 					blit2_32( (byte *)&vq2[( *data ) * 8], status[index] + 8, spl );
476 					data++;
477 					blit2_32( (byte *)&vq2[( *data ) * 8], status[index] + spl * 2, spl );
478 					data++;
479 					blit2_32( (byte *)&vq2[( *data ) * 8], status[index] + spl * 2 + 8, spl );
480 					data++;
481 					break;
482 				case    0x4000:                                             // motion compensation
483 					move4_32( status[index] + cin.mcomp[( *data )], status[index], spl );
484 					data++;
485 					break;
486 				}
487 				index++;
488 			}
489 			break;
490 		case    0x4000:                                                     // motion compensation
491 			move8_32( status[index] + cin.mcomp[( *data )], status[index], spl );
492 			data++;
493 			index += 5;
494 			break;
495 		case    0x0000:
496 			index += 5;
497 			break;
498 		}
499 	} while ( status[index] != NULL );
500 }
501 
502 /******************************************************************************
503 *
504 * Function:
505 *
506 * Description:
507 *
508 ******************************************************************************/
509 
ROQ_GenYUVTables(void)510 static void ROQ_GenYUVTables( void ) {
511 	float t_ub,t_vr,t_ug,t_vg;
512 	long i;
513 
514 	t_ub = ( 1.77200f / 2.0f ) * (float)( 1 << 6 ) + 0.5f;
515 	t_vr = ( 1.40200f / 2.0f ) * (float)( 1 << 6 ) + 0.5f;
516 	t_ug = ( 0.34414f / 2.0f ) * (float)( 1 << 6 ) + 0.5f;
517 	t_vg = ( 0.71414f / 2.0f ) * (float)( 1 << 6 ) + 0.5f;
518 	for ( i = 0; i < 256; i++ ) {
519 		float x = (float)( 2 * i - 255 );
520 
521 		ROQ_UB_tab[i] = (long)( ( t_ub * x ) + ( 1 << 5 ) );
522 		ROQ_VR_tab[i] = (long)( ( t_vr * x ) + ( 1 << 5 ) );
523 		ROQ_UG_tab[i] = (long)( ( -t_ug * x )      );
524 		ROQ_VG_tab[i] = (long)( ( -t_vg * x ) + ( 1 << 5 ) );
525 		ROQ_YY_tab[i] = (long)( ( i << 6 ) | ( i >> 2 ) );
526 	}
527 }
528 
529 #define VQ2TO4( a,b,c,d ) {	\
530 		*c++ = a[0];	\
531 		*d++ = a[0];	\
532 		*d++ = a[0];	\
533 		*c++ = a[1];	\
534 		*d++ = a[1];	\
535 		*d++ = a[1];	\
536 		*c++ = b[0];	\
537 		*d++ = b[0];	\
538 		*d++ = b[0];	\
539 		*c++ = b[1];	\
540 		*d++ = b[1];	\
541 		*d++ = b[1];	\
542 		*d++ = a[0];	\
543 		*d++ = a[0];	\
544 		*d++ = a[1];	\
545 		*d++ = a[1];	\
546 		*d++ = b[0];	\
547 		*d++ = b[0];	\
548 		*d++ = b[1];	\
549 		*d++ = b[1];	\
550 		a += 2; b += 2; }
551 
552 #define VQ2TO2( a,b,c,d ) {	\
553 		*c++ = *a;	\
554 		*d++ = *a;	\
555 		*d++ = *a;	\
556 		*c++ = *b;	\
557 		*d++ = *b;	\
558 		*d++ = *b;	\
559 		*d++ = *a;	\
560 		*d++ = *a;	\
561 		*d++ = *b;	\
562 		*d++ = *b;	\
563 		a++; b++; }
564 
565 /******************************************************************************
566 *
567 * Function:
568 *
569 * Description:
570 *
571 ******************************************************************************/
572 
yuv_to_rgb(long y,long u,long v)573 static unsigned short yuv_to_rgb( long y, long u, long v ) {
574 	long r,g,b,YY = (long)( ROQ_YY_tab[( y )] );
575 
576 	r = ( YY + ROQ_VR_tab[v] ) >> 9;
577 	g = ( YY + ROQ_UG_tab[u] + ROQ_VG_tab[v] ) >> 8;
578 	b = ( YY + ROQ_UB_tab[u] ) >> 9;
579 
580 	if ( r < 0 ) {
581 		r = 0;
582 	}
583 	if ( g < 0 ) {
584 		g = 0;
585 	}
586 	if ( b < 0 ) {
587 		b = 0;
588 	}
589 	if ( r > 31 ) {
590 		r = 31;
591 	}
592 	if ( g > 63 ) {
593 		g = 63;
594 	}
595 	if ( b > 31 ) {
596 		b = 31;
597 	}
598 
599 	return ( unsigned short )( ( r << 11 ) + ( g << 5 ) + ( b ) );
600 }
601 
602 /******************************************************************************
603 *
604 * Function:
605 *
606 * Description:
607 *
608 ******************************************************************************/
yuv_to_rgb24(long y,long u,long v)609 static unsigned int yuv_to_rgb24( long y, long u, long v ) {
610 	long r,g,b,YY = (long)( ROQ_YY_tab[( y )] );
611 
612 	r = ( YY + ROQ_VR_tab[v] ) >> 6;
613 	g = ( YY + ROQ_UG_tab[u] + ROQ_VG_tab[v] ) >> 6;
614 	b = ( YY + ROQ_UB_tab[u] ) >> 6;
615 
616 	if ( r < 0 ) {
617 		r = 0;
618 	}
619 	if ( g < 0 ) {
620 		g = 0;
621 	}
622 	if ( b < 0 ) {
623 		b = 0;
624 	}
625 	if ( r > 255 ) {
626 		r = 255;
627 	}
628 	if ( g > 255 ) {
629 		g = 255;
630 	}
631 	if ( b > 255 ) {
632 		b = 255;
633 	}
634 
635 	return LittleLong( ( unsigned long )( ( r ) | ( g << 8 ) | ( b << 16 ) ) | ( 255UL << 24 ) );
636 }
637 
638 /******************************************************************************
639 *
640 * Function:
641 *
642 * Description:
643 *
644 ******************************************************************************/
645 
decodeCodeBook(byte * input,unsigned short roq_flags)646 static void decodeCodeBook( byte *input, unsigned short roq_flags ) {
647 	long i, j, two, four;
648 	unsigned short  *aptr, *bptr, *cptr, *dptr;
649 	long y0,y1,y2,y3,cr,cb;
650 	byte    *bbptr, *baptr, *bcptr, *bdptr;
651 	union {
652 		unsigned int *i;
653 		unsigned short *s;
654 	} iaptr, ibptr, icptr, idptr;
655 
656 	if ( !roq_flags ) {
657 		two = four = 256;
658 	} else {
659 		two  = roq_flags >> 8;
660 		if ( !two ) {
661 			two = 256;
662 		}
663 		four = roq_flags & 0xff;
664 	}
665 
666 	four *= 2;
667 
668 	bptr = (unsigned short *)vq2;
669 
670 	if ( !cinTable[currentHandle].half ) {
671 		if ( !cinTable[currentHandle].smootheddouble ) {
672 //
673 // normal height
674 //
675 			if ( cinTable[currentHandle].samplesPerPixel == 2 ) {
676 				for ( i = 0; i < two; i++ ) {
677 					y0 = (long)*input++;
678 					y1 = (long)*input++;
679 					y2 = (long)*input++;
680 					y3 = (long)*input++;
681 					cr = (long)*input++;
682 					cb = (long)*input++;
683 					*bptr++ = yuv_to_rgb( y0, cr, cb );
684 					*bptr++ = yuv_to_rgb( y1, cr, cb );
685 					*bptr++ = yuv_to_rgb( y2, cr, cb );
686 					*bptr++ = yuv_to_rgb( y3, cr, cb );
687 				}
688 
689 				cptr = (unsigned short *)vq4;
690 				dptr = (unsigned short *)vq8;
691 
692 				for ( i = 0; i < four; i++ ) {
693 					aptr = (unsigned short *)vq2 + ( *input++ ) * 4;
694 					bptr = (unsigned short *)vq2 + ( *input++ ) * 4;
695 					for ( j = 0; j < 2; j++ )
696 						VQ2TO4( aptr,bptr,cptr,dptr );
697 				}
698 			} else if ( cinTable[currentHandle].samplesPerPixel == 4 ) {
699 				ibptr.s = bptr;
700 				for ( i = 0; i < two; i++ ) {
701 					y0 = (long)*input++;
702 					y1 = (long)*input++;
703 					y2 = (long)*input++;
704 					y3 = (long)*input++;
705 					cr = (long)*input++;
706 					cb = (long)*input++;
707 					*ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
708 					*ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
709 					*ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
710 					*ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
711 				}
712 
713 				icptr.s = vq4;
714 				idptr.s = vq8;
715 
716 				for ( i = 0; i < four; i++ ) {
717 					iaptr.s = vq2;
718 					iaptr.i += (*input++)*4;
719 					ibptr.s = vq2;
720 					ibptr.i += (*input++)*4;
721 					for ( j = 0; j < 2; j++ )
722 						VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
723 				}
724 			} else if ( cinTable[currentHandle].samplesPerPixel == 1 ) {
725 				bbptr = (byte *)bptr;
726 				for ( i = 0; i < two; i++ ) {
727 					*bbptr++ = cinTable[currentHandle].gray[*input++];
728 					*bbptr++ = cinTable[currentHandle].gray[*input++];
729 					*bbptr++ = cinTable[currentHandle].gray[*input++];
730 					*bbptr++ = cinTable[currentHandle].gray[*input]; input += 3;
731 				}
732 
733 				bcptr = (byte *)vq4;
734 				bdptr = (byte *)vq8;
735 
736 				for ( i = 0; i < four; i++ ) {
737 					baptr = (byte *)vq2 + ( *input++ ) * 4;
738 					bbptr = (byte *)vq2 + ( *input++ ) * 4;
739 					for ( j = 0; j < 2; j++ )
740 						VQ2TO4( baptr,bbptr,bcptr,bdptr );
741 				}
742 			}
743 		} else {
744 //
745 // double height, smoothed
746 //
747 			if ( cinTable[currentHandle].samplesPerPixel == 2 ) {
748 				for ( i = 0; i < two; i++ ) {
749 					y0 = (long)*input++;
750 					y1 = (long)*input++;
751 					y2 = (long)*input++;
752 					y3 = (long)*input++;
753 					cr = (long)*input++;
754 					cb = (long)*input++;
755 					*bptr++ = yuv_to_rgb( y0, cr, cb );
756 					*bptr++ = yuv_to_rgb( y1, cr, cb );
757 					*bptr++ = yuv_to_rgb( ( ( y0 * 3 ) + y2 ) / 4, cr, cb );
758 					*bptr++ = yuv_to_rgb( ( ( y1 * 3 ) + y3 ) / 4, cr, cb );
759 					*bptr++ = yuv_to_rgb( ( y0 + ( y2 * 3 ) ) / 4, cr, cb );
760 					*bptr++ = yuv_to_rgb( ( y1 + ( y3 * 3 ) ) / 4, cr, cb );
761 					*bptr++ = yuv_to_rgb( y2, cr, cb );
762 					*bptr++ = yuv_to_rgb( y3, cr, cb );
763 				}
764 
765 				cptr = (unsigned short *)vq4;
766 				dptr = (unsigned short *)vq8;
767 
768 				for ( i = 0; i < four; i++ ) {
769 					aptr = (unsigned short *)vq2 + ( *input++ ) * 8;
770 					bptr = (unsigned short *)vq2 + ( *input++ ) * 8;
771 					for ( j = 0; j < 2; j++ ) {
772 						VQ2TO4( aptr,bptr,cptr,dptr );
773 						VQ2TO4( aptr,bptr,cptr,dptr );
774 					}
775 				}
776 			} else if ( cinTable[currentHandle].samplesPerPixel == 4 ) {
777 				ibptr.s = bptr;
778 				for ( i = 0; i < two; i++ ) {
779 					y0 = (long)*input++;
780 					y1 = (long)*input++;
781 					y2 = (long)*input++;
782 					y3 = (long)*input++;
783 					cr = (long)*input++;
784 					cb = (long)*input++;
785 					*ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
786 					*ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
787 					*ibptr.i++ = yuv_to_rgb24( ((y0*3)+y2)/4, cr, cb );
788 					*ibptr.i++ = yuv_to_rgb24( ((y1*3)+y3)/4, cr, cb );
789 					*ibptr.i++ = yuv_to_rgb24( (y0+(y2*3))/4, cr, cb );
790 					*ibptr.i++ = yuv_to_rgb24( (y1+(y3*3))/4, cr, cb );
791 					*ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
792 					*ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
793 				}
794 
795 				icptr.s = vq4;
796 				idptr.s = vq8;
797 
798 				for ( i = 0; i < four; i++ ) {
799 					iaptr.s = vq2;
800 					iaptr.i += (*input++)*8;
801 					ibptr.s = vq2;
802 					ibptr.i += (*input++)*8;
803 					for ( j = 0; j < 2; j++ ) {
804 						VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
805 						VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
806 					}
807 				}
808 			} else if ( cinTable[currentHandle].samplesPerPixel == 1 ) {
809 				bbptr = (byte *)bptr;
810 				for ( i = 0; i < two; i++ ) {
811 					y0 = (long)*input++;
812 					y1 = (long)*input++;
813 					y2 = (long)*input++;
814 					y3 = (long)*input; input += 3;
815 					*bbptr++ = cinTable[currentHandle].gray[y0];
816 					*bbptr++ = cinTable[currentHandle].gray[y1];
817 					*bbptr++ = cinTable[currentHandle].gray[( ( y0 * 3 ) + y2 ) / 4];
818 					*bbptr++ = cinTable[currentHandle].gray[( ( y1 * 3 ) + y3 ) / 4];
819 					*bbptr++ = cinTable[currentHandle].gray[( y0 + ( y2 * 3 ) ) / 4];
820 					*bbptr++ = cinTable[currentHandle].gray[( y1 + ( y3 * 3 ) ) / 4];
821 					*bbptr++ = cinTable[currentHandle].gray[y2];
822 					*bbptr++ = cinTable[currentHandle].gray[y3];
823 				}
824 
825 				bcptr = (byte *)vq4;
826 				bdptr = (byte *)vq8;
827 
828 				for ( i = 0; i < four; i++ ) {
829 					baptr = (byte *)vq2 + ( *input++ ) * 8;
830 					bbptr = (byte *)vq2 + ( *input++ ) * 8;
831 					for ( j = 0; j < 2; j++ ) {
832 						VQ2TO4( baptr,bbptr,bcptr,bdptr );
833 						VQ2TO4( baptr,bbptr,bcptr,bdptr );
834 					}
835 				}
836 			}
837 		}
838 	} else {
839 //
840 // 1/4 screen
841 //
842 		if ( cinTable[currentHandle].samplesPerPixel == 2 ) {
843 			for ( i = 0; i < two; i++ ) {
844 				y0 = (long)*input; input += 2;
845 				y2 = (long)*input; input += 2;
846 				cr = (long)*input++;
847 				cb = (long)*input++;
848 				*bptr++ = yuv_to_rgb( y0, cr, cb );
849 				*bptr++ = yuv_to_rgb( y2, cr, cb );
850 			}
851 
852 			cptr = (unsigned short *)vq4;
853 			dptr = (unsigned short *)vq8;
854 
855 			for ( i = 0; i < four; i++ ) {
856 				aptr = (unsigned short *)vq2 + ( *input++ ) * 2;
857 				bptr = (unsigned short *)vq2 + ( *input++ ) * 2;
858 				for ( j = 0; j < 2; j++ ) {
859 					VQ2TO2( aptr,bptr,cptr,dptr );
860 				}
861 			}
862 		} else if ( cinTable[currentHandle].samplesPerPixel == 1 ) {
863 			bbptr = (byte *)bptr;
864 
865 			for ( i = 0; i < two; i++ ) {
866 				*bbptr++ = cinTable[currentHandle].gray[*input]; input += 2;
867 				*bbptr++ = cinTable[currentHandle].gray[*input]; input += 4;
868 			}
869 
870 			bcptr = (byte *)vq4;
871 			bdptr = (byte *)vq8;
872 
873 			for ( i = 0; i < four; i++ ) {
874 				baptr = (byte *)vq2 + ( *input++ ) * 2;
875 				bbptr = (byte *)vq2 + ( *input++ ) * 2;
876 				for ( j = 0; j < 2; j++ ) {
877 					VQ2TO2( baptr,bbptr,bcptr,bdptr );
878 				}
879 			}
880 		} else if ( cinTable[currentHandle].samplesPerPixel == 4 ) {
881 			ibptr.s = bptr;
882 			for ( i = 0; i < two; i++ ) {
883 				y0 = (long)*input; input += 2;
884 				y2 = (long)*input; input += 2;
885 				cr = (long)*input++;
886 				cb = (long)*input++;
887 				*ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
888 				*ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
889 			}
890 
891 			icptr.s = vq4;
892 			idptr.s = vq8;
893 
894 			for ( i = 0; i < four; i++ ) {
895 				iaptr.s = vq2;
896 				iaptr.i += (*input++)*2;
897 				ibptr.s = vq2 + (*input++)*2;
898 				ibptr.i += (*input++)*2;
899 				for ( j = 0; j < 2; j++ ) {
900 					VQ2TO2(iaptr.i,ibptr.i,icptr.i,idptr.i);
901 				}
902 			}
903 		}
904 	}
905 }
906 
907 /******************************************************************************
908 *
909 * Function:
910 *
911 * Description:
912 *
913 ******************************************************************************/
914 
recurseQuad(long startX,long startY,long quadSize,long xOff,long yOff)915 static void recurseQuad( long startX, long startY, long quadSize, long xOff, long yOff ) {
916 	byte *scroff;
917 	long bigx, bigy, lowx, lowy, useY;
918 	long offset;
919 
920 	offset = cinTable[currentHandle].screenDelta;
921 
922 	lowx = lowy = 0;
923 	bigx = cinTable[currentHandle].xsize;
924 	bigy = cinTable[currentHandle].ysize;
925 
926 	if ( bigx > cinTable[currentHandle].CIN_WIDTH ) {
927 		bigx = cinTable[currentHandle].CIN_WIDTH;
928 	}
929 	if ( bigy > cinTable[currentHandle].CIN_HEIGHT ) {
930 		bigy = cinTable[currentHandle].CIN_HEIGHT;
931 	}
932 
933 	if ( ( startX >= lowx ) && ( startX + quadSize ) <= ( bigx ) && ( startY + quadSize ) <= ( bigy ) && ( startY >= lowy ) && quadSize <= MAXSIZE ) {
934 		useY = startY;
935 		scroff = cin.linbuf + ( useY + ( ( cinTable[currentHandle].CIN_HEIGHT - bigy ) >> 1 ) + yOff ) * ( cinTable[currentHandle].samplesPerLine ) + ( ( ( startX + xOff ) ) * cinTable[currentHandle].samplesPerPixel );
936 
937 		cin.qStatus[0][cinTable[currentHandle].onQuad  ] = scroff;
938 		cin.qStatus[1][cinTable[currentHandle].onQuad++] = scroff + offset;
939 	}
940 
941 	if ( quadSize != MINSIZE ) {
942 		quadSize >>= 1;
943 		recurseQuad( startX,          startY, quadSize, xOff, yOff );
944 		recurseQuad( startX + quadSize, startY, quadSize, xOff, yOff );
945 		recurseQuad( startX,          startY + quadSize, quadSize, xOff, yOff );
946 		recurseQuad( startX + quadSize, startY + quadSize, quadSize, xOff, yOff );
947 	}
948 }
949 
950 
951 /******************************************************************************
952 *
953 * Function:
954 *
955 * Description:
956 *
957 ******************************************************************************/
958 
setupQuad(long xOff,long yOff)959 static void setupQuad( long xOff, long yOff ) {
960 	long numQuadCels, i,x,y;
961 	byte *temp;
962 
963 	if ( xOff == cin.oldXOff && yOff == cin.oldYOff && cinTable[currentHandle].ysize == cin.oldysize && cinTable[currentHandle].xsize == cin.oldxsize ) {
964 		return;
965 	}
966 
967 	cin.oldXOff = xOff;
968 	cin.oldYOff = yOff;
969 	cin.oldysize = cinTable[currentHandle].ysize;
970 	cin.oldxsize = cinTable[currentHandle].xsize;
971 
972 	numQuadCels  = ( cinTable[currentHandle].xsize * cinTable[currentHandle].ysize ) / ( 16 );
973 	numQuadCels += numQuadCels / 4;
974 	numQuadCels += 64;                            // for overflow
975 
976 	cinTable[currentHandle].onQuad = 0;
977 
978 	for ( y = 0; y < (long)cinTable[currentHandle].ysize; y += 16 )
979 		for ( x = 0; x < (long)cinTable[currentHandle].xsize; x += 16 )
980 			recurseQuad( x, y, 16, xOff, yOff );
981 
982 	temp = NULL;
983 
984 	for ( i = ( numQuadCels - 64 ); i < numQuadCels; i++ ) {
985 		cin.qStatus[0][i] = temp;             // eoq
986 		cin.qStatus[1][i] = temp;             // eoq
987 	}
988 }
989 
990 /******************************************************************************
991 *
992 * Function:
993 *
994 * Description:
995 *
996 ******************************************************************************/
997 
readQuadInfo(byte * qData)998 static void readQuadInfo( byte *qData ) {
999 	if ( currentHandle < 0 ) {
1000 		return;
1001 	}
1002 
1003 	cinTable[currentHandle].xsize    = qData[0] + qData[1] * 256;
1004 	cinTable[currentHandle].ysize    = qData[2] + qData[3] * 256;
1005 	cinTable[currentHandle].maxsize  = qData[4] + qData[5] * 256;
1006 	cinTable[currentHandle].minsize  = qData[6] + qData[7] * 256;
1007 
1008 	cinTable[currentHandle].CIN_HEIGHT = cinTable[currentHandle].ysize;
1009 	cinTable[currentHandle].CIN_WIDTH  = cinTable[currentHandle].xsize;
1010 
1011 	cinTable[currentHandle].samplesPerLine = cinTable[currentHandle].CIN_WIDTH * cinTable[currentHandle].samplesPerPixel;
1012 	cinTable[currentHandle].screenDelta = cinTable[currentHandle].CIN_HEIGHT * cinTable[currentHandle].samplesPerLine;
1013 
1014 	cinTable[currentHandle].half = qfalse;
1015 	cinTable[currentHandle].smootheddouble = qfalse;
1016 
1017 	cinTable[currentHandle].VQ0 = cinTable[currentHandle].VQNormal;
1018 	cinTable[currentHandle].VQ1 = cinTable[currentHandle].VQBuffer;
1019 
1020 	cinTable[currentHandle].t[0] = cinTable[currentHandle].screenDelta;
1021 	cinTable[currentHandle].t[1] = -cinTable[currentHandle].screenDelta;
1022 
1023 	cinTable[currentHandle].drawX = cinTable[currentHandle].CIN_WIDTH;
1024 	cinTable[currentHandle].drawY = cinTable[currentHandle].CIN_HEIGHT;
1025 
1026 	// rage pro is very slow at 512 wide textures, voodoo can't do it at all
1027 	if ( cls.glconfig.hardwareType == GLHW_RAGEPRO || cls.glconfig.maxTextureSize <= 256) {
1028 		if ( cinTable[currentHandle].drawX > 256 ) {
1029 			cinTable[currentHandle].drawX = 256;
1030 		}
1031 		if ( cinTable[currentHandle].drawY > 256 ) {
1032 			cinTable[currentHandle].drawY = 256;
1033 		}
1034 		if ( cinTable[currentHandle].CIN_WIDTH != 256 || cinTable[currentHandle].CIN_HEIGHT != 256 ) {
1035 			Com_Printf( "HACK: approxmimating cinematic for Rage Pro or Voodoo\n" );
1036 		}
1037 	}
1038 }
1039 
1040 /******************************************************************************
1041 *
1042 * Function:
1043 *
1044 * Description:
1045 *
1046 ******************************************************************************/
1047 
RoQPrepMcomp(long xoff,long yoff)1048 static void RoQPrepMcomp( long xoff, long yoff ) {
1049 	long i, j, x, y, temp, temp2;
1050 
1051 	i = cinTable[currentHandle].samplesPerLine; j = cinTable[currentHandle].samplesPerPixel;
1052 	if ( cinTable[currentHandle].xsize == ( cinTable[currentHandle].ysize * 4 ) && !cinTable[currentHandle].half ) {
1053 		j = j + j; i = i + i;
1054 	}
1055 
1056 	for ( y = 0; y < 16; y++ ) {
1057 		temp2 = ( y + yoff - 8 ) * i;
1058 		for ( x = 0; x < 16; x++ ) {
1059 			temp = ( x + xoff - 8 ) * j;
1060 			cin.mcomp[( x * 16 ) + y] = cinTable[currentHandle].normalBuffer0 - ( temp2 + temp );
1061 		}
1062 	}
1063 }
1064 
1065 /******************************************************************************
1066 *
1067 * Function:
1068 *
1069 * Description:
1070 *
1071 ******************************************************************************/
1072 
initRoQ(void)1073 static void initRoQ( void ) {
1074 	if ( currentHandle < 0 ) {
1075 		return;
1076 	}
1077 
1078 	cinTable[currentHandle].VQNormal = ( void( * ) ( byte *, void * ) )blitVQQuad32fs;
1079 	cinTable[currentHandle].VQBuffer = ( void( * ) ( byte *, void * ) )blitVQQuad32fs;
1080 	cinTable[currentHandle].samplesPerPixel = 4;
1081 	ROQ_GenYUVTables();
1082 	RllSetupTable();
1083 }
1084 
1085 /******************************************************************************
1086 *
1087 * Function:
1088 *
1089 * Description:
1090 *
1091 ******************************************************************************/
1092 /*
1093 static byte* RoQFetchInterlaced( byte *source ) {
1094 	int x, *src, *dst;
1095 
1096 	if (currentHandle < 0) return NULL;
1097 
1098 	src = (int *)source;
1099 	dst = (int *)cinTable[currentHandle].buf2;
1100 
1101 	for(x=0;x<256*256;x++) {
1102 		*dst = *src;
1103 		dst++; src += 2;
1104 	}
1105 	return cinTable[currentHandle].buf2;
1106 }
1107 */
RoQReset(void)1108 static void RoQReset( void ) {
1109 
1110 	if ( currentHandle < 0 ) {
1111 		return;
1112 	}
1113 
1114 	// DHM - Properly close file so we don't run out of handles
1115 	FS_FCloseFile( cinTable[currentHandle].iFile );
1116 	cinTable[currentHandle].iFile = 0;
1117 	// dhm - end
1118 
1119 	FS_FOpenFileRead( cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue );
1120 	// let the background thread start reading ahead
1121 	FS_Read (cin.file, 16, cinTable[currentHandle].iFile);
1122 	RoQ_init();
1123 	cinTable[currentHandle].status = FMV_LOOPED;
1124 }
1125 
1126 /******************************************************************************
1127 *
1128 * Function:
1129 *
1130 * Description:
1131 *
1132 ******************************************************************************/
1133 
RoQInterrupt(void)1134 static void RoQInterrupt( void ) {
1135 	byte                *framedata;
1136 	short sbuf[32768];
1137 	int ssize;
1138 
1139 	if ( currentHandle < 0 ) {
1140 		return;
1141 	}
1142 
1143 	FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile );
1144 	if ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) {
1145 		if ( cinTable[currentHandle].holdAtEnd == qfalse ) {
1146 			if ( cinTable[currentHandle].looping ) {
1147 				RoQReset();
1148 			} else {
1149 				cinTable[currentHandle].status = FMV_EOF;
1150 			}
1151 		} else {
1152 			cinTable[currentHandle].status = FMV_IDLE;
1153 		}
1154 		return;
1155 	}
1156 
1157 	framedata = cin.file;
1158 //
1159 // new frame is ready
1160 //
1161 redump:
1162 	switch ( cinTable[currentHandle].roq_id )
1163 	{
1164 	case    ROQ_QUAD_VQ:
1165 		if ( ( cinTable[currentHandle].numQuads & 1 ) ) {
1166 			cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[1];
1167 			RoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );
1168 			cinTable[currentHandle].VQ1( (byte *)cin.qStatus[1], framedata );
1169 			cinTable[currentHandle].buf =   cin.linbuf + cinTable[currentHandle].screenDelta;
1170 		} else {
1171 			cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[0];
1172 			RoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );
1173 			cinTable[currentHandle].VQ0( (byte *)cin.qStatus[0], framedata );
1174 			cinTable[currentHandle].buf =   cin.linbuf;
1175 		}
1176 		if ( cinTable[currentHandle].numQuads == 0 ) {          // first frame
1177 			Com_Memcpy( cin.linbuf + cinTable[currentHandle].screenDelta, cin.linbuf, cinTable[currentHandle].samplesPerLine * cinTable[currentHandle].ysize );
1178 		}
1179 		cinTable[currentHandle].numQuads++;
1180 		cinTable[currentHandle].dirty = qtrue;
1181 		break;
1182 	case    ROQ_CODEBOOK:
1183 		decodeCodeBook( framedata, (unsigned short)cinTable[currentHandle].roq_flags );
1184 		break;
1185 	case    ZA_SOUND_MONO:
1186 		if ( !cinTable[currentHandle].silent ) {
1187 			ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags );
1188 			S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
1189 		}
1190 		break;
1191 	case    ZA_SOUND_STEREO:
1192 		if ( !cinTable[currentHandle].silent ) {
1193 			if ( cinTable[currentHandle].numQuads == -1 ) {
1194 				S_Update();
1195 				Com_DPrintf( "S_Update: Setting rawend to %i\n", s_soundtime );
1196 				s_rawend[0] = s_soundtime;
1197 			}
1198 			ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags );
1199 			S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
1200 		}
1201 		break;
1202 	case    ROQ_QUAD_INFO:
1203 		if ( cinTable[currentHandle].numQuads == -1 ) {
1204 			readQuadInfo( framedata );
1205 			setupQuad( 0, 0 );
1206 			cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds();
1207 		}
1208 		if ( cinTable[currentHandle].numQuads != 1 ) {
1209 			cinTable[currentHandle].numQuads = 0;
1210 		}
1211 		break;
1212 	case    ROQ_PACKET:
1213 		cinTable[currentHandle].inMemory = cinTable[currentHandle].roq_flags;
1214 		cinTable[currentHandle].RoQFrameSize = 0;               // for header
1215 		break;
1216 	case    ROQ_QUAD_HANG:
1217 		cinTable[currentHandle].RoQFrameSize = 0;
1218 		break;
1219 	case    ROQ_QUAD_JPEG:
1220 		break;
1221 	default:
1222 		cinTable[currentHandle].status = FMV_EOF;
1223 		break;
1224 	}
1225 //
1226 // read in next frame data
1227 //
1228 	if ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) {
1229 		if ( cinTable[currentHandle].holdAtEnd == qfalse ) {
1230 			if ( cinTable[currentHandle].looping ) {
1231 				RoQReset();
1232 			} else {
1233 				cinTable[currentHandle].status = FMV_EOF;
1234 			}
1235 		} else {
1236 			cinTable[currentHandle].status = FMV_IDLE;
1237 		}
1238 		return;
1239 	}
1240 
1241 	framedata        += cinTable[currentHandle].RoQFrameSize;
1242 	cinTable[currentHandle].roq_id       = framedata[0] + framedata[1] * 256;
1243 	cinTable[currentHandle].RoQFrameSize = framedata[2] + framedata[3] * 256 + framedata[4] * 65536;
1244 	cinTable[currentHandle].roq_flags    = framedata[6] + framedata[7] * 256;
1245 	cinTable[currentHandle].roqF0		 = (signed char)framedata[7];
1246 	cinTable[currentHandle].roqF1		 = (signed char)framedata[6];
1247 
1248 	if ( cinTable[currentHandle].RoQFrameSize > 65536 || cinTable[currentHandle].roq_id == 0x1084 ) {
1249 		Com_DPrintf( "roq_size>65536||roq_id==0x1084\n" );
1250 		cinTable[currentHandle].status = FMV_EOF;
1251 		if ( cinTable[currentHandle].looping ) {
1252 			RoQReset();
1253 		}
1254 		return;
1255 	}
1256 	if ( cinTable[currentHandle].inMemory && ( cinTable[currentHandle].status != FMV_EOF ) ) {
1257 		cinTable[currentHandle].inMemory--; framedata += 8; goto redump;
1258 	}
1259 //
1260 // one more frame hits the dust
1261 //
1262 //	assert(cinTable[currentHandle].RoQFrameSize <= 65536);
1263 //	r = FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile );
1264 	cinTable[currentHandle].RoQPlayed   += cinTable[currentHandle].RoQFrameSize + 8;
1265 }
1266 
1267 /******************************************************************************
1268 *
1269 * Function:
1270 *
1271 * Description:
1272 *
1273 ******************************************************************************/
1274 
RoQ_init(void)1275 static void RoQ_init( void ) {
1276 	cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds();
1277 
1278 	cinTable[currentHandle].RoQPlayed = 24;
1279 
1280 /*	get frame rate */
1281 	cinTable[currentHandle].roqFPS   = cin.file[ 6] + cin.file[ 7] * 256;
1282 
1283 	if ( !cinTable[currentHandle].roqFPS ) {
1284 		cinTable[currentHandle].roqFPS = 30;
1285 	}
1286 
1287 	cinTable[currentHandle].numQuads = -1;
1288 
1289 	cinTable[currentHandle].roq_id      = cin.file[ 8] + cin.file[ 9] * 256;
1290 	cinTable[currentHandle].RoQFrameSize    = cin.file[10] + cin.file[11] * 256 + cin.file[12] * 65536;
1291 	cinTable[currentHandle].roq_flags   = cin.file[14] + cin.file[15] * 256;
1292 
1293 	if ( cinTable[currentHandle].RoQFrameSize > 65536 || !cinTable[currentHandle].RoQFrameSize ) {
1294 		return;
1295 	}
1296 
1297 }
1298 
1299 /******************************************************************************
1300 *
1301 * Function:
1302 *
1303 * Description:
1304 *
1305 ******************************************************************************/
1306 
RoQShutdown(void)1307 static void RoQShutdown( void ) {
1308 	const char *s;
1309 
1310 	if ( !cinTable[currentHandle].buf ) {
1311 		return;
1312 	}
1313 
1314 	if ( cinTable[currentHandle].status == FMV_IDLE ) {
1315 		return;
1316 	}
1317 	Com_DPrintf( "finished cinematic\n" );
1318 	cinTable[currentHandle].status = FMV_IDLE;
1319 
1320 	if ( cinTable[currentHandle].iFile ) {
1321 		FS_FCloseFile( cinTable[currentHandle].iFile );
1322 		cinTable[currentHandle].iFile = 0;
1323 	}
1324 
1325 	if ( cinTable[currentHandle].alterGameState ) {
1326 		clc.state = CA_DISCONNECTED;
1327 		// we can't just do a vstr nextmap, because
1328 		// if we are aborting the intro cinematic with
1329 		// a devmap command, nextmap would be valid by
1330 		// the time it was referenced
1331 		s = Cvar_VariableString( "nextmap" );
1332 		if ( s[0] ) {
1333 			Cbuf_ExecuteText( EXEC_APPEND, va( "%s\n", s ) );
1334 			Cvar_Set( "nextmap", "" );
1335 		}
1336 		CL_handle = -1;
1337 	}
1338 	cinTable[currentHandle].fileName[0] = 0;
1339 	currentHandle = -1;
1340 }
1341 
1342 /*
1343 ==================
1344 CIN_StopCinematic
1345 ==================
1346 */
CIN_StopCinematic(int handle)1347 e_status CIN_StopCinematic( int handle ) {
1348 
1349 	if ( handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF ) {
1350 		return FMV_EOF;
1351 	}
1352 	currentHandle = handle;
1353 
1354 	Com_DPrintf( "trFMV::stop(), closing %s\n", cinTable[currentHandle].fileName );
1355 
1356 	if ( !cinTable[currentHandle].buf ) {
1357 		return FMV_EOF;
1358 	}
1359 
1360 	if ( cinTable[currentHandle].alterGameState ) {
1361 		if ( clc.state != CA_CINEMATIC ) {
1362 			return cinTable[currentHandle].status;
1363 		}
1364 	}
1365 	cinTable[currentHandle].status = FMV_EOF;
1366 	RoQShutdown();
1367 
1368 	return FMV_EOF;
1369 }
1370 
1371 /*
1372 ==================
1373 CIN_RunCinematic
1374 
1375 Fetch and decompress the pending frame
1376 ==================
1377 */
1378 
1379 
CIN_RunCinematic(int handle)1380 e_status CIN_RunCinematic( int handle ) {
1381 	int start = 0;
1382 	int thisTime = 0;
1383 
1384 	if ( handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF ) {
1385 		return FMV_EOF;
1386 	}
1387 
1388 	if ( cin.currentHandle != handle ) {
1389 		currentHandle = handle;
1390 		cin.currentHandle = currentHandle;
1391 		cinTable[currentHandle].status = FMV_EOF;
1392 		RoQReset();
1393 	}
1394 
1395 	if ( cinTable[handle].playonwalls < -1 ) {
1396 		return cinTable[handle].status;
1397 	}
1398 
1399 	currentHandle = handle;
1400 
1401 	if ( cinTable[currentHandle].alterGameState ) {
1402 		if ( clc.state != CA_CINEMATIC ) {
1403 			return cinTable[currentHandle].status;
1404 		}
1405 	}
1406 
1407 	if ( cinTable[currentHandle].status == FMV_IDLE ) {
1408 		return cinTable[currentHandle].status;
1409 	}
1410 
1411 	thisTime = CL_ScaledMilliseconds();
1412 	if ( cinTable[currentHandle].shader && ( thisTime - cinTable[currentHandle].lastTime ) > 100 ) {
1413 		cinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime;
1414 	}
1415 	cinTable[currentHandle].tfps = ( ( ( CL_ScaledMilliseconds() - cinTable[currentHandle].startTime ) * 3 ) / 100 );
1416 
1417 	start = cinTable[currentHandle].startTime;
1418 	while ( ( cinTable[currentHandle].tfps != cinTable[currentHandle].numQuads ) && ( cinTable[currentHandle].status == FMV_PLAY ) )
1419 	{
1420 		RoQInterrupt();
1421 		if ( start != cinTable[currentHandle].startTime ) {
1422 			cinTable[currentHandle].tfps = ( ( ( CL_ScaledMilliseconds() - cinTable[currentHandle].startTime ) * 3 ) / 100 );
1423 			start = cinTable[currentHandle].startTime;
1424 		}
1425 	}
1426 
1427 	cinTable[currentHandle].lastTime = thisTime;
1428 
1429 	if ( cinTable[currentHandle].status == FMV_LOOPED ) {
1430 		cinTable[currentHandle].status = FMV_PLAY;
1431 	}
1432 
1433 	if ( cinTable[currentHandle].status == FMV_EOF ) {
1434 		if ( cinTable[currentHandle].looping ) {
1435 			RoQReset();
1436 		} else {
1437 			RoQShutdown();
1438 			return FMV_EOF;
1439 		}
1440 	}
1441 
1442 	return cinTable[currentHandle].status;
1443 }
1444 
1445 /*
1446 ==================
1447 CIN_PlayCinematic
1448 ==================
1449 */
CIN_PlayCinematic(const char * arg,int x,int y,int w,int h,int systemBits)1450 int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBits ) {
1451 	unsigned short RoQID;
1452 	char name[MAX_OSPATH];
1453 	int i;
1454 
1455 	if ( strstr( arg, "/" ) == NULL && strstr( arg, "\\" ) == NULL ) {
1456 		Com_sprintf( name, sizeof( name ), "video/%s", arg );
1457 	} else {
1458 		Com_sprintf( name, sizeof( name ), "%s", arg );
1459 	}
1460 
1461 	if ( !( systemBits & CIN_system ) ) {
1462 		for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
1463 			if ( !Q_stricmp( cinTable[i].fileName, name ) ) {
1464 				return i;
1465 			}
1466 		}
1467 	}
1468 
1469 	Com_DPrintf( "CIN_PlayCinematic( %s )\n", arg );
1470 
1471 	Com_Memset( &cin, 0, sizeof( cinematics_t ) );
1472 	currentHandle = CIN_HandleForVideo();
1473 
1474 	cin.currentHandle = currentHandle;
1475 
1476 	strcpy( cinTable[currentHandle].fileName, name );
1477 
1478 	cinTable[currentHandle].ROQSize = 0;
1479 	cinTable[currentHandle].ROQSize = FS_FOpenFileRead( cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue );
1480 
1481 	if ( cinTable[currentHandle].ROQSize <= 0 ) {
1482 		Com_DPrintf( "play(%s), ROQSize<=0\n", arg );
1483 		cinTable[currentHandle].fileName[0] = 0;
1484 		return -1;
1485 	}
1486 
1487 	CIN_SetExtents( currentHandle, x, y, w, h );
1488 	CIN_SetLooping( currentHandle, ( systemBits & CIN_loop ) != 0 );
1489 
1490 	cinTable[currentHandle].CIN_HEIGHT = DEFAULT_CIN_HEIGHT;
1491 	cinTable[currentHandle].CIN_WIDTH  =  DEFAULT_CIN_WIDTH;
1492 	cinTable[currentHandle].holdAtEnd = ( systemBits & CIN_hold ) != 0;
1493 	cinTable[currentHandle].alterGameState = ( systemBits & CIN_system ) != 0;
1494 	cinTable[currentHandle].playonwalls = 1;
1495 	cinTable[currentHandle].silent = ( systemBits & CIN_silent ) != 0;
1496 	cinTable[currentHandle].shader = ( systemBits & CIN_shader ) != 0;
1497 
1498 	if ( cinTable[currentHandle].alterGameState ) {
1499 		// close the menu
1500 		if ( uivm ) {
1501 			VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );
1502 		}
1503 	} else {
1504 		cinTable[currentHandle].playonwalls = cl_inGameVideo->integer;
1505 	}
1506 
1507 	initRoQ();
1508 
1509 	FS_Read( cin.file, 16, cinTable[currentHandle].iFile );
1510 
1511 	RoQID = ( unsigned short )( cin.file[0] ) + ( unsigned short )( cin.file[1] ) * 256;
1512 	if ( RoQID == 0x1084 ) {
1513 		RoQ_init();
1514 //		FS_Read (cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile);
1515 
1516 		cinTable[currentHandle].status = FMV_PLAY;
1517 		Com_DPrintf( "trFMV::play(), playing %s\n", arg );
1518 
1519 		if ( cinTable[currentHandle].alterGameState ) {
1520 			clc.state = CA_CINEMATIC;
1521 		}
1522 
1523 		Con_Close();
1524 
1525 		Com_DPrintf( "Setting rawend to %i\n", s_soundtime );
1526 
1527 		if (!cinTable[currentHandle].silent) {
1528 			s_rawend[0] = s_soundtime;
1529 		}
1530 
1531 		return currentHandle;
1532 	}
1533 	Com_DPrintf( "trFMV::play(), invalid RoQ ID\n" );
1534 
1535 	RoQShutdown();
1536 	return -1;
1537 }
1538 
CIN_SetExtents(int handle,int x,int y,int w,int h)1539 void CIN_SetExtents( int handle, int x, int y, int w, int h ) {
1540 	if ( handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF ) {
1541 		return;
1542 	}
1543 	cinTable[handle].xpos = x;
1544 	cinTable[handle].ypos = y;
1545 	cinTable[handle].width = w;
1546 	cinTable[handle].height = h;
1547 	cinTable[handle].dirty = qtrue;
1548 }
1549 
CIN_SetLooping(int handle,qboolean loop)1550 void CIN_SetLooping( int handle, qboolean loop ) {
1551 	if ( handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF ) {
1552 		return;
1553 	}
1554 	cinTable[handle].looping = loop;
1555 }
1556 
1557 /*
1558 ==================
1559 CIN_ResampleCinematic
1560 
1561 Resample cinematic to 256x256 and store in buf2
1562 ==================
1563 */
CIN_ResampleCinematic(int handle,int * buf2)1564 void CIN_ResampleCinematic(int handle, int *buf2) {
1565 	int ix, iy, *buf3, xm, ym, ll;
1566 	byte	*buf;
1567 
1568 	buf = cinTable[handle].buf;
1569 
1570 	xm = cinTable[handle].CIN_WIDTH/256;
1571 	ym = cinTable[handle].CIN_HEIGHT/256;
1572 	ll = 8;
1573 	if (cinTable[handle].CIN_WIDTH==512) {
1574 		ll = 9;
1575 	}
1576 
1577 	buf3 = (int*)buf;
1578 	if (xm==2 && ym==2) {
1579 		byte *bc2, *bc3;
1580 		int	ic, iiy;
1581 
1582 		bc2 = (byte *)buf2;
1583 		bc3 = (byte *)buf3;
1584 		for (iy = 0; iy<256; iy++) {
1585 			iiy = iy<<12;
1586 			for (ix = 0; ix<2048; ix+=8) {
1587 				for(ic = ix;ic<(ix+4);ic++) {
1588 					*bc2=(bc3[iiy+ic]+bc3[iiy+4+ic]+bc3[iiy+2048+ic]+bc3[iiy+2048+4+ic])>>2;
1589 					bc2++;
1590 				}
1591 			}
1592 		}
1593 	} else if (xm==2 && ym==1) {
1594 		byte *bc2, *bc3;
1595 		int	ic, iiy;
1596 
1597 		bc2 = (byte *)buf2;
1598 		bc3 = (byte *)buf3;
1599 		for (iy = 0; iy<256; iy++) {
1600 			iiy = iy<<11;
1601 			for (ix = 0; ix<2048; ix+=8) {
1602 				for(ic = ix;ic<(ix+4);ic++) {
1603 					*bc2=(bc3[iiy+ic]+bc3[iiy+4+ic])>>1;
1604 					bc2++;
1605 				}
1606 			}
1607 		}
1608 	} else {
1609 		for (iy = 0; iy<256; iy++) {
1610 			for (ix = 0; ix<256; ix++) {
1611 					buf2[(iy<<8)+ix] = buf3[((iy*ym)<<ll) + (ix*xm)];
1612 			}
1613 		}
1614 	}
1615 }
1616 
1617 /*
1618 ==================
1619 CIN_DrawCinematic
1620 ==================
1621 */
CIN_DrawCinematic(int handle)1622 void CIN_DrawCinematic( int handle ) {
1623 	float x, y, w, h;
1624 	byte    *buf;
1625 
1626 	if ( handle < 0 || handle >= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF ) {
1627 		return;
1628 	}
1629 
1630 	if ( !cinTable[handle].buf ) {
1631 		return;
1632 	}
1633 
1634 	x = cinTable[handle].xpos;
1635 	y = cinTable[handle].ypos;
1636 	w = cinTable[handle].width;
1637 	h = cinTable[handle].height;
1638 	buf = cinTable[handle].buf;
1639 	SCR_AdjustFrom640( &x, &y, &w, &h );
1640 
1641 	if ( cinTable[handle].dirty && ( cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY ) ) {
1642 		int *buf2;
1643 
1644 		buf2 = Hunk_AllocateTempMemory( 256 * 256 * 4 );
1645 
1646 		CIN_ResampleCinematic(handle, buf2);
1647 
1648 		re.DrawStretchRaw( x, y, w, h, 256, 256, (byte *)buf2, handle, qtrue );
1649 		cinTable[handle].dirty = qfalse;
1650 		Hunk_FreeTempMemory( buf2 );
1651 		return;
1652 	}
1653 
1654 	re.DrawStretchRaw( x, y, w, h, cinTable[handle].drawX, cinTable[handle].drawY, buf, handle, cinTable[handle].dirty );
1655 	cinTable[handle].dirty = qfalse;
1656 }
1657 
1658 /*
1659 ==============
1660 CL_PlayCinematic_f
1661 ==============
1662 */
CL_PlayCinematic_f(void)1663 void CL_PlayCinematic_f( void ) {
1664 	char    *arg, *s;
1665 	int bits = CIN_system;
1666 
1667 	Com_DPrintf( "CL_PlayCinematic_f\n" );
1668 	if ( clc.state == CA_CINEMATIC ) {
1669 		SCR_StopCinematic();
1670 	}
1671 
1672 	arg = Cmd_Argv( 1 );
1673 	s = Cmd_Argv( 2 );
1674 
1675 	if ( ( s && s[0] == '1' ) || Q_stricmp( arg,"demoend.roq" ) == 0 || Q_stricmp( arg,"end.roq" ) == 0 ) {
1676 		bits |= CIN_hold;
1677 	}
1678 	if ( s && s[0] == '2' ) {
1679 		bits |= CIN_loop;
1680 	}
1681 
1682 	S_StopAllSounds();
1683 
1684 	CL_handle = CIN_PlayCinematic( arg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, bits );
1685 	if ( CL_handle >= 0 ) {
1686 		do {
1687 			SCR_RunCinematic();
1688 		} while ( cinTable[currentHandle].buf == NULL && cinTable[currentHandle].status == FMV_PLAY );        // wait for first frame (load codebook and sound)
1689 	}
1690 }
1691 
1692 
SCR_DrawCinematic(void)1693 void SCR_DrawCinematic( void ) {
1694 	if ( CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES ) {
1695 		CIN_DrawCinematic( CL_handle );
1696 	}
1697 }
1698 
SCR_RunCinematic(void)1699 void SCR_RunCinematic( void ) {
1700 	if ( CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES ) {
1701 		CIN_RunCinematic( CL_handle );
1702 	}
1703 }
1704 
SCR_StopCinematic(void)1705 void SCR_StopCinematic( void ) {
1706 	if ( CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES ) {
1707 		CIN_StopCinematic( CL_handle );
1708 		S_StopAllSounds();
1709 		CL_handle = -1;
1710 	}
1711 }
1712 
CIN_UploadCinematic(int handle)1713 void CIN_UploadCinematic( int handle ) {
1714 	if ( handle >= 0 && handle < MAX_VIDEO_HANDLES ) {
1715 		if ( !cinTable[handle].buf ) {
1716 			return;
1717 		}
1718 		if ( cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty ) {
1719 			if ( cinTable[handle].playonwalls == 0 ) {
1720 				cinTable[handle].playonwalls = -1;
1721 			} else {
1722 				if ( cinTable[handle].playonwalls == -1 ) {
1723 					cinTable[handle].playonwalls = -2;
1724 				} else {
1725 					cinTable[handle].dirty = qfalse;
1726 				}
1727 			}
1728 		}
1729 
1730 		// Resample the video if needed
1731 		if (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY))  {
1732 			int *buf2;
1733 
1734 			buf2 = Hunk_AllocateTempMemory( 256*256*4 );
1735 
1736 			CIN_ResampleCinematic(handle, buf2);
1737 
1738 			re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, 256, 256, (byte *)buf2, handle, qtrue);
1739 			cinTable[handle].dirty = qfalse;
1740 			Hunk_FreeTempMemory(buf2);
1741 		} else {
1742 			// Upload video at normal resolution
1743 			re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, cinTable[handle].drawX, cinTable[handle].drawY,
1744 					cinTable[handle].buf, handle, cinTable[handle].dirty);
1745 			cinTable[handle].dirty = qfalse;
1746 		}
1747 
1748 		if ( cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1 ) {
1749 			cinTable[handle].playonwalls--;
1750 		}
1751 		else if (cl_inGameVideo->integer != 0 && cinTable[handle].playonwalls != 1) {
1752 			cinTable[handle].playonwalls = 1;
1753 		}
1754 	}
1755 }
1756