summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2006-11-28 23:46:04 +0000
committerTim Angus <tim@ngus.net>2006-11-28 23:46:04 +0000
commit92905745a71578eed267f25311d7a18d49976f6d (patch)
tree5836f0a4424b938c6782190ec9c28c6be808f389 /src/client
parent6af24abf02f1d0dedc5dbe655a37d5afc9f0646a (diff)
* Merge ioq3-989
Diffstat (limited to 'src/client')
-rw-r--r--src/client/cl_avi.c8
-rw-r--r--src/client/cl_cgame.c2
-rw-r--r--src/client/cl_console.c4
-rw-r--r--src/client/cl_curl.c358
-rw-r--r--src/client/cl_curl.h101
-rw-r--r--src/client/cl_keys.c3
-rw-r--r--src/client/cl_main.c131
-rw-r--r--src/client/cl_parse.c32
-rw-r--r--src/client/cl_ui.c6
-rw-r--r--src/client/client.h19
-rw-r--r--src/client/qal.c4
-rw-r--r--src/client/snd_codec_ogg.c8
-rw-r--r--src/client/snd_main.c4
-rw-r--r--src/client/snd_openal.c406
14 files changed, 954 insertions, 132 deletions
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c
index 463f873c..c54e7054 100644
--- a/src/client/cl_avi.c
+++ b/src/client/cl_avi.c
@@ -2,20 +2,20 @@
===========================================================================
Copyright (C) 2005-2006 Tim Angus
-This file is part of Quake III Arena source code.
+This file is part of Tremulous.
-Quake III Arena source code is free software; you can redistribute it
+Tremulous 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 2 of the License,
or (at your option) any later version.
-Quake III Arena source code is distributed in the hope that it will be
+Tremulous 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 Quake III Arena source code; if not, write to the Free Software
+along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c
index fd7c29ed..262f6b47 100644
--- a/src/client/cl_cgame.c
+++ b/src/client/cl_cgame.c
@@ -981,7 +981,7 @@ void CL_SetCGameTime( void ) {
}
// allow pause in single player
- if ( sv_paused->integer && cl_paused->integer && com_sv_running->integer ) {
+ if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) {
// paused
return;
}
diff --git a/src/client/cl_console.c b/src/client/cl_console.c
index 22a148a1..3e321394 100644
--- a/src/client/cl_console.c
+++ b/src/client/cl_console.c
@@ -516,13 +516,13 @@ void Con_DrawSolidConsole( float frac ) {
re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
- i = strlen( Q3_VERSION );
+ i = strlen( SVN_VERSION );
for (x=0 ; x<i ; x++) {
SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x ) * SMALLCHAR_WIDTH,
- (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] );
+ (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), SVN_VERSION[x] );
}
diff --git a/src/client/cl_curl.c b/src/client/cl_curl.c
new file mode 100644
index 00000000..246095a1
--- /dev/null
+++ b/src/client/cl_curl.c
@@ -0,0 +1,358 @@
+/*
+===========================================================================
+Copyright (C) 2006 Tony J. White (tjw@tjw.org)
+
+This file is part of Tremulous.
+
+Tremulous 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 2 of the License,
+or (at your option) any later version.
+
+Tremulous 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 Tremulous; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#if USE_CURL
+#include "client.h"
+cvar_t *cl_cURLLib;
+
+#if USE_CURL_DLOPEN
+
+#if USE_SDL_VIDEO
+#include "SDL.h"
+#include "SDL_loadso.h"
+#define OBJTYPE void *
+#define OBJLOAD(x) SDL_LoadObject(x)
+#define SYMLOAD(x,y) SDL_LoadFunction(x,y)
+#define OBJFREE(x) SDL_UnloadObject(x)
+
+#elif defined _WIN32
+#include <windows.h>
+#define OBJTYPE HMODULE
+#define OBJLOAD(x) LoadLibrary(x)
+#define SYMLOAD(x,y) GetProcAddress(x,y)
+#define OBJFREE(x) FreeLibrary(x)
+
+#elif defined __linux__ || defined __FreeBSD__ || defined MACOS_X || defined __sun
+#include <dlfcn.h>
+#define OBJTYPE void *
+#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL)
+#define SYMLOAD(x,y) dlsym(x,y)
+#define OBJFREE(x) dlclose(x)
+#else
+
+#error "Your platform has no lib loading code or it is disabled"
+#endif
+
+#if defined __linux__ || defined __FreeBSD__ || defined MACOS_X
+#include <unistd.h>
+#include <sys/types.h>
+#endif
+
+char* (*qcurl_version)(void);
+
+CURL* (*qcurl_easy_init)(void);
+CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
+CURLcode (*qcurl_easy_perform)(CURL *curl);
+void (*qcurl_easy_cleanup)(CURL *curl);
+CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
+CURL* (*qcurl_easy_duphandle)(CURL *curl);
+void (*qcurl_easy_reset)(CURL *curl);
+const char *(*qcurl_easy_strerror)(CURLcode);
+
+CURLM* (*qcurl_multi_init)(void);
+CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
+ CURL *curl_handle);
+CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
+ CURL *curl_handle);
+CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *exc_fd_set,
+ int *max_fd);
+CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
+ int *running_handles);
+CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
+CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
+ int *msgs_in_queue);
+const char *(*qcurl_multi_strerror)(CURLMcode);
+
+static OBJTYPE cURLLib = NULL;
+
+/*
+=================
+GPA
+=================
+*/
+static void *GPA(char *str)
+{
+ void *rv;
+
+ rv = SYMLOAD(cURLLib, str);
+ if(!rv)
+ {
+ Com_Printf("Can't load symbol %s\n", str);
+ clc.cURLEnabled = qfalse;
+ return NULL;
+ }
+ else
+ {
+ Com_DPrintf("Loaded symbol %s (0x%08X)\n", str, rv);
+ return rv;
+ }
+}
+#endif /* USE_CURL_DLOPEN */
+
+/*
+=================
+CL_cURL_Init
+=================
+*/
+qboolean CL_cURL_Init()
+{
+#if USE_CURL_DLOPEN
+ if(cURLLib)
+ return qtrue;
+
+
+ Com_Printf("Loading \"%s\"...", cl_cURLLib->string);
+ if( (cURLLib = OBJLOAD(cl_cURLLib->string)) == 0 )
+ {
+#ifdef _WIN32
+ return qfalse;
+#else
+ char fn[1024];
+ getcwd(fn, sizeof(fn));
+ strncat(fn, "/", sizeof(fn));
+ strncat(fn, cl_cURLLib->string, sizeof(fn));
+
+ if( (cURLLib = OBJLOAD(fn)) == 0 )
+ {
+ return qfalse;
+ }
+#endif /* _WIN32 */
+ }
+
+ clc.cURLEnabled = qtrue;
+
+ qcurl_version = GPA("curl_version");
+
+ qcurl_easy_init = GPA("curl_easy_init");
+ qcurl_easy_setopt = GPA("curl_easy_setopt");
+ qcurl_easy_perform = GPA("curl_easy_perform");
+ qcurl_easy_cleanup = GPA("curl_easy_cleanup");
+ qcurl_easy_getinfo = GPA("curl_easy_getinfo");
+ qcurl_easy_duphandle = GPA("curl_easy_duphandle");
+ qcurl_easy_reset = GPA("curl_easy_reset");
+ qcurl_easy_strerror = GPA("curl_easy_strerror");
+
+ qcurl_multi_init = GPA("curl_multi_init");
+ qcurl_multi_add_handle = GPA("curl_multi_add_handle");
+ qcurl_multi_remove_handle = GPA("curl_multi_remove_handle");
+ qcurl_multi_fdset = GPA("curl_multi_fdset");
+ qcurl_multi_perform = GPA("curl_multi_perform");
+ qcurl_multi_cleanup = GPA("curl_multi_cleanup");
+ qcurl_multi_info_read = GPA("curl_multi_info_read");
+ qcurl_multi_strerror = GPA("curl_multi_strerror");
+
+ if(!clc.cURLEnabled)
+ {
+ CL_cURL_Shutdown();
+ Com_Printf("FAIL One or more symbols not found\n");
+ return qfalse;
+ }
+ Com_Printf("OK\n");
+
+ return qtrue;
+#else
+ clc.cURLEnabled = qtrue;
+ return qtrue;
+#endif /* USE_CURL_DLOPEN */
+}
+
+/*
+=================
+CL_cURL_Shutdown
+=================
+*/
+void CL_cURL_Shutdown( void )
+{
+ CL_cURL_Cleanup();
+#if USE_CURL_DLOPEN
+ if(cURLLib)
+ {
+ OBJFREE(cURLLib);
+ cURLLib = NULL;
+ }
+ qcurl_easy_init = NULL;
+ qcurl_easy_setopt = NULL;
+ qcurl_easy_perform = NULL;
+ qcurl_easy_cleanup = NULL;
+ qcurl_easy_getinfo = NULL;
+ qcurl_easy_duphandle = NULL;
+ qcurl_easy_reset = NULL;
+
+ qcurl_multi_init = NULL;
+ qcurl_multi_add_handle = NULL;
+ qcurl_multi_remove_handle = NULL;
+ qcurl_multi_fdset = NULL;
+ qcurl_multi_perform = NULL;
+ qcurl_multi_cleanup = NULL;
+ qcurl_multi_info_read = NULL;
+ qcurl_multi_strerror = NULL;
+#endif /* USE_CURL_DLOPEN */
+}
+
+void CL_cURL_Cleanup(void)
+{
+ if(clc.downloadCURLM) {
+ if(clc.downloadCURL) {
+ qcurl_multi_remove_handle(clc.downloadCURLM,
+ clc.downloadCURL);
+ qcurl_easy_cleanup(clc.downloadCURL);
+ }
+ qcurl_multi_cleanup(clc.downloadCURLM);
+ clc.downloadCURLM = NULL;
+ clc.downloadCURL = NULL;
+ }
+ else if(clc.downloadCURL) {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ }
+}
+
+static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow,
+ double ultotal, double ulnow )
+{
+ clc.downloadSize = (int)dltotal;
+ Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
+ clc.downloadCount = (int)dlnow;
+ Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
+ return 0;
+}
+
+static int CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
+ void *stream)
+{
+ FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] );
+ return size*nmemb;
+}
+
+void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
+{
+ clc.cURLUsed = qtrue;
+ Com_Printf("URL: %s\n", remoteURL);
+ Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
+ "Localname: %s\n"
+ "RemoteURL: %s\n"
+ "****************************\n", localName, remoteURL);
+ CL_cURL_Cleanup();
+ Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
+ Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
+ Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName),
+ "%s.tmp", localName);
+
+ // Set so UI gets access to it
+ Cvar_Set("cl_downloadName", localName);
+ Cvar_Set("cl_downloadSize", "0");
+ Cvar_Set("cl_downloadCount", "0");
+ Cvar_SetValue("cl_downloadTime", cls.realtime);
+
+ clc.downloadBlock = 0; // Starting new file
+ clc.downloadCount = 0;
+
+ clc.downloadCURL = qcurl_easy_init();
+ if(!clc.downloadCURL) {
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() "
+ "failed\n");
+ return;
+ }
+ clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
+ if(!clc.download) {
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open "
+ "%s for writing\n", clc.downloadTempName);
+ return;
+ }
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download);
+ if(com_developer->integer)
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER, va("ioQ3://%s",
+ NET_AdrToString(clc.serverAddress)));
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
+ Q3_VERSION, qcurl_version()));
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
+ CL_cURL_CallbackWrite);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
+ CL_cURL_CallbackProgress);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
+ qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
+ clc.downloadCURLM = qcurl_multi_init();
+ if(!clc.downloadCURLM) {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() "
+ "failed\n");
+ return;
+ }
+ qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
+
+ if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) &&
+ !clc.cURLDisconnected) {
+
+ CL_AddReliableCommand("disconnect");
+ CL_WritePacket();
+ CL_WritePacket();
+ CL_WritePacket();
+ clc.cURLDisconnected = qtrue;
+ }
+}
+
+void CL_cURL_PerformDownload(void)
+{
+ CURLMcode res;
+ CURLMsg *msg;
+ int c;
+ int i = 0;
+
+ res = qcurl_multi_perform(clc.downloadCURLM, &c);
+ while(res == CURLM_CALL_MULTI_PERFORM && i < 100) {
+ res = qcurl_multi_perform(clc.downloadCURLM, &c);
+ i++;
+ }
+ if(res == CURLM_CALL_MULTI_PERFORM)
+ return;
+ msg = qcurl_multi_info_read(clc.downloadCURLM, &c);
+ if(msg == NULL) {
+ return;
+ }
+ FS_FCloseFile(clc.download);
+ if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) {
+ FS_SV_Rename(clc.downloadTempName, clc.downloadName);
+ clc.downloadRestart = qtrue;
+ }
+ else {
+ long code;
+
+ qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE,
+ &code);
+ Com_Error(ERR_DROP, "Download Error: %s Code: %d URL: %s",
+ qcurl_easy_strerror(msg->data.result),
+ code, clc.downloadURL);
+ }
+ *clc.downloadTempName = *clc.downloadName = 0;
+ Cvar_Set( "cl_downloadName", "" );
+ CL_NextDownload();
+}
+#endif /* USE_CURL */
diff --git a/src/client/cl_curl.h b/src/client/cl_curl.h
new file mode 100644
index 00000000..7b3f8929
--- /dev/null
+++ b/src/client/cl_curl.h
@@ -0,0 +1,101 @@
+/*
+===========================================================================
+Copyright (C) 2006 Tony J. White (tjw@tjw.org)
+
+This file is part of Tremulous.
+
+Tremulous 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 2 of the License,
+or (at your option) any later version.
+
+Tremulous 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 Tremulous; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+
+#ifndef __QCURL_H__
+#define __QCURL_H__
+
+extern cvar_t *cl_cURLLib;
+
+#include "../qcommon/q_shared.h"
+#include "../qcommon/qcommon.h"
+
+#ifdef WIN32
+#define DEFAULT_CURL_LIB "libcurl-3.dll"
+#elif defined(MACOS_X)
+#define DEFAULT_CURL_LIB "libcurl.dylib"
+#else
+#define DEFAULT_CURL_LIB "libcurl.so.3"
+#endif
+
+#if USE_LOCAL_HEADERS
+ #include "../libcurl/curl/curl.h"
+#else
+ #include <curl/curl.h>
+#endif
+
+
+#if USE_CURL_DLOPEN
+extern char* (*qcurl_version)(void);
+
+extern CURL* (*qcurl_easy_init)(void);
+extern CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
+extern CURLcode (*qcurl_easy_perform)(CURL *curl);
+extern void (*qcurl_easy_cleanup)(CURL *curl);
+extern CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
+extern void (*qcurl_easy_reset)(CURL *curl);
+extern const char *(*qcurl_easy_strerror)(CURLcode);
+
+extern CURLM* (*qcurl_multi_init)(void);
+extern CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
+ CURL *curl_handle);
+extern CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
+ CURL *curl_handle);
+extern CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *exc_fd_set,
+ int *max_fd);
+extern CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
+ int *running_handles);
+extern CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
+extern CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
+ int *msgs_in_queue);
+extern const char *(*qcurl_multi_strerror)(CURLMcode);
+#else
+#define qcurl_version curl_version
+
+#define qcurl_easy_init curl_easy_init
+#define qcurl_easy_setopt curl_easy_setopt
+#define qcurl_easy_perform curl_easy_perform
+#define qcurl_easy_cleanup curl_easy_cleanup
+#define qcurl_easy_getinfo curl_easy_getinfo
+#define qcurl_easy_duphandle curl_easy_duphandle
+#define qcurl_easy_reset curl_easy_reset
+#define qcurl_easy_strerror curl_easy_strerror
+
+#define qcurl_multi_init curl_multi_init
+#define qcurl_multi_add_handle curl_multi_add_handle
+#define qcurl_multi_remove_handle curl_multi_remove_handle
+#define qcurl_multi_fdset curl_multi_fdset
+#define qcurl_multi_perform curl_multi_perform
+#define qcurl_multi_cleanup curl_multi_cleanup
+#define qcurl_multi_info_read curl_multi_info_read
+#define qcurl_multi_strerror curl_multi_strerror
+#endif
+
+qboolean CL_cURL_Init( void );
+void CL_cURL_Shutdown( void );
+void CL_cURL_BeginDownload( const char *localName, const char *remoteURL );
+void CL_cURL_PerformDownload( void );
+void CL_cURL_Cleanup( void );
+#endif // __QCURL_H__
diff --git a/src/client/cl_keys.c b/src/client/cl_keys.c
index 691a59e2..c65ce916 100644
--- a/src/client/cl_keys.c
+++ b/src/client/cl_keys.c
@@ -1071,7 +1071,8 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
if (!down) {
return;
}
- Con_ToggleConsole_f ();
+ Con_ToggleConsole_f ();
+ Key_ClearStates ();
return;
}
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 808553b9..aefbab8c 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -655,6 +655,9 @@ CL_ShutdownAll
*/
void CL_ShutdownAll(void) {
+#if USE_CURL
+ CL_cURL_Shutdown();
+#endif
// clear sounds
S_DisableSounds();
// shutdown CGame
@@ -1159,6 +1162,9 @@ void CL_Vid_Restart_f( void ) {
CL_CloseAVI( );
}
+ if(clc.demorecording)
+ CL_StopRecord_f();
+
// don't let them loop during the restart
S_StopAllSounds();
// shutdown the UI
@@ -1291,6 +1297,23 @@ Called when all downloading has been completed
*/
void CL_DownloadsComplete( void ) {
+#if USE_CURL
+ // if we downloaded with cURL
+ if(clc.cURLUsed) {
+ clc.cURLUsed = qfalse;
+ CL_cURL_Shutdown();
+ if( clc.cURLDisconnected ) {
+ if(clc.downloadRestart) {
+ FS_Restart(clc.checksumFeed);
+ clc.downloadRestart = qfalse;
+ }
+ clc.cURLDisconnected = qfalse;
+ CL_Reconnect_f();
+ return;
+ }
+ }
+#endif
+
// if we downloaded files we need to restart the file system
if (clc.downloadRestart) {
clc.downloadRestart = qfalse;
@@ -1378,6 +1401,7 @@ A download completed or failed
void CL_NextDownload(void) {
char *s;
char *remoteName, *localName;
+ qboolean useCURL = qfalse;
// We are looking to start a download here
if (*clc.downloadList) {
@@ -1401,9 +1425,48 @@ void CL_NextDownload(void) {
*s++ = 0;
else
s = localName + strlen(localName); // point at the nul byte
-
- CL_BeginDownload( localName, remoteName );
-
+#if USE_CURL
+ if(!(cl_allowDownload->integer & DLF_NO_REDIRECT)) {
+ if(clc.sv_allowDownload & DLF_NO_REDIRECT) {
+ Com_Printf("WARNING: server does not "
+ "allow download redirection "
+ "(sv_allowDownload is %d)\n",
+ clc.sv_allowDownload);
+ }
+ else if(!*clc.sv_dlURL) {
+ Com_Printf("WARNING: server allows "
+ "download redirection, but does not "
+ "have sv_dlURL set\n");
+ }
+ else if(!CL_cURL_Init()) {
+ Com_Printf("WARNING: could not load "
+ "cURL library\n");
+ }
+ else {
+ CL_cURL_BeginDownload(localName, va("%s/%s",
+ clc.sv_dlURL, remoteName));
+ useCURL = qtrue;
+ }
+ }
+ else if(!(clc.sv_allowDownload & DLF_NO_REDIRECT)) {
+ Com_Printf("WARNING: server allows download "
+ "redirection, but it disabled by client "
+ "configuration (cl_allowDownload is %d)\n",
+ cl_allowDownload->integer);
+ }
+#endif /* USE_CURL */
+ if(!useCURL) {
+ if((cl_allowDownload->integer & DLF_NO_UDP)) {
+ Com_Error(ERR_DROP, "UDP Downloads are "
+ "disabled on your client. "
+ "(cl_allowDownload is %d)",
+ cl_allowDownload->integer);
+ return;
+ }
+ else {
+ CL_BeginDownload( localName, remoteName );
+ }
+ }
clc.downloadRestart = qtrue;
// move over the rest
@@ -1426,7 +1489,7 @@ and determine if we need to download them
void CL_InitDownloads(void) {
char missingfiles[1024];
- if ( !cl_allowDownload->integer )
+ if ( !(cl_allowDownload->integer & DLF_ENABLE) )
{
// autodownload is disabled on the client
// but it's possible that some referenced files on the server are missing
@@ -1911,7 +1974,7 @@ void CL_CheckTimeout( void ) {
//
// check timeout
//
- if ( ( !cl_paused->integer || !sv_paused->integer )
+ if ( ( !CL_CheckPaused() || !sv_paused->integer )
&& cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC
&& cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) {
if (++cl.timeoutcount > 5) { // timeoutcount saves debugger
@@ -1924,6 +1987,22 @@ void CL_CheckTimeout( void ) {
}
}
+/*
+==================
+CL_CheckPaused
+Check whether client has been paused.
+==================
+*/
+qboolean CL_CheckPaused(void)
+{
+ // if cl_paused->modified is set, the cvar has only been changed in
+ // this frame. Keep paused in this frame to ensure the server doesn't
+ // lag behind.
+ if(cl_paused->integer || cl_paused->modified)
+ return qtrue;
+
+ return qfalse;
+}
//============================================================================
@@ -1935,19 +2014,19 @@ CL_CheckUserinfo
*/
void CL_CheckUserinfo( void ) {
// don't add reliable commands when not yet connected
- if ( cls.state < CA_CHALLENGING ) {
+ if(cls.state < CA_CHALLENGING)
return;
- }
+
// don't overflow the reliable command buffer when paused
- if ( cl_paused->integer ) {
+ if(CL_CheckPaused())
return;
- }
+
// send a reliable userinfo update if needed
- if ( cvar_modifiedFlags & CVAR_USERINFO ) {
+ if(cvar_modifiedFlags & CVAR_USERINFO)
+ {
cvar_modifiedFlags &= ~CVAR_USERINFO;
CL_AddReliableCommand( va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ) );
}
-
}
/*
@@ -1962,6 +2041,25 @@ void CL_Frame ( int msec ) {
return;
}
+#if USE_CURL
+ if(clc.downloadCURLM) {
+ CL_cURL_PerformDownload();
+ // we can't process frames normally when in disconnected
+ // download mode since the ui vm expects cls.state to be
+ // CA_CONNECTED
+ if(clc.cURLDisconnected) {
+ cls.realFrametime = msec;
+ cls.frametime = msec;
+ cls.realtime += cls.frametime;
+ SCR_UpdateScreen();
+ S_Update();
+ Con_RunConsole();
+ cls.framecount++;
+ return;
+ }
+ }
+#endif
+
if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI )
&& !com_sv_running->integer ) {
// if disconnected, bring up the menu
@@ -2273,6 +2371,12 @@ void CL_Video_f( void )
char filename[ MAX_OSPATH ];
int i, last;
+ if( !clc.demoplaying )
+ {
+ Com_Printf( "The video command can only be used when playing back demos\n" );
+ return;
+ }
+
if( Cmd_Argc( ) == 2 )
{
// explicit filename
@@ -2404,6 +2508,9 @@ void CL_Init( void ) {
cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE);
+#if USE_CURL
+ cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE);
+#endif
cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0);
#ifdef MACOS_X
@@ -2718,7 +2825,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING );
if (strlen(info)) {
if (info[strlen(info)-1] != '\n') {
- strncat(info, "\n", sizeof(info));
+ strncat(info, "\n", sizeof(info) - 1);
}
Com_Printf( "%s: %s", NET_AdrToString( from ), info );
}
diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
index 7de07e91..093893a6 100644
--- a/src/client/cl_parse.c
+++ b/src/client/cl_parse.c
@@ -220,6 +220,10 @@ void CL_ParseSnapshot( msg_t *msg ) {
newSnap.serverTime = MSG_ReadLong( msg );
+ // if we were just unpaused, we can only *now* really let the
+ // change come into effect or the client hangs.
+ cl_paused->modified = 0;
+
newSnap.messageNum = clc.serverMessageSequence;
deltaNum = MSG_ReadByte( msg );
@@ -411,6 +415,25 @@ void CL_SystemInfoChanged( void ) {
/*
==================
+CL_ParseServerInfo
+==================
+*/
+static void CL_ParseServerInfo(void)
+{
+ const char *serverInfo;
+
+ serverInfo = cl.gameState.stringData
+ + cl.gameState.stringOffsets[ CS_SERVERINFO ];
+
+ clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo,
+ "sv_allowDownload"));
+ Q_strncpyz(clc.sv_dlURL,
+ Info_ValueForKey(serverInfo, "sv_dlURL"),
+ sizeof(clc.sv_dlURL));
+}
+
+/*
+==================
CL_ParseGamestate
==================
*/
@@ -476,11 +499,18 @@ void CL_ParseGamestate( msg_t *msg ) {
// read the checksum feed
clc.checksumFeed = MSG_ReadLong( msg );
+ // parse useful values out of CS_SERVERINFO
+ CL_ParseServerInfo();
+
// parse serverId and other cvars
CL_SystemInfoChanged();
+ // stop recording now so the demo won't have an unnecessary level load at the end.
+ if(cl_autoRecordDemo->integer && clc.demorecording)
+ CL_StopRecord_f();
+
// reinitialize the filesystem if the game directory has changed
- FS_ConditionalRestart( clc.checksumFeed );
+ FS_ConditionalRestart( clc.checksumFeed );
// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
// cgame
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index 327eaacf..caa9179f 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -603,10 +603,10 @@ static void CL_GetGlconfig( glconfig_t *config ) {
/*
====================
-GetClipboardData
+CL_GetClipboardData
====================
*/
-static void GetClipboardData( char *buf, int buflen ) {
+static void CL_GetClipboardData( char *buf, int buflen ) {
char *cbd;
cbd = Sys_GetClipboardData();
@@ -836,7 +836,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
return 0;
case UI_GETCLIPBOARDDATA:
- GetClipboardData( VMA(1), args[2] );
+ CL_GetClipboardData( VMA(1), args[2] );
return 0;
case UI_GETCLIENTSTATE:
diff --git a/src/client/client.h b/src/client/client.h
index ae5915db..77cf7dca 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -31,12 +31,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../cgame/cg_public.h"
#include "../game/bg_public.h"
+#if USE_CURL
+#include "cl_curl.h"
+#endif /* USE_CURL */
+
// tjw: file full of random crap that gets used to create cl_guid
#define QKEY_FILE "qkey"
#define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits
-
// snapshots are a view of the server at a given time
typedef struct {
qboolean valid; // cleared if delta parsing was invalid
@@ -187,6 +190,16 @@ typedef struct {
fileHandle_t download;
char downloadTempName[MAX_OSPATH];
char downloadName[MAX_OSPATH];
+#ifdef USE_CURL
+ qboolean cURLEnabled;
+ qboolean cURLUsed;
+ qboolean cURLDisconnected;
+ char downloadURL[MAX_OSPATH];
+ CURL *downloadCURL;
+ CURLM *downloadCURLM;
+#endif /* USE_CURL */
+ int sv_allowDownload;
+ char sv_dlURL[MAX_CVAR_VALUE_STRING];
int downloadNumber;
int downloadBlock; // block we are waiting for
int downloadCount; // how many bytes we got
@@ -352,10 +365,12 @@ extern cvar_t *cl_aviMotionJpeg;
extern cvar_t *cl_activeAction;
extern cvar_t *cl_allowDownload;
+extern cvar_t *cl_downloadMethod;
extern cvar_t *cl_conXOffset;
extern cvar_t *cl_inGameVideo;
extern cvar_t *cl_lanForcePackets;
+extern cvar_t *cl_autoRecordDemo;
//=================================================
@@ -380,6 +395,7 @@ void CL_ReadDemoMessage( void );
demoState_t CL_DemoState( void );
int CL_DemoPos( void );
void CL_DemoName( char *buffer, int size );
+void CL_StopRecord_f( void );
void CL_InitDownloads(void);
void CL_NextDownload(void);
@@ -393,6 +409,7 @@ void CL_ShutdownRef( void );
void CL_InitRef( void );
int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen );
+qboolean CL_CheckPaused(void);
//
// cl_input
diff --git a/src/client/qal.c b/src/client/qal.c
index b206881f..4c04bd41 100644
--- a/src/client/qal.c
+++ b/src/client/qal.c
@@ -177,8 +177,8 @@ qboolean QAL_Init(const char *libname)
#else
char fn[1024];
getcwd(fn, sizeof(fn));
- strncat(fn, "/", sizeof(fn));
- strncat(fn, libname, sizeof(fn));
+ strncat(fn, "/", sizeof(fn) - strlen(fn) - 1);
+ strncat(fn, libname, sizeof(fn) - strlen(fn) - 1);
if( (OpenALLib = OBJLOAD(fn)) == 0 )
{
diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c
index 72ece944..f13f9a8d 100644
--- a/src/client/snd_codec_ogg.c
+++ b/src/client/snd_codec_ogg.c
@@ -4,20 +4,20 @@ Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
-This file is part of Quake III Arena source code.
+This file is part of Tremulous.
-Quake III Arena source code is free software; you can redistribute it
+Tremulous 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 2 of the License,
or (at your option) any later version.
-Quake III Arena source code is distributed in the hope that it will be
+Tremulous 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 Quake III Arena source code; if not, write to the Free Software
+along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
diff --git a/src/client/snd_main.c b/src/client/snd_main.c
index 8f09570e..eb31f2d7 100644
--- a/src/client/snd_main.c
+++ b/src/client/snd_main.c
@@ -405,9 +405,9 @@ void S_Init( void )
}
S_SoundInfo( );
- Com_Printf( "Sound intialization successful.\n" );
+ Com_Printf( "Sound initialization successful.\n" );
} else {
- Com_Printf( "Sound intialization failed.\n" );
+ Com_Printf( "Sound initialization failed.\n" );
}
}
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index 39a04179..6f5396c4 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -37,8 +37,12 @@ cvar_t *s_alSources;
cvar_t *s_alDopplerFactor;
cvar_t *s_alDopplerSpeed;
cvar_t *s_alMinDistance;
+cvar_t *s_alMaxDistance;
cvar_t *s_alRolloff;
+cvar_t *s_alGraceDistance;
cvar_t *s_alDriver;
+cvar_t *s_alDevice;
+cvar_t *s_alAvailableDevices;
cvar_t *s_alMaxSpeakerDistance;
/*
@@ -134,7 +138,11 @@ static sfxHandle_t S_AL_BufferFindFree( void )
{
// Got one
if(knownSfx[i].filename[0] == '\0')
+ {
+ if(i >= numSfx)
+ numSfx = i + 1;
return i;
+ }
}
// Shit...
@@ -155,7 +163,7 @@ static sfxHandle_t S_AL_BufferFind(const char *filename)
sfxHandle_t sfx = -1;
int i;
- for(i = 0; i < MAX_SFX; i++)
+ for(i = 0; i < numSfx; i++)
{
if(!Q_stricmp(knownSfx[i].filename, filename))
{
@@ -230,7 +238,7 @@ static qboolean S_AL_BufferEvict( void )
int i, oldestBuffer = -1;
int oldestTime = Sys_Milliseconds( );
- for( i = 0; i < MAX_SFX; i++ )
+ for( i = 0; i < numSfx; i++ )
{
if( !knownSfx[ i ].filename[ 0 ] )
continue;
@@ -404,7 +412,7 @@ void S_AL_BufferShutdown( void )
knownSfx[default_sfx].isLocked = qfalse;
// Free all used effects
- for(i = 0; i < MAX_SFX; i++)
+ for(i = 0; i < numSfx; i++)
S_AL_BufferUnload(i);
// Clear the tables
@@ -463,6 +471,9 @@ typedef struct src_s
int isLooping; // Is this a looping effect (attached to an entity)
int isTracking; // Is this object tracking it's owner
+ float curGain; // gain employed if source is within maxdistance.
+ float scaleGain; // Last gain value for this source. 0 if muted.
+
qboolean local; // Is this local (relative to the cam)
} src_t;
@@ -512,6 +523,50 @@ static void _S_AL_SanitiseVector( vec3_t v, int line )
/*
=================
+S_AL_ScaleGain
+Adapt the gain if necessary to get a quicker fadeout when the source is too far away.
+=================
+*/
+
+static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin)
+{
+ float distance;
+
+ if(chksrc->local)
+ distance = VectorLength(origin);
+ else
+ distance = Distance(origin, lastListenerOrigin);
+
+ // If we exceed a certain distance, scale the gain linearly until the sound
+ // vanishes into nothingness.
+ if((distance -= s_alMaxDistance->value) > 0)
+ {
+ float scaleFactor;
+
+ if(distance >= s_alGraceDistance->value)
+ scaleFactor = 0.0f;
+ else
+ scaleFactor = 1.0f - distance / s_alGraceDistance->value;
+
+ scaleFactor *= chksrc->curGain;
+
+ if(chksrc->scaleGain != scaleFactor);
+ {
+ chksrc->scaleGain = scaleFactor;
+ // if(scaleFactor > 0.0f)
+ // Com_Printf("%f\n", scaleFactor);
+ qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain);
+ }
+ }
+ else if(chksrc->scaleGain != chksrc->curGain)
+ {
+ chksrc->scaleGain = chksrc->curGain;
+ qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain);
+ }
+}
+
+/*
+=================
S_AL_HearingThroughEntity
=================
*/
@@ -615,41 +670,46 @@ static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t prio
int entity, int channel, qboolean local)
{
ALuint buffer;
+ src_t *curSource;
// Mark the SFX as used, and grab the raw AL buffer
S_AL_BufferUse(sfx);
buffer = S_AL_BufferGet(sfx);
// Set up src struct
- srcList[src].lastUsedTime = Sys_Milliseconds();
- srcList[src].sfx = sfx;
- srcList[src].priority = priority;
- srcList[src].entity = entity;
- srcList[src].channel = channel;
- srcList[src].isActive = qtrue;
- srcList[src].isLocked = qfalse;
- srcList[src].isLooping = qfalse;
- srcList[src].isTracking = qfalse;
- srcList[src].local = local;
+ curSource = &srcList[src];
+
+ curSource->lastUsedTime = Sys_Milliseconds();
+ curSource->sfx = sfx;
+ curSource->priority = priority;
+ curSource->entity = entity;
+ curSource->channel = channel;
+ curSource->isActive = qtrue;
+ curSource->isLocked = qfalse;
+ curSource->isLooping = qfalse;
+ curSource->isTracking = qfalse;
+ curSource->curGain = s_alGain->value * s_volume->value;
+ curSource->scaleGain = curSource->curGain;
+ curSource->local = local;
// Set up OpenAL source
- qalSourcei(srcList[src].alSource, AL_BUFFER, buffer);
- qalSourcef(srcList[src].alSource, AL_PITCH, 1.0f);
- qalSourcef(srcList[src].alSource, AL_GAIN, s_alGain->value * s_volume->value);
- qalSourcefv(srcList[src].alSource, AL_POSITION, vec3_origin);
- qalSourcefv(srcList[src].alSource, AL_VELOCITY, vec3_origin);
- qalSourcei(srcList[src].alSource, AL_LOOPING, AL_FALSE);
- qalSourcef(srcList[src].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+ qalSourcei(curSource->alSource, AL_BUFFER, buffer);
+ qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
+ qalSourcef(curSource->alSource, AL_GAIN, curSource->curGain);
+ qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
+ qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
+ qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
if(local)
{
- qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_TRUE);
- qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, 0.0f);
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
}
else
{
- qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_FALSE);
- qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
}
}
@@ -825,6 +885,27 @@ void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin )
/*
=================
+S_AL_CheckInput
+Check whether input values from mods are out of range.
+Necessary for i.g. Western Quake3 mod which is buggy.
+=================
+*/
+static qboolean S_AL_CheckInput(int entityNum, sfxHandle_t sfx)
+{
+ if (entityNum < 0 || entityNum > MAX_GENTITIES)
+ Com_Error(ERR_DROP, "S_StartSound: bad entitynum %i", entityNum);
+
+ if (sfx < 0 || sfx >= numSfx)
+ {
+ Com_Printf(S_COLOR_RED, "ERROR: S_AL_CheckInput: handle %i out of range\n", sfx);
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+=================
S_AL_StartLocalSound
Play a local (non-spatialized) sound effect
@@ -833,6 +914,9 @@ Play a local (non-spatialized) sound effect
static
void S_AL_StartLocalSound(sfxHandle_t sfx, int channel)
{
+ if(S_AL_CheckInput(0, sfx))
+ return;
+
// Try to grab a source
srcHandle_t src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel);
if(src == -1)
@@ -857,6 +941,9 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx
{
vec3_t sorigin;
+ if(S_AL_CheckInput(origin ? 0 : entnum, sfx))
+ return;
+
// Try to grab a source
srcHandle_t src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
if(src == -1)
@@ -865,8 +952,6 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx
// Set up the effect
if( origin == NULL )
{
- srcList[ src ].isTracking = qtrue;
-
if( S_AL_HearingThroughEntity( entnum ) )
{
// Where the entity is the local player, play a local sound
@@ -878,6 +963,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx
S_AL_SrcSetup( src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse );
VectorCopy( entityList[ entnum ].origin, sorigin );
}
+ srcList[ src ].isTracking = qtrue;
}
else
{
@@ -887,6 +973,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx
S_AL_SanitiseVector( sorigin );
qalSourcefv( srcList[ src ].alSource, AL_POSITION, sorigin );
+ S_AL_ScaleGain(&srcList[src], sorigin);
// Start it playing
qalSourcePlay(srcList[src].alSource);
@@ -918,6 +1005,7 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
{
int src;
sentity_t *sent = &entityList[ entityNum ];
+ src_t *curSource;
// Do we need to allocate a new source for this entity
if( !sent->srcAllocated )
@@ -945,28 +1033,33 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
// If this is not set then the looping sound is removed
sent->loopAddedThisFrame = qtrue;
+ curSource = &srcList[src];
+
// UGH
// These lines should be called via S_AL_SrcSetup, but we
// can't call that yet as it buffers sfxes that may change
// with subsequent calls to S_AL_SrcLoop
- srcList[ src ].entity = entityNum;
- srcList[ src ].isLooping = qtrue;
- srcList[ src ].isActive = qtrue;
+ curSource->entity = entityNum;
+ curSource->isLooping = qtrue;
+ curSource->isActive = qtrue;
if( S_AL_HearingThroughEntity( entityNum ) )
{
- srcList[ src ].local = qtrue;
+ curSource->local = qtrue;
- qalSourcefv( srcList[ src ].alSource, AL_POSITION, vec3_origin );
- qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, vec3_origin );
+ qalSourcefv( curSource->alSource, AL_POSITION, vec3_origin );
+ qalSourcefv( curSource->alSource, AL_VELOCITY, vec3_origin );
}
else
{
- srcList[ src ].local = qfalse;
+ curSource->local = qfalse;
- qalSourcefv( srcList[ src ].alSource, AL_POSITION, (ALfloat *)sent->origin );
- qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, (ALfloat *)velocity );
+ qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sent->origin );
+ qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity );
+
}
+
+ S_AL_ScaleGain(curSource, sent->origin);
}
/*
@@ -977,6 +1070,9 @@ S_AL_AddLoopingSound
static
void S_AL_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx )
{
+ if(S_AL_CheckInput(entityNum, sfx))
+ return;
+
S_AL_SanitiseVector( (vec_t *)origin );
S_AL_SanitiseVector( (vec_t *)velocity );
S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum);
@@ -990,6 +1086,9 @@ S_AL_AddRealLoopingSound
static
void S_AL_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx )
{
+ if(S_AL_CheckInput(entityNum, sfx))
+ return;
+
S_AL_SanitiseVector( (vec_t *)origin );
S_AL_SanitiseVector( (vec_t *)velocity );
@@ -1028,63 +1127,65 @@ void S_AL_SrcUpdate( void )
int i;
int entityNum;
ALint state;
+ src_t *curSource;
for(i = 0; i < srcCount; i++)
{
entityNum = srcList[i].entity;
+ curSource = &srcList[i];
- if(srcList[i].isLocked)
+ if(curSource->isLocked)
continue;
- if(!srcList[i].isActive)
+ if(!curSource->isActive)
continue;
// Update source parameters
if((s_alGain->modified)||(s_volume->modified))
- qalSourcef(srcList[i].alSource, AL_GAIN, s_alGain->value * s_volume->value);
- if((s_alRolloff->modified)&&(!srcList[i].local))
- qalSourcef(srcList[i].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+ curSource->curGain = s_alGain->value * s_volume->value;
+ if((s_alRolloff->modified)&&(!curSource->local))
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
if(s_alMinDistance->modified)
- qalSourcef(srcList[i].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+ qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
- if( srcList[ i ].isLooping )
+ if(curSource->isLooping)
{
sentity_t *sent = &entityList[ entityNum ];
// If a looping effect hasn't been touched this frame, kill it
- if( sent->loopAddedThisFrame )
+ if(sent->loopAddedThisFrame)
{
// The sound has changed without an intervening removal
- if( srcList[ i ].isActive && !sent->startLoopingSound &&
- srcList[ i ].sfx != sent->loopSfx )
+ if(curSource->isActive && !sent->startLoopingSound &&
+ curSource->sfx != sent->loopSfx)
{
- qalSourceStop( srcList[ i ].alSource );
- qalSourcei( srcList[ i ].alSource, AL_BUFFER, 0 );
+ qalSourceStop(curSource->alSource);
+ qalSourcei(curSource->alSource, AL_BUFFER, 0);
sent->startLoopingSound = qtrue;
}
- // Ths sound hasn't been started yet
- if( sent->startLoopingSound )
+ // The sound hasn't been started yet
+ if(sent->startLoopingSound)
{
- S_AL_SrcSetup( i, sent->loopSfx, sent->loopPriority,
- entityNum, -1, srcList[ i ].local );
- srcList[ i ].isLooping = qtrue;
- qalSourcei( srcList[ i ].alSource, AL_LOOPING, AL_TRUE );
- qalSourcePlay( srcList[ i ].alSource );
+ S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority,
+ entityNum, -1, curSource->local);
+ curSource->isLooping = qtrue;
+ qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE);
+ qalSourcePlay(curSource->alSource);
sent->startLoopingSound = qfalse;
}
// Update locality
- if( srcList[ i ].local)
+ if(curSource->local)
{
- qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_TRUE );
- qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, 0.0f );
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
}
else
{
- qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_FALSE );
- qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value );
+ qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
+ qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
}
}
else
@@ -1093,20 +1194,23 @@ void S_AL_SrcUpdate( void )
continue;
}
- // Query relativity of source, don't move if it's true
- qalGetSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, &state );
-
- // See if it needs to be moved
- if( srcList[ i ].isTracking && !state )
- qalSourcefv(srcList[i].alSource, AL_POSITION, entityList[entityNum].origin);
-
// Check if it's done, and flag it
- qalGetSourcei(srcList[i].alSource, AL_SOURCE_STATE, &state);
+ qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
if(state == AL_STOPPED)
{
S_AL_SrcKill(i);
continue;
}
+
+ // Query relativity of source, don't move if it's true
+ qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
+
+ // See if it needs to be moved
+ if(curSource->isTracking && !state)
+ {
+ qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin);
+ S_AL_ScaleGain(curSource, entityList[entityNum].origin);
+ }
}
}
@@ -1290,6 +1394,7 @@ static ALuint musicSource;
static ALuint musicBuffers[NUM_MUSIC_BUFFERS];
static snd_stream_t *mus_stream;
+static snd_stream_t *intro_stream;
static char s_backgroundLoop[MAX_QPATH];
static byte decode_buffer[MUSIC_BUFFER_SIZE];
@@ -1333,6 +1438,26 @@ static void S_AL_MusicSourceFree( void )
/*
=================
+S_AL_CloseMusicFiles
+=================
+*/
+static void S_AL_CloseMusicFiles(void)
+{
+ if(intro_stream)
+ {
+ S_CodecCloseStream(intro_stream);
+ intro_stream = NULL;
+ }
+
+ if(mus_stream)
+ {
+ S_CodecCloseStream(mus_stream);
+ mus_stream = NULL;
+ }
+}
+
+/*
+=================
S_AL_StopBackgroundTrack
=================
*/
@@ -1355,9 +1480,7 @@ void S_AL_StopBackgroundTrack( void )
S_AL_MusicSourceFree();
// Unload the stream
- if(mus_stream)
- S_CodecCloseStream(mus_stream);
- mus_stream = NULL;
+ S_AL_CloseMusicFiles();
musicPlaying = qfalse;
}
@@ -1373,27 +1496,42 @@ void S_AL_MusicProcess(ALuint b)
ALenum error;
int l;
ALuint format;
+ snd_stream_t *curstream;
- if(!mus_stream)
+ if(intro_stream)
+ curstream = intro_stream;
+ else
+ curstream = mus_stream;
+
+ if(!curstream)
return;
- l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer);
+ l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
// Run out data to read, start at the beginning again
if(l == 0)
{
- S_CodecCloseStream(mus_stream);
- mus_stream = S_CodecOpenStream(s_backgroundLoop);
- if(!mus_stream)
+ S_CodecCloseStream(curstream);
+
+ // the intro stream just finished playing so we don't need to reopen
+ // the music stream.
+ if(intro_stream)
+ intro_stream = NULL;
+ else
+ mus_stream = S_CodecOpenStream(s_backgroundLoop);
+
+ curstream = mus_stream;
+
+ if(!curstream)
{
S_AL_StopBackgroundTrack();
return;
}
- l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer);
+ l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
}
- format = S_AL_Format(mus_stream->info.width, mus_stream->info.channels);
+ format = S_AL_Format(curstream->info.width, curstream->info.channels);
if( l == 0 )
{
@@ -1403,7 +1541,7 @@ void S_AL_MusicProcess(ALuint b)
qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 );
}
else
- qalBufferData(b, format, decode_buffer, l, mus_stream->info.rate);
+ qalBufferData(b, format, decode_buffer, l, curstream->info.rate);
if( ( error = qalGetError( ) ) != AL_NO_ERROR )
{
@@ -1423,27 +1561,12 @@ static
void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
{
int i;
+ qboolean issame;
// Stop any existing music that might be playing
S_AL_StopBackgroundTrack();
- if ( !intro || !intro[0] ) {
- intro = loop;
- }
- if ( !loop || !loop[0] ) {
- loop = intro;
- }
-
- if((!intro || !intro[0]) && (!intro || !intro[0]))
- return;
-
- // Copy the loop over
- strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
-
- // Open the intro
- mus_stream = S_CodecOpenStream(intro);
-
- if(!mus_stream)
+ if((!intro || !*intro) && (!loop || !*loop))
return;
// Allocate a musicSource
@@ -1451,9 +1574,32 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
if(musicSourceHandle == -1)
return;
+ if (!loop || !*loop)
+ {
+ loop = intro;
+ issame = qtrue;
+ }
+ else if(intro && *intro && !strcmp(intro, loop))
+ issame = qtrue;
+ else
+ issame = qfalse;
+
+ // Copy the loop over
+ strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+
+ if(!issame)
+ {
+ // Open the intro and don't mind whether it succeeds.
+ // The important part is the loop.
+ intro_stream = S_CodecOpenStream(intro);
+ }
+ else
+ intro_stream = NULL;
+
mus_stream = S_CodecOpenStream(s_backgroundLoop);
if(!mus_stream)
{
+ S_AL_CloseMusicFiles();
S_AL_MusicSourceFree();
return;
}
@@ -1526,6 +1672,7 @@ static ALCcontext *alContext;
#ifdef _WIN32
#define ALDRIVER_DEFAULT "OpenAL32.dll"
+#define ALDEVICE_DEFAULT "Generic Software"
#elif defined(MACOS_X)
#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
#else
@@ -1674,7 +1821,11 @@ void S_AL_SoundInfo( void )
Com_Printf( " Version: %s\n", qalGetString( AL_VERSION ) );
Com_Printf( " Renderer: %s\n", qalGetString( AL_RENDERER ) );
Com_Printf( " Extensions: %s\n", qalGetString( AL_EXTENSIONS ) );
-
+ if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
+ {
+ Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
+ Com_Printf("Available Devices:\n%s", s_alAvailableDevices->string);
+ }
}
/*
@@ -1714,6 +1865,9 @@ S_AL_Init
qboolean S_AL_Init( soundInterface_t *si )
{
#if USE_OPENAL
+
+ qboolean enumsupport, founddev = qfalse;
+
if( !si ) {
return qfalse;
}
@@ -1725,7 +1879,9 @@ qboolean S_AL_Init( soundInterface_t *si )
s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE );
s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE );
s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT );
- s_alRolloff = Cvar_Get( "s_alRolloff", "0.8", CVAR_CHEAT );
+ s_alMaxDistance = Cvar_Get("s_alMaxDistance", "1024", CVAR_CHEAT);
+ s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT);
+ s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT);
s_alMaxSpeakerDistance = Cvar_Get( "s_alMaxSpeakerDistance", "1024", CVAR_ARCHIVE );
s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE );
@@ -1737,8 +1893,56 @@ qboolean S_AL_Init( soundInterface_t *si )
return qfalse;
}
- // Open default device
- alDevice = qalcOpenDevice( NULL );
+ // Device enumeration support (extension is implemented reasonably only on Windows right now).
+ if((enumsupport = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")))
+ {
+ char devicenames[1024] = "";
+ const char *devicelist;
+ const char *defaultdevice;
+ int curlen;
+
+ // get all available devices + the default device name.
+ devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+
+#ifdef _WIN32
+ // check whether the default device is generic hardware. If it is, change to
+ // Generic Software as that one works more reliably with various sound systems.
+ // If it's not, use OpenAL's default selection as we don't want to ignore
+ // native hardware acceleration.
+ if(!strcmp(defaultdevice, "Generic Hardware"))
+ s_alDevice = Cvar_Get("s_alDevice", ALDEVICE_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH);
+ else
+#endif
+ s_alDevice = Cvar_Get("s_alDevice", defaultdevice, CVAR_ARCHIVE | CVAR_LATCH);
+
+ // dump a list of available devices to a cvar for the user to see.
+ while((curlen = strlen(devicelist)))
+ {
+ Q_strcat(devicenames, sizeof(devicenames), devicelist);
+ Q_strcat(devicenames, sizeof(devicenames), "\n");
+
+ // check whether the device we want to load is available at all.
+ if(!strcmp(s_alDevice->string, devicelist))
+ founddev = qtrue;
+
+ devicelist += curlen + 1;
+ }
+
+ s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART);
+
+ if(!founddev)
+ {
+ Cvar_ForceReset("s_alDevice");
+ founddev = 1;
+ }
+ }
+
+ if(founddev)
+ alDevice = qalcOpenDevice(s_alDevice->string);
+ else
+ alDevice = qalcOpenDevice(NULL);
+
if( !alDevice )
{
QAL_Shutdown( );
@@ -1746,6 +1950,9 @@ qboolean S_AL_Init( soundInterface_t *si )
return qfalse;
}
+ if(enumsupport)
+ Cvar_Set("s_alDevice", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
+
// Create OpenAL context
alContext = qalcCreateContext( alDevice, NULL );
if( !alContext )
@@ -1762,6 +1969,7 @@ qboolean S_AL_Init( soundInterface_t *si )
S_AL_SrcInit( );
// Set up OpenAL parameters (doppler, etc)
+ qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
qalDopplerFactor( s_alDopplerFactor->value );
qalDopplerVelocity( s_alDopplerSpeed->value );