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