the Linux client now uses SDL 2 for: window, GL context, video modes, audio, kb and mouse input, monitor list, clipboard

This commit is contained in:
myT 2017-10-28 03:35:51 +02:00
parent ef83d7314d
commit b3831fcc87
22 changed files with 1835 additions and 3225 deletions

View file

@ -49,7 +49,10 @@ Building on Linux with GCC
Requirements:
- NASM | On Debian and Ubuntu, run `sudo apt-get install nasm` to install it
| Name | Server | Client | Package name (apt-get) |
|-------|:------:|:------:|------------------------|
| NASM | X | X | nasm |
| SDL 2 | | X | libsdl2-dev |
Options:
@ -79,7 +82,19 @@ There are 2 environment variables used for compiling and debugging:
| QUAKE3DIR | required for building | optional |
| CPMADIR | required for debugging | unused |
Build with other compilers
--------------------------
Building with other compilers
-----------------------------
While it's not officially supported, you can modify the premake Lua script and run premake on it to generate new makefiles for your own needs.
Bonus: Building SDL 2 from source on Linux
------------------------------------------
- Download the sources of the latest stable release
- Extract to sdl-src
- Create sdl-build next to sdl-src (it *has* to be out-of-tree)
- Navigate to the sdl-build directory with `cd`
- Run `../sdl-src/configure`
- Run `make`
- As superuser, run `make install` (or `sudo make install`)
- Run `ldconfig` to update the library paths

View file

@ -141,6 +141,21 @@ fix: in raw mouse input mode, keeping any button pressed while focusing the wind
Linux:
chg: the client requires SDL 2 - the following things are handled by it:
window, GL context, video modes, audio, kb and mouse input, monitor list, clipboard
add: in_noGrab <0|1> (default: 0) disables input grabbing
add: m_relative <0|1> (default: 1) enables SDL's relative mouse mode
you might want to set it to 0 if you have a messed up input driver
add: s_autoMute selects when the audio output should be disabled
s_autoMute 0 = never mute
s_autoMute 1 (default) = mute when the window doesn't have input focus
s_autoMute 2 = mute when the window is minimized
add: minimize command to minimize the client's window
add: automatic dedicated server process restarts for crashes and timed reboots (sv_minRebootDelayMins)
this means 2 CNQ3 processes run per server: a parent (fixed pid) and a child (new pid after each restart)
this behavior can be disabled by passing "nohardreboot" as a command-line argument
@ -156,14 +171,6 @@ fix: the crash handler will reset tty input mode correctly
chg: tty input behavior matches in-game behavior when cgame is running and fixed the truncated tty input
fix: clear modifier keys on focus change to avoid ctrl/alt/shift being "stuck"
chg: new Linux mouse input code, support for raw input with XInput 2
in_mouse 0 = no input
in_mouse 1 = raw input (XInput 2)
in_mouse 2 = normal input (XWindows)
m_device to select a device explicity when using raw input
17 Sep 11 - 1.47

View file

@ -21,26 +21,37 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// linux_local.h: Linux-specific Quake3 header file
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );
void Sys_SendKeyEvents (void);
void Sys_ConsoleInputShutdown(void);
// Input subsystem
void IN_Init (void);
void IN_Frame (void);
void IN_Shutdown (void);
void IN_JoyMove( void );
void IN_StartupJoystick( void );
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#ifndef DEDICATED
#include "../client/client.h"
#endif
// GL subsystem
qboolean QGL_Init( const char *dllname );
void QGL_EnableLogging( qboolean enable );
void QGL_Shutdown( void );
// signals.c
void SIG_InitChild();
void SIG_InitParent();
void SIG_Frame();
void Lin_HardRebootHandler( int argc, char** argv );
void Lin_TrackParentProcess();
void Lin_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );
void Lin_ConsoleInputInit();
void Lin_ConsoleInputShutdown();
const char* Lin_ConsoleInput();
extern int q_argc;
extern char** q_argv;
qbool tty_Enabled();
void tty_Hide();
history_t* tty_GetHistory();
#ifndef DEDICATED
qbool sdl_Init();
void sdl_InitCvarsAndCmds();
void sdl_PollEvents();
void sdl_Frame(); // polling AND dealing with state changes (e.g. input grab)
void sdl_UpdateMonitorIndexFromWindow();
void sdl_MuteAudio( qbool mute );
#endif
void SIG_InitChild();
void SIG_InitParent();
void SIG_Frame();
extern int q_argc;
extern char** q_argv;

57
code/linux/linux_main.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "linux_local.h"
int q_argc = 0;
char** q_argv = NULL;
int main( int argc, char** argv )
{
q_argc = argc;
q_argv = argv;
#ifdef DEDICATED
Lin_HardRebootHandler(argc, argv);
#endif
SIG_InitChild();
#ifndef DEDICATED
if (!sdl_Init())
return 1;
#endif
// merge the command line: we need it in a single chunk
int len = 1, i;
for (i = 1; i < argc; ++i)
len += strlen(argv[i]) + 1;
char* cmdline = (char*)malloc(len);
*cmdline = 0;
for (i = 1; i < argc; ++i) {
if (i > 1)
strcat( cmdline, " " );
strcat( cmdline, argv[i] );
}
Com_Init( cmdline );
NET_Init();
Com_Printf( "Working directory: %s\n", Sys_Cwd() );
Lin_ConsoleInputInit();
Lin_TrackParentProcess();
#ifndef DEDICATED
sdl_InitCvarsAndCmds();
#endif
for (;;) {
SIG_Frame();
#ifndef DEDICATED
sdl_Frame();
#endif
Com_Frame();
}
return 0;
}

View file

@ -30,12 +30,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
** QGL_Shutdown() - unloads libraries, NULLs function pointers
*/
#include "../qcommon/q_shared.h"
#include <unistd.h>
#include <sys/types.h>
#include <float.h>
#include "unix_glw.h"
#include <dlfcn.h>
#include <SDL2/SDL.h>
#include "../renderer/tr_local.h"
@ -748,30 +745,6 @@ static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei
*/
void QGL_Shutdown( void )
{
if ( glw_state.OpenGLLib )
{
// 25/09/05 Tim Angus <tim@ngus.net>
// Certain combinations of hardware and software, specifically
// Linux/SMP/Nvidia/agpgart (OK, OK. MY combination of hardware and
// software), seem to cause a catastrophic (hard reboot required) crash
// when libGL is dynamically unloaded. I'm unsure of the precise cause,
// suffice to say I don't see anything in the Q3 code that could cause it.
// I suspect it's an Nvidia driver bug, but without the source or means to
// debug I obviously can't prove (or disprove) this. Interestingly (though
// perhaps not suprisingly), Enemy Territory and Doom 3 both exhibit the
// same problem.
//
// After many, many reboots and prodding here and there, it seems that a
// placing a short delay before libGL is unloaded works around the problem.
// This delay is changable via the r_GLlibCoolDownMsec cvar (nice name
// huh?), and it defaults to 0. For me, 500 seems to work.
//if( r_GLlibCoolDownMsec->integer )
usleep( 500 * 1000 );
dlclose ( glw_state.OpenGLLib );
glw_state.OpenGLLib = NULL;
}
qglAccum = NULL;
qglAlphaFunc = NULL;
qglAreTexturesResident = NULL;
@ -1130,23 +1103,7 @@ void QGL_Shutdown( void )
**
*/
static void *QGL_GetProcAddress( const char *symbol )
{
void *sym;
if ( qglXGetProcAddress )
{
sym = qglXGetProcAddress( symbol );
if ( sym )
{
return sym;
}
}
return dlsym( glw_state.OpenGLLib, symbol );
}
#define GPA( a ) QGL_GetProcAddress( a )
#define GPA( a ) SDL_GL_GetProcAddress( a )
/*
@ -1160,20 +1117,9 @@ static void *QGL_GetProcAddress( const char *symbol )
**
*/
qboolean QGL_Init( const char *dllname )
qbool QGL_Init( const char * )
{
if (glw_state.OpenGLLib == 0)
{
glw_state.OpenGLLib = dlopen( dllname, RTLD_LAZY|RTLD_GLOBAL );
}
if ( glw_state.OpenGLLib == 0 ) {
ri.Printf( PRINT_ALL, "QGL_Init: Failed to load %s: %s\n", dllname, dlerror() );
return qfalse;
}
qglXGetProcAddress = (void* (*)( const char *symbol ))GPA( "glXGetProcAddress" );
qglAccum = dllAccum =(void (*)(GLenum, GLfloat))GPA( "glAccum" );
qglAlphaFunc = dllAlphaFunc =(void (*)(GLenum, GLclampf))GPA( "glAlphaFunc" );
qglAreTexturesResident = dllAreTexturesResident =(GLboolean (*)(GLsizei, const GLuint*, GLboolean*))GPA( "glAreTexturesResident" );
@ -1592,7 +1538,6 @@ qbool GLW_InitGL2()
{
if (atof((const char*)qglGetString(GL_VERSION)) < 2.0f)
{
Com_Error( ERR_FATAL, "OpenGL 2 is the required minimum" );
return qfalse;
}
@ -1651,43 +1596,25 @@ qbool GLW_InitGL2()
typedef void ( APIENTRY * PFNGLTEXIMAGE2DMULTISAMPLE )(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLboolean);
// 3.0
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC qglRenderbufferStorageMultisample;
PFNGLTEXIMAGE2DMULTISAMPLE qglTexImage2DMultisample;
// 3.2
PFNGLTEXIMAGE2DMULTISAMPLE qglTexImage2DMultisample;
qbool GLW_InitGL3()
{
if (atof((const char*)qglGetString(GL_VERSION)) < 3.2f)
if (atof((const char*)qglGetString(GL_VERSION)) < 3.0f)
{
return qfalse;
}
// 3.0
QGL_EXT( glRenderbufferStorageMultisample, PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC );
// 3.2
QGL_EXT( glTexImage2DMultisample, PFNGLTEXIMAGE2DMULTISAMPLE );
return qtrue;
}
void QGL_SwapInterval( Display *dpy, Window win, int interval )
{
if( qglSwapIntervalEXT )
{
qglSwapIntervalEXT( interval );
}
else if ( qglXSwapIntervalEXT )
{
qglXSwapIntervalEXT( dpy, win, interval );
}
else if ( qglXSwapIntervalMESA )
{
qglXSwapIntervalMESA( interval );
}
else if ( qglXSwapIntervalSGI )
{
qglXSwapIntervalSGI( (unsigned int)interval );
}
}
// END linux_qgl.c

656
code/linux/linux_shared.cpp Normal file
View file

@ -0,0 +1,656 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#ifdef DEDICATED
#include <sys/wait.h>
#endif
#include "linux_local.h"
#define MEM_THRESHOLD 96*1024*1024
qboolean Sys_LowPhysicalMemory()
{
return qfalse; // FIXME
}
void Sys_Error( const char *error, ... )
{
va_list argptr;
char string[1024];
if (tty_Enabled())
tty_Hide();
#ifndef DEDICATED
CL_Shutdown();
#endif
va_start (argptr,error);
vsprintf (string,error,argptr);
va_end (argptr);
fprintf(stderr, "Sys_Error: %s\n", string);
Lin_ConsoleInputShutdown();
exit(1);
}
void Sys_Quit( int status )
{
Lin_ConsoleInputShutdown();
exit( status );
}
///////////////////////////////////////////////////////////////
const char* Sys_DllError()
{
return dlerror();
}
void Sys_UnloadDll( void* dllHandle )
{
if ( !dllHandle )
return;
dlclose( dllHandle );
const char* err = Sys_DllError();
if ( err ) {
Com_Error( ERR_FATAL, "Sys_UnloadDll failed: %s\n", err );
}
}
static void* try_dlopen( const char* base, const char* gamedir, const char* filename )
{
const char* fn = FS_BuildOSPath( base, gamedir, filename );
void* libHandle = dlopen( fn, RTLD_NOW );
if (!libHandle) {
Com_Printf( "Sys_LoadDll(%s) failed: %s\n", fn, Sys_DllError() );
return NULL;
}
Com_Printf( "Sys_LoadDll(%s) succeeded\n", fn );
return libHandle;
}
// used to load a development dll instead of a virtual machine
// in release builds, the load procedure matches the VFS logic (fs_homepath, then fs_basepath)
// in debug builds, the current working directory is tried first
void* QDECL Sys_LoadDll( const char* name, dllSyscall_t *entryPoint, dllSyscall_t systemcalls )
{
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "%s" ARCH_STRING DLL_EXT, name );
void* libHandle = 0;
// FIXME: use fs_searchpaths from files.c
const char* homepath = Cvar_VariableString( "fs_homepath" );
const char* basepath = Cvar_VariableString( "fs_basepath" );
const char* gamedir = Cvar_VariableString( "fs_game" );
#ifndef NDEBUG
libHandle = try_dlopen( Sys_Cwd(), gamedir, filename );
#endif
if (!libHandle && homepath)
libHandle = try_dlopen( homepath, gamedir, filename );
if (!libHandle && basepath)
libHandle = try_dlopen( basepath, gamedir, filename );
if ( !libHandle )
return NULL;
dllEntry_t dllEntry = (dllEntry_t)dlsym( libHandle, "dllEntry" );
*entryPoint = (dllSyscall_t)dlsym( libHandle, "vmMain" );
if ( !*entryPoint || !dllEntry ) {
const char* err = Sys_DllError();
Com_Printf( "Sys_LoadDll(%s) failed dlsym: %s\n", name, err );
Sys_UnloadDll( libHandle );
return NULL;
}
dllEntry( systemcalls );
return libHandle;
}
#ifdef DEDICATED
char *Sys_GetClipboardData(void)
{
return NULL;
}
#endif
void Sys_Init()
{
Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
}
qbool Sys_HardReboot()
{
#ifdef DEDICATED
return qtrue;
#else
return qfalse;
#endif
}
#ifdef DEDICATED
static int Lin_RunProcess( char** argv )
{
const pid_t pid = fork();
if (pid == 0) {
if (execve(argv[0], argv , NULL) == -1) {
fprintf(stderr, "failed to launch child process: %s\n", strerror(errno));
_exit(1); // quit without calling atexit handlers
return 0;
}
}
int status;
while (waitpid(pid, &status, WNOHANG) == 0)
sleep(1); // in seconds
return WEXITSTATUS(status);
}
void Lin_HardRebootHandler( int argc, char** argv )
{
for (int i = 0; i < argc; ++i) {
if (!Q_stricmp(argv[i], "nohardreboot")) {
return;
}
}
static char* args[256];
if (argc + 2 >= sizeof(args) / sizeof(args[0])) {
fprintf(stderr, "too many arguments: %d\n", argc);
_exit(1); // quit without calling atexit handlers
return;
}
for (int i = 0; i < argc; ++i)
args[i] = argv[i];
args[argc + 0] = (char*)"nohardreboot";
args[argc + 1] = NULL;
SIG_InitParent();
for (;;) {
if (Lin_RunProcess(args) == 0)
_exit(0); // quit without calling atexit handlers
}
}
#endif
static qbool lin_hasParent = qfalse;
static pid_t lix_parentPid;
static const char* Lin_GetExeName(const char* path)
{
const char* lastSlash = strrchr(path, '/');
if (lastSlash == NULL)
return path;
return lastSlash + 1;
}
void Lin_TrackParentProcess()
{
static char cmdLine[1024];
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%d/cmdline", (int)getppid());
const int fd = open(fileName, O_RDONLY);
if (fd == -1)
return;
const qbool hasCmdLine = read(fd, cmdLine, sizeof(cmdLine)) > 0;
close(fd);
if (!hasCmdLine)
return;
cmdLine[sizeof(cmdLine) - 1] = '\0';
lin_hasParent = strcmp(Lin_GetExeName(cmdLine), Lin_GetExeName(q_argv[0])) == 0;
}
qbool Sys_HasCNQ3Parent()
{
return lin_hasParent;
}
static int Sys_GetProcessUptime( pid_t pid )
{
// length must be in sync with the fscanf call!
static char word[256];
// The process start time is the 22nd column and
// encoded as jiffies after system boot.
const int jiffiesPerSec = sysconf(_SC_CLK_TCK);
if (jiffiesPerSec <= 0)
return -1;
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%ld/stat", (long)pid);
FILE* const file = fopen(fileName, "r");
if (file == NULL)
return -1;
for (int i = 0; i < 21; ++i) {
if (fscanf(file, "%255s", word) != 1) {
fclose(file);
return -1;
}
}
int jiffies;
const qbool success = fscanf(file, "%d", &jiffies) == 1;
fclose(file);
if (!success)
return -1;
const int secondsSinceBoot = jiffies / jiffiesPerSec;
struct sysinfo info;
sysinfo(&info);
return (int)info.uptime - secondsSinceBoot;
}
int Sys_GetUptimeSeconds( qbool parent )
{
if (!lin_hasParent)
return -1;
return Sys_GetProcessUptime( parent ? getppid() : getpid() );
}
void Sys_LoadHistory()
{
#ifdef DEDICATED
History_LoadFromFile( tty_GetHistory() );
#else
History_LoadFromFile( &g_history );
#endif
}
void Sys_SaveHistory()
{
#ifdef DEDICATED
History_SaveToFile( tty_GetHistory() );
#else
History_SaveToFile( &g_history );
#endif
}
int Sys_Milliseconds()
{
static int sys_timeBase = 0;
struct timeval tv;
gettimeofday( &tv, NULL );
if (!sys_timeBase) {
sys_timeBase = tv.tv_sec;
return tv.tv_usec/1000;
}
return ((tv.tv_sec - sys_timeBase)*1000 + tv.tv_usec/1000);
}
void Sys_Mkdir( const char* path )
{
mkdir( path, 0777 );
}
#define MAX_FOUND_FILES 0x1000
// bk001129 - new in 1.26
static void Sys_ListFilteredFiles( const char *basedir, const char *subdirs, const char *filter, char **list, int *numfiles ) {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
DIR *fdir;
struct dirent *d;
struct stat st;
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
return;
}
if (strlen(subdirs)) {
Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
}
else {
Com_sprintf( search, sizeof(search), "%s", basedir );
}
if ((fdir = opendir(search)) == NULL) {
return;
}
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
if (stat(filename, &st) == -1)
continue;
if (st.st_mode & S_IFDIR) {
if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
if (strlen(subdirs)) {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
}
else {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
break;
}
Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
if (!Com_FilterPath( filter, filename ))
continue;
list[ *numfiles ] = CopyString( filename );
(*numfiles)++;
}
closedir(fdir);
}
char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qboolean wantsubs )
{
struct dirent *d;
DIR *fdir;
qboolean dironly = wantsubs;
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
int i;
struct stat st;
int extLen;
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = NULL;
*numfiles = nfiles;
if (!nfiles)
return NULL;
listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
if ( !extension)
extension = "";
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
dironly = qtrue;
}
extLen = strlen( extension );
// search
nfiles = 0;
if ((fdir = opendir(directory)) == NULL) {
*numfiles = 0;
return NULL;
}
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
if (stat(search, &st) == -1)
continue;
if ((dironly && !(st.st_mode & S_IFDIR)) ||
(!dironly && (st.st_mode & S_IFDIR)))
continue;
if (*extension) {
if ( strlen( d->d_name ) < strlen( extension ) ||
Q_stricmp(
d->d_name + strlen( d->d_name ) - strlen( extension ),
extension ) ) {
continue; // didn't match
}
}
if ( nfiles == MAX_FOUND_FILES - 1 )
break;
list[ nfiles ] = CopyString( d->d_name );
nfiles++;
}
list[ nfiles ] = NULL;
closedir(fdir);
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
void Sys_FreeFileList( char **list ) {
int i;
if ( !list ) {
return;
}
for ( i = 0 ; list[i] ; i++ ) {
Z_Free( list[i] );
}
Z_Free( list );
}
const char* Sys_Cwd()
{
static char cwd[MAX_OSPATH];
getcwd( cwd, sizeof( cwd ) - 1 );
cwd[MAX_OSPATH-1] = 0;
return cwd;
}
const char* Sys_DefaultHomePath()
{
// Used to determine where to store user-specific files
static char homePath[MAX_OSPATH];
if (*homePath)
return homePath;
const char* p;
if (p = getenv("HOME")) {
Q_strncpyz(homePath, p, sizeof(homePath));
#ifdef MACOS_X
Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3");
#else
Q_strcat(homePath, sizeof(homePath), "/.q3a");
#endif
if (mkdir(homePath, 0777)) {
if (errno != EEXIST)
Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno);
}
return homePath;
}
return ""; // assume current dir
}
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
{
}
#define MAX_QUED_EVENTS 512
#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
static sysEvent_t eventQue[MAX_QUED_EVENTS];
static int eventHead, eventTail;
// a time of 0 will get the current time
// ptr should either be null, or point to a block of data that can be freed by the game later
void Lin_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr )
{
sysEvent_t* ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
Com_Printf("Sys_QueEvent: overflow\n");
// we are discarding an event, but don't leak memory
if ( ev->evPtr )
Z_Free( ev->evPtr );
++eventTail;
}
++eventHead;
if ( time == 0 )
time = Sys_Milliseconds();
ev->evTime = time;
ev->evType = type;
ev->evValue = value;
ev->evValue2 = value2;
ev->evPtrLength = ptrLength;
ev->evPtr = ptr;
}
sysEvent_t Sys_GetEvent()
{
// return if we have data
if ( eventHead > eventTail ) {
++eventTail;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// check for console commands
const char* s = Lin_ConsoleInput();
if ( s ) {
const int slen = strlen( s );
const int blen = slen + 1;
char* b = (char*)Z_Malloc( blen );
Q_strncpyz( b, s, blen );
Lin_QueEvent( 0, SE_CONSOLE, 0, 0, slen, b );
}
#ifndef DEDICATED
sdl_PollEvents();
#endif
// check for network packets
msg_t netmsg;
netadr_t adr;
static byte sys_packetReceived[MAX_MSGLEN]; // static or it'll blow half the stack
MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
if ( Sys_GetPacket( &adr, &netmsg ) ) {
// copy out to a separate buffer for queuing
int len = sizeof( netadr_t ) + netmsg.cursize;
netadr_t* buf = (netadr_t*)Z_Malloc( len );
*buf = adr;
memcpy( buf+1, netmsg.data, netmsg.cursize );
Lin_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
}
// return if we have data
if ( eventHead > eventTail ) {
++eventTail;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// create an empty event to return
sysEvent_t ev;
memset( &ev, 0, sizeof( ev ) );
ev.evTime = Sys_Milliseconds();
return ev;
}

View file

@ -21,7 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <signal.h>
#include <execinfo.h>
#include <backtrace.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@ -263,7 +262,7 @@ static void Sig_PrintSignalCaught(int sig)
static void Sig_HandleExit()
{
Sys_ConsoleInputShutdown();
Lin_ConsoleInputShutdown();
}
@ -321,7 +320,7 @@ static void Sig_HandleCrash(int sig)
//
Sig_PrintAttempt("restore tty settings");
Sys_ConsoleInputShutdown();
Lin_ConsoleInputShutdown();
Sig_PrintDone();
Sig_PrintAttempt("write JSON report");

View file

@ -19,51 +19,24 @@ along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <string.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <errno.h>
#include <dlfcn.h>
#if defined(__sun)
#include <sys/file.h>
#endif
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include "../client/client.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "linux_local.h"
///////////////////////////////////////////////////////////////
int q_argc = 0;
char** q_argv = NULL;
static qboolean stdin_active = qtrue;
static qbool stdin_active = qtrue;
// enable/disable tty input mode
// NOTE TTimo this is used during startup, cannot be changed during run
static cvar_t *ttycon = NULL;
// general flag to tell about tty console mode
static qboolean ttycon_on = qfalse;
static qbool ttycon_on = qfalse;
// when printing general stuff to stdout stderr (Sys_Printf)
// we need to disable the tty console stuff
// this increments so we can recursively disable
@ -114,7 +87,7 @@ static void tty_Back()
// clear the display of the line currently edited
// bring cursor back to beginning of line
static void tty_Hide()
void tty_Hide()
{
assert(ttycon_on);
if (ttycon_hide)
@ -166,7 +139,7 @@ static void tty_Show()
// initialize the console input (tty mode if wanted and possible)
static void Sys_ConsoleInputInit()
void Lin_ConsoleInputInit()
{
struct termios tc;
@ -222,7 +195,7 @@ static void Sys_ConsoleInputInit()
}
const char* Sys_ConsoleInput()
const char* Lin_ConsoleInput()
{
// we use this when sending back commands
static char text[256];
@ -470,7 +443,7 @@ const char* Sys_ConsoleInput()
// never exit without calling this, or your terminal will be left in a pretty bad state
void Sys_ConsoleInputShutdown()
void Lin_ConsoleInputShutdown()
{
if (ttycon_on)
{
@ -484,237 +457,6 @@ void Sys_ConsoleInputShutdown()
}
///////////////////////////////////////////////////////////////
#define MEM_THRESHOLD 96*1024*1024
qboolean Sys_LowPhysicalMemory()
{
return qfalse; // FIXME
}
void Sys_Error( const char *error, ... )
{
va_list argptr;
char string[1024];
if (ttycon_on)
tty_Hide();
#ifndef DEDICATED
CL_Shutdown();
#endif
va_start (argptr,error);
vsprintf (string,error,argptr);
va_end (argptr);
fprintf(stderr, "Sys_Error: %s\n", string);
Sys_ConsoleInputShutdown();
exit(1);
}
void Sys_Quit( int status )
{
Sys_ConsoleInputShutdown();
exit( status );
}
///////////////////////////////////////////////////////////////
const char* Sys_DllError()
{
return dlerror();
}
void Sys_UnloadDll( void* dllHandle )
{
if ( !dllHandle )
return;
dlclose( dllHandle );
const char* err = Sys_DllError();
if ( err ) {
Com_Error( ERR_FATAL, "Sys_UnloadDll failed: %s\n", err );
}
}
static void* try_dlopen( const char* base, const char* gamedir, const char* filename )
{
const char* fn = FS_BuildOSPath( base, gamedir, filename );
void* libHandle = dlopen( fn, RTLD_NOW );
if (!libHandle) {
Com_Printf( "Sys_LoadDll(%s) failed: %s\n", fn, Sys_DllError() );
return NULL;
}
Com_Printf( "Sys_LoadDll(%s) succeeded\n", fn );
return libHandle;
}
// used to load a development dll instead of a virtual machine
// in release builds, the load procedure matches the VFS logic (fs_homepath, then fs_basepath)
// in debug builds, the current working directory is tried first
void* QDECL Sys_LoadDll( const char* name, dllSyscall_t *entryPoint, dllSyscall_t systemcalls )
{
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "%s" ARCH_STRING DLL_EXT, name );
void* libHandle = 0;
// FIXME: use fs_searchpaths from files.c
const char* homepath = Cvar_VariableString( "fs_homepath" );
const char* basepath = Cvar_VariableString( "fs_basepath" );
const char* gamedir = Cvar_VariableString( "fs_game" );
#ifndef NDEBUG
libHandle = try_dlopen( Sys_Cwd(), gamedir, filename );
#endif
if (!libHandle && homepath)
libHandle = try_dlopen( homepath, gamedir, filename );
if (!libHandle && basepath)
libHandle = try_dlopen( basepath, gamedir, filename );
if ( !libHandle )
return NULL;
dllEntry_t dllEntry = (dllEntry_t)dlsym( libHandle, "dllEntry" );
*entryPoint = (dllSyscall_t)dlsym( libHandle, "vmMain" );
if ( !*entryPoint || !dllEntry ) {
const char* err = Sys_DllError();
Com_Printf( "Sys_LoadDll(%s) failed dlsym: %s\n", name, err );
Sys_UnloadDll( libHandle );
return NULL;
}
dllEntry( systemcalls );
return libHandle;
}
/*
========================================================================
EVENT LOOP
========================================================================
*/
#define MAX_QUED_EVENTS 512
#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
static sysEvent_t eventQue[MAX_QUED_EVENTS];
static int eventHead, eventTail;
// a time of 0 will get the current time
// ptr should either be null, or point to a block of data that can be freed by the game later
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr )
{
sysEvent_t* ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
Com_Printf("Sys_QueEvent: overflow\n");
// we are discarding an event, but don't leak memory
if ( ev->evPtr )
Z_Free( ev->evPtr );
++eventTail;
}
++eventHead;
if ( time == 0 )
time = Sys_Milliseconds();
ev->evTime = time;
ev->evType = type;
ev->evValue = value;
ev->evValue2 = value2;
ev->evPtrLength = ptrLength;
ev->evPtr = ptr;
}
sysEvent_t Sys_GetEvent()
{
// return if we have data
if ( eventHead > eventTail ) {
++eventTail;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
#ifndef DEDICATED
// pump the message loop
// in vga this calls KBD_Update, under X, it calls GetEvent
Sys_SendKeyEvents();
#endif
// check for console commands
const char* s = Sys_ConsoleInput();
if ( s ) {
const int slen = strlen( s );
const int blen = slen + 1;
char* b = (char*)Z_Malloc( blen );
Q_strncpyz( b, s, blen );
Sys_QueEvent( 0, SE_CONSOLE, 0, 0, slen, b );
}
#ifndef DEDICATED
// check for other input devices
IN_Frame();
#endif
// check for network packets
msg_t netmsg;
netadr_t adr;
static byte sys_packetReceived[MAX_MSGLEN]; // static or it'll blow half the stack
MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
if ( Sys_GetPacket( &adr, &netmsg ) ) {
// copy out to a separate buffer for queuing
int len = sizeof( netadr_t ) + netmsg.cursize;
netadr_t* buf = (netadr_t*)Z_Malloc( len );
*buf = adr;
memcpy( buf+1, netmsg.data, netmsg.cursize );
Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
}
// return if we have data
if ( eventHead > eventTail ) {
++eventTail;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// create an empty event to return
sysEvent_t ev;
memset( &ev, 0, sizeof( ev ) );
ev.evTime = Sys_Milliseconds();
return ev;
}
///////////////////////////////////////////////////////////////
char *Sys_GetClipboardData(void)
{
return NULL;
}
static struct Q3ToAnsiColorTable_s
{
char Q3color;
@ -734,7 +476,7 @@ static struct Q3ToAnsiColorTable_s
static const int tty_colorTableSize = sizeof( tty_colorTable ) / sizeof( tty_colorTable[0] );
static void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize )
static void ANSIColorify( const char *msg, char *buffer, int bufferSize )
{
int msgLength, pos;
int i, j;
@ -810,7 +552,7 @@ static char* CleanTermStr( char* string )
}
void Sys_Print( const char *msg )
void Sys_Print( const char *msg )
{
static char finalMsg[ MAXPRINTMSG ];
@ -821,7 +563,7 @@ void Sys_Print( const char *msg )
if( ttycon_on && ttycon_ansicolor && ttycon_ansicolor->integer )
{
Sys_ANSIColorify( msg, finalMsg, sizeof(finalMsg) );
ANSIColorify( msg, finalMsg, sizeof(finalMsg) );
}
else
{
@ -836,226 +578,12 @@ void Sys_Print( const char *msg )
}
}
///////////////////////////////////////////////////////////////
void Sys_Init()
qbool tty_Enabled()
{
Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
return ttycon_on;
}
qbool Sys_HardReboot()
history_t* tty_GetHistory()
{
#ifdef DEDICATED
return qtrue;
#else
return qfalse;
#endif
return &tty_history;
}
#ifdef DEDICATED
static int Lin_RunProcess( char** argv )
{
const pid_t pid = fork();
if (pid == 0) {
if (execve(argv[0], argv , NULL) == -1) {
fprintf(stderr, "failed to launch child process: %s\n", strerror(errno));
_exit(1); // quit without calling atexit handlers
return 0;
}
}
int status;
while (waitpid(pid, &status, WNOHANG) == 0)
sleep(1); // in seconds
return WEXITSTATUS(status);
}
static void Lin_HardRebootHandler( int argc, char** argv )
{
for (int i = 0; i < argc; ++i) {
if (!Q_stricmp(argv[i], "nohardreboot")) {
return;
}
}
static char* args[256];
if (argc + 2 >= sizeof(args) / sizeof(args[0])) {
fprintf(stderr, "too many arguments: %d\n", argc);
_exit(1); // quit without calling atexit handlers
return;
}
for (int i = 0; i < argc; ++i)
args[i] = argv[i];
args[argc + 0] = (char*)"nohardreboot";
args[argc + 1] = NULL;
SIG_InitParent();
for (;;) {
if (Lin_RunProcess(args) == 0)
_exit(0); // quit without calling atexit handlers
}
}
#endif
static qbool lin_hasParent = qfalse;
static pid_t lix_parentPid;
static const char* Lin_GetExeName(const char* path)
{
const char* lastSlash = strrchr(path, '/');
if (lastSlash == NULL)
return path;
return lastSlash + 1;
}
static void Lin_TrackParentProcess()
{
static char cmdLine[1024];
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%d/cmdline", (int)getppid());
const int fd = open(fileName, O_RDONLY);
if (fd == -1)
return;
const qbool hasCmdLine = read(fd, cmdLine, sizeof(cmdLine)) > 0;
close(fd);
if (!hasCmdLine)
return;
cmdLine[sizeof(cmdLine) - 1] = '\0';
lin_hasParent = strcmp(Lin_GetExeName(cmdLine), Lin_GetExeName(q_argv[0])) == 0;
}
qbool Sys_HasCNQ3Parent()
{
return lin_hasParent;
}
static int Sys_GetProcessUptime( pid_t pid )
{
// length must be in sync with the fscanf call!
static char word[256];
// The process start time is the 22nd column and
// encoded as jiffies after system boot.
const int jiffiesPerSec = sysconf(_SC_CLK_TCK);
if (jiffiesPerSec <= 0)
return -1;
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%ld/stat", (long)pid);
FILE* const file = fopen(fileName, "r");
if (file == NULL)
return -1;
for (int i = 0; i < 21; ++i) {
if (fscanf(file, "%255s", word) != 1) {
fclose(file);
return -1;
}
}
int jiffies;
const qbool success = fscanf(file, "%d", &jiffies) == 1;
fclose(file);
if (!success)
return -1;
const int secondsSinceBoot = jiffies / jiffiesPerSec;
struct sysinfo info;
sysinfo(&info);
return (int)info.uptime - secondsSinceBoot;
}
int Sys_GetUptimeSeconds( qbool parent )
{
if (!lin_hasParent)
return -1;
return Sys_GetProcessUptime( parent ? getppid() : getpid() );
}
void Sys_LoadHistory()
{
#ifdef DEDICATED
History_LoadFromFile( &tty_history );
#else
History_LoadFromFile( &g_history );
#endif
}
void Sys_SaveHistory()
{
#ifdef DEDICATED
History_SaveToFile( &tty_history );
#else
History_SaveToFile( &g_history );
#endif
}
int main( int argc, char** argv )
{
q_argc = argc;
q_argv = argv;
#ifdef DEDICATED
Lin_HardRebootHandler(argc, argv);
#endif
SIG_InitChild();
// merge the command line: we need it in a single chunk
int len = 1, i;
for (i = 1; i < argc; ++i)
len += strlen(argv[i]) + 1;
char* cmdline = (char*)malloc(len);
*cmdline = 0;
for (i = 1; i < argc; ++i) {
if (i > 1)
strcat( cmdline, " " );
strcat( cmdline, argv[i] );
}
Com_Init( cmdline );
NET_Init();
Com_Printf( "Working directory: %s\n", Sys_Cwd() );
Sys_ConsoleInputInit();
Lin_TrackParentProcess();
for (;;) {
SIG_Frame();
Com_Frame();
}
return 0;
}

459
code/linux/sdl_core.cpp Normal file
View file

@ -0,0 +1,459 @@
#include "linux_local.h"
#include <SDL2/SDL.h>
#include "sdl_local.h"
#include <stdlib.h>
static qbool sdl_inputActive = qfalse;
static cvar_t* in_noGrab;
static cvar_t* m_relative;
static cvar_t* s_autoMute;
static const cvarTableItem_t in_cvars[] = {
{ &in_noGrab, "in_noGrab", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "disables input grabbing" },
{ &m_relative, "m_relative", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables SDL's relative mouse mode" },
{ &s_autoMute, "s_autoMute", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", "0=never, 1=when unfocused, 2=when minimized" }
};
static void Minimize_f();
static const cmdTableItem_t in_cmds[] = {
{ "minimize", &Minimize_f, NULL, "minimizes the window" }
};
static qbool sdl_Version_AtLeast( int major, int minor, int patch )
{
SDL_version v;
SDL_GetVersion(&v);
// has to be SDL 2
if (v.major != major)
return qfalse;
if (v.minor < minor)
return qfalse;
if (v.minor > minor)
return qtrue;
return v.patch >= patch;
}
static void Minimize_f()
{
SDL_MinimizeWindow(glimp.window);
}
static int QuakeKeyFromSDLKey( SDL_Keysym key )
{
if (key.scancode == SDL_SCANCODE_GRAVE)
return '`';
const SDL_Keycode sym = key.sym;
// these ranges map directly to ASCII chars
if ((sym >= SDLK_a && sym < SDLK_z) ||
(sym >= SDLK_0 && sym < SDLK_9))
return (int)sym;
// F1 to F24
// SDL splits the values 1-12 and 13-24
// the engine splits the values 1-15 and 16-24
switch (sym) {
case SDLK_F1: return K_F1;
case SDLK_F2: return K_F2;
case SDLK_F3: return K_F3;
case SDLK_F4: return K_F4;
case SDLK_F5: return K_F5;
case SDLK_F6: return K_F6;
case SDLK_F7: return K_F7;
case SDLK_F8: return K_F8;
case SDLK_F9: return K_F9;
case SDLK_F10: return K_F10;
case SDLK_F11: return K_F11;
case SDLK_F12: return K_F12;
case SDLK_F13: return K_F13;
case SDLK_F14: return K_F14;
case SDLK_F15: return K_F15;
case SDLK_F16: return K_F16;
case SDLK_F17: return K_F17;
case SDLK_F18: return K_F18;
case SDLK_F19: return K_F19;
case SDLK_F20: return K_F20;
case SDLK_F21: return K_F21;
case SDLK_F22: return K_F22;
case SDLK_F23: return K_F23;
case SDLK_F24: return K_F24;
case SDLK_UP: return K_UPARROW;
case SDLK_DOWN: return K_DOWNARROW;
case SDLK_LEFT: return K_LEFTARROW;
case SDLK_RIGHT: return K_RIGHTARROW;
case SDLK_TAB: return K_TAB;
case SDLK_RETURN: return K_ENTER;
case SDLK_ESCAPE: return K_ESCAPE;
case SDLK_SPACE: return K_SPACE;
case SDLK_BACKSPACE: return K_BACKSPACE;
case SDLK_CAPSLOCK: return K_CAPSLOCK;
case SDLK_LALT: return K_ALT;
case SDLK_RALT: return K_ALT;
case SDLK_LCTRL: return K_CTRL;
case SDLK_RCTRL: return K_CTRL;
case SDLK_LSHIFT: return K_SHIFT;
case SDLK_RSHIFT: return K_SHIFT;
case SDLK_INSERT: return K_INS;
case SDLK_DELETE: return K_DEL;
case SDLK_PAGEDOWN: return K_PGDN;
case SDLK_PAGEUP: return K_PGUP;
case SDLK_HOME: return K_HOME;
case SDLK_END: return K_END;
case SDLK_KP_7: return K_KP_HOME;
case SDLK_KP_8: return K_KP_UPARROW;
case SDLK_KP_9: return K_KP_PGUP;
case SDLK_KP_4: return K_KP_LEFTARROW;
case SDLK_KP_5: return K_KP_5;
case SDLK_KP_6: return K_KP_RIGHTARROW;
case SDLK_KP_1: return K_KP_END;
case SDLK_KP_2: return K_KP_DOWNARROW;
case SDLK_KP_3: return K_KP_PGDN;
case SDLK_KP_ENTER: return K_KP_ENTER;
case SDLK_KP_0: return K_KP_INS;
case SDLK_KP_DECIMAL: return K_KP_DEL;
case SDLK_KP_DIVIDE: return K_KP_SLASH;
case SDLK_KP_MINUS: return K_KP_MINUS;
case SDLK_KP_PLUS: return K_KP_PLUS;
case SDLK_KP_MULTIPLY: return K_KP_STAR;
case SDLK_BACKSLASH: return K_BACKSLASH;
// missing:
// K_KP_NUMLOCK
// K_KP_EQUALS
default: return -1;
}
}
static void sdl_Key( const SDL_KeyboardEvent* event, qbool down )
{
const int key = QuakeKeyFromSDLKey(event->keysym);
if (key >= 0)
Lin_QueEvent(Sys_Milliseconds(), SE_KEY, key, down, 0, NULL);
if (down && key == K_BACKSPACE)
Lin_QueEvent(Sys_Milliseconds(), SE_CHAR, 8, 0, 0, NULL);
// ctrl+v
if (down && key == 'v' && (event->keysym.mod & KMOD_CTRL) != 0)
Lin_QueEvent(Sys_Milliseconds(), SE_CHAR, 22, 0, 0, NULL);
}
static void sdl_Text( const SDL_TextInputEvent* event )
{
// text is UTF-8 encoded but we only care for
// chars that are single-byte encoded
const byte key = (byte)event->text[0];
if (key >= 0 && key <= 0x7F)
Lin_QueEvent(Sys_Milliseconds(), SE_CHAR, (int)key, 0, 0, NULL);
}
static void sdl_MouseMotion( const SDL_MouseMotionEvent* event )
{
if (!sdl_inputActive)
return;
Lin_QueEvent(Sys_Milliseconds(), SE_MOUSE, event->xrel, event->yrel, 0, NULL);
}
static void sdl_MouseButton( const SDL_MouseButtonEvent* event, qbool down )
{
if (!sdl_inputActive && down)
return;
static const int mouseButtonCount = 5;
static const int mouseButtons[mouseButtonCount][2] = {
{ SDL_BUTTON_LEFT, K_MOUSE1 },
{ SDL_BUTTON_RIGHT, K_MOUSE2 },
{ SDL_BUTTON_MIDDLE, K_MOUSE3 },
{ SDL_BUTTON_X1, K_MOUSE4 },
{ SDL_BUTTON_X2, K_MOUSE5 }
};
int button = -1;
for(int i = 0; i < mouseButtonCount; ++i) {
if (event->button == mouseButtons[i][0]) {
button = i;
break;
}
}
if (button < 0)
return;
Lin_QueEvent(Sys_Milliseconds(), SE_KEY, mouseButtons[button][1], down, 0, NULL);
}
static void sdl_MouseWheel( const SDL_MouseWheelEvent* event )
{
if (event->y == 0)
return;
#if SDL_VERSION_ATLEAST(2, 0, 4)
int delta = event->y;
if (sdl_Version_AtLeast(2, 0, 4) &&
event->direction == SDL_MOUSEWHEEL_FLIPPED)
delta = -delta;
#else
const int delta = event->y;
#endif
const int key = (delta < 0) ? K_MWHEELDOWN : K_MWHEELUP;
Lin_QueEvent(Sys_Milliseconds(), SE_KEY, key, qtrue, 0, NULL);
Lin_QueEvent(Sys_Milliseconds(), SE_KEY, key, qfalse, 0, NULL);
}
static void sdl_Window( const SDL_WindowEvent* event )
{
// events of interest:
//SDL_WINDOWEVENT_SHOWN
//SDL_WINDOWEVENT_HIDDEN
//SDL_WINDOWEVENT_RESIZED
//SDL_WINDOWEVENT_SIZE_CHANGED // should prevent this from happening except on creation?
//SDL_WINDOWEVENT_MINIMIZED
//SDL_WINDOWEVENT_MAXIMIZED
//SDL_WINDOWEVENT_RESTORED
//SDL_WINDOWEVENT_ENTER // mouse focus gained
//SDL_WINDOWEVENT_LEAVE // mouse focus lost
//SDL_WINDOWEVENT_FOCUS_GAINED // kb focus gained
//SDL_WINDOWEVENT_FOCUS_LOST // kb focus lost
//SDL_WINDOWEVENT_CLOSE
switch (event->event) {
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_MOVED:
// if this turns out to be too expensive, track movement and
// only call when movement stops
sdl_UpdateMonitorIndexFromWindow();
break;
default:
break;
}
}
static void sdl_Event( const SDL_Event* event )
{
switch (event->type) {
case SDL_QUIT:
Com_Quit(0);
break;
case SDL_KEYDOWN:
sdl_Key(&event->key, qtrue);
break;
case SDL_KEYUP:
sdl_Key(&event->key, qfalse);
break;
case SDL_TEXTINPUT:
sdl_Text(&event->text);
break;
case SDL_MOUSEMOTION:
sdl_MouseMotion(&event->motion);
break;
case SDL_MOUSEBUTTONDOWN:
sdl_MouseButton(&event->button, qtrue);
break;
case SDL_MOUSEBUTTONUP:
sdl_MouseButton(&event->button, qfalse);
break;
case SDL_MOUSEWHEEL:
sdl_MouseWheel(&event->wheel);
break;
case SDL_WINDOWEVENT:
sdl_Window(&event->window);
break;
default:
break;
}
}
qbool sdl_Init()
{
atexit(SDL_Quit);
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
fprintf(stderr, "Failed to initialize SDL 2: %s\n", SDL_GetError());
return qfalse;
}
SDL_version version;
SDL_GetVersion(&version);
printf("Opened SDL %d.%d.%d\n", version.major, version.minor, version.patch);
// @TODO: investigate/test these?
// SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
// SDL_HINT_MOUSE_RELATIVE_MODE_WARP
#if SDL_VERSION_ATLEAST(2, 0, 4)
if (sdl_Version_AtLeast(2, 0, 4))
SDL_SetHintWithPriority(SDL_HINT_NO_SIGNAL_HANDLERS, "1", SDL_HINT_OVERRIDE);
#endif
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_CRITICAL);
SDL_StartTextInput();
return qtrue;
}
void sdl_InitCvarsAndCmds()
{
Cvar_RegisterArray(in_cvars, MODULE_CLIENT);
Cmd_RegisterArray(in_cmds, MODULE_CLIENT);
}
void sdl_PollEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event))
sdl_Event(&event);
}
static qbool sdl_IsInputActive()
{
if (in_noGrab->integer)
return qfalse;
const qbool hasFocus = (SDL_GetWindowFlags(glimp.window) & SDL_WINDOW_INPUT_FOCUS) != 0;
if (!hasFocus)
return qfalse;
const qbool isConsoleDown = (cls.keyCatchers & KEYCATCH_CONSOLE) != 0;
const qbool isFullScreen = Cvar_VariableIntegerValue("r_fullscreen");
if (isConsoleDown && !isFullScreen)
return qfalse;
return qtrue;
}
void sdl_Frame()
{
sdl_inputActive = sdl_IsInputActive();
sdl_PollEvents();
SDL_SetRelativeMouseMode((sdl_inputActive && m_relative->integer) ? SDL_TRUE : SDL_FALSE);
SDL_SetWindowGrab(glimp.window, sdl_inputActive ? SDL_TRUE : SDL_FALSE);
SDL_ShowCursor(sdl_inputActive ? SDL_DISABLE : SDL_ENABLE);
// @NOTE: SDL_WarpMouseInWindow generates a motion event
if (s_autoMute->integer == 1) {
const qbool hasFocus = (SDL_GetWindowFlags(glimp.window) & SDL_WINDOW_INPUT_FOCUS) != 0;
sdl_MuteAudio(!hasFocus);
} else if (s_autoMute->integer == 2) {
const Uint32 hidingFlags = SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED;
const qbool hidden = (SDL_GetWindowFlags(glimp.window) & hidingFlags) != 0;
sdl_MuteAudio(hidden);
} else {
sdl_MuteAudio(qfalse);
}
}
void Sys_InitInput()
{
}
void Sys_ShutdownInput()
{
}
// returns the number of bytes to skip
static int UTF8_ReadNextChar( char* c, const char* input )
{
if (*input == '\0')
return 0;
const byte byte0 = (byte)input[0];
if (byte0 <= 127) {
*c = (char)byte0;
return 1;
}
// Starts with 110?
if ((byte0 >> 5) == 6)
return 2;
// Starts with 1110?
if ((byte0 >> 4) == 14)
return 3;
// Starts with 11110?
if ((byte0 >> 3) == 30)
return 4;
return 0;
}
char* Sys_GetClipboardData()
{
if (SDL_HasClipboardText() == SDL_FALSE)
return NULL;
char* const textUTF8 = SDL_GetClipboardText();
if (textUTF8 == NULL)
return NULL;
// the cleaned up string can only be
// as long or shorter
char* const text = (char*)Z_Malloc(strlen(textUTF8) + 1);
if (text == NULL) {
SDL_free(textUTF8);
return NULL;
}
// clean up the text so we're sure
// the console can display it
char* d = text;
const char* s = textUTF8;
for (;;) {
char c;
const int bytes = UTF8_ReadNextChar(&c, s);
if (bytes == 0) {
*d = '\0';
break;
}
if (c >= 0x20 && c <= 0x7E)
*d++ = c;
s += bytes;
}
SDL_free(textUTF8);
return text;
}

292
code/linux/sdl_glimp.cpp Normal file
View file

@ -0,0 +1,292 @@
#include "linux_local.h"
#include "../renderer/tr_local.h"
#include "../renderer/qgl.h"
#include <SDL2/SDL.h>
#include "sdl_local.h"
glImp_t glimp;
cvar_t* r_fullscreen;
static cvar_t* r_monitor; // 1-based, 0 means use primary monitor
static const cvarTableItem_t glimp_cvars[] = {
{ &r_fullscreen, "r_fullscreen", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "full-screen mode" },
{ &r_monitor, "r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", NULL, "1-based monitor index, 0=primary" }
};
static void sdl_PrintMonitorList();
static const cmdTableItem_t glimp_cmds[] = {
{ "monitorlist", &sdl_PrintMonitorList, NULL, "prints the list of monitors" }
};
static qbool sdl_IsMonitorListValid()
{
const int count = glimp.monitorCount;
const int curr = glimp.monitor;
const int prim = glimp.primaryMonitor;
return
count >= 1 &&
curr >= 0 &&
curr < count &&
prim >= 0 &&
prim < count &&
glimp.monitorRects[prim].x == 0 &&
glimp.monitorRects[prim].y == 0;
}
static void sdl_CreateMonitorList()
{
const int count = SDL_GetNumVideoDisplays();
if (count <= 0) {
glimp.monitorCount = 0;
return;
}
int gi = 0;
for (int si = 0; si < count; ++si) {
if (gi >= MAX_MONITOR_COUNT)
break;
if (SDL_GetDisplayBounds(si, &glimp.monitorRects[gi]) == 0)
++gi;
}
glimp.monitorCount = gi;
glimp.primaryMonitor = -1;
const int finalCount = glimp.monitorCount;
for(int i = 0; i < finalCount; ++i) {
const SDL_Rect rect = glimp.monitorRects[i];
if (rect.x == 0 && rect.y == 0) {
glimp.primaryMonitor = i;
break;
}
}
if (!sdl_IsMonitorListValid())
glimp.monitorCount = 0;
}
// call this before creating the window
static void sdl_UpdateMonitorIndexFromCvar()
{
if (glimp.monitorCount <= 0)
return;
const int monitor = Cvar_Get("r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH)->integer;
if (monitor <= 0 || monitor > glimp.monitorCount) {
glimp.monitor = glimp.primaryMonitor;
return;
}
glimp.monitor = Com_ClampInt(0, glimp.monitorCount - 1, monitor - 1);
}
// call this after the window has been moved
void sdl_UpdateMonitorIndexFromWindow()
{
if (glimp.monitorCount <= 0)
return;
// update the glimp index
const int current = SDL_GetWindowDisplayIndex(glimp.window);
if (current < 0) {
glimp.monitorCount = 0;
return;
}
glimp.monitor = current;
// update the cvar index
if( r_monitor->integer == 0 &&
glimp.monitor == glimp.primaryMonitor)
return;
Cvar_Set("r_monitor", va("%d", glimp.monitor + 1));
}
static void sdl_GetSafeDesktopRect( SDL_Rect* rect )
{
if (glimp.monitorCount <= 0 ||
glimp.monitor < 0 ||
glimp.monitor >= glimp.monitorCount) {
rect->x = 0;
rect->y = 0;
rect->w = 1280;
rect->h = 720;
}
*rect = glimp.monitorRects[glimp.monitor];
}
static void sdl_PrintMonitorList()
{
const int count = glimp.monitorCount;
Com_Printf("Monitor count: %d\n", count);
for (int i = 0; i < count; ++i) {
const SDL_Rect rect = glimp.monitorRects[i];
Com_Printf("Monitor #%d: %d,%d %dx%d\n", i + 1, rect.x, rect.y, rect.w, rect.h);
}
}
// @TODO: this should be handled by the renderer, not the platform layer!
static void GLW_InitExtensions()
{
ri.Printf(PRINT_ALL, "Initializing OpenGL extensions\n");
int maxAnisotropy = 0;
if (strstr(glConfig.extensions_string, "GL_EXT_texture_filter_anisotropic")) {
if (r_ext_max_anisotropy->integer > 1) {
qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
if (maxAnisotropy <= 0) {
ri.Printf(PRINT_DEVELOPER, "...GL_EXT_texture_filter_anisotropic not properly supported!\n");
maxAnisotropy = 0;
} else {
ri.Printf(PRINT_DEVELOPER, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy);
}
} else {
ri.Printf(PRINT_DEVELOPER, "...ignoring GL_EXT_texture_filter_anisotropic\n");
}
} else {
ri.Printf(PRINT_DEVELOPER, "...GL_EXT_texture_filter_anisotropic not found\n");
}
Cvar_Set("r_ext_max_anisotropy", va("%i", maxAnisotropy));
}
void GLimp_Init()
{
if (glimp.window != NULL)
return;
Cvar_RegisterArray(glimp_cvars, MODULE_CLIENT);
Cmd_RegisterArray(glimp_cmds, MODULE_CLIENT);
sdl_CreateMonitorList();
sdl_UpdateMonitorIndexFromCvar();
sdl_PrintMonitorList();
SDL_Rect deskropRect;
sdl_GetSafeDesktopRect(&deskropRect);
const qbool desktopRes = !R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect);
if (desktopRes) {
glConfig.vidWidth = deskropRect.w;
glConfig.vidHeight = deskropRect.h;
glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight;
}
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
if (r_fullscreen->integer) {
if (desktopRes)
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
else
windowFlags |= SDL_WINDOW_FULLSCREEN;
}
// @TODO: make a cvar defaulting to an empty string for this? e.g. value: "libGL.so.1"
if (SDL_GL_LoadLibrary(NULL) < 0)
ri.Error(ERR_FATAL, "GLimp_Init - SDL_GL_LoadLibrary failed: %s\n", SDL_GetError());
glimp.window = SDL_CreateWindow("CNQ3", deskropRect.x, deskropRect.y, glConfig.vidWidth, glConfig.vidHeight, windowFlags);
if (glimp.window == NULL)
ri.Error(ERR_FATAL, "GLimp_Init - SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
glimp.glContext = SDL_GL_CreateContext(glimp.window);
if (glimp.glContext == NULL)
ri.Error(ERR_FATAL, "GLimp_Init - SDL_GL_CreateContext failed: %s\n", SDL_GetError());
glConfig.colorBits = 32;
glConfig.depthBits = 24;
glConfig.stencilBits = 8;
if (SDL_GL_MakeCurrent(glimp.window, glimp.glContext) < 0)
ri.Error(ERR_FATAL, "GLimp_Init - SDL_GL_MakeCurrent failed: %s\n", SDL_GetError());
if (!QGL_Init(NULL))
ri.Error(ERR_FATAL, "GLimp_Init - failed to initialize core OpenGL\n");
GLW_InitExtensions();
if (!GLW_InitGL2())
ri.Error(ERR_FATAL, "GLimp_Init - could not find or initialize a suitable OpenGL 2+ subsystem\n");
GLW_InitGL3();
if (!QGL_InitGL2())
ri.Error(ERR_FATAL, "GLimp_Init - could not initialize OpenGL 2 objects\n");
SDL_GL_SetSwapInterval(r_swapInterval->integer);
ri.Printf(PRINT_ALL, "Loaded OpenGL %s\n", (const char*)qglGetString(GL_VERSION));
}
void GLimp_Shutdown()
{
if (glimp.glContext != NULL) {
SDL_GL_DeleteContext(glimp.glContext);
glimp.glContext = NULL;
}
if (glimp.window != NULL) {
SDL_DestroyWindow(glimp.window);
glimp.window = NULL;
}
SDL_GL_UnloadLibrary();
QGL_Shutdown();
memset(&glConfig, 0, sizeof(glConfig));
memset(&glState, 0, sizeof(glState));
}
void GLimp_EndFrame()
{
if (r_swapInterval->modified) {
r_swapInterval->modified = qfalse;
SDL_GL_SetSwapInterval(r_swapInterval->integer);
}
SDL_GL_SwapWindow(glimp.window);
}
qbool GLimp_SpawnRenderThread( void (*function)() )
{
return qfalse;
}
void* GLimp_RendererSleep()
{
return NULL;
}
void GLimp_FrontEnderSleep()
{
}
void GLimp_WakeRenderer( void* data )
{
}

18
code/linux/sdl_local.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#define MAX_MONITOR_COUNT 16
struct glImp_t {
SDL_Window* window;
SDL_GLContext glContext;
SDL_Rect monitorRects[MAX_MONITOR_COUNT];
int monitorCount;
int primaryMonitor; // primary monitor, 0-based
int monitor; // current monitor, 0-based
};
extern glImp_t glimp;

170
code/linux/sdl_snd.cpp Normal file
View file

@ -0,0 +1,170 @@
#include "../qcommon/q_shared.h"
#include "../client/snd_local.h"
#include <SDL2/SDL.h>
// @TODO: cvars for freq and samples?
// @TODO: cvar for the device name? ("alsa", "pulseaudio", etc)
static const int bits = 16;
static const int channels = 2;
static const int freq = 44100; // got issues with 22050 in the VM
static const int samples = 2048;
static const SDL_AudioFormat format = AUDIO_S16SYS;
struct audio_t {
qbool valid;
int q3SamplePos;
int q3Bytes;
SDL_AudioDeviceID device;
};
static audio_t audio;
static void FillAudioBufferCallback( void* userData, Uint8* sdlBuffer, int sdlBytesToWrite )
{
if (sdlBuffer == NULL || sdlBytesToWrite == 0)
return;
if (!audio.valid) {
memset(sdlBuffer, 0, sdlBytesToWrite);
return;
}
// fix up sample offset if needed
const int bytesPerSample = dma.samplebits / 8;
int q3BytePos = audio.q3SamplePos * bytesPerSample;
if (q3BytePos >= audio.q3Bytes) {
q3BytePos = 0;
audio.q3SamplePos = 0;
}
// compute the sizes for the memcpy call(s)
int q3BytesToEnd = audio.q3Bytes - q3BytePos;
int bytes1 = sdlBytesToWrite;
int bytes2 = 0;
if (bytes1 > q3BytesToEnd) {
bytes1 = q3BytesToEnd;
bytes2 = sdlBytesToWrite - q3BytesToEnd;
}
// copy the new mixed data to the device
memcpy(sdlBuffer, dma.buffer + q3BytePos, bytes1);
if (bytes2 > 0) {
memcpy(sdlBuffer + bytes1, dma.buffer, bytes2);
audio.q3SamplePos = bytes2 / bytesPerSample;
} else {
audio.q3SamplePos += bytes1 / bytesPerSample;
}
// fix up sample offset if needed
if (audio.q3SamplePos * bytesPerSample >= audio.q3Bytes)
audio.q3SamplePos = 0;
}
qbool SNDDMA_Init()
{
if (audio.valid)
return qtrue;
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
Com_Printf("SDL_Init failed: %s\n", SDL_GetError());
return qfalse;
}
// open the default audio device
SDL_AudioSpec desired;
memset(&desired, 0, sizeof(desired));
desired.freq = freq;
desired.format = format;
desired.samples = samples;
desired.channels = channels;
desired.callback = &FillAudioBufferCallback;
SDL_AudioSpec obtained;
memset(&obtained, 0, sizeof(obtained));
audio.device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
if (audio.device == 0) {
Com_Printf("SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
SNDDMA_Shutdown();
return qfalse;
}
// save all the data we need to
const int q3Samples = obtained.samples * 16;
audio.q3SamplePos = 0;
dma.samplebits = obtained.format & 0xFF;
dma.channels = obtained.channels;
dma.samples = q3Samples;
dma.submission_chunk = 1;
dma.speed = obtained.freq;
audio.q3Bytes = dma.samples * (dma.samplebits / 8);
dma.buffer = (byte*)calloc(1, audio.q3Bytes);
audio.valid = qtrue;
// opened devices are always paused by default
SDL_PauseAudioDevice(audio.device, 0);
return qtrue;
}
int SNDDMA_GetDMAPos()
{
if (!audio.valid)
return 0;
return audio.q3SamplePos;
}
void SNDDMA_Shutdown()
{
if (audio.device != 0) {
SDL_PauseAudioDevice(audio.device, 1);
SDL_CloseAudioDevice(audio.device);
audio.device = 0;
}
SDL_QuitSubSystem(SDL_INIT_AUDIO);
free(dma.buffer);
dma.buffer = NULL;
audio.q3SamplePos = 0;
audio.q3Bytes = 0;
audio.valid = qfalse;
}
void SNDDMA_Submit()
{
if (!audio.valid)
return;
// let SDL call our registered callback function again
SDL_UnlockAudioDevice(audio.device);
}
void SNDDMA_BeginPainting()
{
if (!audio.valid)
return;
// prevent SDL from calling our registered callback function
SDL_LockAudioDevice(audio.device);
}
void sdl_MuteAudio( qbool mute )
{
if (!audio.valid)
return;
const qbool playing = SDL_GetAudioDeviceStatus(audio.device) == SDL_AUDIO_PLAYING;
if (mute && playing) {
SDL_PauseAudioDevice(audio.device, 1);
} else if (!mute && !playing) {
S_ClearSoundBuffer();
SDL_PauseAudioDevice(audio.device, 0);
}
}

View file

@ -193,7 +193,7 @@ static qbool GL2_DynLights_MultitextureStage( int stage )
qglDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes );
return qtrue;
}
if ( r_fullbright->integer ) {
if ( pStage->type == ST_LIGHTMAP ) {
Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
@ -270,7 +270,7 @@ void GL2_DynLights_StageIterator()
// so color changes are ignored unless we "update" the color pointer again
qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords );
if ( pStage->mtStages ) {
// we can't really cope with massive collapses, so
assert( pStage->mtStages == 1 );
@ -282,7 +282,7 @@ void GL2_DynLights_StageIterator()
qglDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes );
}
if ( tess.fogNum && tess.shader->fogPass )
RB_FogPass();
@ -414,7 +414,7 @@ static const char* GL2_GetErrorString( GLenum ec )
CASE( GL_STACK_UNDERFLOW );
CASE( GL_STACK_OVERFLOW );
default: return "?";
}
}
}
@ -540,13 +540,16 @@ static qbool GL2_FBO_CreateMS( FrameBuffer& fb )
static qbool GL2_FBO_Init()
{
const int msaa = r_msaa->integer;
const qbool enableAA = msaa >= 2 && msaa <= 16 && qglRenderbufferStorageMultisample != NULL;
frameBufferMultiSampling = enableAA;
const qbool validOption = msaa >= 2 && msaa <= 16;
const qbool enable = validOption && qglRenderbufferStorageMultisample != NULL;
frameBufferMultiSampling = enable;
if ( validOption && !enable )
Com_Printf( "Warning: MSAA requested but disabled because glRenderbufferStorageMultisample wasn't found\n" );
if ( !enableAA )
if ( !enable )
return GL2_FBO_CreateSS( frameBuffersPostProcess[0], qtrue ) &&
GL2_FBO_CreateSS( frameBuffersPostProcess[1], qtrue );
return GL2_FBO_CreateMS( frameBufferMain ) &&
GL2_FBO_CreateSS( frameBuffersPostProcess[0], qfalse ) &&
GL2_FBO_CreateSS( frameBuffersPostProcess[1], qfalse );
@ -641,7 +644,7 @@ static void GL2_PostProcessGamma()
GL2_FBO_Swap();
GL2_FBO_Bind();
GL_Program( gammaProg );
qglUniform1i( gammaProgAttribs.texture, 0 ); // we use texture unit 0
qglUniform4f( gammaProgAttribs.gammaOverbright, gamma, gamma, gamma, obScale );
@ -694,7 +697,7 @@ static void GL2_PostProcessGreyscale()
GL2_FBO_Swap();
GL2_FBO_Bind();
GL_Program( greyscaleProg );
qglUniform1i( greyscaleProgAttribs.texture, 0 ); // we use texture unit 0
qglUniform1f( greyscaleProgAttribs.greyscale, greyscale );
@ -734,7 +737,7 @@ qbool QGL_InitGL2()
if ( !GL2_CreateProgram( dynLightProg, dynLightVS, dynLightFS ) ) {
Com_Printf( "ERROR: failed to compile dynamic light shaders\n" );
return qfalse;
return qfalse;
}
dynLightProgAttribs.osEyePos = qglGetUniformLocation( dynLightProg.p, "osEyePos" );
dynLightProgAttribs.osLightPos = qglGetUniformLocation( dynLightProg.p, "osLightPos" );
@ -751,7 +754,7 @@ qbool QGL_InitGL2()
greyscaleProgramValid = GL2_CreateProgram( greyscaleProg, greyscaleVS, greyscaleFS );
if ( greyscaleProgramValid ) {
greyscaleProgAttribs.texture = qglGetUniformLocation( greyscaleProg.p, "texture" );
greyscaleProgAttribs.greyscale = qglGetUniformLocation( greyscaleProg.p, "greyscale" );
greyscaleProgAttribs.greyscale = qglGetUniformLocation( greyscaleProg.p, "greyscale" );
} else {
Com_Printf( "ERROR: failed to compile greyscale shaders\n" );
}

File diff suppressed because it is too large Load diff

View file

@ -1,211 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/*
** linux_joystick.c
**
** This file contains ALL Linux specific stuff having to do with the
** Joystick input. When a port is being made the following functions
** must be implemented by the port:
**
** Authors: mkv, bk
**
*/
#if !USE_SDL_VIDEO
#include <linux/joystick.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h> // bk001204
#include "../client/client.h"
#include "linux_local.h"
/* We translate axes movement into keypresses. */
int joy_keys[16] = {
K_LEFTARROW, K_RIGHTARROW,
K_UPARROW, K_DOWNARROW,
K_JOY16, K_JOY17,
K_JOY18, K_JOY19,
K_JOY20, K_JOY21,
K_JOY22, K_JOY23,
K_JOY24, K_JOY25,
K_JOY26, K_JOY27
};
/* Our file descriptor for the joystick device. */
static int joy_fd = -1;
// bk001130 - from linux_glimp.c
extern cvar_t * in_joystick;
extern cvar_t * in_joystickDebug;
extern cvar_t * joy_threshold;
/**********************************************/
/* Joystick routines. */
/**********************************************/
// bk001130 - from cvs1.17 (mkv), removed from linux_glimp.c
void IN_StartupJoystick( void )
{
int i = 0;
joy_fd = -1;
if( !in_joystick->integer ) {
Com_Printf( "Joystick is not active.\n" );
return;
}
for( i = 0; i < 4; i++ ) {
char filename[MAX_OSPATH];
snprintf( filename, MAX_OSPATH, "/dev/js%d", i );
joy_fd = open( filename, O_RDONLY | O_NONBLOCK );
if( joy_fd != -1 ) {
struct js_event event;
char axes = 0;
char buttons = 0;
char name[128];
int n = -1;
Com_Printf( "Joystick %s found\n", filename );
/* Get rid of initialization messages. */
do {
n = read( joy_fd, &event, sizeof( event ) );
if( n == -1 ) {
break;
}
} while( ( event.type & JS_EVENT_INIT ) );
/* Get joystick statistics. */
ioctl( joy_fd, JSIOCGAXES, &axes );
ioctl( joy_fd, JSIOCGBUTTONS, &buttons );
if( ioctl( joy_fd, JSIOCGNAME( sizeof( name ) ), name ) < 0 ) {
strncpy( name, "Unknown", sizeof( name ) );
}
Com_Printf( "Name: %s\n", name );
Com_Printf( "Axes: %d\n", axes );
Com_Printf( "Buttons: %d\n", buttons );
/* Our work here is done. */
return;
}
}
/* No soup for you. */
if( joy_fd == -1 ) {
Com_Printf( "No joystick found.\n" );
return;
}
}
void IN_JoyMove( void )
{
/* Store instantaneous joystick state. Hack to get around
* event model used in Linux joystick driver.
*/
static int axes_state[16];
/* Old bits for Quake-style input compares. */
static unsigned int old_axes = 0;
/* Our current goodies. */
unsigned int axes = 0;
int i = 0;
if( joy_fd == -1 ) {
return;
}
/* Empty the queue, dispatching button presses immediately
* and updating the instantaneous state for the axes.
*/
do {
int n = -1;
struct js_event event;
n = read( joy_fd, &event, sizeof( event ) );
if( n == -1 ) {
/* No error, we're non-blocking. */
break;
}
if( event.type & JS_EVENT_BUTTON ) {
Sys_QueEvent( 0, SE_KEY, K_JOY1 + event.number, event.value, 0, NULL );
} else if( event.type & JS_EVENT_AXIS ) {
if( event.number >= 16 ) {
continue;
}
axes_state[event.number] = event.value;
} else {
Com_Printf( "Unknown joystick event type\n" );
}
} while( 1 );
/* Translate our instantaneous state to bits. */
for( i = 0; i < 16; i++ ) {
float f = ( (float) axes_state[i] ) / 32767.0f;
if( f < -joy_threshold->value ) {
axes |= ( 1 << ( i * 2 ) );
} else if( f > joy_threshold->value ) {
axes |= ( 1 << ( ( i * 2 ) + 1 ) );
}
}
/* Time to update axes state based on old vs. new. */
for( i = 0; i < 16; i++ ) {
if( ( axes & ( 1 << i ) ) && !( old_axes & ( 1 << i ) ) ) {
Sys_QueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL );
}
if( !( axes & ( 1 << i ) ) && ( old_axes & ( 1 << i ) ) ) {
Sys_QueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL );
}
}
/* Save for future generations. */
old_axes = axes;
}
#endif // !USE_SDL_VIDEO

View file

@ -1,294 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#if !USE_SDL_SOUND
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/wait.h>
#ifdef __linux__ // rb0101023 - guard this
#include <linux/soundcard.h>
#endif
#ifdef __FreeBSD__ // rb0101023 - added
#include <sys/soundcard.h>
#endif
#include <stdio.h>
#include "../qcommon/q_shared.h"
#include "../client/snd_local.h"
int audio_fd;
int snd_inited=0;
cvar_t *sndbits;
cvar_t *sndspeed;
cvar_t *sndchannels;
cvar_t *snddevice;
/* Some devices may work only with 48000 */
static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
static qboolean use_custom_memset = qfalse;
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
void Snd_Memset (void* dest, const int val, const size_t count)
{
int *pDest;
int i, iterate;
if (!use_custom_memset)
{
Com_Memset(dest,val,count);
return;
}
iterate = count / sizeof(int);
pDest = (int*)dest;
for(i=0; i<iterate; i++)
{
pDest[i] = val;
}
}
qboolean SNDDMA_Init(void)
{
int rc;
int fmt;
int tmp;
int i;
// char *s; // bk001204 - unused
struct audio_buf_info info;
int caps;
if (snd_inited)
return 1;
if (!snddevice) {
sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
}
// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
if (!audio_fd) {
audio_fd = open(snddevice->string, O_RDWR);
if (audio_fd < 0) {
perror(snddevice->string);
Com_Printf("Could not open %s\n", snddevice->string);
return 0;
}
}
if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
perror(snddevice->string);
Com_Printf("Sound driver too old\n");
close(audio_fd);
return 0;
}
if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) {
Com_Printf("Sorry but your soundcard can't do this\n");
close(audio_fd);
return 0;
}
/* SNDCTL_DSP_GETOSPACE moved to be called later */
// set sample bits & speed
dma.samplebits = (int)sndbits->value;
if (dma.samplebits != 16 && dma.samplebits != 8) {
ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
if (fmt & AFMT_S16_LE)
dma.samplebits = 16;
else if (fmt & AFMT_U8)
dma.samplebits = 8;
}
dma.speed = (int)sndspeed->value;
if (!dma.speed) {
for (i=0 ; i<sizeof(tryrates)/4 ; i++)
if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
break;
dma.speed = tryrates[i];
}
dma.channels = (int)sndchannels->value;
if (dma.channels < 1 || dma.channels > 2)
dma.channels = 2;
/* mmap() call moved forward */
tmp = 0;
if (dma.channels == 2)
tmp = 1;
rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
close(audio_fd);
return 0;
}
if (tmp)
dma.channels = 2;
else
dma.channels = 1;
rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
close(audio_fd);
return 0;
}
if (dma.samplebits == 16) {
rc = AFMT_S16_LE;
rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not support 16-bit data. Try 8-bit.\n");
close(audio_fd);
return 0;
}
} else if (dma.samplebits == 8) {
rc = AFMT_U8;
rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not support 8-bit data.\n");
close(audio_fd);
return 0;
}
} else {
perror(snddevice->string);
Com_Printf("%d-bit sound not supported.", dma.samplebits);
close(audio_fd);
return 0;
}
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) {
perror("GETOSPACE");
Com_Printf("Um, can't do GETOSPACE?\n");
close(audio_fd);
return 0;
}
dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
dma.submission_chunk = 1;
// memory map the dma buffer
// TTimo 2001/10/08 added PROT_READ to the mmap
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
// checking Alsa bug, doesn't allow dma alloc with PROT_READ?
if (!dma.buffer)
dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
* info.fragsize, PROT_WRITE|PROT_READ, MAP_FILE|MAP_SHARED, audio_fd, 0);
if (dma.buffer == MAP_FAILED)
{
Com_Printf("Could not mmap dma buffer PROT_WRITE|PROT_READ\n");
Com_Printf("trying mmap PROT_WRITE (with associated better compatibility / less performance code)\n");
dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
* info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
// NOTE TTimo could add a variable to force using regular memset on systems that are known to be safe
use_custom_memset = qtrue;
}
if (dma.buffer == MAP_FAILED) {
perror(snddevice->string);
Com_Printf("Could not mmap %s\n", snddevice->string);
close(audio_fd);
return 0;
}
// toggle the trigger & start her up
tmp = 0;
rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not toggle.\n");
close(audio_fd);
return 0;
}
tmp = PCM_ENABLE_OUTPUT;
rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
if (rc < 0) {
perror(snddevice->string);
Com_Printf("Could not toggle.\n");
close(audio_fd);
return 0;
}
snd_inited = 1;
return 1;
}
int SNDDMA_GetDMAPos(void)
{
struct count_info count;
if (!snd_inited) return 0;
if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
perror(snddevice->string);
Com_Printf("Uh, sound dead.\n");
close(audio_fd);
snd_inited = 0;
return 0;
}
return count.ptr / (dma.samplebits / 8);
}
void SNDDMA_Shutdown(void)
{
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
===============
*/
void SNDDMA_Submit(void)
{
}
void SNDDMA_BeginPainting (void)
{
}
#endif // !USE_SDL_SOUND

View file

@ -1,362 +0,0 @@
#if USE_SDL_SOUND
/*
* SDL implementation for Quake 3: Arena's GPL source release.
*
* This is a replacement of the Linux/OpenSoundSystem code with
* an SDL backend, since it allows us to trivially point just about any
* existing 2D audio backend known to man on any platform at the code,
* plus it benefits from all of SDL's tapdancing to support buggy drivers,
* etc, and gets us free ALSA support, too.
*
* This is the best idea for a direct modernization of the Linux sound code
* in Quake 3. However, it would be nice to replace this with true 3D
* positional audio, compliments of OpenAL...
*
* Written by Ryan C. Gordon (icculus@icculus.org). Please refer to
* http://icculus.org/quake3/ for the latest version of this code.
*
* Patches and comments are welcome at the above address.
*
* I cut-and-pasted this from linux_snd.c, and moved it to SDL line-by-line.
* There is probably some cruft that could be removed here.
*
* You should define USE_SDL=1 and then add this to the makefile.
* USE_SDL will disable the Open Sound System target.
*/
/*
Original copyright on Q3A sources:
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <stdlib.h>
#include <stdio.h>
#include "SDL.h"
#include "../qcommon/q_shared.h"
#include "../client/snd_local.h"
qboolean snd_inited = qfalse;
cvar_t *s_sdlBits;
cvar_t *s_sdlSpeed;
cvar_t *s_sdlChannels;
cvar_t *s_sdlDevSamps;
cvar_t *s_sdlMixSamps;
static qboolean use_custom_memset = qfalse;
/*
===============
Snd_Memset
https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
<TTimo> some shitty mess with DMA buffers
<TTimo> the mmap'ing permissions were write only
<TTimo> and glibc optimized for mmx would do memcpy with a prefetch and a read
<TTimo> causing segfaults
<TTimo> some other systems would not let you mmap the DMA with read permissions
<TTimo> so I think I ended up attempting opening with read/write, then try write only
<TTimo> and use my own copy instead of the glibc crap
===============
*/
#ifdef Snd_Memset
#undef Snd_Memset
#endif
void Snd_Memset (void* dest, const int val, const size_t count)
{
int *pDest;
int i, iterate;
if (!use_custom_memset)
{
Com_Memset(dest,val,count);
return;
}
iterate = count / sizeof(int);
pDest = (int*)dest;
for(i=0; i<iterate; i++)
{
pDest[i] = val;
}
}
/* The audio callback. All the magic happens here. */
static int dmapos = 0;
static int dmasize = 0;
/*
===============
sdl_audio_callback
===============
*/
static void sdl_audio_callback(void *userdata, Uint8 *stream, int len)
{
int pos = (dmapos * (dma.samplebits/8));
if (pos >= dmasize)
dmapos = pos = 0;
if (!snd_inited) /* shouldn't happen, but just in case... */
{
memset(stream, '\0', len);
return;
}
else
{
int tobufend = dmasize - pos; /* bytes to buffer's end. */
int len1 = len;
int len2 = 0;
if (len1 > tobufend)
{
len1 = tobufend;
len2 = len - len1;
}
memcpy(stream, dma.buffer + pos, len1);
if (len2 <= 0)
dmapos += (len1 / (dma.samplebits/8));
else /* wraparound? */
{
memcpy(stream+len1, dma.buffer, len2);
dmapos = (len2 / (dma.samplebits/8));
}
}
if (dmapos >= dmasize)
dmapos = 0;
}
static struct
{
Uint16 enumFormat;
char *stringFormat;
} formatToStringTable[ ] =
{
{ AUDIO_U8, "AUDIO_U8" },
{ AUDIO_S8, "AUDIO_S8" },
{ AUDIO_U16LSB, "AUDIO_U16LSB" },
{ AUDIO_S16LSB, "AUDIO_S16LSB" },
{ AUDIO_U16MSB, "AUDIO_U16MSB" },
{ AUDIO_S16MSB, "AUDIO_S16MSB" }
};
static int formatToStringTableSize =
sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] );
/*
===============
print_audiospec
===============
*/
static void print_audiospec(const char *str, const SDL_AudioSpec *spec)
{
int i;
char *fmt = NULL;
Com_Printf("%s:\n", str);
for( i = 0; i < formatToStringTableSize; i++ ) {
if( spec->format == formatToStringTable[ i ].enumFormat ) {
fmt = formatToStringTable[ i ].stringFormat;
}
}
if( fmt ) {
Com_Printf( " Format: %s\n", fmt );
} else {
Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n", fmt );
}
Com_Printf( " Freq: %d\n", (int) spec->freq );
Com_Printf( " Samples: %d\n", (int) spec->samples );
Com_Printf( " Channels: %d\n", (int) spec->channels );
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
char drivername[128];
SDL_AudioSpec desired;
SDL_AudioSpec obtained;
int tmp;
if (snd_inited)
return qtrue;
Com_Printf("Initializing SDL audio driver...\n");
if (!s_sdlBits) {
s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
}
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
if (SDL_Init(SDL_INIT_AUDIO) == -1)
{
Com_Printf("SDL_Init(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError());
return qfalse;
}
}
if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL)
strcpy(drivername, "(UNKNOWN)");
Com_Printf("SDL audio driver is \"%s\".\n", drivername);
memset(&desired, '\0', sizeof (desired));
memset(&obtained, '\0', sizeof (obtained));
tmp = ((int) s_sdlBits->value);
if ((tmp != 16) && (tmp != 8))
tmp = 16;
desired.freq = (int) s_sdlSpeed->value;
if(!desired.freq) desired.freq = 22050;
desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
// I dunno if this is the best idea, but I'll give it a try...
// should probably check a cvar for this...
if (s_sdlDevSamps->value)
desired.samples = s_sdlDevSamps->value;
else
{
// just pick a sane default.
if (desired.freq <= 11025)
desired.samples = 256;
else if (desired.freq <= 22050)
desired.samples = 512;
else if (desired.freq <= 44100)
desired.samples = 1024;
else
desired.samples = 2048; // (*shrug*)
}
desired.channels = (int) s_sdlChannels->value;
desired.callback = sdl_audio_callback;
if (SDL_OpenAudio(&desired, &obtained) == -1)
{
Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return qfalse;
} // if
print_audiospec("SDL_AudioSpec", &obtained);
// dma.samples needs to be big, or id's mixer will just refuse to
// work at all; we need to keep it significantly bigger than the
// amount of SDL callback samples, and just copy a little each time
// the callback runs.
// 32768 is what the OSS driver filled in here on my system. I don't
// know if it's a good value overall, but at least we know it's
// reasonable...this is why I let the user override.
tmp = s_sdlMixSamps->value;
if (!tmp)
tmp = (obtained.samples * obtained.channels) * 10;
if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something.
{
int val = 1;
while (val < tmp)
val <<= 1;
tmp = val;
}
dmapos = 0;
dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
dma.channels = obtained.channels;
dma.samples = tmp;
dma.submission_chunk = 1;
dma.speed = obtained.freq;
dmasize = (dma.samples * (dma.samplebits/8));
dma.buffer = (byte*)calloc(1, dmasize);
Com_Printf("Starting SDL audio callback...\n");
SDL_PauseAudio(0); // start callback.
Com_Printf("SDL audio initialized.\n");
snd_inited = qtrue;
return qtrue;
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void)
{
return dmapos;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void)
{
Com_Printf("Closing SDL audio device...\n");
SDL_PauseAudio(1);
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
free(dma.buffer);
dma.buffer = NULL;
dmapos = dmasize = 0;
snd_inited = qfalse;
Com_Printf("SDL audio device shut down.\n");
}
/*
===============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
===============
*/
void SNDDMA_Submit(void)
{
SDL_UnlockAudio();
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting (void)
{
SDL_LockAudio();
}
#endif // USE_SDL_SOUND

View file

@ -1,38 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#if !( defined __linux__ || defined __FreeBSD__ || defined __sun || defined MACOS_X )
#error You should include this file only on Linux/FreeBSD/Solaris platforms
#endif
#ifndef __GLW_LINUX_H__
#define __GLW_LINUX_H__
typedef struct
{
void *OpenGLLib; // instance of OpenGL library
int desktopWidth, desktopHeight, desktopBPP;
} glwstate_t;
extern glwstate_t glw_state;
#endif

View file

@ -1,263 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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
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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <pwd.h>
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
// Used to determine where to store user-specific files
static char homePath[MAX_OSPATH];
int Sys_Milliseconds()
{
static int sys_timeBase = 0;
struct timeval tv;
gettimeofday( &tv, NULL );
if (!sys_timeBase) {
sys_timeBase = tv.tv_sec;
return tv.tv_usec/1000;
}
return ((tv.tv_sec - sys_timeBase)*1000 + tv.tv_usec/1000);
}
void Sys_Mkdir( const char* path )
{
mkdir( path, 0777 );
}
#define MAX_FOUND_FILES 0x1000
// bk001129 - new in 1.26
static void Sys_ListFilteredFiles( const char *basedir, const char *subdirs, const char *filter, char **list, int *numfiles ) {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
DIR *fdir;
struct dirent *d;
struct stat st;
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
return;
}
if (strlen(subdirs)) {
Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
}
else {
Com_sprintf( search, sizeof(search), "%s", basedir );
}
if ((fdir = opendir(search)) == NULL) {
return;
}
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
if (stat(filename, &st) == -1)
continue;
if (st.st_mode & S_IFDIR) {
if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
if (strlen(subdirs)) {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
}
else {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
break;
}
Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
if (!Com_FilterPath( filter, filename ))
continue;
list[ *numfiles ] = CopyString( filename );
(*numfiles)++;
}
closedir(fdir);
}
char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qboolean wantsubs )
{
struct dirent *d;
DIR *fdir;
qboolean dironly = wantsubs;
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
int i;
struct stat st;
int extLen;
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = NULL;
*numfiles = nfiles;
if (!nfiles)
return NULL;
listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
if ( !extension)
extension = "";
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
dironly = qtrue;
}
extLen = strlen( extension );
// search
nfiles = 0;
if ((fdir = opendir(directory)) == NULL) {
*numfiles = 0;
return NULL;
}
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
if (stat(search, &st) == -1)
continue;
if ((dironly && !(st.st_mode & S_IFDIR)) ||
(!dironly && (st.st_mode & S_IFDIR)))
continue;
if (*extension) {
if ( strlen( d->d_name ) < strlen( extension ) ||
Q_stricmp(
d->d_name + strlen( d->d_name ) - strlen( extension ),
extension ) ) {
continue; // didn't match
}
}
if ( nfiles == MAX_FOUND_FILES - 1 )
break;
list[ nfiles ] = CopyString( d->d_name );
nfiles++;
}
list[ nfiles ] = NULL;
closedir(fdir);
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = (char**)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
void Sys_FreeFileList( char **list ) {
int i;
if ( !list ) {
return;
}
for ( i = 0 ; list[i] ; i++ ) {
Z_Free( list[i] );
}
Z_Free( list );
}
const char* Sys_Cwd()
{
static char cwd[MAX_OSPATH];
getcwd( cwd, sizeof( cwd ) - 1 );
cwd[MAX_OSPATH-1] = 0;
return cwd;
}
const char* Sys_DefaultHomePath()
{
if (*homePath)
return homePath;
const char* p;
if (p = getenv("HOME")) {
Q_strncpyz(homePath, p, sizeof(homePath));
#ifdef MACOS_X
Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3");
#else
Q_strcat(homePath, sizeof(homePath), "/.q3a");
#endif
if (mkdir(homePath, 0777)) {
if (errno != EEXIST)
Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno);
}
return homePath;
}
return ""; // assume current dir
}
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
{
}

