/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 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 Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. 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. =========================================================================== */ #include "sys/platform.h" #include #include "framework/FileSystem.h" #include "renderer/tr_local.h" #include "sound/sound.h" #include "renderer/Cinematic.h" #define CIN_system 1 #define CIN_loop 2 #define CIN_hold 4 #define CIN_silent 8 #define CIN_shader 16 class idCinematicLocal : public idCinematic { public: idCinematicLocal(); virtual ~idCinematicLocal(); virtual bool InitFromFile( const char *qpath, bool looping ); virtual cinData_t ImageForTime( int milliseconds ); virtual int AnimationLength(); virtual void Close(); virtual void ResetTime(int time); private: size_t mcomp[256]; byte ** qStatus[2]; idStr fileName; int CIN_WIDTH, CIN_HEIGHT; idFile * iFile; cinStatus_t status; int tfps; int RoQPlayed; int ROQSize; unsigned int RoQFrameSize; int onQuad; int numQuads; int samplesPerLine; unsigned int roq_id; int screenDelta; byte * buf; int samplesPerPixel; // defaults to 2 unsigned int xsize, ysize, maxsize, minsize; int normalBuffer0; int roq_flags; int roqF0; int roqF1; int t[2]; int roqFPS; int drawX, drawY; int animationLength; int startTime; float frameRate; byte * image; bool looping; bool dirty; bool half; bool smootheddouble; bool inMemory; void RoQ_init( void ); void blitVQQuad32fs( byte **status, unsigned char *data ); void RoQShutdown( void ); void RoQInterrupt(void); void move8_32( byte *src, byte *dst, int spl ); void move4_32( byte *src, byte *dst, int spl ); void blit8_32( byte *src, byte *dst, int spl ); void blit4_32( byte *src, byte *dst, int spl ); void blit2_32( byte *src, byte *dst, int spl ); unsigned short yuv_to_rgb( int y, int u, int v ); unsigned int yuv_to_rgb24( int y, int u, int v ); void decodeCodeBook( byte *input, unsigned short roq_flags ); void recurseQuad( int startX, int startY, int quadSize, int xOff, int yOff ); void setupQuad( int xOff, int yOff ); void readQuadInfo( byte *qData ); void RoQPrepMcomp( int xoff, int yoff ); void RoQReset(); }; const int DEFAULT_CIN_WIDTH = 512; const int DEFAULT_CIN_HEIGHT = 512; const int MAXSIZE = 8; const int MINSIZE = 4; const int ROQ_FILE = 0x1084; const int ROQ_QUAD = 0x1000; const int ROQ_QUAD_INFO = 0x1001; const int ROQ_CODEBOOK = 0x1002; const int ROQ_QUAD_VQ = 0x1011; const int ROQ_QUAD_JPEG = 0x1012; const int ROQ_QUAD_HANG = 0x1013; const int ROQ_PACKET = 0x1030; const int ZA_SOUND_MONO = 0x1020; const int ZA_SOUND_STEREO = 0x1021; // temporary buffers used by all cinematics static int ROQ_YY_tab[256]; static int ROQ_UB_tab[256]; static int ROQ_UG_tab[256]; static int ROQ_VG_tab[256]; static int ROQ_VR_tab[256]; static byte * file = NULL; static unsigned short * vq2 = NULL; static unsigned short * vq4 = NULL; static unsigned short * vq8 = NULL; //=========================================== /* ============== idCinematicLocal::InitCinematic ============== */ void idCinematic::InitCinematic( void ) { float t_ub,t_vr,t_ug,t_vg; int i; // generate YUV tables t_ub = (1.77200f/2.0f) * (float)(1<<6) + 0.5f; t_vr = (1.40200f/2.0f) * (float)(1<<6) + 0.5f; t_ug = (0.34414f/2.0f) * (float)(1<<6) + 0.5f; t_vg = (0.71414f/2.0f) * (float)(1<<6) + 0.5f; for( i = 0; i < 256; i++ ) { float x = (float)(2 * i - 255); ROQ_UB_tab[i] = (int)( ( t_ub * x) + (1<<5)); ROQ_VR_tab[i] = (int)( ( t_vr * x) + (1<<5)); ROQ_UG_tab[i] = (int)( (-t_ug * x) ); ROQ_VG_tab[i] = (int)( (-t_vg * x) + (1<<5)); ROQ_YY_tab[i] = (int)( (i << 6) | (i >> 2) ); } file = (byte *)Mem_Alloc( 65536 ); vq2 = (word *)Mem_Alloc( 256*16*4 * sizeof( word ) ); vq4 = (word *)Mem_Alloc( 256*64*4 * sizeof( word ) ); vq8 = (word *)Mem_Alloc( 256*256*4 * sizeof( word ) ); } /* ============== idCinematicLocal::ShutdownCinematic ============== */ void idCinematic::ShutdownCinematic( void ) { Mem_Free( file ); file = NULL; Mem_Free( vq2 ); vq2 = NULL; Mem_Free( vq4 ); vq4 = NULL; Mem_Free( vq8 ); vq8 = NULL; } /* ============== idCinematicLocal::Alloc ============== */ idCinematic *idCinematic::Alloc() { return new idCinematicLocal; } /* ============== idCinematicLocal::~idCinematic ============== */ idCinematic::~idCinematic( ) { Close(); } /* ============== idCinematicLocal::InitFromFile ============== */ bool idCinematic::InitFromFile( const char *qpath, bool looping ) { return false; } /* ============== idCinematicLocal::AnimationLength ============== */ int idCinematic::AnimationLength() { return 0; } /* ============== idCinematicLocal::ResetTime ============== */ void idCinematic::ResetTime(int milliseconds) { } /* ============== idCinematicLocal::ImageForTime ============== */ cinData_t idCinematic::ImageForTime( int milliseconds ) { cinData_t c; memset( &c, 0, sizeof( c ) ); return c; } /* ============== idCinematicLocal::Close ============== */ void idCinematic::Close() { } //=========================================== /* ============== idCinematicLocal::idCinematicLocal ============== */ idCinematicLocal::idCinematicLocal() { image = NULL; status = FMV_EOF; buf = NULL; iFile = NULL; qStatus[0] = (byte **)Mem_Alloc( 32768 * sizeof( byte *) ); qStatus[1] = (byte **)Mem_Alloc( 32768 * sizeof( byte *) ); } /* ============== idCinematicLocal::~idCinematicLocal ============== */ idCinematicLocal::~idCinematicLocal() { Close(); Mem_Free( qStatus[0] ); qStatus[0] = NULL; Mem_Free( qStatus[1] ); qStatus[1] = NULL; } /* ============== idCinematicLocal::InitFromFile ============== */ bool idCinematicLocal::InitFromFile( const char *qpath, bool amilooping ) { unsigned short RoQID; Close(); inMemory = 0; animationLength = 100000; if ( strstr( qpath, "/" ) == NULL && strstr( qpath, "\\" ) == NULL ) { sprintf( fileName, "video/%s", qpath ); } else { sprintf( fileName, "%s", qpath ); } iFile = fileSystem->OpenFileRead( fileName ); if ( !iFile ) { return false; } ROQSize = iFile->Length(); looping = amilooping; CIN_HEIGHT = DEFAULT_CIN_HEIGHT; CIN_WIDTH = DEFAULT_CIN_WIDTH; samplesPerPixel = 4; startTime = 0; //Sys_Milliseconds(); buf = NULL; iFile->Read( file, 16 ); RoQID = (unsigned short)(file[0]) + (unsigned short)(file[1])*256; frameRate = file[6]; if ( frameRate == 32.0f ) { frameRate = 1000.0f / 32.0f; } if ( RoQID == ROQ_FILE ) { RoQ_init(); status = FMV_PLAY; ImageForTime( 0 ); status = ( looping ) ? FMV_PLAY : FMV_IDLE; return true; } RoQShutdown(); return false; } /* ============== idCinematicLocal::Close ============== */ void idCinematicLocal::Close() { if ( image ) { Mem_Free( (void *)image ); image = NULL; buf = NULL; status = FMV_EOF; } RoQShutdown(); } /* ============== idCinematicLocal::AnimationLength ============== */ int idCinematicLocal::AnimationLength() { return animationLength; } /* ============== idCinematicLocal::ResetTime ============== */ void idCinematicLocal::ResetTime(int time) { startTime = ( backEnd.viewDef ) ? 1000 * backEnd.viewDef->floatTime : -1; status = FMV_PLAY; } /* ============== idCinematicLocal::ImageForTime ============== */ cinData_t idCinematicLocal::ImageForTime( int thisTime ) { cinData_t cinData; if ( thisTime < 0 ) { thisTime = 0; } memset( &cinData, 0, sizeof(cinData) ); if ( r_skipROQ.GetBool() ) { return cinData; } if ( status == FMV_EOF || status == FMV_IDLE ) { return cinData; } if ( buf == NULL || startTime == -1 ) { if ( startTime == -1 ) { RoQReset(); } startTime = thisTime; } tfps = ( ( thisTime - startTime ) * frameRate ) / 1000; if ( tfps < 0 ) { tfps = 0; } if ( tfps < numQuads ) { RoQReset(); buf = NULL; status = FMV_PLAY; } if ( buf == NULL ) { while( buf == NULL ) { RoQInterrupt(); } } else { while( (tfps != numQuads && status == FMV_PLAY) ) { RoQInterrupt(); } } if ( status == FMV_LOOPED ) { status = FMV_PLAY; while( buf == NULL && status == FMV_PLAY ) { RoQInterrupt(); } startTime = thisTime; } if ( status == FMV_EOF ) { if ( looping ) { RoQReset(); buf = NULL; if ( status == FMV_LOOPED ) { status = FMV_PLAY; } while ( buf == NULL && status == FMV_PLAY ) { RoQInterrupt(); } startTime = thisTime; } else { status = FMV_IDLE; RoQShutdown(); } } cinData.imageWidth = CIN_WIDTH; cinData.imageHeight = CIN_HEIGHT; cinData.status = status; cinData.image = buf; return cinData; } /* ============== idCinematicLocal::move8_32 ============== */ void idCinematicLocal::move8_32( byte *src, byte *dst, int spl ) { #if 1 int *dsrc, *ddst; int dspl; dsrc = (int *)src; ddst = (int *)dst; dspl = spl>>2; ddst[0*dspl+0] = dsrc[0*dspl+0]; ddst[0*dspl+1] = dsrc[0*dspl+1]; ddst[0*dspl+2] = dsrc[0*dspl+2]; ddst[0*dspl+3] = dsrc[0*dspl+3]; ddst[0*dspl+4] = dsrc[0*dspl+4]; ddst[0*dspl+5] = dsrc[0*dspl+5]; ddst[0*dspl+6] = dsrc[0*dspl+6]; ddst[0*dspl+7] = dsrc[0*dspl+7]; ddst[1*dspl+0] = dsrc[1*dspl+0]; ddst[1*dspl+1] = dsrc[1*dspl+1]; ddst[1*dspl+2] = dsrc[1*dspl+2]; ddst[1*dspl+3] = dsrc[1*dspl+3]; ddst[1*dspl+4] = dsrc[1*dspl+4]; ddst[1*dspl+5] = dsrc[1*dspl+5]; ddst[1*dspl+6] = dsrc[1*dspl+6]; ddst[1*dspl+7] = dsrc[1*dspl+7]; ddst[2*dspl+0] = dsrc[2*dspl+0]; ddst[2*dspl+1] = dsrc[2*dspl+1]; ddst[2*dspl+2] = dsrc[2*dspl+2]; ddst[2*dspl+3] = dsrc[2*dspl+3]; ddst[2*dspl+4] = dsrc[2*dspl+4]; ddst[2*dspl+5] = dsrc[2*dspl+5]; ddst[2*dspl+6] = dsrc[2*dspl+6]; ddst[2*dspl+7] = dsrc[2*dspl+7]; ddst[3*dspl+0] = dsrc[3*dspl+0]; ddst[3*dspl+1] = dsrc[3*dspl+1]; ddst[3*dspl+2] = dsrc[3*dspl+2]; ddst[3*dspl+3] = dsrc[3*dspl+3]; ddst[3*dspl+4] = dsrc[3*dspl+4]; ddst[3*dspl+5] = dsrc[3*dspl+5]; ddst[3*dspl+6] = dsrc[3*dspl+6]; ddst[3*dspl+7] = dsrc[3*dspl+7]; ddst[4*dspl+0] = dsrc[4*dspl+0]; ddst[4*dspl+1] = dsrc[4*dspl+1]; ddst[4*dspl+2] = dsrc[4*dspl+2]; ddst[4*dspl+3] = dsrc[4*dspl+3]; ddst[4*dspl+4] = dsrc[4*dspl+4]; ddst[4*dspl+5] = dsrc[4*dspl+5]; ddst[4*dspl+6] = dsrc[4*dspl+6]; ddst[4*dspl+7] = dsrc[4*dspl+7]; ddst[5*dspl+0] = dsrc[5*dspl+0]; ddst[5*dspl+1] = dsrc[5*dspl+1]; ddst[5*dspl+2] = dsrc[5*dspl+2]; ddst[5*dspl+3] = dsrc[5*dspl+3]; ddst[5*dspl+4] = dsrc[5*dspl+4]; ddst[5*dspl+5] = dsrc[5*dspl+5]; ddst[5*dspl+6] = dsrc[5*dspl+6]; ddst[5*dspl+7] = dsrc[5*dspl+7]; ddst[6*dspl+0] = dsrc[6*dspl+0]; ddst[6*dspl+1] = dsrc[6*dspl+1]; ddst[6*dspl+2] = dsrc[6*dspl+2]; ddst[6*dspl+3] = dsrc[6*dspl+3]; ddst[6*dspl+4] = dsrc[6*dspl+4]; ddst[6*dspl+5] = dsrc[6*dspl+5]; ddst[6*dspl+6] = dsrc[6*dspl+6]; ddst[6*dspl+7] = dsrc[6*dspl+7]; ddst[7*dspl+0] = dsrc[7*dspl+0]; ddst[7*dspl+1] = dsrc[7*dspl+1]; ddst[7*dspl+2] = dsrc[7*dspl+2]; ddst[7*dspl+3] = dsrc[7*dspl+3]; ddst[7*dspl+4] = dsrc[7*dspl+4]; ddst[7*dspl+5] = dsrc[7*dspl+5]; ddst[7*dspl+6] = dsrc[7*dspl+6]; ddst[7*dspl+7] = dsrc[7*dspl+7]; #else double *dsrc, *ddst; int dspl; dsrc = (double *)src; ddst = (double *)dst; dspl = spl>>3; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; #endif } /* ============== idCinematicLocal::move4_32 ============== */ void idCinematicLocal::move4_32( byte *src, byte *dst, int spl ) { #if 1 int *dsrc, *ddst; int dspl; dsrc = (int *)src; ddst = (int *)dst; dspl = spl>>2; ddst[0*dspl+0] = dsrc[0*dspl+0]; ddst[0*dspl+1] = dsrc[0*dspl+1]; ddst[0*dspl+2] = dsrc[0*dspl+2]; ddst[0*dspl+3] = dsrc[0*dspl+3]; ddst[1*dspl+0] = dsrc[1*dspl+0]; ddst[1*dspl+1] = dsrc[1*dspl+1]; ddst[1*dspl+2] = dsrc[1*dspl+2]; ddst[1*dspl+3] = dsrc[1*dspl+3]; ddst[2*dspl+0] = dsrc[2*dspl+0]; ddst[2*dspl+1] = dsrc[2*dspl+1]; ddst[2*dspl+2] = dsrc[2*dspl+2]; ddst[2*dspl+3] = dsrc[2*dspl+3]; ddst[3*dspl+0] = dsrc[3*dspl+0]; ddst[3*dspl+1] = dsrc[3*dspl+1]; ddst[3*dspl+2] = dsrc[3*dspl+2]; ddst[3*dspl+3] = dsrc[3*dspl+3]; #else double *dsrc, *ddst; int dspl; dsrc = (double *)src; ddst = (double *)dst; dspl = spl>>3; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += dspl; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; #endif } /* ============== idCinematicLocal::blit8_32 ============== */ void idCinematicLocal::blit8_32( byte *src, byte *dst, int spl ) { #if 1 int *dsrc, *ddst; int dspl; dsrc = (int *)src; ddst = (int *)dst; dspl = spl>>2; ddst[0*dspl+0] = dsrc[ 0]; ddst[0*dspl+1] = dsrc[ 1]; ddst[0*dspl+2] = dsrc[ 2]; ddst[0*dspl+3] = dsrc[ 3]; ddst[0*dspl+4] = dsrc[ 4]; ddst[0*dspl+5] = dsrc[ 5]; ddst[0*dspl+6] = dsrc[ 6]; ddst[0*dspl+7] = dsrc[ 7]; ddst[1*dspl+0] = dsrc[ 8]; ddst[1*dspl+1] = dsrc[ 9]; ddst[1*dspl+2] = dsrc[10]; ddst[1*dspl+3] = dsrc[11]; ddst[1*dspl+4] = dsrc[12]; ddst[1*dspl+5] = dsrc[13]; ddst[1*dspl+6] = dsrc[14]; ddst[1*dspl+7] = dsrc[15]; ddst[2*dspl+0] = dsrc[16]; ddst[2*dspl+1] = dsrc[17]; ddst[2*dspl+2] = dsrc[18]; ddst[2*dspl+3] = dsrc[19]; ddst[2*dspl+4] = dsrc[20]; ddst[2*dspl+5] = dsrc[21]; ddst[2*dspl+6] = dsrc[22]; ddst[2*dspl+7] = dsrc[23]; ddst[3*dspl+0] = dsrc[24]; ddst[3*dspl+1] = dsrc[25]; ddst[3*dspl+2] = dsrc[26]; ddst[3*dspl+3] = dsrc[27]; ddst[3*dspl+4] = dsrc[28]; ddst[3*dspl+5] = dsrc[29]; ddst[3*dspl+6] = dsrc[30]; ddst[3*dspl+7] = dsrc[31]; ddst[4*dspl+0] = dsrc[32]; ddst[4*dspl+1] = dsrc[33]; ddst[4*dspl+2] = dsrc[34]; ddst[4*dspl+3] = dsrc[35]; ddst[4*dspl+4] = dsrc[36]; ddst[4*dspl+5] = dsrc[37]; ddst[4*dspl+6] = dsrc[38]; ddst[4*dspl+7] = dsrc[39]; ddst[5*dspl+0] = dsrc[40]; ddst[5*dspl+1] = dsrc[41]; ddst[5*dspl+2] = dsrc[42]; ddst[5*dspl+3] = dsrc[43]; ddst[5*dspl+4] = dsrc[44]; ddst[5*dspl+5] = dsrc[45]; ddst[5*dspl+6] = dsrc[46]; ddst[5*dspl+7] = dsrc[47]; ddst[6*dspl+0] = dsrc[48]; ddst[6*dspl+1] = dsrc[49]; ddst[6*dspl+2] = dsrc[50]; ddst[6*dspl+3] = dsrc[51]; ddst[6*dspl+4] = dsrc[52]; ddst[6*dspl+5] = dsrc[53]; ddst[6*dspl+6] = dsrc[54]; ddst[6*dspl+7] = dsrc[55]; ddst[7*dspl+0] = dsrc[56]; ddst[7*dspl+1] = dsrc[57]; ddst[7*dspl+2] = dsrc[58]; ddst[7*dspl+3] = dsrc[59]; ddst[7*dspl+4] = dsrc[60]; ddst[7*dspl+5] = dsrc[61]; ddst[7*dspl+6] = dsrc[62]; ddst[7*dspl+7] = dsrc[63]; #else double *dsrc, *ddst; int dspl; dsrc = (double *)src; ddst = (double *)dst; dspl = spl>>3; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; dsrc += 4; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3]; #endif } /* ============== idCinematicLocal::blit4_32 ============== */ void idCinematicLocal::blit4_32( byte *src, byte *dst, int spl ) { #if 1 int *dsrc, *ddst; int dspl; dsrc = (int *)src; ddst = (int *)dst; dspl = spl>>2; ddst[0*dspl+0] = dsrc[ 0]; ddst[0*dspl+1] = dsrc[ 1]; ddst[0*dspl+2] = dsrc[ 2]; ddst[0*dspl+3] = dsrc[ 3]; ddst[1*dspl+0] = dsrc[ 4]; ddst[1*dspl+1] = dsrc[ 5]; ddst[1*dspl+2] = dsrc[ 6]; ddst[1*dspl+3] = dsrc[ 7]; ddst[2*dspl+0] = dsrc[ 8]; ddst[2*dspl+1] = dsrc[ 9]; ddst[2*dspl+2] = dsrc[10]; ddst[2*dspl+3] = dsrc[11]; ddst[3*dspl+0] = dsrc[12]; ddst[3*dspl+1] = dsrc[13]; ddst[3*dspl+2] = dsrc[14]; ddst[3*dspl+3] = dsrc[15]; #else double *dsrc, *ddst; int dspl; dsrc = (double *)src; ddst = (double *)dst; dspl = spl>>3; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += 2; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += 2; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; dsrc += 2; ddst += dspl; ddst[0] = dsrc[0]; ddst[1] = dsrc[1]; #endif } /* ============== idCinematicLocal::blit2_32 ============== */ void idCinematicLocal::blit2_32( byte *src, byte *dst, int spl ) { #if 1 int *dsrc, *ddst; int dspl; dsrc = (int *)src; ddst = (int *)dst; dspl = spl>>2; ddst[0*dspl+0] = dsrc[0]; ddst[0*dspl+1] = dsrc[1]; ddst[1*dspl+0] = dsrc[2]; ddst[1*dspl+1] = dsrc[3]; #else double *dsrc, *ddst; int dspl; dsrc = (double *)src; ddst = (double *)dst; dspl = spl>>3; ddst[0] = dsrc[0]; ddst[dspl] = dsrc[1]; #endif } /* ============== idCinematicLocal::blitVQQuad32fs ============== */ void idCinematicLocal::blitVQQuad32fs( byte **status, unsigned char *data ) { unsigned short newd, celdata, code; unsigned int index, i; newd = 0; celdata = 0; index = 0; do { if (!newd) { newd = 7; celdata = data[0] + data[1]*256; data += 2; } else { newd--; } code = (unsigned short)(celdata&0xc000); celdata <<= 2; switch (code) { case 0x8000: // vq code blit8_32( (byte *)&vq8[(*data)*128], status[index], samplesPerLine ); data++; index += 5; break; case 0xc000: // drop index++; // skip 8x8 for(i=0;i<4;i++) { if (!newd) { newd = 7; celdata = data[0] + data[1]*256; data += 2; } else { newd--; } code = (unsigned short)(celdata&0xc000); celdata <<= 2; switch (code) { // code in top two bits of code case 0x8000: // 4x4 vq code blit4_32( (byte *)&vq4[(*data)*32], status[index], samplesPerLine ); data++; break; case 0xc000: // 2x2 vq code blit2_32( (byte *)&vq2[(*data)*8], status[index], samplesPerLine ); data++; blit2_32( (byte *)&vq2[(*data)*8], status[index]+8, samplesPerLine ); data++; blit2_32( (byte *)&vq2[(*data)*8], status[index]+samplesPerLine*2, samplesPerLine ); data++; blit2_32( (byte *)&vq2[(*data)*8], status[index]+samplesPerLine*2+8, samplesPerLine ); data++; break; case 0x4000: // motion compensation move4_32( status[index] + mcomp[(*data)], status[index], samplesPerLine ); data++; break; } index++; } break; case 0x4000: // motion compensation move8_32( status[index] + mcomp[(*data)], status[index], samplesPerLine ); data++; index += 5; break; case 0x0000: index += 5; break; } } while ( status[index] != NULL ); } #define VQ2TO4(a,b,c,d) { \ *c++ = a[0]; \ *d++ = a[0]; \ *d++ = a[0]; \ *c++ = a[1]; \ *d++ = a[1]; \ *d++ = a[1]; \ *c++ = b[0]; \ *d++ = b[0]; \ *d++ = b[0]; \ *c++ = b[1]; \ *d++ = b[1]; \ *d++ = b[1]; \ *d++ = a[0]; \ *d++ = a[0]; \ *d++ = a[1]; \ *d++ = a[1]; \ *d++ = b[0]; \ *d++ = b[0]; \ *d++ = b[1]; \ *d++ = b[1]; \ a += 2; b += 2; } #define VQ2TO2(a,b,c,d) { \ *c++ = *a; \ *d++ = *a; \ *d++ = *a; \ *c++ = *b; \ *d++ = *b; \ *d++ = *b; \ *d++ = *a; \ *d++ = *a; \ *d++ = *b; \ *d++ = *b; \ a++; b++; } /* ============== idCinematicLocal::yuv_to_rgb ============== */ unsigned short idCinematicLocal::yuv_to_rgb( int y, int u, int v ) { int r,g,b,YY = (int)(ROQ_YY_tab[(y)]); r = (YY + ROQ_VR_tab[v]) >> 9; g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8; b = (YY + ROQ_UB_tab[u]) >> 9; if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; if (r > 31) r = 31; if (g > 63) g = 63; if (b > 31) b = 31; return (unsigned short)((r<<11)+(g<<5)+(b)); } /* ============== idCinematicLocal::yuv_to_rgb24 ============== */ unsigned int idCinematicLocal::yuv_to_rgb24( int y, int u, int v ) { int r,g,b,YY = (int)(ROQ_YY_tab[(y)]); r = (YY + ROQ_VR_tab[v]) >> 6; g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6; b = (YY + ROQ_UB_tab[u]) >> 6; if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return LittleLong((r)+(g<<8)+(b<<16)); } /* ============== idCinematicLocal::decodeCodeBook ============== */ void idCinematicLocal::decodeCodeBook( byte *input, unsigned short roq_flags ) { int i, j, two, four; unsigned short *aptr, *bptr, *cptr, *dptr; int y0,y1,y2,y3,cr,cb; unsigned int *iaptr, *ibptr, *icptr, *idptr; if (!roq_flags) { two = four = 256; } else { two = roq_flags>>8; if (!two) two = 256; four = roq_flags&0xff; } four *= 2; bptr = (unsigned short *)vq2; if (!half) { if (!smootheddouble) { // // normal height // if (samplesPerPixel==2) { for(i=0;i CIN_WIDTH) bigx = CIN_WIDTH; if (bigy > CIN_HEIGHT) bigy = CIN_HEIGHT; if ( (startX >= lowx) && (startX+quadSize) <= (bigx) && (startY+quadSize) <= (bigy) && (startY >= lowy) && quadSize <= MAXSIZE) { useY = startY; scroff = image + (useY+((CIN_HEIGHT-bigy)>>1)+yOff)*(samplesPerLine) + (((startX+xOff))*samplesPerPixel); qStatus[0][onQuad ] = scroff; qStatus[1][onQuad++] = scroff+offset; } if ( quadSize != MINSIZE ) { quadSize >>= 1; recurseQuad( startX, startY , quadSize, xOff, yOff ); recurseQuad( startX+quadSize, startY , quadSize, xOff, yOff ); recurseQuad( startX, startY+quadSize , quadSize, xOff, yOff ); recurseQuad( startX+quadSize, startY+quadSize , quadSize, xOff, yOff ); } } /* ============== idCinematicLocal::setupQuad ============== */ void idCinematicLocal::setupQuad( int xOff, int yOff ) { int numQuadCels, i,x,y; byte *temp; numQuadCels = (CIN_WIDTH*CIN_HEIGHT) / (16); numQuadCels += numQuadCels/4 + numQuadCels/16; numQuadCels += 64; // for overflow numQuadCels = (xsize*ysize) / (16); numQuadCels += numQuadCels/4; numQuadCels += 64; // for overflow onQuad = 0; for(y=0;y<(int)ysize;y+=16) for(x=0;x<(int)xsize;x+=16) recurseQuad( x, y, 16, xOff, yOff ); temp = NULL; for(i=(numQuadCels-64);iSeek( 0, FS_SEEK_SET ); iFile->Read( file, 16 ); RoQ_init(); status = FMV_LOOPED; } typedef struct { struct jpeg_source_mgr pub; /* public fields */ byte *infile; /* source stream */ JOCTET * buffer; /* start of buffer */ boolean start_of_file; /* have we gotten any data yet? */ int memsize; } my_source_mgr; typedef my_source_mgr * my_src_ptr; #define INPUT_BUF_SIZE 32768 /* choose an efficiently fread'able size */ /* jpeg error handling */ struct jpeg_error_mgr jerr; /* * Fill the input buffer --- called whenever buffer is emptied. * * In typical applications, this should read fresh data into the buffer * (ignoring the current state of next_input_byte & bytes_in_buffer), * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been reloaded. It is not necessary to * fill the buffer entirely, only to obtain at least one more byte. * * There is no such thing as an EOF return. If the end of the file has been * reached, the routine has a choice of ERREXIT() or inserting fake data into * the buffer. In most cases, generating a warning message and inserting a * fake EOI marker is the best course of action --- this will allow the * decompressor to output however much of the image is there. However, * the resulting error message is misleading if the real problem is an empty * input file, so we handle that case specially. * * In applications that need to be able to suspend compression due to input * not being available yet, a FALSE return indicates that no more data can be * obtained right now, but more may be forthcoming later. In this situation, * the decompressor will return to its caller (with an indication of the * number of scanlines it has read, if any). The application should resume * decompression after it has loaded more data into the input buffer. Note * that there are substantial restrictions on the use of suspension --- see * the documentation. * * When suspending, the decompressor will back up to a convenient restart point * (typically the start of the current MCU). next_input_byte & bytes_in_buffer * indicate where the restart point will be if the current call returns FALSE. * Data beyond this point must be rescanned after resumption, so move it to * the front of the buffer rather than discarding it. */ static boolean fill_input_buffer( j_decompress_ptr cinfo ) { my_src_ptr src = (my_src_ptr) cinfo->src; int nbytes; nbytes = INPUT_BUF_SIZE; if (nbytes > src->memsize) nbytes = src->memsize; if (nbytes == 0) { /* Insert a fake EOI marker */ src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } else { memcpy( src->buffer, src->infile, INPUT_BUF_SIZE ); src->infile = src->infile + nbytes; src->memsize = src->memsize - INPUT_BUF_SIZE; } src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; src->start_of_file = FALSE; return TRUE; } /* * Initialize source --- called by jpeg_read_header * before any data is actually read. */ static void init_source (j_decompress_ptr cinfo) { my_src_ptr src = (my_src_ptr) cinfo->src; /* We reset the empty-input-file flag for each image, * but we don't clear the input buffer. * This is correct behavior for reading a series of images from one source. */ src->start_of_file = TRUE; } /* * Skip data --- used to skip over a potentially large amount of * uninteresting data (such as an APPn marker). * * Writers of suspendable-input applications must note that skip_input_data * is not granted the right to give a suspension return. If the skip extends * beyond the data currently in the buffer, the buffer can be marked empty so * that the next read will cause a fill_input_buffer call that can suspend. * Arranging for additional bytes to be discarded before reloading the input * buffer is the application writer's problem. */ static void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { my_src_ptr src = (my_src_ptr) cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { src->infile = src->infile + num_bytes; src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } /* * An additional method that can be provided by data source modules is the * resync_to_restart method for error recovery in the presence of RST markers. * For the moment, this source module just uses the default resync method * provided by the JPEG library. That method assumes that no backtracking * is possible. */ /* * Terminate source --- called by jpeg_finish_decompress * after all data has been read. Often a no-op. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */ static void term_source (j_decompress_ptr cinfo) { /* no work necessary here */ } void jpeg_memory_src (j_decompress_ptr cinfo, byte *infile, int size) { my_src_ptr src; /* The source object and input buffer are made permanent so that a series * of JPEG images can be read from the same file by calling jpeg_stdio_src * only before the first one. (If we discarded the buffer at the end of * one image, we'd likely lose the start of the next one.) * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); src = (my_src_ptr) cinfo->src; src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof(JOCTET)); } src = (my_src_ptr) cinfo->src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->infile = infile; src->memsize = size; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } int JPEGBlit( byte *wStatus, byte *data, int datasize ) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_memory_src(&cinfo, data, datasize); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ cinfo.dct_method = JDCT_IFAST; cinfo.dct_method = JDCT_FASTEST; cinfo.dither_mode = JDITHER_NONE; cinfo.do_fancy_upsampling = FALSE; // cinfo.out_color_space = JCS_GRAYSCALE; (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ wStatus += (cinfo.output_height-1)*row_stride; while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void) jpeg_read_scanlines(&cinfo, &buffer[0], 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ memcpy( wStatus, &buffer[0][0], row_stride ); /* int x; unsigned int *buf = (unsigned int *)&buffer[0][0]; unsigned int *out = (unsigned int *)wStatus; for(x=0;xRead( file, RoQFrameSize+8 ); if ( RoQPlayed >= ROQSize ) { if (looping) { RoQReset(); } else { status = FMV_EOF; } return; } framedata = file; // // new frame is ready // redump: switch(roq_id) { case ROQ_QUAD_VQ: if ((numQuads&1)) { normalBuffer0 = t[1]; RoQPrepMcomp( roqF0, roqF1 ); blitVQQuad32fs( qStatus[1], framedata); buf = image + screenDelta; } else { normalBuffer0 = t[0]; RoQPrepMcomp( roqF0, roqF1 ); blitVQQuad32fs( qStatus[0], framedata ); buf = image; } if (numQuads == 0) { // first frame memcpy(image+screenDelta, image, samplesPerLine*ysize); } numQuads++; dirty = true; break; case ROQ_CODEBOOK: decodeCodeBook( framedata, (unsigned short)roq_flags ); break; case ZA_SOUND_MONO: break; case ZA_SOUND_STEREO: break; case ROQ_QUAD_INFO: if (numQuads == -1) { readQuadInfo( framedata ); setupQuad( 0, 0 ); } if (numQuads != 1) numQuads = 0; break; case ROQ_PACKET: inMemory = ( roq_flags != 0 ); RoQFrameSize = 0; // for header break; case ROQ_QUAD_HANG: RoQFrameSize = 0; break; case ROQ_QUAD_JPEG: if (!numQuads) { normalBuffer0 = t[0]; JPEGBlit( image, framedata, RoQFrameSize ); memcpy(image+screenDelta, image, samplesPerLine*ysize); numQuads++; } break; default: status = FMV_EOF; break; } // // read in next frame data // if ( RoQPlayed >= ROQSize ) { if (looping) { RoQReset(); } else { status = FMV_EOF; } return; } framedata += RoQFrameSize; roq_id = framedata[0] + framedata[1]*256; RoQFrameSize = framedata[2] + framedata[3]*256 + framedata[4]*65536; roq_flags = framedata[6] + framedata[7]*256; roqF0 = (char)framedata[7]; roqF1 = (char)framedata[6]; if (RoQFrameSize>65536||roq_id==0x1084) { common->DPrintf("roq_size>65536||roq_id==0x1084\n"); status = FMV_EOF; if (looping) { RoQReset(); } return; } if (inMemory && (status != FMV_EOF)) { inMemory = false; framedata += 8; goto redump; } // // one more frame hits the dust // // assert(RoQFrameSize <= 65536); // r = Sys_StreamedRead( file, RoQFrameSize+8, 1, iFile ); RoQPlayed += RoQFrameSize+8; } /* ============== idCinematicLocal::RoQ_init ============== */ void idCinematicLocal::RoQ_init( void ) { RoQPlayed = 24; /* get frame rate */ roqFPS = file[ 6] + file[ 7]*256; if (!roqFPS) roqFPS = 30; numQuads = -1; roq_id = file[ 8] + file[ 9]*256; RoQFrameSize= file[10] + file[11]*256 + file[12]*65536; roq_flags = file[14] + file[15]*256; } /* ============== idCinematicLocal::RoQShutdown ============== */ void idCinematicLocal::RoQShutdown( void ) { if ( status == FMV_IDLE ) { return; } status = FMV_IDLE; if ( iFile ) { fileSystem->CloseFile( iFile ); iFile = NULL; } fileName = ""; } //=========================================== /* ============== idSndWindow::InitFromFile ============== */ bool idSndWindow::InitFromFile( const char *qpath, bool looping ) { idStr fname = qpath; fname.ToLower(); if ( !fname.Icmp( "waveform" ) ) { showWaveform = true; } else { showWaveform = false; } return true; } /* ============== idSndWindow::ImageForTime ============== */ cinData_t idSndWindow::ImageForTime( int milliseconds ) { return soundSystem->ImageForTime( milliseconds, showWaveform ); } /* ============== idSndWindow::AnimationLength ============== */ int idSndWindow::AnimationLength() { return -1; }