UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_cinematic_roq.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 
27 #include "cl_cinematic_roq.h"
28 #include "cl_cinematic.h"
29 #include "../client.h" /* needed by r_draw.h */
30 #include "../renderer/r_draw.h"
31 #include "../sound/s_main.h"
32 #include "../sound/s_music.h"
33 
34 typedef struct {
35  int vr[256];
36  int ug[256];
37  int vg[256];
38  int ub[256];
39 } yuvTable_t;
40 
41 #define ROQ_IDENT 0x1084
42 
43 #define ROQ_QUAD_INFO 0x1001
44 #define ROQ_QUAD_CODEBOOK 0x1002
45 #define ROQ_QUAD_VQ 0x1011
46 #define ROQ_SOUND_MONO 0x1020
47 #define ROQ_SOUND_STEREO 0x1021
48 
49 #define ROQ_CHUNK_HEADER_SIZE 8 /* Size of a RoQ chunk header */
50 
51 #define ROQ_MAX_CHUNK_SIZE 65536 /* Max size of a RoQ chunk */
52 
53 #define ROQ_SOUND_RATE 22050
54 
55 #define ROQ_ID_FCC 0x4000
56 #define ROQ_ID_SLD 0x8000
57 #define ROQ_ID_CCC 0xC000
58 
59 typedef struct {
60  uint16_t id;
61  uint32_t size;
62  uint16_t flags;
63 } roqChunk_t;
64 
65 typedef struct {
66  uint32_t pixel[4];
68 
69 typedef struct {
70  byte index[4];
72 
73 typedef struct {
75  int size;
76  int offset;
77 
80  int frameRate;
81  unsigned* frameBuffer[2];
82 
83  int startTime;
85 
88 
90  roqQuadVector_t quadVectors[256];
91  roqQuadCell_t quadCells[256];
92 
95 
96 static short roqCin_sqrTable[256];
98 
99 static int roqCin_quadOffsets2[2][4];
100 static int roqCin_quadOffsets4[2][4];
101 
102 #define ROQCIN (*((roqCinematic_t*)cin->codecData))
103 
107 static inline byte CIN_ROQ_ClampByte (int value)
108 {
109  if (value < 0)
110  return 0;
111 
112  if (value > 255)
113  return 255;
114 
115  return value;
116 }
117 
121 static void CIN_ROQ_ApplyVector2x2 (cinematic_t* cin, int x, int y, const byte* indices)
122 {
123  for (int i = 0; i < 4; i++) {
124  const int xp = x + roqCin_quadOffsets2[0][i];
125  const int yp = y + roqCin_quadOffsets2[1][i];
126  const unsigned int* src = (const unsigned int*)ROQCIN.quadVectors + (indices[i] * 4);
127  unsigned* dst = ROQCIN.frameBuffer[0] + (yp * ROQCIN.frameWidth + xp);
128 
129  dst[0] = src[0];
130  dst[1] = src[1];
131 
132  dst += ROQCIN.frameWidth;
133 
134  dst[0] = src[2];
135  dst[1] = src[3];
136  }
137 }
138 
142 static void CIN_ROQ_ApplyVector4x4 (cinematic_t* cin, int x, int y, const byte* indices)
143 {
144  for (int i = 0; i < 4; i++) {
145  const int xp = x + roqCin_quadOffsets4[0][i];
146  const int yp = y + roqCin_quadOffsets4[1][i];
147  const unsigned int* src = (const unsigned int*)ROQCIN.quadVectors + (indices[i] * 4);
148  unsigned* dst = ROQCIN.frameBuffer[0] + (yp * ROQCIN.frameWidth + xp);
149 
150  dst[0] = src[0];
151  dst[1] = src[0];
152  dst[2] = src[1];
153  dst[3] = src[1];
154 
155  dst += ROQCIN.frameWidth;
156 
157  dst[0] = src[0];
158  dst[1] = src[0];
159  dst[2] = src[1];
160  dst[3] = src[1];
161 
162  dst += ROQCIN.frameWidth;
163 
164  dst[0] = src[2];
165  dst[1] = src[2];
166  dst[2] = src[3];
167  dst[3] = src[3];
168 
169  dst += ROQCIN.frameWidth;
170 
171  dst[0] = src[2];
172  dst[1] = src[2];
173  dst[2] = src[3];
174  dst[3] = src[3];
175  }
176 }
177 
181 static void CIN_ROQ_ApplyMotion4x4 (cinematic_t* cin, int x, int y, int mx, int my, int mv)
182 {
183  const int xp = x + 8 - (mv >> 4) - mx;
184  const int yp = y + 8 - (mv & 15) - my;
185  unsigned const* src = ROQCIN.frameBuffer[1] + (yp * ROQCIN.frameWidth + xp);
186  unsigned* dst = ROQCIN.frameBuffer[0] + (y * ROQCIN.frameWidth + x);
187 
188  for (int i = 0; i < 4; i++, src += ROQCIN.frameWidth, dst += ROQCIN.frameWidth) {
189  dst[0] = src[0];
190  dst[1] = src[1];
191  dst[2] = src[2];
192  dst[3] = src[3];
193  }
194 }
195 
199 static void CIN_ROQ_ApplyMotion8x8 (cinematic_t* cin, int x, int y, int mx, int my, int mv)
200 {
201  const int xp = x + 8 - (mv >> 4) - mx;
202  const int yp = y + 8 - (mv & 15) - my;
203  unsigned const* src = ROQCIN.frameBuffer[1] + (yp * ROQCIN.frameWidth + xp);
204  unsigned* dst = ROQCIN.frameBuffer[0] + (y * ROQCIN.frameWidth + x);
205 
206  for (int i = 0; i < 8; i++, src += ROQCIN.frameWidth, dst += ROQCIN.frameWidth) {
207  dst[0] = src[0];
208  dst[1] = src[1];
209  dst[2] = src[2];
210  dst[3] = src[3];
211  dst[4] = src[4];
212  dst[5] = src[5];
213  dst[6] = src[6];
214  dst[7] = src[7];
215  }
216 }
217 
221 static void CIN_ROQ_DecodeInfo (cinematic_t* cin, const byte* data)
222 {
223  if (ROQCIN.frameBuffer[0] && ROQCIN.frameBuffer[1])
224  return; /* Already allocated */
225 
226  /* Allocate the frame buffer */
227  ROQCIN.frameWidth = data[0] | (data[1] << 8);
228  ROQCIN.frameHeight = data[2] | (data[3] << 8);
229 
230  ROQCIN.frameWidth = LittleShort(ROQCIN.frameWidth);
231  ROQCIN.frameHeight = LittleShort(ROQCIN.frameHeight);
232 
233  if (!Q_IsPowerOfTwo(ROQCIN.frameWidth) || !Q_IsPowerOfTwo(ROQCIN.frameHeight))
234  Com_Error(ERR_DROP, "CIN_DecodeInfo: size is not a power of two (%i x %i)", ROQCIN.frameWidth, ROQCIN.frameHeight);
235 
236  ROQCIN.frameBuffer[0] = Mem_PoolAllocTypeN(unsigned, ROQCIN.frameWidth * ROQCIN.frameHeight, cl_genericPool);
237  ROQCIN.frameBuffer[1] = Mem_PoolAllocTypeN(unsigned, ROQCIN.frameWidth * ROQCIN.frameHeight, cl_genericPool);
238 }
239 
243 static void CIN_ROQ_DecodeCodeBook (cinematic_t* cin, const byte* data)
244 {
245  int numQuadVectors, numQuadCells;
246 
247  if (ROQCIN.chunk.flags) {
248  numQuadVectors = (ROQCIN.chunk.flags >> 8) & 0xFF;
249  numQuadCells = (ROQCIN.chunk.flags >> 0) & 0xFF;
250 
251  if (!numQuadVectors)
252  numQuadVectors = 256;
253  } else {
254  numQuadVectors = 256;
255  numQuadCells = 256;
256  }
257 
258  /* Decode YUV quad vectors to RGB */
259  for (int i = 0; i < numQuadVectors; i++) {
260  const int r = roqCin_yuvTable.vr[data[5]];
261  const int g = roqCin_yuvTable.ug[data[4]] + roqCin_yuvTable.vg[data[5]];
262  const int b = roqCin_yuvTable.ub[data[4]];
263 
264  ((byte*)&ROQCIN.quadVectors[i].pixel[0])[0] = CIN_ROQ_ClampByte(data[0] + r);
265  ((byte*)&ROQCIN.quadVectors[i].pixel[0])[1] = CIN_ROQ_ClampByte(data[0] - g);
266  ((byte*)&ROQCIN.quadVectors[i].pixel[0])[2] = CIN_ROQ_ClampByte(data[0] + b);
267  ((byte*)&ROQCIN.quadVectors[i].pixel[0])[3] = 255;
268 
269  ((byte*)&ROQCIN.quadVectors[i].pixel[1])[0] = CIN_ROQ_ClampByte(data[1] + r);
270  ((byte*)&ROQCIN.quadVectors[i].pixel[1])[1] = CIN_ROQ_ClampByte(data[1] - g);
271  ((byte*)&ROQCIN.quadVectors[i].pixel[1])[2] = CIN_ROQ_ClampByte(data[1] + b);
272  ((byte*)&ROQCIN.quadVectors[i].pixel[1])[3] = 255;
273 
274  ((byte*)&ROQCIN.quadVectors[i].pixel[2])[0] = CIN_ROQ_ClampByte(data[2] + r);
275  ((byte*)&ROQCIN.quadVectors[i].pixel[2])[1] = CIN_ROQ_ClampByte(data[2] - g);
276  ((byte*)&ROQCIN.quadVectors[i].pixel[2])[2] = CIN_ROQ_ClampByte(data[2] + b);
277  ((byte*)&ROQCIN.quadVectors[i].pixel[2])[3] = 255;
278 
279  ((byte*)&ROQCIN.quadVectors[i].pixel[3])[0] = CIN_ROQ_ClampByte(data[3] + r);
280  ((byte*)&ROQCIN.quadVectors[i].pixel[3])[1] = CIN_ROQ_ClampByte(data[3] - g);
281  ((byte*)&ROQCIN.quadVectors[i].pixel[3])[2] = CIN_ROQ_ClampByte(data[3] + b);
282  ((byte*)&ROQCIN.quadVectors[i].pixel[3])[3] = 255;
283 
284  data += 6;
285  }
286 
287  /* Copy quad cells */
288  for (int i = 0; i < numQuadCells; i++) {
289  ROQCIN.quadCells[i].index[0] = data[0];
290  ROQCIN.quadCells[i].index[1] = data[1];
291  ROQCIN.quadCells[i].index[2] = data[2];
292  ROQCIN.quadCells[i].index[3] = data[3];
293 
294  data += 4;
295  }
296 }
297 
301 static void CIN_ROQ_DecodeVideo (cinematic_t* cin, const byte* data)
302 {
303  if (!ROQCIN.frameBuffer[0] || !ROQCIN.frameBuffer[1])
304  return; /* No frame buffer */
305 
306  int vqFlag = 0;
307  int vqFlagPos = 0;
308 
309  int xPos = 0;
310  int yPos = 0;
311 
312  const int xMot = (char)((ROQCIN.chunk.flags >> 8) & 0xFF);
313  const int yMot = (char)((ROQCIN.chunk.flags >> 0) & 0xFF);
314 
315  int index = 0;
316 
317  while (1) {
318  for (int y = yPos; y < yPos + 16; y += 8) {
319  for (int x = xPos; x < xPos + 16; x += 8) {
320  if (!vqFlagPos) {
321  vqFlagPos = 7;
322  vqFlag = data[index + 0] | (data[index + 1] << 8);
323  vqFlag = LittleShort(vqFlag);
324  index += 2;
325  } else
326  vqFlagPos--;
327 
328  int vqCode = vqFlag & ROQ_ID_CCC;
329  vqFlag <<= 2;
330 
331  switch (vqCode) {
332  case ROQ_ID_FCC:
333  CIN_ROQ_ApplyMotion8x8(cin, x, y, xMot, yMot, data[index]);
334  index += 1;
335  break;
336  case ROQ_ID_SLD:
337  CIN_ROQ_ApplyVector4x4(cin, x, y, ROQCIN.quadCells[data[index]].index);
338  index += 1;
339  break;
340  case ROQ_ID_CCC:
341  for (int i = 0; i < 4; i++) {
342  const int xp = x + roqCin_quadOffsets4[0][i];
343  const int yp = y + roqCin_quadOffsets4[1][i];
344 
345  if (!vqFlagPos) {
346  vqFlagPos = 7;
347  vqFlag = data[index + 0] | (data[index + 1] << 8);
348  vqFlag = LittleShort(vqFlag);
349 
350  index += 2;
351  } else
352  vqFlagPos--;
353 
354  vqCode = vqFlag & ROQ_ID_CCC;
355  vqFlag <<= 2;
356 
357  switch (vqCode) {
358  case ROQ_ID_FCC:
359  CIN_ROQ_ApplyMotion4x4(cin, xp, yp, xMot, yMot, data[index]);
360  index += 1;
361  break;
362  case ROQ_ID_SLD:
363  CIN_ROQ_ApplyVector2x2(cin, xp, yp, ROQCIN.quadCells[data[index]].index);
364  index += 1;
365  break;
366  case ROQ_ID_CCC:
367  CIN_ROQ_ApplyVector2x2(cin, xp, yp, &data[index]);
368  index += 4;
369  break;
370  }
371  }
372  break;
373  }
374  }
375  }
376 
377  xPos += 16;
378  if (xPos >= ROQCIN.frameWidth) {
379  xPos -= ROQCIN.frameWidth;
380 
381  yPos += 16;
382  if (yPos >= ROQCIN.frameHeight)
383  break;
384  }
385  }
386 
387  /* Copy or swap the buffers */
388  if (!ROQCIN.currentFrame)
389  memcpy(ROQCIN.frameBuffer[1], ROQCIN.frameBuffer[0], sizeof(*ROQCIN.frameBuffer[1]) * ROQCIN.frameWidth * ROQCIN.frameHeight);
390  else {
391  unsigned* const buffer = ROQCIN.frameBuffer[0];
392  ROQCIN.frameBuffer[0] = ROQCIN.frameBuffer[1];
393  ROQCIN.frameBuffer[1] = buffer;
394  }
395 
396  ROQCIN.currentFrame++;
397 }
398 
403 static void CIN_ROQ_DecodeSoundMono (cinematic_t* cin, const byte* data)
404 {
405  short samples[ROQ_MAX_CHUNK_SIZE * 2];
406  int prev = 0;
407  int i = 0;
408 
409  for (int j = 0; i < ROQCIN.chunk.size; i++, j += 2) {
410  prev = (short)(prev + roqCin_sqrTable[data[i]]);
411  samples[j] = (short)prev;
412  samples[j + 1] = (short)prev;
413  }
414 
415  M_AddToSampleBuffer(&ROQCIN.musicStream, ROQ_SOUND_RATE, i, (const byte*)samples);
416 }
417 
422 static void CIN_ROQ_DecodeSoundStereo (cinematic_t* cin, const byte* data)
423 {
424  short samples[ROQ_MAX_CHUNK_SIZE];
425  int i;
426  short prevL = (ROQCIN.chunk.flags & 0xFF00) << 0;
427  short prevR = (ROQCIN.chunk.flags & 0x00FF) << 8;
428 
429  for (i = 0; i < ROQCIN.chunk.size; i += 2) {
430  prevL = prevL + roqCin_sqrTable[data[i + 0]];
431  prevR = prevR + roqCin_sqrTable[data[i + 1]];
432 
433  samples[i + 0] = prevL;
434  samples[i + 1] = prevR;
435  }
436 
437  M_AddToSampleBuffer(&ROQCIN.musicStream, ROQ_SOUND_RATE, i / 2, (const byte*)samples);
438 }
439 
445 {
446  if (ROQCIN.startTime + ((1000 / ROQCIN.frameRate) * ROQCIN.currentFrame) > CL_Milliseconds())
447  return true;
448 
449  const int frame = ROQCIN.currentFrame;
450 
451  do {
452  if (ROQCIN.offset >= ROQCIN.size)
453  return false; /* Finished */
454 
455  /* Parse the chunk header */
456  ROQCIN.chunk.id = LittleShort(*(short*)&ROQCIN.header[0]);
457  ROQCIN.chunk.size = LittleLong(*(int*)&ROQCIN.header[2]);
458  ROQCIN.chunk.flags = LittleShort(*(short*)&ROQCIN.header[6]);
459 
460  if (ROQCIN.chunk.id == ROQ_IDENT || ROQCIN.chunk.size > ROQ_MAX_CHUNK_SIZE) {
461  Com_Printf("Invalid chunk id during decode: %i\n", ROQCIN.chunk.id);
462  cin->replay = false;
463  return false; /* Invalid chunk */
464  }
465 
466  /* Read the chunk data and the next chunk header */
467  FS_Read(ROQCIN.data, ROQCIN.chunk.size + ROQ_CHUNK_HEADER_SIZE, &ROQCIN.file);
468  ROQCIN.offset += ROQCIN.chunk.size + ROQ_CHUNK_HEADER_SIZE;
469 
470  ROQCIN.header = ROQCIN.data + ROQCIN.chunk.size;
471 
472  /* Decode the chunk data */
473  switch (ROQCIN.chunk.id) {
474  case ROQ_QUAD_INFO:
475  CIN_ROQ_DecodeInfo(cin, ROQCIN.data);
476  break;
477  case ROQ_QUAD_CODEBOOK:
478  CIN_ROQ_DecodeCodeBook(cin, ROQCIN.data);
479  break;
480  case ROQ_QUAD_VQ:
481  CIN_ROQ_DecodeVideo(cin, ROQCIN.data);
482  break;
483  case ROQ_SOUND_MONO:
484  if (!cin->noSound)
485  CIN_ROQ_DecodeSoundMono(cin, ROQCIN.data);
486  break;
487  case ROQ_SOUND_STEREO:
488  if (!cin->noSound)
490  break;
491  default:
492  Com_Printf("Invalid chunk id: %i\n", ROQCIN.chunk.id);
493  break;
494  }
495  /* loop until we finally got a new frame */
496  } while (frame == ROQCIN.currentFrame && cin->status);
497 
498  return true;
499 }
500 
505 {
506  assert(cin->status != CIN_STATUS_NONE);
507 
508  if (!ROQCIN.frameBuffer[1])
509  return;
510  const int texnum = R_UploadData("***cinematic***", ROQCIN.frameBuffer[1], ROQCIN.frameWidth, ROQCIN.frameHeight);
511  R_DrawTexture(texnum, cin->x, cin->y, cin->w, cin->h);
512 }
513 
518 {
519  const bool runState = CIN_ROQ_DecodeChunk(cin);
520  if (runState)
522  return runState;
523 }
524 
526 {
527  if (ROQCIN.file.f || ROQCIN.file.z)
528  FS_CloseFile(&ROQCIN.file);
529  else
530  Com_Printf("CIN_ROQ_StopCinematic: Warning no opened file\n");
531 
532  Mem_Free(ROQCIN.frameBuffer[0]);
533  Mem_Free(ROQCIN.frameBuffer[1]);
534 
535  M_StopMusicStream(&ROQCIN.musicStream);
536 
537  Mem_Free(cin->codecData);
538  cin->codecData = nullptr;
539 }
540 
541 int CIN_ROQ_OpenCinematic (cinematic_t* cin, const char* fileName)
542 {
543  roqChunk_t chunk;
544  byte header[ROQ_CHUNK_HEADER_SIZE];
545 
546  if (cin->codecData && (ROQCIN.file.f || ROQCIN.file.z)) {
547  Com_Printf("WARNING: it seams there was already a roq running, it will be killed to start %s\n", fileName);
549  }
550 
551  assert(cin->codecData == nullptr);
553  OBJZERO(ROQCIN);
554 
555  /* Open the file */
556  const int size = FS_OpenFile(fileName, &ROQCIN.file, FILE_READ);
557  if (!ROQCIN.file.f && !ROQCIN.file.z) {
558  Com_Printf("Cinematic %s not found\n", fileName);
559  return 1;
560  }
561 
562  /* Parse the header */
563  FS_Read(header, sizeof(header), &ROQCIN.file);
564 
565  /* first 8 bytes are the header */
566  chunk.id = LittleShort(*(short*)&header[0]);
567  chunk.size = LittleLong(*(int*)&header[2]);
568  chunk.flags = LittleShort(*(short*)&header[6]);
569 
570  if (chunk.id != ROQ_IDENT) {
571  FS_CloseFile(&ROQCIN.file);
572  Com_Printf("CIN_PlayCinematic: invalid RoQ header\n");
573  return 1;
574  }
575 
577 
578  /* Fill it in */
579  Q_strncpyz(cin->name, fileName, sizeof(cin->name));
580 
581  ROQCIN.size = size;
582  ROQCIN.offset = sizeof(header);
583 
584  ROQCIN.frameWidth = 0;
585  ROQCIN.frameHeight = 0;
586  ROQCIN.startTime = CL_Milliseconds();
587  ROQCIN.frameRate = (chunk.flags != 0) ? chunk.flags : 30;
588  Mem_Free(ROQCIN.frameBuffer[0]);
589  ROQCIN.frameBuffer[0] = nullptr;
590  Mem_Free(ROQCIN.frameBuffer[1]);
591  ROQCIN.frameBuffer[1] = nullptr;
592 
593  ROQCIN.currentFrame = 0;
594 
595  /* Read the first chunk header */
597  ROQCIN.offset += ROQ_CHUNK_HEADER_SIZE;
598 
599  ROQCIN.header = ROQCIN.data;
600 
601  return 0;
602 }
603 
604 void CIN_ROQ_Init (void)
605 {
606  /* Build square table */
607  for (int i = 0; i < 128; i++) {
608  const short s = (short)(i * i);
609  roqCin_sqrTable[i] = s;
610  roqCin_sqrTable[i + 128] = -s;
611  }
612 
613  /* Set up quad offsets */
614  for (int i = 0; i < 4; i++) {
615  roqCin_quadOffsets2[0][i] = 2 * (i & 1);
616  roqCin_quadOffsets2[1][i] = 2 * (i >> 1);
617  roqCin_quadOffsets4[0][i] = 4 * (i & 1);
618  roqCin_quadOffsets4[1][i] = 4 * (i >> 1);
619  }
620 
621  /* Build YUV table */
622  for (int i = 0; i < 256; i++) {
623  const float f = (float)(i - 128);
624  roqCin_yuvTable.vr[i] = Q_ftol(f * 1.40200f);
625  roqCin_yuvTable.ug[i] = Q_ftol(f * 0.34414f);
626  roqCin_yuvTable.vg[i] = Q_ftol(f * 0.71414f);
627  roqCin_yuvTable.ub[i] = Q_ftol(f * 1.77200f);
628  }
629 }
#define ROQ_QUAD_INFO
#define ROQ_SOUND_STEREO
static void CIN_ROQ_DrawCinematic(cinematic_t *cin)
static bool CIN_ROQ_DecodeChunk(cinematic_t *cin)
#define ROQ_ID_CCC
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
static void CIN_ROQ_DecodeVideo(cinematic_t *cin, const byte *data)
static yuvTable_t roqCin_yuvTable
void CIN_ROQ_Init(void)
memPool_t * vid_genericPool
Definition: cl_main.cpp:87
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
static void CIN_ROQ_DecodeSoundMono(cinematic_t *cin, const byte *data)
static short roqCin_sqrTable[256]
static void CIN_ROQ_DecodeSoundStereo(cinematic_t *cin, const byte *data)
#define ROQ_CHUNK_HEADER_SIZE
#define ROQ_SOUND_MONO
memPool_t * cl_genericPool
Definition: cl_main.cpp:86
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define ROQ_ID_SLD
#define LittleShort(X)
Definition: byte.h:35
#define ERR_DROP
Definition: common.h:211
void R_DrawTexture(int texnum, int x, int y, int w, int h)
Bind and draw a texture.
Definition: r_draw.cpp:328
#define ROQ_QUAD_CODEBOOK
#define ROQ_IDENT
GLsizei size
Definition: r_gl.h:152
#define OBJZERO(obj)
Definition: shared.h:178
static void CIN_ROQ_ApplyVector4x4(cinematic_t *cin, int x, int y, const byte *indices)
static int roqCin_quadOffsets4[2][4]
void CIN_ROQ_CloseCinematic(cinematic_t *cin)
void M_StopMusicStream(musicStream_t *userdata)
Definition: s_music.cpp:465
void FS_CloseFile(qFILE *f)
static void CIN_ROQ_DecodeInfo(cinematic_t *cin, const byte *data)
static void CIN_ROQ_ApplyMotion4x4(cinematic_t *cin, int x, int y, int mx, int my, int mv)
static void CIN_ROQ_DecodeCodeBook(cinematic_t *cin, const byte *data)
int R_UploadData(const char *name, unsigned *frame, int width, int height)
Uploads image data.
Definition: r_draw.cpp:270
bool CIN_ROQ_RunCinematic(cinematic_t *cin)
#define ROQ_QUAD_VQ
#define ROQ_SOUND_RATE
QGL_EXTERN GLuint index
Definition: r_gl.h:110
int CIN_ROQ_OpenCinematic(cinematic_t *cin, const char *fileName)
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
musicStream_t musicStream
Header file for ROQ cinematics.
int FS_Read(void *buffer, int len, qFILE *f)
Definition: files.cpp:371
QGL_EXTERN GLint i
Definition: r_gl.h:113
void M_AddToSampleBuffer(musicStream_t *userdata, int rate, int samples, const byte *data)
Add stereo samples with a 16 byte width to the stream buffer.
Definition: s_music.cpp:431
#define Q_ftol(f)
Definition: mathlib.h:48
#define Mem_Free(ptr)
Definition: mem.h:35
#define ROQ_ID_FCC
static void CIN_ROQ_ApplyVector2x2(cinematic_t *cin, int x, int y, const byte *indices)
static void CIN_ROQ_ApplyMotion8x8(cinematic_t *cin, int x, int y, int mx, int my, int mv)
char name[MAX_QPATH]
Definition: cl_cinematic.h:38
GLsizei const GLvoid * data
Definition: r_gl.h:152
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
bool Q_IsPowerOfTwo(int i)
Checks whether i is power of two value.
Definition: mathlib.cpp:972
static byte CIN_ROQ_ClampByte(int value)
Clamps integer value into byte.
uint8_t byte
Definition: ufotypes.h:34
void * codecData
Definition: cl_cinematic.h:50
Header file for cinematics.
int cinematicType
Definition: cl_cinematic.h:46
#define ROQ_MAX_CHUNK_SIZE
int CL_Milliseconds(void)
Definition: cl_main.cpp:1208
#define LittleLong(X)
Definition: byte.h:37
static int roqCin_quadOffsets2[2][4]
#define ROQCIN