Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cl_cin.c (49828B)


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