View file

@ -135,6 +135,10 @@ all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET)
endif
OBJECTS := \
$(OBJDIR)/linux_main.o \
$(OBJDIR)/linux_shared.o \
$(OBJDIR)/linux_signals.o \
$(OBJDIR)/linux_tty.o \
$(OBJDIR)/cm_load.o \
$(OBJDIR)/cm_patch.o \
$(OBJDIR)/cm_polylib.o \
@ -168,9 +172,6 @@ OBJECTS := \
$(OBJDIR)/sv_net_chan.o \
$(OBJDIR)/sv_snapshot.o \
$(OBJDIR)/sv_world.o \
$(OBJDIR)/linux_signals.o \
$(OBJDIR)/unix_main.o \
$(OBJDIR)/unix_shared.o \
RESOURCES := \
@ -228,6 +229,18 @@ $(GCH): $(PCH)
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
endif
$(OBJDIR)/linux_main.o: ../../code/linux/linux_main.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_shared.o: ../../code/linux/linux_shared.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_signals.o: ../../code/linux/linux_signals.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_tty.o: ../../code/linux/linux_tty.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/cm_load.o: ../../code/qcommon/cm_load.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
@ -327,15 +340,6 @@ $(OBJDIR)/sv_snapshot.o: ../../code/server/sv_snapshot.cpp
$(OBJDIR)/sv_world.o: ../../code/server/sv_world.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_signals.o: ../../code/unix/linux_signals.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/unix_main.o: ../../code/unix/unix_main.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/unix_shared.o: ../../code/unix/unix_shared.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
-include $(OBJECTS:%.o=%.d)
ifneq (,$(PCH))

