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