mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-30 07:31:13 +00:00
5b0843e0c7
tweak rtlights a bit, to not bug out on The Waste's decals. use compatibility glsl in order to get ftransform working for consistent vertex coords (still uses core if there's no fixed function stuff). this fixes z-fighting issues with rtlights. Rework punchangles for greater compatibility. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5059 fc73d0e0-1445-4013-8a0c-d673dee63da5
637 lines
15 KiB
C
637 lines
15 KiB
C
/* ------------------------------------------------------------------------
|
|
* Id Software's RoQ video file format decoder
|
|
*
|
|
* Dr. Tim Ferguson, 2001.
|
|
* For more details on the algorithm:
|
|
* http://www.csse.monash.edu.au/~timf/videocodec.html
|
|
*
|
|
* This is a simple decoder for the Id Software RoQ video format. In
|
|
* this format, audio samples are DPCM coded and the video frames are
|
|
* coded using motion blocks and vector quantisation.
|
|
*
|
|
* Note: All information on the RoQ file format has been obtained through
|
|
* pure reverse engineering. This was achieved by giving known input
|
|
* audio and video frames to the roq.exe encoder and analysing the
|
|
* resulting output text and RoQ file. No decompiling of the Quake III
|
|
* Arena game was required.
|
|
*
|
|
* You may freely use this source code. I only ask that you reference its
|
|
* source in your projects documentation:
|
|
* Tim Ferguson: http://www.csse.monash.edu.au/~timf/
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
#include "quakedef.h"
|
|
|
|
#ifdef HAVE_MEDIA_DECODER
|
|
|
|
|
|
static int VFS_GETC(vfsfile_t *fp)
|
|
{
|
|
unsigned char c;
|
|
VFS_READ(fp, &c, 1);
|
|
return c;
|
|
}
|
|
|
|
//#include <stdio.h>
|
|
//#include <stdlib.h>
|
|
//#include <string.h>
|
|
#include "roq.h"
|
|
|
|
//#define DBUG 1
|
|
|
|
#define FAST
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static unsigned int get_word(vfsfile_t *fp)
|
|
{
|
|
unsigned int ret;
|
|
|
|
ret = ((VFS_GETC(fp)) & 0xff);
|
|
ret |= ((VFS_GETC(fp)) & 0xff) << 8;
|
|
return(ret);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static unsigned long get_long(vfsfile_t *fp)
|
|
{
|
|
unsigned long ret;
|
|
|
|
ret = ((VFS_GETC(fp)) & 0xff);
|
|
ret |= ((VFS_GETC(fp)) & 0xff) << 8;
|
|
ret |= ((VFS_GETC(fp)) & 0xff) << 16;
|
|
ret |= ((VFS_GETC(fp)) & 0xff) << 24;
|
|
return(ret);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static int roq_parse_file(vfsfile_t *fp, roq_info *ri)
|
|
{
|
|
unsigned int head1, head3, chunk_id;//, chunk_arg;
|
|
long head2, chunk_size;
|
|
qofs_t fpos;
|
|
#ifndef FAST
|
|
int max_frame;
|
|
#endif
|
|
|
|
#ifndef FAST
|
|
ri->num_audio_bytes = ri->num_frames = max_frame = 0;
|
|
ri->audio_channels = 0;
|
|
ri->frame_offset = NULL;
|
|
#endif
|
|
ri->buf_size = 0;
|
|
head1 = get_word(fp);
|
|
head2 = get_long(fp);
|
|
head3 = get_word(fp);
|
|
if(head1 != 0x1084 && head2 != 0xffffffff && head3 != 0x1e)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ri->roq_start = fpos = VFS_TELL(fp);
|
|
while(fpos+8 <= ri->maxpos)
|
|
{
|
|
#if DBUG > 20
|
|
Con_Printf("---------------------------------------------------------------------------\n");
|
|
#endif
|
|
VFS_SEEK(fp, fpos);
|
|
|
|
chunk_id = get_word(fp);
|
|
chunk_size = get_long(fp);
|
|
/*chunk_arg =*/ get_word(fp);
|
|
fpos += 8 + chunk_size;
|
|
if (chunk_size == 0xffffffff || fpos > ri->maxpos) //FIXME: THIS SHOULD NOT HAPPEN
|
|
break;
|
|
if (chunk_size > ri->buf_size)
|
|
ri->buf_size = chunk_size;
|
|
#if DBUG > 20
|
|
Con_Printf("%03d 0x%06lx: chunk: 0x%02x size: %ld cells: 2x2=%d,4x4=%d\n", i,
|
|
fpos, chunk_id, chunk_size, v1>>8,v1&0xff);
|
|
#endif
|
|
|
|
if(chunk_id == RoQ_INFO) /* video info */
|
|
{
|
|
ri->width = get_word(fp);
|
|
ri->height = get_word(fp);
|
|
get_word(fp);
|
|
get_word(fp);
|
|
#ifdef FAST
|
|
return 0; //we have all the data we need now. We always find a sound chunk first, or none at all.
|
|
#endif
|
|
}
|
|
#ifndef FAST
|
|
else if(chunk_id == RoQ_QUAD_VQ)
|
|
{
|
|
ri->num_frames++;
|
|
if(ri->num_frames > max_frame)
|
|
{
|
|
max_frame += 5000;
|
|
if((ri->frame_offset = BZ_Realloc(ri->frame_offset, sizeof(long) * max_frame)) == NULL)
|
|
return 1;
|
|
}
|
|
ri->frame_offset[ri->num_frames] = fpos;
|
|
}
|
|
}
|
|
#endif
|
|
else if(chunk_id == RoQ_SOUND_MONO || chunk_id == RoQ_SOUND_STEREO)
|
|
{
|
|
if(chunk_id == RoQ_SOUND_MONO)
|
|
ri->audio_channels = 1;
|
|
else
|
|
ri->audio_channels = 2;
|
|
#ifndef FAST
|
|
ri->num_audio_bytes += chunk_size;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static void apply_vector_2x2(roq_info *ri, int x, int y, roq_cell *cell)
|
|
{
|
|
unsigned char *yptr;
|
|
|
|
yptr = ri->y[0] + (y * ri->width) + x;
|
|
*yptr++ = cell->y0;
|
|
*yptr++ = cell->y1;
|
|
yptr += (ri->width - 2);
|
|
*yptr++ = cell->y2;
|
|
*yptr++ = cell->y3;
|
|
ri->u[0][(y/2) * (ri->width/2) + x/2] = cell->u;
|
|
ri->v[0][(y/2) * (ri->width/2) + x/2] = cell->v;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static void apply_vector_4x4(roq_info *ri, int x, int y, roq_cell *cell)
|
|
{
|
|
unsigned long row_inc, c_row_inc;
|
|
register unsigned char y0, y1, u, v;
|
|
unsigned char *yptr, *uptr, *vptr;
|
|
|
|
yptr = ri->y[0] + (y * ri->width) + x;
|
|
uptr = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
|
vptr = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
|
|
|
row_inc = ri->width - 4;
|
|
c_row_inc = (ri->width/2) - 2;
|
|
*yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v;
|
|
*yptr++ = y0;
|
|
*yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v;
|
|
*yptr++ = y1;
|
|
|
|
yptr += row_inc;
|
|
|
|
*yptr++ = y0;
|
|
*yptr++ = y0;
|
|
*yptr++ = y1;
|
|
*yptr++ = y1;
|
|
|
|
yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc;
|
|
|
|
*yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v;
|
|
*yptr++ = y0;
|
|
*yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v;
|
|
*yptr++ = y1;
|
|
|
|
yptr += row_inc;
|
|
|
|
*yptr++ = y0;
|
|
*yptr++ = y0;
|
|
*yptr++ = y1;
|
|
*yptr++ = y1;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static void apply_motion_4x4(roq_info *ri, int x, int y, unsigned char mv, char mean_x, char mean_y)
|
|
{
|
|
int i, mx, my;
|
|
unsigned char *pa, *pb;
|
|
|
|
mx = x + 8 - (mv >> 4) - mean_x;
|
|
my = y + 8 - (mv & 0xf) - mean_y;
|
|
|
|
pa = ri->y[0] + (y * ri->width) + x;
|
|
pb = ri->y[1] + (my * ri->width) + mx;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa[2] = pb[2];
|
|
pa[3] = pb[3];
|
|
pa += ri->width;
|
|
pb += ri->width;
|
|
}
|
|
|
|
pa = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
|
pb = ri->u[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
|
for(i = 0; i < 2; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa += ri->width/2;
|
|
pb += ri->width/2;
|
|
}
|
|
|
|
pa = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
|
pb = ri->v[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
|
for(i = 0; i < 2; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa += ri->width/2;
|
|
pb += ri->width/2;
|
|
}
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static void apply_motion_8x8(roq_info *ri, int x, int y, unsigned char mv, char mean_x, char mean_y)
|
|
{
|
|
int mx, my, i;
|
|
unsigned char *pa, *pb;
|
|
|
|
mx = x + 8 - (mv >> 4) - mean_x;
|
|
my = y + 8 - (mv & 0xf) - mean_y;
|
|
|
|
pa = ri->y[0] + (y * ri->width) + x;
|
|
pb = ri->y[1] + (my * ri->width) + mx;
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa[2] = pb[2];
|
|
pa[3] = pb[3];
|
|
pa[4] = pb[4];
|
|
pa[5] = pb[5];
|
|
pa[6] = pb[6];
|
|
pa[7] = pb[7];
|
|
pa += ri->width;
|
|
pb += ri->width;
|
|
}
|
|
|
|
pa = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
|
pb = ri->u[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa[2] = pb[2];
|
|
pa[3] = pb[3];
|
|
pa += ri->width/2;
|
|
pb += ri->width/2;
|
|
}
|
|
|
|
pa = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
|
pb = ri->v[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
pa[0] = pb[0];
|
|
pa[1] = pb[1];
|
|
pa[2] = pb[2];
|
|
pa[3] = pb[3];
|
|
pa += ri->width/2;
|
|
pb += ri->width/2;
|
|
}
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
roq_info *roq_open(char *fname)
|
|
{
|
|
vfsfile_t *fp;
|
|
roq_info *ri;
|
|
int i;
|
|
|
|
if((fp = FS_OpenVFS(fname, "rb", FS_GAME)) == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if((ri = BZF_Malloc(sizeof(roq_info))) == NULL)
|
|
{
|
|
Con_Printf("Error allocating memory.\n");
|
|
return NULL;
|
|
}
|
|
|
|
memset(ri, 0, sizeof(roq_info));
|
|
|
|
ri->maxpos = VFS_TELL(fp)+VFS_GETLEN(fp);//no adds/subracts for fileoffset here
|
|
|
|
ri->fp = fp;
|
|
if(roq_parse_file(fp, ri))
|
|
return NULL;
|
|
#ifndef FAST
|
|
ri->stream_length = (ri->num_frames * 1000)/30;
|
|
#endif
|
|
for(i = 0; i < 128; i++)
|
|
{
|
|
ri->snd_sqr_arr[i] = i * i;
|
|
ri->snd_sqr_arr[i + 128] = -(i * i);
|
|
}
|
|
|
|
for(i = 0; i < 2; i++)
|
|
{
|
|
if((ri->y[i] = BZF_Malloc(ri->width * ri->height)) == NULL ||
|
|
(ri->u[i] = BZF_Malloc((ri->width * ri->height)/4)) == NULL ||
|
|
(ri->v[i] = BZF_Malloc((ri->width * ri->height)/4)) == NULL)
|
|
{
|
|
Con_Printf("Memory allocation error.\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
ri->buf_size *= 2;
|
|
if((ri->buf = BZF_Malloc(ri->buf_size)) == NULL)
|
|
{
|
|
Con_Printf("Memory allocation error.\n");
|
|
return NULL;
|
|
}
|
|
ri->audio_buf_size = 0;
|
|
ri->audio = NULL;
|
|
|
|
ri->frame_num = 0;
|
|
ri->aud_pos = ri->vid_pos = ri->roq_start;
|
|
|
|
return ri;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
void roq_close(roq_info *ri)
|
|
{
|
|
int i;
|
|
|
|
if(ri == NULL)
|
|
return;
|
|
VFS_CLOSE(ri->fp);
|
|
for(i = 0; i < 2; i++)
|
|
{
|
|
if(ri->y[i] != NULL)
|
|
BZ_Free(ri->y[i]);
|
|
if(ri->u[i] != NULL)
|
|
BZ_Free(ri->u[i]);
|
|
if(ri->v[i] != NULL)
|
|
BZ_Free(ri->v[i]);
|
|
}
|
|
if(ri->buf != NULL)
|
|
BZ_Free(ri->buf);
|
|
if (ri->audio)
|
|
BZ_Free(ri->audio);
|
|
BZ_Free(ri);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
int roq_read_frame(roq_info *ri)
|
|
{
|
|
vfsfile_t *fp = ri->fp;
|
|
unsigned int chunk_id = 0, chunk_arg = 0;
|
|
unsigned long chunk_size = 0;
|
|
int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1, vqid, bpos, xpos, ypos, xp, yp, x, y;
|
|
unsigned char *tp, *buf;
|
|
int frame_stats[2][4] = {{0},{0}};
|
|
roq_qcell *qcell;
|
|
|
|
qofs_t fpos = ri->vid_pos;
|
|
|
|
VFS_SEEK(fp, fpos);
|
|
while(fpos+8 < ri->maxpos)
|
|
{
|
|
chunk_id = get_word(fp);
|
|
chunk_size = get_long(fp);
|
|
chunk_arg = get_word(fp);
|
|
fpos += 8+chunk_size;
|
|
if (chunk_size == 0xffffffff || fpos > ri->maxpos)
|
|
return -1;
|
|
if (chunk_id == RoQ_QUAD_VQ)
|
|
break;
|
|
if(chunk_id == RoQ_QUAD_CODEBOOK)
|
|
{
|
|
if((nv1 = chunk_arg >> 8) == 0)
|
|
nv1 = 256;
|
|
if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size)
|
|
nv2 = 256;
|
|
VFS_READ(fp, ri->cells, nv1 * sizeof(roq_cell));
|
|
for(i = 0; i < nv2; i++)
|
|
for(j = 0; j < 4; j++) ri->qcells[i].idx[j] = VFS_GETC(fp);
|
|
}
|
|
else
|
|
VFS_SEEK(fp, fpos);
|
|
}
|
|
|
|
if(chunk_id != RoQ_QUAD_VQ)
|
|
{
|
|
ri->vid_pos = fpos;
|
|
return 0;
|
|
}
|
|
|
|
ri->frame_num++;
|
|
if(ri->buf_size < chunk_size)
|
|
{
|
|
ri->buf_size *= 2;
|
|
if (ri->buf_size < chunk_size) //double wasn't enough
|
|
ri->buf_size = chunk_size;
|
|
BZ_Free(ri->buf);
|
|
if((ri->buf = BZ_Malloc(ri->buf_size)) == NULL)
|
|
{
|
|
Con_Printf("Memory allocation error.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
VFS_READ(fp, ri->buf, chunk_size);
|
|
buf = ri->buf;
|
|
|
|
bpos = xpos = ypos = 0;
|
|
while(bpos < chunk_size)
|
|
{
|
|
for(yp = ypos; yp < ypos + 16; yp += 8)
|
|
for(xp = xpos; xp < xpos + 16; xp += 8)
|
|
{
|
|
if(vqflg_pos < 0)
|
|
{
|
|
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
|
|
vqflg_pos = 7;
|
|
}
|
|
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
|
|
frame_stats[0][vqid]++;
|
|
vqflg_pos--;
|
|
|
|
switch(vqid)
|
|
{
|
|
case RoQ_ID_MOT: break;
|
|
case RoQ_ID_FCC:
|
|
apply_motion_8x8(ri, xp, yp, buf[bpos++], (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
|
break;
|
|
case RoQ_ID_SLD:
|
|
qcell = ri->qcells + buf[bpos++];
|
|
apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]);
|
|
apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]);
|
|
apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]);
|
|
apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]);
|
|
break;
|
|
case RoQ_ID_CCC:
|
|
for(k = 0; k < 4; k++)
|
|
{
|
|
x = xp; y = yp;
|
|
if(k & 0x01) x += 4;
|
|
if(k & 0x02) y += 4;
|
|
|
|
if(vqflg_pos < 0)
|
|
{
|
|
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
|
|
vqflg_pos = 7;
|
|
}
|
|
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
|
|
frame_stats[1][vqid]++;
|
|
vqflg_pos--;
|
|
switch(vqid)
|
|
{
|
|
case RoQ_ID_MOT: break;
|
|
case RoQ_ID_FCC:
|
|
apply_motion_4x4(ri, x, y, buf[bpos++], (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
|
break;
|
|
case RoQ_ID_SLD:
|
|
qcell = ri->qcells + buf[bpos++];
|
|
apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]);
|
|
apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]);
|
|
apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]);
|
|
apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]);
|
|
break;
|
|
case RoQ_ID_CCC:
|
|
apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]);
|
|
apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]);
|
|
apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]);
|
|
apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]);
|
|
bpos += 4;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Con_Printf("Unknown vq code: %d\n", vqid);
|
|
}
|
|
}
|
|
|
|
xpos += 16;
|
|
if(xpos >= ri->width)
|
|
{
|
|
xpos -= ri->width;
|
|
ypos += 16;
|
|
}
|
|
if(ypos >= ri->height) break;
|
|
}
|
|
|
|
#if 0
|
|
frame_stats[0][3] = 0;
|
|
Con_Printf("<%d 0x%04x -> %d,%d>\n", ri->frame_num, chunk_arg, (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
|
Con_Printf("for 08x08 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = 0\n", frame_stats[0][3], frame_stats[0][1], frame_stats[0][0], frame_stats[0][2]);
|
|
Con_Printf("for 04x04 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = 0\n", frame_stats[1][3], frame_stats[1][1], frame_stats[1][0], frame_stats[1][2]);
|
|
#endif
|
|
|
|
ri->vid_pos = fpos;
|
|
|
|
if(ri->frame_num == 1)
|
|
{
|
|
memcpy(ri->y[1], ri->y[0], ri->width * ri->height);
|
|
memcpy(ri->u[1], ri->u[0], (ri->width * ri->height)/4);
|
|
memcpy(ri->v[1], ri->v[0], (ri->width * ri->height)/4);
|
|
}
|
|
else
|
|
{
|
|
tp = ri->y[0];
|
|
ri->y[0] = ri->y[1];
|
|
ri->y[1] = tp;
|
|
|
|
tp = ri->u[0];
|
|
ri->u[0] = ri->u[1];
|
|
ri->u[1] = tp;
|
|
|
|
tp = ri->v[0];
|
|
ri->v[0] = ri->v[1];
|
|
ri->v[1] = tp;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
int roq_read_audio(roq_info *ri)
|
|
{
|
|
vfsfile_t *fp = ri->fp;
|
|
unsigned int chunk_id = 0, chunk_arg = 0;
|
|
unsigned long chunk_size = 0;
|
|
int i, snd_left, snd_right;
|
|
|
|
long fpos;
|
|
|
|
fpos = ri->aud_pos;
|
|
|
|
ri->audio_size = 0;
|
|
|
|
for(;;)
|
|
{
|
|
VFS_SEEK(fp, fpos);
|
|
if(fpos >= ri->maxpos)
|
|
return -1;
|
|
chunk_id = get_word(fp);
|
|
chunk_size = get_long(fp);
|
|
chunk_arg = get_word(fp);
|
|
fpos += 8+chunk_size;
|
|
if (chunk_size == 0xffffffff || fpos > ri->maxpos)
|
|
return -1;
|
|
if (chunk_id == RoQ_SOUND_MONO || chunk_id == RoQ_SOUND_STEREO)
|
|
break;
|
|
}
|
|
|
|
if(ri->audio_buf_size < chunk_size*2)
|
|
{
|
|
if(ri->audio != NULL) BZ_Free(ri->audio);
|
|
ri->audio=NULL;
|
|
ri->audio_buf_size = chunk_size * 3;
|
|
if (ri->audio_buf_size <= 0)
|
|
return -1;
|
|
if((ri->audio = BZ_Malloc(ri->audio_buf_size)) == NULL) return -1;
|
|
}
|
|
if (ri->audio_buf_size < 0)
|
|
return -1;
|
|
|
|
if(chunk_id == RoQ_SOUND_MONO)
|
|
{
|
|
ri->audio_size = chunk_size;
|
|
snd_left = chunk_arg;
|
|
for(i = 0; i < chunk_size; i++)
|
|
{
|
|
snd_left += (int)ri->snd_sqr_arr[(unsigned)VFS_GETC(fp)];
|
|
*(short *)&ri->audio[i * 2] = snd_left;
|
|
}
|
|
ri->aud_pos = fpos;
|
|
return chunk_size;
|
|
}
|
|
|
|
if(chunk_id == RoQ_SOUND_STEREO)
|
|
{
|
|
ri->audio_size = chunk_size;
|
|
snd_left = (chunk_arg & 0xFF00);
|
|
snd_right = (chunk_arg & 0xFF) << 8;
|
|
for(i = 0; i < chunk_size; i += 2)
|
|
{
|
|
snd_left += (int)ri->snd_sqr_arr[(unsigned)VFS_GETC(fp)];
|
|
snd_right += (int)ri->snd_sqr_arr[(unsigned)VFS_GETC(fp)];
|
|
*(short *)&ri->audio[i * 2] = snd_left & 0xffff;
|
|
*(short *)&ri->audio[i * 2 + 2] = snd_right & 0xffff;
|
|
}
|
|
ri->aud_pos = fpos;
|
|
return chunk_size;
|
|
}
|
|
|
|
ri->aud_pos = fpos;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|