cl_cinematic_roq.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 
00027 #include "cl_cinematic_roq.h"
00028 #include "cl_cinematic.h"
00029 #include "../renderer/r_draw.h"
00030 #include "../sound/s_main.h"
00031 #include "../sound/s_music.h"
00032 
00033 typedef struct {
00034     int vr[256];
00035     int ug[256];
00036     int vg[256];
00037     int ub[256];
00038 } yuvTable_t;
00039 
00040 #define ROQ_IDENT                   0x1084
00041 
00042 #define ROQ_QUAD_INFO               0x1001
00043 #define ROQ_QUAD_CODEBOOK           0x1002
00044 #define ROQ_QUAD_VQ                 0x1011
00045 #define ROQ_SOUND_MONO              0x1020
00046 #define ROQ_SOUND_STEREO            0x1021
00047 
00048 #define ROQ_CHUNK_HEADER_SIZE       8           /* Size of a RoQ chunk header */
00049 
00050 #define ROQ_MAX_CHUNK_SIZE          65536       /* Max size of a RoQ chunk */
00051 
00052 #define ROQ_SOUND_RATE              22050
00053 
00054 #define ROQ_ID_FCC 0x4000
00055 #define ROQ_ID_SLD 0x8000
00056 #define ROQ_ID_CCC 0xC000
00057 
00058 typedef struct {
00059     unsigned short  id;
00060     unsigned int    size;
00061     unsigned short  flags;
00062 } roqChunk_t;
00063 
00064 typedef struct {
00065     unsigned int            pixel[4];
00066 } roqQuadVector_t;
00067 
00068 typedef struct {
00069     byte            index[4];
00070 } roqQuadCell_t;
00071 
00072 typedef struct {
00073     qFILE           file;
00074     int             size;
00075     int             offset;
00076 
00077     int             frameWidth;
00078     int             frameHeight;
00079     int             frameRate;
00080     byte *          frameBuffer[2];
00081 
00082     int             startTime;  
00083     int             currentFrame;
00084 
00085     int             soundChannel;   
00087     byte            data[ROQ_MAX_CHUNK_SIZE + ROQ_CHUNK_HEADER_SIZE];
00088     byte *          header;
00089 
00090     roqChunk_t      chunk;
00091     roqQuadVector_t quadVectors[256];
00092     roqQuadCell_t   quadCells[256];
00093 
00094     musicStream_t   musicStream;
00095 } roqCinematic_t;
00096 
00097 static short        roqCin_sqrTable[256];
00098 static yuvTable_t   roqCin_yuvTable;
00099 
00100 static int          roqCin_quadOffsets2[2][4];
00101 static int          roqCin_quadOffsets4[2][4];
00102 
00103 #define ROQCIN (*((roqCinematic_t*)cin->codecData))
00104 
00108 static inline byte CIN_ROQ_ClampByte (int value)
00109 {
00110     if (value < 0)
00111         return 0;
00112 
00113     if (value > 255)
00114         return 255;
00115 
00116     return value;
00117 }
00118 
00122 static void CIN_ROQ_ApplyVector2x2 (cinematic_t *cin, int x, int y, const byte *indices)
00123 {
00124     int i;
00125 
00126     for (i = 0; i < 4; i++) {
00127         const int xp = x + roqCin_quadOffsets2[0][i];
00128         const int yp = y + roqCin_quadOffsets2[1][i];
00129         const unsigned int *src = (const unsigned int *)ROQCIN.quadVectors + (indices[i] * 4);
00130         unsigned int *dst = (unsigned int *)ROQCIN.frameBuffer[0] + (yp * ROQCIN.frameWidth + xp);
00131 
00132         dst[0] = src[0];
00133         dst[1] = src[1];
00134 
00135         dst += ROQCIN.frameWidth;
00136 
00137         dst[0] = src[2];
00138         dst[1] = src[3];
00139     }
00140 }
00141 
00145 static void CIN_ROQ_ApplyVector4x4 (cinematic_t *cin, int x, int y, const byte *indices)
00146 {
00147     int i;
00148 
00149     for (i = 0; i < 4; i++) {
00150         const int xp = x + roqCin_quadOffsets4[0][i];
00151         const int yp = y + roqCin_quadOffsets4[1][i];
00152         const unsigned int *src = (const unsigned int *)ROQCIN.quadVectors + (indices[i] * 4);
00153         unsigned int *dst = (unsigned int *)ROQCIN.frameBuffer[0] + (yp * ROQCIN.frameWidth + xp);
00154 
00155         dst[0] = src[0];
00156         dst[1] = src[0];
00157         dst[2] = src[1];
00158         dst[3] = src[1];
00159 
00160         dst += ROQCIN.frameWidth;
00161 
00162         dst[0] = src[0];
00163         dst[1] = src[0];
00164         dst[2] = src[1];
00165         dst[3] = src[1];
00166 
00167         dst += ROQCIN.frameWidth;
00168 
00169         dst[0] = src[2];
00170         dst[1] = src[2];
00171         dst[2] = src[3];
00172         dst[3] = src[3];
00173 
00174         dst += ROQCIN.frameWidth;
00175 
00176         dst[0] = src[2];
00177         dst[1] = src[2];
00178         dst[2] = src[3];
00179         dst[3] = src[3];
00180     }
00181 }
00182 
00186 static void CIN_ROQ_ApplyMotion4x4 (cinematic_t *cin, int x, int y, int mx, int my, int mv)
00187 {
00188     int i;
00189     const int xp = x + 8 - (mv >> 4) - mx;
00190     const int yp = y + 8 - (mv & 15) - my;
00191     const unsigned int *src = (const unsigned int *)ROQCIN.frameBuffer[1] + (yp * ROQCIN.frameWidth + xp);
00192     unsigned int *dst = (unsigned int *)ROQCIN.frameBuffer[0] + (y * ROQCIN.frameWidth + x);
00193 
00194     for (i = 0; i < 4; i++, src += ROQCIN.frameWidth, dst += ROQCIN.frameWidth) {
00195         dst[0] = src[0];
00196         dst[1] = src[1];
00197         dst[2] = src[2];
00198         dst[3] = src[3];
00199     }
00200 }
00201 
00205 static void CIN_ROQ_ApplyMotion8x8 (cinematic_t *cin, int x, int y, int mx, int my, int mv)
00206 {
00207     int i;
00208     const int xp = x + 8 - (mv >> 4) - mx;
00209     const int yp = y + 8 - (mv & 15) - my;
00210     const unsigned int *src = (const unsigned int *)ROQCIN.frameBuffer[1] + (yp * ROQCIN.frameWidth + xp);
00211     unsigned int *dst = (unsigned int *)ROQCIN.frameBuffer[0] + (y * ROQCIN.frameWidth + x);
00212 
00213     for (i = 0; i < 8; i++, src += ROQCIN.frameWidth, dst += ROQCIN.frameWidth) {
00214         dst[0] = src[0];
00215         dst[1] = src[1];
00216         dst[2] = src[2];
00217         dst[3] = src[3];
00218         dst[4] = src[4];
00219         dst[5] = src[5];
00220         dst[6] = src[6];
00221         dst[7] = src[7];
00222     }
00223 }
00224 
00228 static void CIN_ROQ_DecodeInfo (cinematic_t *cin, const byte *data)
00229 {
00230     if (ROQCIN.frameBuffer[0] && ROQCIN.frameBuffer[1])
00231         return;     /* Already allocated */
00232 
00233     /* Allocate the frame buffer */
00234     ROQCIN.frameWidth = data[0] | (data[1] << 8);
00235     ROQCIN.frameHeight = data[2] | (data[3] << 8);
00236 
00237     ROQCIN.frameWidth = LittleShort(ROQCIN.frameWidth);
00238     ROQCIN.frameHeight = LittleShort(ROQCIN.frameHeight);
00239 
00240     if (!Q_IsPowerOfTwo(ROQCIN.frameWidth) || !Q_IsPowerOfTwo(ROQCIN.frameHeight))
00241         Com_Error(ERR_DROP, "CIN_DecodeInfo: size is not a power of two (%i x %i)", ROQCIN.frameWidth, ROQCIN.frameHeight);
00242 
00243     ROQCIN.frameBuffer[0] = (byte *)Mem_PoolAlloc(ROQCIN.frameWidth * ROQCIN.frameHeight * 4, cl_genericPool, 0);
00244     ROQCIN.frameBuffer[1] = (byte *)Mem_PoolAlloc(ROQCIN.frameWidth * ROQCIN.frameHeight * 4, cl_genericPool, 0);
00245 }
00246 
00250 static void CIN_ROQ_DecodeCodeBook (cinematic_t *cin, const byte *data)
00251 {
00252     int     numQuadVectors, numQuadCells;
00253     int     i;
00254 
00255     if (ROQCIN.chunk.flags) {
00256         numQuadVectors = (ROQCIN.chunk.flags >> 8) & 0xFF;
00257         numQuadCells = (ROQCIN.chunk.flags >> 0) & 0xFF;
00258 
00259         if (!numQuadVectors)
00260             numQuadVectors = 256;
00261     } else {
00262         numQuadVectors = 256;
00263         numQuadCells = 256;
00264     }
00265 
00266     /* Decode YUV quad vectors to RGB */
00267     for (i = 0; i < numQuadVectors; i++) {
00268         const int r = roqCin_yuvTable.vr[data[5]];
00269         const int g = roqCin_yuvTable.ug[data[4]] + roqCin_yuvTable.vg[data[5]];
00270         const int b = roqCin_yuvTable.ub[data[4]];
00271 
00272         ((byte *)&ROQCIN.quadVectors[i].pixel[0])[0] = CIN_ROQ_ClampByte(data[0] + r);
00273         ((byte *)&ROQCIN.quadVectors[i].pixel[0])[1] = CIN_ROQ_ClampByte(data[0] - g);
00274         ((byte *)&ROQCIN.quadVectors[i].pixel[0])[2] = CIN_ROQ_ClampByte(data[0] + b);
00275         ((byte *)&ROQCIN.quadVectors[i].pixel[0])[3] = 255;
00276 
00277         ((byte *)&ROQCIN.quadVectors[i].pixel[1])[0] = CIN_ROQ_ClampByte(data[1] + r);
00278         ((byte *)&ROQCIN.quadVectors[i].pixel[1])[1] = CIN_ROQ_ClampByte(data[1] - g);
00279         ((byte *)&ROQCIN.quadVectors[i].pixel[1])[2] = CIN_ROQ_ClampByte(data[1] + b);
00280         ((byte *)&ROQCIN.quadVectors[i].pixel[1])[3] = 255;
00281 
00282         ((byte *)&ROQCIN.quadVectors[i].pixel[2])[0] = CIN_ROQ_ClampByte(data[2] + r);
00283         ((byte *)&ROQCIN.quadVectors[i].pixel[2])[1] = CIN_ROQ_ClampByte(data[2] - g);
00284         ((byte *)&ROQCIN.quadVectors[i].pixel[2])[2] = CIN_ROQ_ClampByte(data[2] + b);
00285         ((byte *)&ROQCIN.quadVectors[i].pixel[2])[3] = 255;
00286 
00287         ((byte *)&ROQCIN.quadVectors[i].pixel[3])[0] = CIN_ROQ_ClampByte(data[3] + r);
00288         ((byte *)&ROQCIN.quadVectors[i].pixel[3])[1] = CIN_ROQ_ClampByte(data[3] - g);
00289         ((byte *)&ROQCIN.quadVectors[i].pixel[3])[2] = CIN_ROQ_ClampByte(data[3] + b);
00290         ((byte *)&ROQCIN.quadVectors[i].pixel[3])[3] = 255;
00291 
00292         data += 6;
00293     }
00294 
00295     /* Copy quad cells */
00296     for (i = 0; i < numQuadCells; i++) {
00297         ROQCIN.quadCells[i].index[0] = data[0];
00298         ROQCIN.quadCells[i].index[1] = data[1];
00299         ROQCIN.quadCells[i].index[2] = data[2];
00300         ROQCIN.quadCells[i].index[3] = data[3];
00301 
00302         data += 4;
00303     }
00304 }
00305 
00309 static void CIN_ROQ_DecodeVideo (cinematic_t *cin, const byte *data)
00310 {
00311     byte    *buffer;
00312     int     vqFlag, vqFlagPos, vqCode;
00313     int     xPos, yPos, xMot, yMot;
00314     int     x, y;
00315     int     index;
00316     int     i;
00317 
00318     if (!ROQCIN.frameBuffer[0] || !ROQCIN.frameBuffer[1])
00319         return;     /* No frame buffer */
00320 
00321     vqFlag = 0;
00322     vqFlagPos = 0;
00323 
00324     xPos = 0;
00325     yPos = 0;
00326 
00327     xMot = (char)((ROQCIN.chunk.flags >> 8) & 0xFF);
00328     yMot = (char)((ROQCIN.chunk.flags >> 0) & 0xFF);
00329 
00330     index = 0;
00331 
00332     while (1) {
00333         for (y = yPos; y < yPos + 16; y += 8) {
00334             for (x = xPos; x < xPos + 16; x += 8) {
00335                 if (!vqFlagPos) {
00336                     vqFlagPos = 7;
00337                     vqFlag = data[index + 0] | (data[index + 1] << 8);
00338                     vqFlag = LittleShort(vqFlag);
00339                     index += 2;
00340                 } else
00341                     vqFlagPos--;
00342 
00343                 vqCode = vqFlag & ROQ_ID_CCC;
00344                 vqFlag <<= 2;
00345 
00346                 switch (vqCode) {
00347                 case ROQ_ID_FCC:
00348                     CIN_ROQ_ApplyMotion8x8(cin, x, y, xMot, yMot, data[index]);
00349                     index += 1;
00350                     break;
00351                 case ROQ_ID_SLD:
00352                     CIN_ROQ_ApplyVector4x4(cin, x, y, ROQCIN.quadCells[data[index]].index);
00353                     index += 1;
00354                     break;
00355                 case ROQ_ID_CCC:
00356                     for (i = 0; i < 4; i++) {
00357                         const int xp = x + roqCin_quadOffsets4[0][i];
00358                         const int yp = y + roqCin_quadOffsets4[1][i];
00359 
00360                         if (!vqFlagPos) {
00361                             vqFlagPos = 7;
00362                             vqFlag = data[index + 0] | (data[index + 1] << 8);
00363                             vqFlag = LittleShort(vqFlag);
00364 
00365                             index += 2;
00366                         } else
00367                             vqFlagPos--;
00368 
00369                         vqCode = vqFlag & ROQ_ID_CCC;
00370                         vqFlag <<= 2;
00371 
00372                         switch (vqCode) {
00373                         case ROQ_ID_FCC:
00374                             CIN_ROQ_ApplyMotion4x4(cin, xp, yp, xMot, yMot, data[index]);
00375                             index += 1;
00376                             break;
00377                         case ROQ_ID_SLD:
00378                             CIN_ROQ_ApplyVector2x2(cin, xp, yp, ROQCIN.quadCells[data[index]].index);
00379                             index += 1;
00380                             break;
00381                         case ROQ_ID_CCC:
00382                             CIN_ROQ_ApplyVector2x2(cin, xp, yp, &data[index]);
00383                             index += 4;
00384                             break;
00385                         }
00386                     }
00387                     break;
00388                 }
00389             }
00390         }
00391 
00392         xPos += 16;
00393         if (xPos >= ROQCIN.frameWidth) {
00394             xPos -= ROQCIN.frameWidth;
00395 
00396             yPos += 16;
00397             if (yPos >= ROQCIN.frameHeight)
00398                 break;
00399         }
00400     }
00401 
00402     /* Copy or swap the buffers */
00403     if (!ROQCIN.currentFrame)
00404         memcpy(ROQCIN.frameBuffer[1], ROQCIN.frameBuffer[0], ROQCIN.frameWidth * ROQCIN.frameHeight * 4);
00405     else {
00406         buffer = ROQCIN.frameBuffer[0];
00407         ROQCIN.frameBuffer[0] = ROQCIN.frameBuffer[1];
00408         ROQCIN.frameBuffer[1] = buffer;
00409     }
00410 
00411     ROQCIN.currentFrame++;
00412 }
00413 
00418 static void CIN_ROQ_DecodeSoundMono (cinematic_t *cin, const byte *data)
00419 {
00420     short samples[ROQ_MAX_CHUNK_SIZE * 2];
00421     int prev = 0;
00422     int i, j;
00423 
00424     for (i = 0, j = 0; i < ROQCIN.chunk.size; i++, j += 2) {
00425         prev = (short)(prev + roqCin_sqrTable[data[i]]);
00426         samples[j] = (short)prev;
00427         samples[j + 1] = (short)prev;
00428     }
00429 
00430     M_AddToSampleBuffer(&ROQCIN.musicStream, ROQ_SOUND_RATE, i, (const byte *)samples);
00431 }
00432 
00437 static void CIN_ROQ_DecodeSoundStereo (cinematic_t *cin, const byte *data)
00438 {
00439     short samples[ROQ_MAX_CHUNK_SIZE];
00440     int i;
00441     short prevL = (ROQCIN.chunk.flags & 0xFF00) << 0;
00442     short prevR = (ROQCIN.chunk.flags & 0x00FF) << 8;
00443 
00444     for (i = 0; i < ROQCIN.chunk.size; i += 2) {
00445         prevL = prevL + roqCin_sqrTable[data[i + 0]];
00446         prevR = prevR + roqCin_sqrTable[data[i + 1]];
00447 
00448         samples[i + 0] = prevL;
00449         samples[i + 1] = prevR;
00450     }
00451 
00452     M_AddToSampleBuffer(&ROQCIN.musicStream, ROQ_SOUND_RATE, i / 2, (const byte *)samples);
00453 }
00454 
00459 static qboolean CIN_ROQ_DecodeChunk (cinematic_t *cin)
00460 {
00461     int frame;
00462 
00463     if (ROQCIN.startTime + ((1000 / ROQCIN.frameRate) * ROQCIN.currentFrame) > CL_Milliseconds())
00464         return qtrue;
00465 
00466     frame = ROQCIN.currentFrame;
00467 
00468     do {
00469         if (ROQCIN.offset >= ROQCIN.size)
00470             return qfalse;  /* Finished */
00471 
00472         /* Parse the chunk header */
00473         ROQCIN.chunk.id = LittleShort(*(short *)&ROQCIN.header[0]);
00474         ROQCIN.chunk.size = LittleLong(*(int *)&ROQCIN.header[2]);
00475         ROQCIN.chunk.flags = LittleShort(*(short *)&ROQCIN.header[6]);
00476 
00477         if (ROQCIN.chunk.id == ROQ_IDENT || ROQCIN.chunk.size > ROQ_MAX_CHUNK_SIZE) {
00478             Com_Printf("Invalid chunk id during decode: %i\n", ROQCIN.chunk.id);
00479             cin->replay = qfalse;
00480             return qfalse;  /* Invalid chunk */
00481         }
00482 
00483         /* Read the chunk data and the next chunk header */
00484         FS_Read(ROQCIN.data, ROQCIN.chunk.size + ROQ_CHUNK_HEADER_SIZE, &ROQCIN.file);
00485         ROQCIN.offset += ROQCIN.chunk.size + ROQ_CHUNK_HEADER_SIZE;
00486 
00487         ROQCIN.header = ROQCIN.data + ROQCIN.chunk.size;
00488 
00489         /* Decode the chunk data */
00490         switch (ROQCIN.chunk.id) {
00491         case ROQ_QUAD_INFO:
00492             CIN_ROQ_DecodeInfo(cin, ROQCIN.data);
00493             break;
00494         case ROQ_QUAD_CODEBOOK:
00495             CIN_ROQ_DecodeCodeBook(cin, ROQCIN.data);
00496             break;
00497         case ROQ_QUAD_VQ:
00498             CIN_ROQ_DecodeVideo(cin, ROQCIN.data);
00499             break;
00500         case ROQ_SOUND_MONO:
00501             if (!cin->noSound)
00502                 CIN_ROQ_DecodeSoundMono(cin, ROQCIN.data);
00503         case ROQ_SOUND_STEREO:
00504             if (!cin->noSound)
00505                 CIN_ROQ_DecodeSoundStereo(cin, ROQCIN.data);
00506             break;
00507         default:
00508             Com_Printf("Invalid chunk id: %i\n", ROQCIN.chunk.id);
00509             break;
00510         }
00511     /* loop until we finally got a new frame */
00512     } while (frame == ROQCIN.currentFrame && cin->status);
00513 
00514     return qtrue;
00515 }
00516 
00520 static void CIN_ROQ_DrawCinematic (cinematic_t *cin)
00521 {
00522     int texnum;
00523 
00524     assert(cin->status != CIN_STATUS_NONE);
00525 
00526     if (!ROQCIN.frameBuffer[1])
00527         return;
00528     texnum = R_UploadData("***cinematic***", ROQCIN.frameBuffer[1], ROQCIN.frameWidth, ROQCIN.frameHeight);
00529     R_DrawTexture(texnum, cin->x, cin->y, cin->w, cin->h);
00530 }
00531 
00535 qboolean CIN_ROQ_RunCinematic (cinematic_t *cin)
00536 {
00537     qboolean runState = CIN_ROQ_DecodeChunk(cin);
00538     if (runState)
00539         CIN_ROQ_DrawCinematic(cin);
00540     return runState;
00541 }
00542 
00543 void CIN_ROQ_StopCinematic (cinematic_t *cin)
00544 {
00545     if (ROQCIN.file.f || ROQCIN.file.z)
00546         FS_CloseFile(&ROQCIN.file);
00547     else
00548         Com_Printf("CIN_ROQ_StopCinematic: Warning no opened file\n");
00549 
00550     if (ROQCIN.frameBuffer[0]) {
00551         Mem_Free(ROQCIN.frameBuffer[0]);
00552         Mem_Free(ROQCIN.frameBuffer[1]);
00553     }
00554 
00555     M_StopMusicStream(&ROQCIN.musicStream);
00556 
00557     Mem_Free(cin->codecData);
00558     cin->codecData = NULL;
00559 }
00560 
00561 void CIN_ROQ_PlayCinematic (cinematic_t *cin, const char *fileName)
00562 {
00563     roqChunk_t chunk;
00564     int size;
00565     byte header[ROQ_CHUNK_HEADER_SIZE];
00566 
00567     assert(cin->codecData);
00568     cin->codecData = Mem_PoolAlloc(sizeof(ROQCIN), vid_genericPool, 0);
00569     memset(&ROQCIN, 0, sizeof(ROQCIN));
00570 
00571     /* Open the file */
00572     size = FS_OpenFile(fileName, &ROQCIN.file, FILE_READ);
00573     if (!ROQCIN.file.f && !ROQCIN.file.z) {
00574         Com_Printf("Cinematic %s not found\n", fileName);
00575         return;
00576     }
00577 
00578     /* Parse the header */
00579     FS_Read(header, sizeof(header), &ROQCIN.file);
00580 
00581     /* first 8 bytes are the header */
00582     chunk.id = LittleShort(*(short *)&header[0]);
00583     chunk.size = LittleLong(*(int *)&header[2]);
00584     chunk.flags = LittleShort(*(short *)&header[6]);
00585 
00586     if (chunk.id != ROQ_IDENT) {
00587         FS_CloseFile(&ROQCIN.file);
00588         Com_Error(ERR_DROP, "CIN_PlayCinematic: invalid RoQ header");
00589     }
00590 
00591     cin->cinematicType = CINEMATIC_TYPE_ROQ;
00592 
00593     /* Fill it in */
00594     Q_strncpyz(cin->name, fileName, sizeof(cin->name));
00595 
00596     M_PlayMusicStream(&ROQCIN.musicStream);
00597 
00598     ROQCIN.size = size;
00599     ROQCIN.offset = sizeof(header);
00600 
00601     ROQCIN.frameWidth = 0;
00602     ROQCIN.frameHeight = 0;
00603     ROQCIN.startTime = CL_Milliseconds();
00604     ROQCIN.frameRate = (chunk.flags != 0) ? chunk.flags : 30;
00605     if (ROQCIN.frameBuffer[0]) {
00606         Mem_Free(ROQCIN.frameBuffer[0]);
00607         ROQCIN.frameBuffer[0] = NULL;
00608     }
00609     if (ROQCIN.frameBuffer[1]) {
00610         Mem_Free(ROQCIN.frameBuffer[1]);
00611         ROQCIN.frameBuffer[1] = NULL;
00612     }
00613 
00614     ROQCIN.currentFrame = 0;
00615 
00616     /* Read the first chunk header */
00617     FS_Read(ROQCIN.data, ROQ_CHUNK_HEADER_SIZE, &ROQCIN.file);
00618     ROQCIN.offset += ROQ_CHUNK_HEADER_SIZE;
00619 
00620     ROQCIN.header = ROQCIN.data;
00621 }
00622 
00623 void CIN_ROQ_Init (void)
00624 {
00625     int i;
00626 
00627     /* Build square table */
00628     for (i = 0; i < 128; i++) {
00629         const short s = (short)(i * i);
00630         roqCin_sqrTable[i] = s;
00631         roqCin_sqrTable[i + 128] = -s;
00632     }
00633 
00634     /* Set up quad offsets */
00635     for (i = 0; i < 4; i++) {
00636         roqCin_quadOffsets2[0][i] = 2 * (i & 1);
00637         roqCin_quadOffsets2[1][i] = 2 * (i >> 1);
00638         roqCin_quadOffsets4[0][i] = 4 * (i & 1);
00639         roqCin_quadOffsets4[1][i] = 4 * (i >> 1);
00640     }
00641 
00642     /* Build YUV table */
00643     for (i = 0; i < 256; i++) {
00644         const float f = (float)(i - 128);
00645         roqCin_yuvTable.vr[i] = Q_ftol(f * 1.40200f);
00646         roqCin_yuvTable.ug[i] = Q_ftol(f * 0.34414f);
00647         roqCin_yuvTable.vg[i] = Q_ftol(f * 0.71414f);
00648         roqCin_yuvTable.ub[i] = Q_ftol(f * 1.77200f);
00649     }
00650 }

Generated by  doxygen 1.6.2