View file

@ -19,10 +19,10 @@ ifeq ($(config),debug_x32)
INCLUDES += -I../../code/freetype/include
FORCE_INCLUDE +=
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g -Wno-unused-parameter -Wno-write-strings -pthread -x c++ -std=c++98
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g -Wno-unused-parameter -Wno-write-strings -x c++ -std=c++98
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CFLAGS) -fno-exceptions -fno-rtti
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
LIBS += ../../.build/debug_x32/libbotlib.a ../../.build/debug_x32/librenderer.a ../../.build/debug_x32/libfreetype.a ../../.build/debug_x32/liblibjpeg-turbo.a -ldl -lm -lX11 -lpthread
LIBS += ../../.build/debug_x32/libbotlib.a ../../.build/debug_x32/librenderer.a ../../.build/debug_x32/libfreetype.a ../../.build/debug_x32/liblibjpeg-turbo.a -ldl -lm -lSDL2
LDDEPS += ../../.build/debug_x32/libbotlib.a ../../.build/debug_x32/librenderer.a ../../.build/debug_x32/libfreetype.a ../../.build/debug_x32/liblibjpeg-turbo.a
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -L../../.build/debug_x32 -m32
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
@ -50,10 +50,10 @@ ifeq ($(config),debug_x64)
INCLUDES += -I../../code/freetype/include
FORCE_INCLUDE +=
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g -Wno-unused-parameter -Wno-write-strings -pthread -x c++ -std=c++98
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g -Wno-unused-parameter -Wno-write-strings -x c++ -std=c++98
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CFLAGS) -fno-exceptions -fno-rtti
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
LIBS += ../../.build/debug_x64/libbotlib.a ../../.build/debug_x64/librenderer.a ../../.build/debug_x64/libfreetype.a ../../.build/debug_x64/liblibjpeg-turbo.a -ldl -lm -lX11 -lpthread
LIBS += ../../.build/debug_x64/libbotlib.a ../../.build/debug_x64/librenderer.a ../../.build/debug_x64/libfreetype.a ../../.build/debug_x64/liblibjpeg-turbo.a -ldl -lm -lSDL2
LDDEPS += ../../.build/debug_x64/libbotlib.a ../../.build/debug_x64/librenderer.a ../../.build/debug_x64/libfreetype.a ../../.build/debug_x64/liblibjpeg-turbo.a
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -L../../.build/debug_x64 -m64
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
@ -81,10 +81,10 @@ ifeq ($(config),release_x32)
INCLUDES += -I../../code/freetype/include
FORCE_INCLUDE +=
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -fomit-frame-pointer -ffast-math -Os -g -msse2 -Wno-unused-parameter -Wno-write-strings -g1 -pthread -x c++ -std=c++98
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -fomit-frame-pointer -ffast-math -Os -g -msse2 -Wno-unused-parameter -Wno-write-strings -g1 -x c++ -std=c++98
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CFLAGS) -fno-exceptions -fno-rtti
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
LIBS += ../../.build/release_x32/libbotlib.a ../../.build/release_x32/librenderer.a ../../.build/release_x32/libfreetype.a ../../.build/release_x32/liblibjpeg-turbo.a -ldl -lm -lX11 -lpthread
LIBS += ../../.build/release_x32/libbotlib.a ../../.build/release_x32/librenderer.a ../../.build/release_x32/libfreetype.a ../../.build/release_x32/liblibjpeg-turbo.a -ldl -lm -lSDL2
LDDEPS += ../../.build/release_x32/libbotlib.a ../../.build/release_x32/librenderer.a ../../.build/release_x32/libfreetype.a ../../.build/release_x32/liblibjpeg-turbo.a
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -L../../.build/release_x32 -m32
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
@ -112,10 +112,10 @@ ifeq ($(config),release_x64)
INCLUDES += -I../../code/freetype/include
FORCE_INCLUDE +=
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -fomit-frame-pointer -ffast-math -Os -g -msse2 -Wno-unused-parameter -Wno-write-strings -g1 -pthread -x c++ -std=c++98
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -fomit-frame-pointer -ffast-math -Os -g -msse2 -Wno-unused-parameter -Wno-write-strings -g1 -x c++ -std=c++98
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CFLAGS) -fno-exceptions -fno-rtti
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
LIBS += ../../.build/release_x64/libbotlib.a ../../.build/release_x64/librenderer.a ../../.build/release_x64/libfreetype.a ../../.build/release_x64/liblibjpeg-turbo.a -ldl -lm -lX11 -lpthread
LIBS += ../../.build/release_x64/libbotlib.a ../../.build/release_x64/librenderer.a ../../.build/release_x64/libfreetype.a ../../.build/release_x64/liblibjpeg-turbo.a -ldl -lm -lSDL2
LDDEPS += ../../.build/release_x64/libbotlib.a ../../.build/release_x64/librenderer.a ../../.build/release_x64/libfreetype.a ../../.build/release_x64/liblibjpeg-turbo.a
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -L../../.build/release_x64 -m64
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
@ -154,6 +154,14 @@ OBJECTS := \
$(OBJDIR)/snd_main.o \
$(OBJDIR)/snd_mem.o \
$(OBJDIR)/snd_mix.o \
$(OBJDIR)/linux_main.o \
$(OBJDIR)/linux_qgl.o \
$(OBJDIR)/linux_shared.o \
$(OBJDIR)/linux_signals.o \
$(OBJDIR)/linux_tty.o \
$(OBJDIR)/sdl_core.o \
$(OBJDIR)/sdl_glimp.o \
$(OBJDIR)/sdl_snd.o \
$(OBJDIR)/cm_load.o \
$(OBJDIR)/cm_patch.o \
$(OBJDIR)/cm_polylib.o \
@ -187,13 +195,6 @@ OBJECTS := \
$(OBJDIR)/sv_net_chan.o \
$(OBJDIR)/sv_snapshot.o \
$(OBJDIR)/sv_world.o \
$(OBJDIR)/linux_glimp.o \
$(OBJDIR)/linux_joystick.o \
$(OBJDIR)/linux_qgl.o \
$(OBJDIR)/linux_signals.o \
$(OBJDIR)/linux_snd.o \
$(OBJDIR)/unix_main.o \
$(OBJDIR)/unix_shared.o \
RESOURCES := \
@ -308,6 +309,30 @@ $(OBJDIR)/snd_mem.o: ../../code/client/snd_mem.cpp
$(OBJDIR)/snd_mix.o: ../../code/client/snd_mix.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_main.o: ../../code/linux/linux_main.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_qgl.o: ../../code/linux/linux_qgl.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_shared.o: ../../code/linux/linux_shared.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_signals.o: ../../code/linux/linux_signals.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_tty.o: ../../code/linux/linux_tty.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/sdl_core.o: ../../code/linux/sdl_core.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/sdl_glimp.o: ../../code/linux/sdl_glimp.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/sdl_snd.o: ../../code/linux/sdl_snd.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/cm_load.o: ../../code/qcommon/cm_load.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
@ -407,27 +432,6 @@ $(OBJDIR)/sv_snapshot.o: ../../code/server/sv_snapshot.cpp
$(OBJDIR)/sv_world.o: ../../code/server/sv_world.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_glimp.o: ../../code/unix/linux_glimp.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_joystick.o: ../../code/unix/linux_joystick.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_qgl.o: ../../code/unix/linux_qgl.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_signals.o: ../../code/unix/linux_signals.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/linux_snd.o: ../../code/unix/linux_snd.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/unix_main.o: ../../code/unix/unix_main.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/unix_shared.o: ../../code/unix/unix_shared.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
-include $(OBJECTS:%.o=%.d)
ifneq (,$(PCH))

