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