fteqw/engine/client/snd_ov.c
Spoike 869e544ad4 fix glsl not being used for skeletal animations (10->50 fps jump)
fix vbos not being used for skeletal animations (50->770 fps jump, yes, really. OOPS!)
so yeah, 7700% speedup there. lol... *sigh*
fixed update notification prompt not appearing by splitting menu key dest into emenu+gmenu. thus the prompt is no longer killed by menu.dat starting up.
fog command now displays a the extra params.
rewrote console char handling to support 32bit unicode chars. font code does not support more than 16bit codepoints still, however.
rewrote beam code in order to restore models on vid_restart. this solves a crash where they were invalid pointers afterwards.
revived old menu_media, because jogi wanted shuffle.
music now fades out for a sec when changing fake-cd-tracks.
music no longer abruptly stops when changing maps.
added fxaa support.
reworked bloom a bit. can now bloom further.
added r_renderscale cvar, for people that want supersampling (max 2), or subsampling for more speed or whatever.
$timer now favours cvars with that name, rather than the $time macro.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4942 fc73d0e0-1445-4013-8a0c-d673dee63da5
2015-07-14 14:47:00 +00:00

461 lines
11 KiB
C

#include "quakedef.h"
#ifdef AVAIL_OGGVORBIS
#define OV_EXCLUDE_STATIC_CALLBACKS
#ifdef __MORPHOS__
#include <exec/exec.h>
#include <libraries/vorbisfile.h>
#include <proto/exec.h>
#include <proto/vorbisfile.h>
#else
#include <vorbis/vorbisfile.h>
#endif
#ifdef LIBVORBISFILE_STATIC
#define p_ov_open_callbacks ov_open_callbacks
#define p_ov_clear ov_clear
#define p_ov_info ov_info
#define p_ov_comment ov_comment
#define p_ov_pcm_total ov_pcm_total
#define p_ov_read ov_read
#define p_ov_pcm_seek ov_pcm_seek
#else
#if defined(__MORPHOS__)
#define oggvorbislibrary VorbisFileBase
struct Library *VorbisFileBase;
#else
dllhandle_t *oggvorbislibrary;
#endif
#ifdef __MORPHOS__
#define p_ov_open_callbacks(a, b, c, d, e) ov_open_callbacks(a, b, c, d, &e)
#define p_ov_clear ov_clear
#define p_ov_info ov_info
#define p_ov_comment ov_comment
#define p_ov_pcm_total ov_pcm_total
#define p_ov_read ov_read
#define p_ov_pcm_seek ov_pcm_seek
#else
int (VARGS *p_ov_open_callbacks) (void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
int (VARGS *p_ov_clear)(OggVorbis_File *vf);
vorbis_info *(VARGS *p_ov_info)(OggVorbis_File *vf,int link);
vorbis_comment *(VARGS *p_ov_comment) (OggVorbis_File *vf,int link);
ogg_int64_t (VARGS *p_ov_pcm_total)(OggVorbis_File *vf,int i);
long (VARGS *p_ov_read)(OggVorbis_File *vf,char *buffer,int length,
int bigendianp,int word,int sgned,int *bitstream);
int (VARGS *p_ov_pcm_seek)(OggVorbis_File *vf,ogg_int64_t pos);
#endif
#endif
typedef struct {
unsigned char *start; //file positions
unsigned long length;
unsigned long pos;
int srcspeed;
int srcchannels;
qboolean failed;
char *tempbuffer;
int tempbufferbytes;
char *decodedbuffer;
int decodedbufferbytes;
int decodedbytestart;
int decodedbytecount;
OggVorbis_File vf;
sfx_t *s;
} ovdecoderbuffer_t;
static sfxcache_t *OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf);
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, int start, int length);
static void OV_CancelDecoder(sfx_t *s);
static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer);
qboolean S_LoadOVSound (sfx_t *s, qbyte *data, int datalen, int sndspeed)
{
ovdecoderbuffer_t *buffer;
if (datalen < 4 || strncmp(data, "OggS", 4))
return false;
buffer = Z_Malloc(sizeof(ovdecoderbuffer_t));
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
buffer->s = s;
s->decoder.buf = buffer;
s->decoder.decodedata = OV_DecodeSome;
s->decoder.querydata = OV_Query;
s->decoder.purge = OV_CancelDecoder;
s->decoder.ended = OV_CancelDecoder;
if (!OV_StartDecode(data, datalen, buffer))
{
if (buffer->decodedbuffer)
{
BZ_Free(buffer->decodedbuffer);
buffer->decodedbuffer = NULL;
}
buffer->decodedbufferbytes = 0;
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
Z_Free(s->decoder.buf);
s->decoder.buf = NULL;
s->loadstate = SLS_FAILED; //failed!
return false;
}
s->decoder.decodedata(s, NULL, 0, 100);
return true;
}
static sfxcache_t *OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf)
{
ovdecoderbuffer_t *dec = sfx->decoder.buf;
if (!dec)
buf = NULL;
if (buf)
{
buf->data = NULL; //you're not meant to actually be using the data here
buf->soundoffset = 0;
buf->length = p_ov_pcm_total(&dec->vf, -1);
buf->loopstart = -1;
buf->numchannels = dec->srcchannels;
buf->speed = dec->srcspeed;
buf->width = 2;
}
return buf;
}
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, int start, int length)
{
extern int snd_speed;
extern cvar_t snd_linearresample_stream;
int bigendianp = bigendian;
int current_section = 0;
ovdecoderbuffer_t *dec = sfx->decoder.buf;
int bytesread;
int outspeed = snd_speed;
// Con_Printf("Minlength = %03i ", minlength);
start *= 2*dec->srcchannels;
length *= 2*dec->srcchannels;
if (start < dec->decodedbytestart)
{
/*something rewound, purge clear the buffer*/
dec->decodedbytecount = 0;
dec->decodedbytestart = start;
//check pos
//fixme: seeking might not be supported
p_ov_pcm_seek(&dec->vf, dec->decodedbytestart);
}
/* if (start > dec->decodedbytestart + dec->decodedbytecount)
{
dec->decodedbytestart = start;
p_ov_pcm_seek(&dec->vf, dec->decodedbytestart);
}
*/
if (dec->decodedbytecount > snd_speed*8)
{
/*everything is okay, but our buffer is getting needlessly large.
keep anything after the 'new' position, but discard all before that
trim shouldn't be able to go negative
*/
int trim = start - dec->decodedbytestart;
if (trim < 0)
{
dec->decodedbytecount = 0;
dec->decodedbytestart = start;
}
else
{
//FIXME: retain an extra half-second for dual+ sound devices running slightly out of sync
memmove(dec->decodedbuffer, dec->decodedbuffer + trim, dec->decodedbytecount - trim);
dec->decodedbytecount -= trim;
dec->decodedbytestart += trim;
}
}
for (;;)
{
if (start+length <= dec->decodedbytestart + dec->decodedbytecount)
break;
if (dec->decodedbufferbytes < start+length - dec->decodedbytestart + 128) //expand if needed.
{
// Con_Printf("Expand buffer\n");
dec->decodedbufferbytes = (start+length - dec->decodedbytestart) + snd_speed;
dec->decodedbuffer = BZ_Realloc(dec->decodedbuffer, dec->decodedbufferbytes);
}
if (outspeed == dec->srcspeed)
{
bytesread = p_ov_read(&dec->vf, dec->decodedbuffer+dec->decodedbytecount, (start+length) - (dec->decodedbytestart+dec->decodedbytecount), bigendianp, 2, 1, &current_section);
if (bytesread <= 0)
{
if (bytesread != 0) //0==eof
{
Con_Printf("ogg decoding failed\n");
return NULL;
}
break;
}
}
else
{
double scale = dec->srcspeed / (double)outspeed;
int decodesize = ceil((dec->decodedbufferbytes-dec->decodedbytecount) * scale);
/*round down...*/
decodesize &= ~(2 * dec->srcchannels - 1);
if (decodesize > dec->tempbufferbytes)
{
dec->tempbuffer = BZ_Realloc(dec->tempbuffer, decodesize);
dec->tempbufferbytes = decodesize;
}
bytesread = p_ov_read(&dec->vf, dec->tempbuffer, decodesize, bigendianp, 2, 1, &current_section);
if (bytesread <= 0)
{
if (bytesread != 0) //0==eof
{
Con_Printf("ogg decoding failed\n");
return NULL;
}
return NULL;
}
SND_ResampleStream(dec->tempbuffer,
dec->srcspeed,
2,
dec->srcchannels,
bytesread / (2 * dec->srcchannels),
dec->decodedbuffer+dec->decodedbytecount,
outspeed,
2,
dec->srcchannels,
snd_linearresample_stream.ival);
bytesread = (int)floor(bytesread / scale) & ~(2 * dec->srcchannels - 1);
}
dec->decodedbytecount += bytesread;
}
if (buf)
{
buf->data = dec->decodedbuffer;
buf->soundoffset = dec->decodedbytestart / (2 * dec->srcchannels);
buf->length = dec->decodedbytecount / (2 * dec->srcchannels);
buf->loopstart = -1;
buf->numchannels = dec->srcchannels;
buf->speed = snd_speed;
buf->width = 2;
}
return buf;
}
static void OV_CanceledDecoder(void *ctx, void *data, size_t a, size_t b)
{
sfx_t *s = ctx;
if (s->loadstate != SLS_LOADING)
s->loadstate = SLS_NOTLOADED;
}
static void OV_CancelDecoder(sfx_t *s)
{
ovdecoderbuffer_t *dec;
s->loadstate = SLS_FAILED;
dec = s->decoder.buf;
s->decoder.buf = NULL;
s->decoder.purge = NULL;
s->decoder.ended = NULL;
s->decoder.querydata = NULL;
s->decoder.decodedata = NULL;
p_ov_clear (&dec->vf); //close the decoder
if (dec->tempbuffer)
{
BZ_Free(dec->tempbuffer);
dec->tempbufferbytes = 0;
}
BZ_Free(dec->decodedbuffer);
dec->decodedbuffer = NULL;
BZ_Free(dec);
//due to the nature of message passing, we can get into a state where the main thread is going to flag us as loaded when we have already failed.
//that is bad.
//so post a message to the main thread to override it, just in case.
// COM_AddWork(0, OV_CanceledDecoder, s, NULL, SLS_NOTLOADED, 0);
s->loadstate = SLS_NOTLOADED;
}
static size_t VARGS read_func (void *ptr, size_t size, size_t nmemb, void *datasource)
{
ovdecoderbuffer_t *buffer = datasource;
int spare = buffer->length - buffer->pos;
if (size*nmemb > spare)
nmemb = spare / size;
memcpy(ptr, &buffer->start[buffer->pos], size*nmemb);
buffer->pos += size*nmemb;
return nmemb;
}
static int VARGS seek_func (void *datasource, ogg_int64_t offset, int whence)
{
ovdecoderbuffer_t *buffer = datasource;
switch(whence)
{
case SEEK_SET:
buffer->pos = offset;
break;
case SEEK_END:
buffer->pos = buffer->length+offset;
break;
case SEEK_CUR:
buffer->pos+=offset;
break;
}
return 0;
}
static int VARGS close_func (void *datasource)
{
ovdecoderbuffer_t *buffer = datasource;
BZ_Free(buffer->start);
buffer->start=0;
return 0;
}
static long VARGS tell_func (void *datasource)
{
ovdecoderbuffer_t *buffer = datasource;
return buffer->pos;
}
static ov_callbacks callbacks = {
read_func,
seek_func,
close_func,
tell_func,
};
static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer)
{
#ifndef LIBVORBISFILE_STATIC
static qboolean tried;
#ifndef __MORPHOS__
static dllfunction_t funcs[] =
{
{(void*)&p_ov_open_callbacks, "ov_open_callbacks"},
{(void*)&p_ov_comment, "ov_comment"},
{(void*)&p_ov_pcm_total, "ov_pcm_total"},
{(void*)&p_ov_clear, "ov_clear"},
{(void*)&p_ov_info, "ov_info"},
{(void*)&p_ov_read, "ov_read"},
{(void*)&p_ov_pcm_seek, "ov_pcm_seek"},
{NULL}
};
#endif
if (!oggvorbislibrary && !tried)
#if defined(__MORPHOS__)
{
VorbisFileBase = OpenLibrary("vorbisfile.library", 2);
if (!VorbisFileBase)
{
Con_Printf("Unable to open vorbisfile.library version 2\n");
}
}
#elif defined(_WIN32)
{
oggvorbislibrary = Sys_LoadLibrary("vorbisfile", funcs);
if (!oggvorbislibrary)
oggvorbislibrary = Sys_LoadLibrary("libvorbisfile", funcs);
if (!oggvorbislibrary)
{
oggvorbislibrary = Sys_LoadLibrary("libvorbisfile-3", funcs);
if (!oggvorbislibrary)
oggvorbislibrary = Sys_LoadLibrary("libvorbisfile", funcs);
}
if (!oggvorbislibrary)
Con_Printf("Couldn't load DLL: \"vorbisfile.dll\" or \"libvorbisfile-3\".\n");
}
#else
{
oggvorbislibrary = Sys_LoadLibrary("libvorbisfile", funcs);
if (!oggvorbislibrary)
Con_Printf("Couldn't load library: \"libvorbisfile\".\n");
}
#endif
tried = true;
if (!oggvorbislibrary)
{
Con_Printf("ogg vorbis library is not loaded.\n");
return false;
}
#endif
buffer->start = start;
buffer->length = length;
buffer->pos = 0;
if (p_ov_open_callbacks(buffer, &buffer->vf, NULL, 0, callbacks))
{
Con_Printf("Input does not appear to be an Ogg bitstream.\n");
return false;
}
/* Print the comments plus a few lines about the bitstream we're
decoding */
{
// char **ptr=p_ov_comment(&buffer->vf,-1)->user_comments;
vorbis_info *vi=p_ov_info(&buffer->vf,-1);
if (vi->channels < 1 || vi->channels > 2)
{
p_ov_clear (&buffer->vf);
return false;
}
buffer->srcchannels = vi->channels;
buffer->srcspeed = vi->rate;
/*
while(*ptr){
Con_Printf("%s\n",*ptr);
ptr++;
}
Con_Printf("\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
Con_Printf("\nDecoded length: %ld samples\n",
(long)p_ov_pcm_total(&buffer->vf,-1));
Con_Printf("Encoded by: %s\n\n",p_ov_comment(&buffer->vf,-1)->vendor);
*/ }
buffer->tempbuffer = NULL;
buffer->tempbufferbytes = 0;
buffer->start = BZ_Malloc(length);
memcpy(buffer->start, start, length);
return true;
}
#endif