View file

@ -319,11 +319,12 @@ local function ApplyExeProjectSettings(exeName, server)
"win32/win_syscon.cpp"
}
local server_sources_unix =
local server_sources_linux =
{
"unix/unix_main.cpp",
"unix/unix_shared.cpp",
"unix/linux_signals.cpp"
"linux/linux_main.cpp",
"linux/linux_shared.cpp",
"linux/linux_signals.cpp",
"linux/linux_tty.cpp"
}
local client_sources =
@ -395,15 +396,16 @@ local function ApplyExeProjectSettings(exeName, server)
"win32/win_qgl.c"
}
local client_sources_unix =
local client_sources_linux =
{
"unix/unix_main.cpp",
"unix/unix_shared.cpp",
"unix/linux_joystick.c",
"unix/linux_signals.cpp",
"unix/linux_qgl.c",
"unix/linux_snd.c",
"unix/linux_glimp.cpp"
"linux/linux_main.cpp",
"linux/linux_qgl.c",
"linux/linux_shared.cpp",
"linux/linux_signals.cpp",
"linux/linux_tty.cpp",
"linux/sdl_core.cpp",
"linux/sdl_glimp.cpp",
"linux/sdl_snd.cpp"
}
AddHeaders("botlib")
@ -435,9 +437,9 @@ local function ApplyExeProjectSettings(exeName, server)
filter { "system:not windows" }
if (server == 1) then
AddSourcesFromArray(".", server_sources_unix)
AddSourcesFromArray(".", server_sources_linux)
else
AddSourcesFromArray(".", client_sources_unix)
AddSourcesFromArray(".", client_sources_linux)
end
-- create git info header
@ -474,8 +476,7 @@ local function ApplyExeProjectSettings(exeName, server)
filter "system:not windows"
links { "dl", "m" }
if (server == 0) then
buildoptions { "-pthread" }
links { "X11", "pthread" }
links { "SDL2" }
end
-- RC will compile the .rc into a .res