mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2025-04-07 18:01:16 +00:00
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:
parent
ef83d7314d
commit
b3831fcc87
22 changed files with 1835 additions and 3225 deletions
21
build.md
21
build.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
57
code/linux/linux_main.cpp
Normal 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;
|
||||
}
|
|
@ -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
656
code/linux/linux_shared.cpp
Normal 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;
|
||||
}
|
|
@ -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");
|
|
@ -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
459
code/linux/sdl_core.cpp
Normal 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
292
code/linux/sdl_glimp.cpp
Normal 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
18
code/linux/sdl_local.h
Normal 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
170
code/linux/sdl_snd.cpp
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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 )
|
||||
{
|
||||
}
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue