Ported the Win32 threads to POSIX pthreads.

This commit is contained in:
Robert Beckebans 2012-12-09 01:55:59 +01:00
parent 3b0dabe30a
commit 6d70f04cc9
11 changed files with 4051 additions and 13 deletions

View file

@ -731,6 +731,14 @@ set(WIN32_RESOURCES
# list(APPEND WIN32_RESOURCES sys/win32/rc/doom_nomfc.rc)
#endif()
file(GLOB POSIX_INCLUDES sys/posix/*.h)
file(GLOB POSIX_SOURCES sys/posix/*.cpp)
file(GLOB SDL_INCLUDES sys/sdl/*.h)
file(GLOB SDL_SOURCES sys/sdl/*.cpp)
source_group("aas" FILES ${AAS_INCLUDES})
source_group("aas" FILES ${AAS_SOURCES})
@ -819,6 +827,13 @@ source_group("sys\\win32" FILES ${WIN32_INCLUDES})
source_group("sys\\win32" FILES ${WIN32_SOURCES})
source_group("sys\\win32\\Resources" FILES ${WIN32_RESOURCES})
source_group("sys\\posix" FILES ${POSIX_INCLUDES})
source_group("sys\\posix" FILES ${POSIX_SOURCES})
source_group("sys\\sdl" FILES ${SDL_INCLUDES})
source_group("sys\\sdl" FILES ${SDL_SOURCES})
source_group("tools\\compilers" FILES ${COMPILER_INCLUDES})
source_group("tools\\compilers\\aas" FILES ${COMPILER_AAS_INCLUDES})
@ -1029,6 +1044,17 @@ else()
#list(REMOVE_ITEM WIN32_SOURCES sys/win32/win_cpu.cpp)
list(APPEND WIN32_SOURCES sys/sdl/sdl_cpu.cpp)
endif()
if(UNIX)
find_package(SDL REQUIRED)
include_directories(${SDL_INCLUDE_DIR})
set(SDLx_LIBRARY ${SDL_LIBRARY})
list(APPEND RBDOOM3_SOURCES
${POSIX_INCLUDES} ${POSIX_SOURCES}
${SDL_INCLUDES} ${SDL_SOURCES})
endif()
list(REMOVE_DUPLICATES RBDOOM3_SOURCES)
@ -1061,10 +1087,12 @@ else()
endif()
if(UNIX)
if(UNIX)
target_link_libraries(RBDoom3
idlib
GL
pthread
${SDLx_LIBRARY}
)
endif()

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -92,6 +93,8 @@ that a thread can wait on for it to be raised. It's used to indicate data is av
a thread has reached a specific point.
================================================
*/
// RB begin
#if defined(_WIN32)
class idSysSignal
{
public:
@ -129,6 +132,144 @@ private:
idSysSignal( const idSysSignal& s ) {}
void operator=( const idSysSignal& s ) {}
};
#else
class idSysSignal
{
public:
static const int WAIT_INFINITE = -1;
idSysSignal( bool manualReset = false )
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
pthread_mutex_init( &mutex, &attr );
pthread_mutexattr_destroy( &attr );
pthread_cond_init( &cond, NULL );
signaled = false;
waiting = false;
}
~idSysSignal()
{
pthread_cond_destroy( &cond );
}
void Raise()
{
pthread_mutex_lock( &mutex );
if( waiting )
{
pthread_cond_signal( &cond );
}
else
{
// emulate Windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going
signaled = true;
}
pthread_mutex_unlock( &mutex );
}
void Clear()
{
pthread_mutex_lock( &mutex );
signaled = false;
pthread_mutex_unlock( &mutex );
}
// Wait returns true if the object is in a signalled state and
// returns false if the wait timed out. Wait also clears the signalled
// state when the signalled state is reached within the time out period.
bool Wait( int timeout = WAIT_INFINITE )
{
pthread_mutex_lock( &mutex );
//DWORD result = WaitForSingleObject( handle, timeout == idSysSignal::WAIT_INFINITE ? INFINITE : timeout );
//assert( result == WAIT_OBJECT_0 || ( timeout != idSysSignal::WAIT_INFINITE && result == WAIT_TIMEOUT ) );
//return ( result == WAIT_OBJECT_0 );
int result = 1;
/*
Return Value
Except in the case of [ETIMEDOUT], all these error checks shall act as if they were performed immediately at the beginning of processing for the function and shall cause an error return, in effect, prior to modifying the state of the mutex specified by mutex or the condition variable specified by cond.
Upon successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate the error.
Errors
The pthread_cond_timedwait() function shall fail if:
ETIMEDOUT
The time specified by abstime to pthread_cond_timedwait() has passed.
The pthread_cond_timedwait() and pthread_cond_wait() functions may fail if:
EINVAL
The value specified by cond, mutex, or abstime is invalid.
EINVAL
Different mutexes were supplied for concurrent pthread_cond_timedwait() or pthread_cond_wait() operations on the same condition variable.
EPERM
The mutex was not owned by the current thread at the time of the call.
*/
assert( !waiting ); // WaitForEvent from multiple threads? that wouldn't be good
if( signaled )
{
// emulate Windows behaviour: signal has been raised already. clear and keep going
signaled = false;
result = 0;
}
else
{
waiting = true;
#if 0
result = pthread_cond_wait( &cond, &mutex );
#else
if( timeout == WAIT_INFINITE )
{
result = pthread_cond_wait( &cond, &mutex );
assert( result == 0 );
}
else
{
timespec ts;
clock_gettime( CLOCK_REALTIME, &ts );
ts.tv_nsec += ( timeout * 1000000 );
result = pthread_cond_timedwait( &cond, &mutex, &ts );
assert( result == 0 || ( timeout != idSysSignal::WAIT_INFINITE && result == ETIMEDOUT ) );
}
#endif
waiting = false;
}
pthread_mutex_unlock( &mutex );
return ( result == 0 );
}
private:
pthread_mutex_t mutex;
pthread_cond_t cond;
bool signaled;
bool waiting;
idSysSignal( const idSysSignal& s ) {}
void operator=( const idSysSignal& s ) {}
};
#endif
/*
================================================

View file

@ -0,0 +1,320 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#pragma hdrstop
#include "../../precompiled.h"
//#include <SDL_thread.h>
typedef void* ( *pthread_function_t )( void* );
/*
========================
Sys_Createthread
========================
*/
uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority priority, const char* name, core_t core, int stackSize, bool suspended )
{
//Sys_EnterCriticalSection();
pthread_attr_t attr;
pthread_attr_init( &attr );
if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) != 0 )
{
idLib::common->FatalError( "ERROR: pthread_attr_setdetachstate %s failed\n", name );
return ( uintptr_t )0;
}
pthread_t handle;
if( pthread_create( ( pthread_t* )&handle, &attr, ( pthread_function_t )function, parms ) != 0 )
{
idLib::common->FatalError( "ERROR: pthread_create %s failed\n", name );
return ( uintptr_t )0;
}
pthread_attr_destroy( &attr );
// RB: TODO pthread_setname_np is different on Linux, MacOSX and other systems
if( pthread_setname_np( handle, name ) != 0 )
{
idLib::common->FatalError( "ERROR: pthread_setname_np %s failed\n", name );
return ( uintptr_t )0;
}
/*
TODO RB: support thread priorities?
if( priority == THREAD_HIGHEST )
{
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_HIGHEST ); // we better sleep enough to do this
}
else if( priority == THREAD_ABOVE_NORMAL )
{
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_ABOVE_NORMAL );
}
else if( priority == THREAD_BELOW_NORMAL )
{
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_BELOW_NORMAL );
}
else if( priority == THREAD_LOWEST )
{
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_LOWEST );
}
*/
// Under Linux, we don't set the thread affinity and let the OS deal with scheduling
return ( uintptr_t )handle;
}
/*
========================
Sys_GetCurrentThreadID
========================
*/
uintptr_t Sys_GetCurrentThreadID()
{
return pthread_self();
}
/*
========================
Sys_DestroyThread
========================
*/
void Sys_DestroyThread( uintptr_t threadHandle )
{
if( threadHandle == 0 )
{
return;
}
char name[128];
pthread_getname_np( threadHandle, name, sizeof( name ) );
#if !defined(__ANDROID__)
if( pthread_cancel( ( pthread_t )threadHandle ) != 0 )
{
idLib::common->FatalError( "ERROR: pthread_cancel %s failed\n", name );
}
#endif
if( pthread_join( ( pthread_t )threadHandle, NULL ) != 0 )
{
idLib::common->FatalError( "ERROR: pthread_join %s failed\n", name );
}
}
/*
========================
Sys_Yield
========================
*/
void Sys_Yield()
{
pthread_yield();
}
/*
================================================================================================
Signal
================================================================================================
*/
/*
================================================================================================
Mutex
================================================================================================
*/
/*
========================
Sys_MutexCreate
========================
*/
void Sys_MutexCreate( mutexHandle_t& handle )
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
pthread_mutex_init( &handle, &attr );
pthread_mutexattr_destroy( &attr );
}
/*
========================
Sys_MutexDestroy
========================
*/
void Sys_MutexDestroy( mutexHandle_t& handle )
{
pthread_mutex_destroy( &handle );
}
/*
========================
Sys_MutexLock
========================
*/
bool Sys_MutexLock( mutexHandle_t& handle, bool blocking )
{
if( pthread_mutex_trylock( &handle ) == 0 )
{
if( !blocking )
{
return false;
}
pthread_mutex_lock( &handle );
}
return true;
}
/*
========================
Sys_MutexUnlock
========================
*/
void Sys_MutexUnlock( mutexHandle_t& handle )
{
pthread_mutex_unlock( & handle );
}
/*
================================================================================================
Interlocked Integer
================================================================================================
*/
/*
========================
Sys_InterlockedIncrement
========================
*/
interlockedInt_t Sys_InterlockedIncrement( interlockedInt_t& value )
{
// return InterlockedIncrementAcquire( & value );
return __sync_add_and_fetch( &value, 1 );
}
/*
========================
Sys_InterlockedDecrement
========================
*/
interlockedInt_t Sys_InterlockedDecrement( interlockedInt_t& value )
{
// return InterlockedDecrementRelease( & value );
return __sync_sub_and_fetch( &value, 1 );
}
/*
========================
Sys_InterlockedAdd
========================
*/
interlockedInt_t Sys_InterlockedAdd( interlockedInt_t& value, interlockedInt_t i )
{
//return InterlockedExchangeAdd( & value, i ) + i;
return __sync_add_and_fetch( &value, i );
}
/*
========================
Sys_InterlockedSub
========================
*/
interlockedInt_t Sys_InterlockedSub( interlockedInt_t& value, interlockedInt_t i )
{
//return InterlockedExchangeAdd( & value, - i ) - i;
return __sync_sub_and_fetch( &value, i );
}
/*
========================
Sys_InterlockedExchange
========================
*/
interlockedInt_t Sys_InterlockedExchange( interlockedInt_t& value, interlockedInt_t exchange )
{
//return InterlockedExchange( & value, exchange );
// source: http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html
// These builtins perform an atomic compare and swap. That is, if the current value of *ptr is oldval, then write newval into *ptr.
return __sync_val_compare_and_swap( &value, value, exchange );
}
/*
========================
Sys_InterlockedCompareExchange
========================
*/
interlockedInt_t Sys_InterlockedCompareExchange( interlockedInt_t& value, interlockedInt_t comparand, interlockedInt_t exchange )
{
//return InterlockedCompareExchange( & value, exchange, comparand );
return __sync_val_compare_and_swap( &value, comparand, exchange );
}
/*
================================================================================================
Interlocked Pointer
================================================================================================
*/
/*
========================
Sys_InterlockedExchangePointer
========================
*/
void* Sys_InterlockedExchangePointer( void*& ptr, void* exchange )
{
//return InterlockedExchangePointer( & ptr, exchange );
return __sync_val_compare_and_swap( &ptr, ptr, exchange );
}
/*
========================
Sys_InterlockedCompareExchangePointer
========================
*/
void* Sys_InterlockedCompareExchangePointer( void*& ptr, void* comparand, void* exchange )
{
//return InterlockedCompareExchangePointer( & ptr, exchange, comparand );
return __sync_val_compare_and_swap( &ptr, comparand, exchange );
}

View file

@ -190,15 +190,20 @@ uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority p
const char* name, core_t core, int stackSize = DEFAULT_THREAD_STACK_SIZE,
bool suspended = false );
void Sys_WaitForThread( uintptr_t threadHandle );
// RB begin
// removed unused Sys_WaitForThread
void Sys_DestroyThread( uintptr_t threadHandle );
void Sys_SetCurrentThreadName( const char* name );
// use alternative pthread implementation in idSysSignal
#if defined(_WIN32)
void Sys_SignalCreate( signalHandle_t& handle, bool manualReset );
void Sys_SignalDestroy( signalHandle_t& handle );
void Sys_SignalRaise( signalHandle_t& handle );
void Sys_SignalClear( signalHandle_t& handle );
bool Sys_SignalWait( signalHandle_t& handle, int timeout );
#endif
// RB end
void Sys_MutexCreate( mutexHandle_t& handle );
void Sys_MutexDestroy( mutexHandle_t& handle );

View file

@ -96,7 +96,7 @@ uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority pri
// Without this flag the 'dwStackSize' parameter to CreateThread specifies the "Stack Commit Size"
// and the "Stack Reserve Size" is set to the value specified at link-time.
// With this flag the 'dwStackSize' parameter to CreateThread specifies the "Stack Reserve Size"
// and the “Stack Commit Size” is set to the value specified at link-time.
// and the <EFBFBD>Stack Commit Size<7A> is set to the value specified at link-time.
// For various reasons (some of which historic) we reserve a large amount of stack space in the
// project settings. By setting this flag and by specifying 64 kB for the "Stack Commit Size" in
// the project settings we can create new threads with a much smaller reserved (and committed)
@ -156,16 +156,6 @@ uintptr_t Sys_GetCurrentThreadID()
return GetCurrentThreadId();
}
/*
========================
Sys_WaitForThread
========================
*/
void Sys_WaitForThread( uintptr_t threadHandle )
{
WaitForSingleObject( ( HANDLE )threadHandle, INFINITE );
}
/*
========================
Sys_DestroyThread

1279
neo/sys/posix/posix_main.cpp Normal file

File diff suppressed because it is too large Load diff

929
neo/sys/posix/posix_net.cpp Normal file
View file

@ -0,0 +1,929 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 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 3 of the License, or
(at your option) any later version.
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <errno.h>
#include <sys/select.h>
#include <net/if.h>
#if MACOS_X
#include <ifaddrs.h>
#endif
#include "../../idlib/precompiled.h"
idPort clientPort, serverPort;
idCVar net_ip( "net_ip", "localhost", CVAR_SYSTEM, "local IP address" );
idCVar net_port( "net_port", "", CVAR_SYSTEM | CVAR_INTEGER, "local IP port number" );
typedef struct
{
// RB: 64 bit fixes, changed long to int
unsigned int ip;
unsigned int mask;
// RB end
} net_interface;
#define MAX_INTERFACES 32
int num_interfaces = 0;
net_interface netint[MAX_INTERFACES];
/*
=============
NetadrToSockadr
=============
*/
static void NetadrToSockadr( const netadr_t* a, struct sockaddr_in* s )
{
memset( s, 0, sizeof( *s ) );
if( a->type == NA_BROADCAST )
{
s->sin_family = AF_INET;
s->sin_port = htons( ( short )a->port );
*( int* ) &s->sin_addr = -1;
}
else if( a->type == NA_IP || a->type == NA_LOOPBACK )
{
s->sin_family = AF_INET;
*( int* ) &s->sin_addr = *( int* ) &a->ip;
s->sin_port = htons( ( short )a->port );
}
}
/*
=============
SockadrToNetadr
=============
*/
static void SockadrToNetadr( struct sockaddr_in* s, netadr_t* a )
{
unsigned int ip = *( int* )&s->sin_addr;
*( int* )&a->ip = ip;
a->port = ntohs( s->sin_port );
// we store in network order, that loopback test is host order..
ip = ntohl( ip );
if( ip == INADDR_LOOPBACK )
{
a->type = NA_LOOPBACK;
}
else
{
a->type = NA_IP;
}
}
/*
=============
ExtractPort
=============
*/
static bool ExtractPort( const char* src, char* buf, int bufsize, int* port )
{
char* p;
strncpy( buf, src, bufsize );
p = buf;
p += Min( bufsize - 1, ( int )strlen( src ) );
*p = '\0';
p = strchr( buf, ':' );
if( !p )
{
return false;
}
*p = '\0';
*port = strtol( p + 1, NULL, 10 );
if( ( *port == 0 && errno == EINVAL ) ||
// RB: 64 bit fixes, changed LONG_ to INT_
( ( *port == INT_MIN || *port == INT_MAX ) && errno == ERANGE ) )
{
// RB end
return false;
}
return true;
}
/*
=============
StringToSockaddr
=============
*/
static bool StringToSockaddr( const char* s, struct sockaddr_in* sadr, bool doDNSResolve )
{
struct hostent* h;
char buf[256];
int port;
memset( sadr, 0, sizeof( *sadr ) );
sadr->sin_family = AF_INET;
sadr->sin_port = 0;
if( s[0] >= '0' && s[0] <= '9' )
{
if( !inet_aton( s, &sadr->sin_addr ) )
{
// check for port
if( !ExtractPort( s, buf, sizeof( buf ), &port ) )
{
return false;
}
if( !inet_aton( buf, &sadr->sin_addr ) )
{
return false;
}
sadr->sin_port = htons( port );
}
}
else if( doDNSResolve )
{
// try to remove the port first, otherwise the DNS gets confused into multiple timeouts
// failed or not failed, buf is expected to contain the appropriate host to resolve
if( ExtractPort( s, buf, sizeof( buf ), &port ) )
{
sadr->sin_port = htons( port );
}
if( !( h = gethostbyname( buf ) ) )
{
return false;
}
*( int* ) &sadr->sin_addr =
*( int* ) h->h_addr_list[0];
}
return true;
}
/*
=============
Sys_StringToAdr
=============
*/
bool Sys_StringToNetAdr( const char* s, netadr_t* a, bool doDNSResolve )
{
struct sockaddr_in sadr;
if( !StringToSockaddr( s, &sadr, doDNSResolve ) )
{
return false;
}
SockadrToNetadr( &sadr, a );
return true;
}
/*
=============
Sys_NetAdrToString
=============
*/
const char* Sys_NetAdrToString( const netadr_t a )
{
static char s[64];
if( a.type == NA_LOOPBACK )
{
if( a.port )
{
idStr::snPrintf( s, sizeof( s ), "localhost:%i", a.port );
}
else
{
idStr::snPrintf( s, sizeof( s ), "localhost" );
}
}
else if( a.type == NA_IP )
{
idStr::snPrintf( s, sizeof( s ), "%i.%i.%i.%i:%i",
a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port );
}
return s;
}
/*
==================
Sys_IsLANAddress
==================
*/
bool Sys_IsLANAddress( const netadr_t adr )
{
int i;
// RB: 64 bit fixes, changed long to int
unsigned int* p_ip;
unsigned int ip;
// RB end
#if ID_NOLANADDRESS
common->Printf( "Sys_IsLANAddress: ID_NOLANADDRESS\n" );
return false;
#endif
if( adr.type == NA_LOOPBACK )
{
return true;
}
if( adr.type != NA_IP )
{
return false;
}
if( !num_interfaces )
{
return false; // well, if there's no networking, there are no LAN addresses, right
}
for( i = 0; i < num_interfaces; i++ )
{
// RB: 64 bit fixes, changed long to int
p_ip = ( unsigned int* )&adr.ip[0];
// RB end
ip = ntohl( *p_ip );
if( ( netint[i].ip & netint[i].mask ) == ( ip & netint[i].mask ) )
{
return true;
}
}
return false;
}
/*
===================
Sys_CompareNetAdrBase
Compares without the port
===================
*/
bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b )
{
if( a.type != b.type )
{
return false;
}
if( a.type == NA_LOOPBACK )
{
return true;
}
if( a.type == NA_IP )
{
if( a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] )
{
return true;
}
return false;
}
common->Printf( "Sys_CompareNetAdrBase: bad address type\n" );
return false;
}
/*
====================
NET_InitNetworking
====================
*/
void Sys_InitNetworking()
{
// haven't been able to clearly pinpoint which standards or RFCs define SIOCGIFCONF, SIOCGIFADDR, SIOCGIFNETMASK ioctls
// it seems fairly widespread, in Linux kernel ioctl, and in BSD .. so let's assume it's always available on our targets
#if MACOS_X
unsigned int ip, mask;
struct ifaddrs* ifap, *ifp;
num_interfaces = 0;
if( getifaddrs( &ifap ) < 0 )
{
common->FatalError( "InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) );
return;
}
for( ifp = ifap; ifp; ifp = ifp->ifa_next )
{
if( ifp->ifa_addr->sa_family != AF_INET )
continue;
if( !( ifp->ifa_flags & IFF_UP ) )
continue;
if( !ifp->ifa_addr )
continue;
if( !ifp->ifa_netmask )
continue;
// RB: 64 bit fixes, changed long to int
ip = ntohl( *( unsigned int* )&ifp->ifa_addr->sa_data[2] );
mask = ntohl( *( unsigned int* )&ifp->ifa_netmask->sa_data[2] );
// RB end
if( ip == INADDR_LOOPBACK )
{
common->Printf( "loopback\n" );
}
else
{
common->Printf( "IP: %d.%d.%d.%d\n",
( unsigned char )ifp->ifa_addr->sa_data[2],
( unsigned char )ifp->ifa_addr->sa_data[3],
( unsigned char )ifp->ifa_addr->sa_data[4],
( unsigned char )ifp->ifa_addr->sa_data[5] );
common->Printf( "NetMask: %d.%d.%d.%d\n",
( unsigned char )ifp->ifa_netmask->sa_data[2],
( unsigned char )ifp->ifa_netmask->sa_data[3],
( unsigned char )ifp->ifa_netmask->sa_data[4],
( unsigned char )ifp->ifa_netmask->sa_data[5] );
}
netint[ num_interfaces ].ip = ip;
netint[ num_interfaces ].mask = mask;
num_interfaces++;
}
#else
int s;
char buf[ MAX_INTERFACES * sizeof( ifreq ) ];
ifconf ifc;
ifreq* ifr;
int ifindex;
unsigned int ip, mask;
num_interfaces = 0;
s = socket( AF_INET, SOCK_DGRAM, 0 );
ifc.ifc_len = MAX_INTERFACES * sizeof( ifreq );
ifc.ifc_buf = buf;
if( ioctl( s, SIOCGIFCONF, &ifc ) < 0 )
{
common->FatalError( "InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) );
return;
}
ifindex = 0;
while( ifindex < ifc.ifc_len )
{
common->Printf( "found interface %s - ", ifc.ifc_buf + ifindex );
// find the type - ignore interfaces for which we can find we can't get IP and mask ( not configured )
ifr = ( ifreq* )( ifc.ifc_buf + ifindex );
if( ioctl( s, SIOCGIFADDR, ifr ) < 0 )
{
common->Printf( "SIOCGIFADDR failed: %s\n", strerror( errno ) );
}
else
{
if( ifr->ifr_addr.sa_family != AF_INET )
{
common->Printf( "not AF_INET\n" );
}
else
{
// RB: 64 bit fixes, changed long to int
ip = ntohl( *( unsigned int* )&ifr->ifr_addr.sa_data[2] );
// RB end
if( ip == INADDR_LOOPBACK )
{
common->Printf( "loopback\n" );
}
else
{
common->Printf( "%d.%d.%d.%d",
( unsigned char )ifr->ifr_addr.sa_data[2],
( unsigned char )ifr->ifr_addr.sa_data[3],
( unsigned char )ifr->ifr_addr.sa_data[4],
( unsigned char )ifr->ifr_addr.sa_data[5] );
}
if( ioctl( s, SIOCGIFNETMASK, ifr ) < 0 )
{
common->Printf( " SIOCGIFNETMASK failed: %s\n", strerror( errno ) );
}
else
{
// RB: 64 bit fixes, changed long to int
mask = ntohl( *( unsigned int* )&ifr->ifr_addr.sa_data[2] );
// RB end
if( ip != INADDR_LOOPBACK )
{
common->Printf( "/%d.%d.%d.%d\n",
( unsigned char )ifr->ifr_addr.sa_data[2],
( unsigned char )ifr->ifr_addr.sa_data[3],
( unsigned char )ifr->ifr_addr.sa_data[4],
( unsigned char )ifr->ifr_addr.sa_data[5] );
}
netint[ num_interfaces ].ip = ip;
netint[ num_interfaces ].mask = mask;
num_interfaces++;
}
}
}
ifindex += sizeof( ifreq );
}
#endif
}
/*
====================
IPSocket
====================
*/
static int IPSocket( const char* net_interface, int port, netadr_t* bound_to = NULL )
{
int newsocket;
struct sockaddr_in address;
int i = 1;
if( net_interface )
{
common->Printf( "Opening IP socket: %s:%i\n", net_interface, port );
}
else
{
common->Printf( "Opening IP socket: localhost:%i\n", port );
}
if( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == -1 )
{
common->Printf( "ERROR: IPSocket: socket: %s", strerror( errno ) );
return 0;
}
// make it non-blocking
int on = 1;
if( ioctl( newsocket, FIONBIO, &on ) == -1 )
{
common->Printf( "ERROR: IPSocket: ioctl FIONBIO:%s\n",
strerror( errno ) );
return 0;
}
// make it broadcast capable
if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, ( char* ) &i, sizeof( i ) ) == -1 )
{
common->Printf( "ERROR: IPSocket: setsockopt SO_BROADCAST:%s\n", strerror( errno ) );
return 0;
}
if( !net_interface || !net_interface[ 0 ]
|| !idStr::Icmp( net_interface, "localhost" ) )
{
address.sin_addr.s_addr = INADDR_ANY;
}
else
{
StringToSockaddr( net_interface, &address, true );
}
if( port == PORT_ANY )
{
address.sin_port = 0;
}
else
{
address.sin_port = htons( ( short ) port );
}
address.sin_family = AF_INET;
if( bind( newsocket, ( const struct sockaddr* )&address, sizeof( address ) ) == -1 )
{
common->Printf( "ERROR: IPSocket: bind: %s\n", strerror( errno ) );
close( newsocket );
return 0;
}
if( bound_to )
{
unsigned int len = sizeof( address );
if( ( unsigned int )( getsockname( newsocket, ( struct sockaddr* )&address, ( socklen_t* )&len ) ) == -1 )
{
common->Printf( "ERROR: IPSocket: getsockname: %s\n", strerror( errno ) );
close( newsocket );
return 0;
}
SockadrToNetadr( &address, bound_to );
}
return newsocket;
}
/*
==================
idPort::idPort
==================
*/
idPort::idPort()
{
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
}
/*
==================
idPort::~idPort
==================
*/
idPort::~idPort()
{
Close();
}
/*
==================
idPort::Close
==================
*/
void idPort::Close()
{
if( netSocket )
{
close( netSocket );
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
}
}
/*
==================
idPort::GetPacket
==================
*/
bool idPort::GetPacket( netadr_t& net_from, void* data, int& size, int maxSize )
{
int ret;
struct sockaddr_in from;
int fromlen;
if( !netSocket )
{
return false;
}
fromlen = sizeof( from );
ret = recvfrom( netSocket, data, maxSize, 0, ( struct sockaddr* ) &from, ( socklen_t* ) &fromlen );
if( ret == -1 )
{
if( errno == EWOULDBLOCK || errno == ECONNREFUSED )
{
// those commonly happen, don't verbose
return false;
}
common->DPrintf( "idPort::GetPacket recvfrom(): %s\n", strerror( errno ) );
return false;
}
assert( ret < maxSize );
SockadrToNetadr( &from, &net_from );
size = ret;
return true;
}
/*
==================
idPort::GetPacketBlocking
==================
*/
bool idPort::GetPacketBlocking( netadr_t& net_from, void* data, int& size, int maxSize, int timeout )
{
fd_set set;
struct timeval tv;
int ret;
if( !netSocket )
{
return false;
}
if( timeout < 0 )
{
return GetPacket( net_from, data, size, maxSize );
}
FD_ZERO( &set );
FD_SET( netSocket, &set );
tv.tv_sec = timeout / 1000;
tv.tv_usec = ( timeout % 1000 ) * 1000;
ret = select( netSocket + 1, &set, NULL, NULL, &tv );
if( ret == -1 )
{
if( errno == EINTR )
{
common->DPrintf( "idPort::GetPacketBlocking: select EINTR\n" );
return false;
}
else
{
common->Error( "idPort::GetPacketBlocking: select failed: %s\n", strerror( errno ) );
}
}
if( ret == 0 )
{
// timed out
return false;
}
struct sockaddr_in from;
int fromlen;
fromlen = sizeof( from );
ret = recvfrom( netSocket, data, maxSize, 0, ( struct sockaddr* )&from, ( socklen_t* )&fromlen );
if( ret == -1 )
{
// there should be no blocking errors once select declares things are good
common->DPrintf( "idPort::GetPacketBlocking: %s\n", strerror( errno ) );
return false;
}
assert( ret < maxSize );
SockadrToNetadr( &from, &net_from );
size = ret;
return true;
}
/*
==================
idPort::SendPacket
==================
*/
void idPort::SendPacket( const netadr_t to, const void* data, int size )
{
int ret;
struct sockaddr_in addr;
if( to.type == NA_BAD )
{
common->Warning( "idPort::SendPacket: bad address type NA_BAD - ignored" );
return;
}
if( !netSocket )
{
return;
}
NetadrToSockadr( &to, &addr );
ret = sendto( netSocket, data, size, 0, ( struct sockaddr* ) &addr, sizeof( addr ) );
if( ret == -1 )
{
common->Printf( "idPort::SendPacket ERROR: to %s: %s\n", Sys_NetAdrToString( to ), strerror( errno ) );
}
}
/*
==================
idPort::InitForPort
==================
*/
bool idPort::InitForPort( int portNumber )
{
netSocket = IPSocket( net_ip.GetString(), portNumber, &bound_to );
if( netSocket <= 0 )
{
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
return false;
}
return true;
}
//=============================================================================
/*
==================
idTCP::idTCP
==================
*/
idTCP::idTCP()
{
fd = 0;
memset( &address, 0, sizeof( address ) );
}
/*
==================
idTCP::~idTCP
==================
*/
idTCP::~idTCP()
{
Close();
}
/*
==================
idTCP::Init
==================
*/
bool idTCP::Init( const char* host, short port )
{
struct sockaddr_in sadr;
if( !Sys_StringToNetAdr( host, &address, true ) )
{
common->Printf( "Couldn't resolve server name \"%s\"\n", host );
return false;
}
address.type = NA_IP;
if( !address.port )
{
address.port = port;
}
common->Printf( "\"%s\" resolved to %i.%i.%i.%i:%i\n", host,
address.ip[0], address.ip[1], address.ip[2], address.ip[3], address.port );
NetadrToSockadr( &address, &sadr );
if( fd )
{
common->Warning( "idTCP::Init: already initialized?\n" );
}
if( ( fd = socket( PF_INET, SOCK_STREAM, 0 ) ) == -1 )
{
fd = 0;
common->Printf( "ERROR: idTCP::Init: socket: %s\n", strerror( errno ) );
return false;
}
if( connect( fd, ( const sockaddr* )&sadr, sizeof( sadr ) ) == -1 )
{
common->Printf( "ERROR: idTCP::Init: connect: %s\n", strerror( errno ) );
close( fd );
fd = 0;
return false;
}
int status;
if( ( status = fcntl( fd, F_GETFL, 0 ) ) != -1 )
{
status |= O_NONBLOCK; /* POSIX */
status = fcntl( fd, F_SETFL, status );
}
if( status == -1 )
{
common->Printf( "ERROR: idTCP::Init: fcntl / O_NONBLOCK: %s\n", strerror( errno ) );
close( fd );
fd = 0;
return false;
}
common->DPrintf( "Opened TCP connection\n" );
return true;
}
/*
==================
idTCP::Close
==================
*/
void idTCP::Close()
{
if( fd )
{
close( fd );
}
fd = 0;
}
/*
==================
idTCP::Read
==================
*/
int idTCP::Read( void* data, int size )
{
int nbytes;
if( !fd )
{
common->Printf( "idTCP::Read: not initialized\n" );
return -1;
}
#if defined(_GNU_SOURCE)
// handle EINTR interrupted system call with TEMP_FAILURE_RETRY - this is probably GNU libc specific
if( ( nbytes = TEMP_FAILURE_RETRY( read( fd, data, size ) ) ) == -1 )
{
#else
do
{
nbytes = read( fd, data, size );
}
while( nbytes == -1 && errno == EINTR );
if( nbytes == -1 )
{
#endif
if( errno == EAGAIN )
{
return 0;
}
common->Printf( "ERROR: idTCP::Read: %s\n", strerror( errno ) );
Close();
return -1;
}
// a successful read of 0 bytes indicates remote has closed the connection
if( nbytes == 0 )
{
common->DPrintf( "idTCP::Read: read 0 bytes - assume connection closed\n" );
return -1;
}
return nbytes;
}
/*
==================
idTCP::Write
==================
*/
static void got_SIGPIPE( int signum )
{
common->Printf( "idTCP: SIGPIPE\n" );
}
int idTCP::Write( void* data, int size )
{
int nbytes;
if( !fd )
{
common->Printf( "idTCP::Write: not initialized\n" );
return -1;
}
struct sigaction bak_action;
struct sigaction action;
action.sa_handler = got_SIGPIPE;
sigemptyset( &action.sa_mask );
action.sa_flags = 0;
if( sigaction( SIGPIPE, &action, &bak_action ) != 0 )
{
common->Printf( "ERROR: idTCP::Write: failed to set temporary SIGPIPE handler\n" );
Close();
return -1;
}
#if defined(_GNU_SOURCE)
// handle EINTR interrupted system call with TEMP_FAILURE_RETRY - this is probably GNU libc specific
if( ( nbytes = TEMP_FAILURE_RETRY( write( fd, data, size ) ) ) == -1 )
{
#else
do
{
nbytes = write( fd, data, size );
}
while( nbytes == -1 && errno == EINTR );
if( nbytes == -1 )
{
#endif
common->Printf( "ERROR: idTCP::Write: %s\n", strerror( errno ) );
Close();
return -1;
}
if( sigaction( SIGPIPE, &bak_action, NULL ) != 0 )
{
common->Printf( "ERROR: idTCP::Write: failed to reset SIGPIPE handler\n" );
Close();
return -1;
}
return nbytes;
}

View file

@ -0,0 +1,61 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 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 3 of the License, or
(at your option) any later version.
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __SYS_POSIX__
#define __SYS_POSIX__
#include <signal.h>
void Posix_QueEvent( sysEventType_t type, int value, int value2, int ptrLength, void* ptr );
const char* Posix_Cwd();
// called first thing. does InitSigs and various things
void Posix_EarlyInit( );
// called after common has been initialized
void Posix_LateInit( );
void Posix_InitPThreads( );
void Posix_InitSigs( );
void Posix_ClearSigs( );
void Posix_Exit( int ret );
void Posix_SetExit( int ret ); // override the exit code
void Posix_SetExitSpawn( const char* exeName ); // set the process to be spawned when we quit
bool Posix_AddKeyboardPollEvent( int key, bool state );
bool Posix_AddMousePollEvent( int action, int value );
void Posix_PollInput();
void Posix_InitConsoleInput();
void Posix_Shutdown();
void Sys_FPE_handler( int signum, siginfo_t* info, void* context );
void Sys_DoStartProcess( const char* exeName, bool dofork = true ); // if not forking, current process gets replaced
#endif

View file

@ -0,0 +1,181 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 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 3 of the License, or
(at your option) any later version.
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../../idlib/precompiled.h"
#include "posix_public.h"
#include <string.h>
#include <errno.h>
const int siglist[] =
{
SIGHUP,
SIGQUIT,
SIGILL,
SIGTRAP,
SIGIOT,
SIGBUS,
SIGFPE,
SIGSEGV,
SIGPIPE,
SIGABRT,
// SIGTTIN,
// SIGTTOU,
-1
};
const char* signames[] =
{
"SIGHUP",
"SIGQUIT",
"SIGILL",
"SIGTRAP",
"SIGIOT",
"SIGBUS",
"SIGFPE",
"SIGSEGV",
"SIGPIPE",
"SIGABRT",
// "SIGTTIN",
// "SIGTTOUT"
};
static char fatalError[ 1024 ];
/*
================
Posix_ClearSigs
================
*/
void Posix_ClearSigs( )
{
struct sigaction action;
int i;
/* Set up the structure */
action.sa_handler = SIG_DFL;
sigemptyset( &action.sa_mask );
action.sa_flags = 0;
i = 0;
while( siglist[ i ] != -1 )
{
if( sigaction( siglist[ i ], &action, NULL ) != 0 )
{
Sys_Printf( "Failed to reset %s handler: %s\n", signames[ i ], strerror( errno ) );
}
i++;
}
}
/*
================
sig_handler
================
*/
static void sig_handler( int signum, siginfo_t* info, void* context )
{
static bool double_fault = false;
if( double_fault )
{
Sys_Printf( "double fault %s, bailing out\n", strsignal( signum ) );
Posix_Exit( signum );
}
double_fault = true;
// NOTE: see sigaction man page, could verbose the whole siginfo_t and print human readable si_code
Sys_Printf( "signal caught: %s\nsi_code %d\n", strsignal( signum ), info->si_code );
#ifndef ID_BT_STUB
Sys_Printf( "callstack:\n%s", Sys_GetCallStackCurStr( 30 ) );
#endif
if( fatalError[ 0 ] )
{
Sys_Printf( "Was in fatal error shutdown: %s\n", fatalError );
}
Sys_Printf( "Trying to exit gracefully..\n" );
Posix_SetExit( signum );
common->Quit();
}
/*
================
Posix_InitSigs
================
*/
void Posix_InitSigs( )
{
struct sigaction action;
int i;
fatalError[0] = '\0';
/* Set up the structure */
action.sa_sigaction = sig_handler;
sigemptyset( &action.sa_mask );
action.sa_flags = SA_SIGINFO | SA_NODEFER;
i = 0;
while( siglist[ i ] != -1 )
{
if( siglist[ i ] == SIGFPE )
{
action.sa_sigaction = Sys_FPE_handler;
if( sigaction( siglist[ i ], &action, NULL ) != 0 )
{
Sys_Printf( "Failed to set SIGFPE handler: %s\n", strerror( errno ) );
}
action.sa_sigaction = sig_handler;
}
else if( sigaction( siglist[ i ], &action, NULL ) != 0 )
{
Sys_Printf( "Failed to set %s handler: %s\n", signames[ i ], strerror( errno ) );
}
i++;
}
// if the process is backgrounded (running non interactively)
// then SIGTTIN or SIGTOU could be emitted, if not caught, turns into a SIGSTP
signal( SIGTTIN, SIG_IGN );
signal( SIGTTOU, SIG_IGN );
}
/*
==================
Sys_SetFatalError
==================
*/
void Sys_SetFatalError( const char* error )
{
strncpy( fatalError, error, sizeof( fatalError ) );
}

763
neo/sys/sdl/sdl_events.cpp Normal file
View file

@ -0,0 +1,763 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 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 3 of the License, or
(at your option) any later version.
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include <SDL.h>
#include "sys/platform.h"
#include "idlib/containers/List.h"
#include "idlib/Heap.h"
#include "framework/Common.h"
#include "framework/KeyInput.h"
#include "renderer/RenderSystem.h"
#include "renderer/tr_local.h"
#include "sys/sys_public.h"
#if !SDL_VERSION_ATLEAST(2, 0, 0)
#define SDL_Keycode SDLKey
#define SDLK_APPLICATION SDLK_COMPOSE
#define SDLK_SCROLLLOCK SDLK_SCROLLOCK
#define SDLK_LGUI SDLK_LSUPER
#define SDLK_RGUI SDLK_RSUPER
#define SDLK_KP_0 SDLK_KP0
#define SDLK_KP_1 SDLK_KP1
#define SDLK_KP_2 SDLK_KP2
#define SDLK_KP_3 SDLK_KP3
#define SDLK_KP_4 SDLK_KP4
#define SDLK_KP_5 SDLK_KP5
#define SDLK_KP_6 SDLK_KP6
#define SDLK_KP_7 SDLK_KP7
#define SDLK_KP_8 SDLK_KP8
#define SDLK_KP_9 SDLK_KP9
#define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK
#define SDLK_PRINTSCREEN SDLK_PRINT
#endif
const char* kbdNames[] =
{
"english", "french", "german", "italian", "spanish", "turkish", "norwegian", NULL
};
idCVar in_kbd( "in_kbd", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> );
struct kbd_poll_t
{
int key;
bool state;
kbd_poll_t()
{
}
kbd_poll_t( int k, bool s )
{
key = k;
state = s;
}
};
struct mouse_poll_t
{
int action;
int value;
mouse_poll_t()
{
}
mouse_poll_t( int a, int v )
{
action = a;
value = v;
}
};
static idList<kbd_poll_t> kbd_polls;
static idList<mouse_poll_t> mouse_polls;
static byte mapkey( SDL_Keycode key )
{
switch( key )
{
case SDLK_BACKSPACE:
return K_BACKSPACE;
case SDLK_PAUSE:
return K_PAUSE;
}
if( key <= SDLK_z )
return key & 0xff;
switch( key )
{
case SDLK_APPLICATION:
return K_COMMAND;
case SDLK_CAPSLOCK:
return K_CAPSLOCK;
case SDLK_SCROLLLOCK:
return K_SCROLL;
case SDLK_POWER:
return K_POWER;
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_LGUI:
return K_LWIN;
case SDLK_RGUI:
return K_RWIN;
case SDLK_MENU:
return K_MENU;
case SDLK_LALT:
case SDLK_RALT:
return K_ALT;
case SDLK_RCTRL:
case SDLK_LCTRL:
return K_CTRL;
case SDLK_RSHIFT:
case SDLK_LSHIFT:
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_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;
// K_INVERTED_EXCLAMATION;
case SDLK_F13:
return K_F13;
case SDLK_F14:
return K_F14;
case SDLK_F15:
return K_F15;
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_PERIOD:
return K_KP_DEL;
case SDLK_KP_DIVIDE:
return K_KP_SLASH;
// K_SUPERSCRIPT_TWO;
case SDLK_KP_MINUS:
return K_KP_MINUS;
// K_ACUTE_ACCENT;
case SDLK_KP_PLUS:
return K_KP_PLUS;
case SDLK_NUMLOCKCLEAR:
return K_KP_NUMLOCK;
case SDLK_KP_MULTIPLY:
return K_KP_STAR;
case SDLK_KP_EQUALS:
return K_KP_EQUALS;
// K_MASCULINE_ORDINATOR;
// K_GRAVE_A;
// K_AUX1;
// K_CEDILLA_C;
// K_GRAVE_E;
// K_AUX2;
// K_AUX3;
// K_AUX4;
// K_GRAVE_I;
// K_AUX5;
// K_AUX6;
// K_AUX7;
// K_AUX8;
// K_TILDE_N;
// K_GRAVE_O;
// K_AUX9;
// K_AUX10;
// K_AUX11;
// K_AUX12;
// K_AUX13;
// K_AUX14;
// K_GRAVE_U;
// K_AUX15;
// K_AUX16;
case SDLK_PRINTSCREEN:
return K_PRINT_SCR;
case SDLK_MODE:
return K_RIGHT_ALT;
}
return 0;
}
static void PushConsoleEvent( const char* s )
{
char* b;
size_t len;
len = strlen( s ) + 1;
b = ( char* )Mem_Alloc( len );
strcpy( b, s );
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = SE_CONSOLE;
event.user.data1 = ( void* )len;
event.user.data2 = b;
SDL_PushEvent( &event );
}
/*
=================
Sys_InitInput
=================
*/
void Sys_InitInput()
{
kbd_polls.SetGranularity( 64 );
mouse_polls.SetGranularity( 64 );
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_EnableUNICODE( 1 );
SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
#endif
in_kbd.SetModified();
}
/*
=================
Sys_ShutdownInput
=================
*/
void Sys_ShutdownInput()
{
kbd_polls.Clear();
mouse_polls.Clear();
}
/*
===========
Sys_InitScanTable
===========
*/
// Windows has its own version due to the tools
#ifndef _WIN32
void Sys_InitScanTable()
{
}
#endif
/*
===============
Sys_GetConsoleKey
===============
*/
unsigned char Sys_GetConsoleKey( bool shifted )
{
static unsigned char keys[2] = { '`', '~' };
if( in_kbd.IsModified() )
{
idStr lang = in_kbd.GetString();
if( lang.Length() )
{
if( !lang.Icmp( "french" ) )
{
keys[0] = '<';
keys[1] = '>';
}
else if( !lang.Icmp( "german" ) )
{
keys[0] = '^';
keys[1] = 176; // °
}
else if( !lang.Icmp( "italian" ) )
{
keys[0] = '\\';
keys[1] = '|';
}
else if( !lang.Icmp( "spanish" ) )
{
keys[0] = 186; // º
keys[1] = 170; // ª
}
else if( !lang.Icmp( "turkish" ) )
{
keys[0] = '"';
keys[1] = 233; // é
}
else if( !lang.Icmp( "norwegian" ) )
{
keys[0] = 124; // |
keys[1] = 167; // §
}
}
in_kbd.ClearModified();
}
return shifted ? keys[1] : keys[0];
}
/*
===============
Sys_MapCharForKey
===============
*/
unsigned char Sys_MapCharForKey( int key )
{
return key & 0xff;
}
/*
===============
Sys_GrabMouseCursor
===============
*/
void Sys_GrabMouseCursor( bool grabIt )
{
int flags;
if( grabIt )
flags = GRAB_ENABLE | GRAB_HIDECURSOR | GRAB_SETSTATE;
else
flags = GRAB_SETSTATE;
GLimp_GrabInput( flags );
}
/*
================
Sys_GetEvent
================
*/
sysEvent_t Sys_GetEvent()
{
SDL_Event ev;
sysEvent_t res = { };
byte key;
static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL };
#if SDL_VERSION_ATLEAST(2, 0, 0)
static char* s = NULL;
static size_t s_pos = 0;
if( s )
{
res.evType = SE_CHAR;
res.evValue = s[s_pos];
s_pos++;
if( !s[s_pos] )
{
free( s );
s = NULL;
s_pos = 0;
}
return res;
}
#endif
static byte c = 0;
if( c )
{
res.evType = SE_CHAR;
res.evValue = c;
c = 0;
return res;
}
if( SDL_PollEvent( &ev ) )
{
switch( ev.type )
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_WINDOWEVENT:
switch( ev.window.event )
{
case SDL_WINDOWEVENT_FOCUS_GAINED:
// unset modifier, in case alt-tab was used to leave window and ALT is still set
// as that can cause fullscreen-toggling when pressing enter...
SDL_Keymod currentmod = SDL_GetModState();
int newmod = KMOD_NONE;
if( currentmod & KMOD_CAPS ) // preserve capslock
newmod |= KMOD_CAPS;
SDL_SetModState( ( SDL_Keymod )newmod );
GLimp_GrabInput( GRAB_ENABLE | GRAB_REENABLE | GRAB_HIDECURSOR );
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
GLimp_GrabInput( 0 );
break;
}
return res_none;
#else
case SDL_ACTIVEEVENT:
{
int flags = 0;
if( ev.active.gain )
{
flags = GRAB_ENABLE | GRAB_REENABLE | GRAB_HIDECURSOR;
// unset modifier, in case alt-tab was used to leave window and ALT is still set
// as that can cause fullscreen-toggling when pressing enter...
SDLMod currentmod = SDL_GetModState();
int newmod = KMOD_NONE;
if( currentmod & KMOD_CAPS ) // preserve capslock
newmod |= KMOD_CAPS;
SDL_SetModState( ( SDLMod )newmod );
}
GLimp_GrabInput( flags );
}
return res_none;
case SDL_VIDEOEXPOSE:
return res_none;
#endif
case SDL_KEYDOWN:
if( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 )
{
cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
PushConsoleEvent( "vid_restart" );
return res_none;
}
// fall through
case SDL_KEYUP:
key = mapkey( ev.key.keysym.sym );
if( !key )
{
unsigned char c;
// check if its an unmapped console key
if( ev.key.keysym.unicode == ( c = Sys_GetConsoleKey( false ) ) )
{
key = c;
}
else if( ev.key.keysym.unicode == ( c = Sys_GetConsoleKey( true ) ) )
{
key = c;
}
else
{
if( ev.type == SDL_KEYDOWN )
common->Warning( "unmapped SDL key %d (0x%x)", ev.key.keysym.sym, ev.key.keysym.unicode );
return res_none;
}
}
res.evType = SE_KEY;
res.evValue = key;
res.evValue2 = ev.key.state == SDL_PRESSED ? 1 : 0;
kbd_polls.Append( kbd_poll_t( key, ev.key.state == SDL_PRESSED ) );
#if SDL_VERSION_ATLEAST(2, 0, 0)
if( key == K_BACKSPACE && ev.key.state == SDL_PRESSED )
c = key;
#else
if( ev.key.state == SDL_PRESSED && ( ev.key.keysym.unicode & 0xff00 ) == 0 )
c = ev.key.keysym.unicode & 0xff;
#endif
return res;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_TEXTINPUT:
if( ev.text.text && *ev.text.text )
{
if( !ev.text.text[1] )
c = *ev.text.text;
else
s = strdup( ev.text.text );
}
return res_none;
#endif
case SDL_MOUSEMOTION:
res.evType = SE_MOUSE;
res.evValue = ev.motion.xrel;
res.evValue2 = ev.motion.yrel;
mouse_polls.Append( mouse_poll_t( M_DELTAX, ev.motion.xrel ) );
mouse_polls.Append( mouse_poll_t( M_DELTAY, ev.motion.yrel ) );
return res;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_MOUSEWHEEL:
res.evType = SE_KEY;
if( ev.wheel.y > 0 )
{
res.evValue = K_MWHEELUP;
mouse_polls.Append( mouse_poll_t( M_DELTAZ, 1 ) );
}
else
{
res.evValue = K_MWHEELDOWN;
mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) );
}
res.evValue2 = 1;
return res;
#endif
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
res.evType = SE_KEY;
switch( ev.button.button )
{
case SDL_BUTTON_LEFT:
res.evValue = K_MOUSE1;
mouse_polls.Append( mouse_poll_t( M_ACTION1, ev.button.state == SDL_PRESSED ? 1 : 0 ) );
break;
case SDL_BUTTON_MIDDLE:
res.evValue = K_MOUSE3;
mouse_polls.Append( mouse_poll_t( M_ACTION3, ev.button.state == SDL_PRESSED ? 1 : 0 ) );
break;
case SDL_BUTTON_RIGHT:
res.evValue = K_MOUSE2;
mouse_polls.Append( mouse_poll_t( M_ACTION2, ev.button.state == SDL_PRESSED ? 1 : 0 ) );
break;
#if !SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_BUTTON_WHEELUP:
res.evValue = K_MWHEELUP;
if( ev.button.state == SDL_PRESSED )
mouse_polls.Append( mouse_poll_t( M_DELTAZ, 1 ) );
break;
case SDL_BUTTON_WHEELDOWN:
res.evValue = K_MWHEELDOWN;
if( ev.button.state == SDL_PRESSED )
mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) );
break;
#endif
}
res.evValue2 = ev.button.state == SDL_PRESSED ? 1 : 0;
return res;
case SDL_QUIT:
PushConsoleEvent( "quit" );
return res_none;
case SDL_USEREVENT:
switch( ev.user.code )
{
case SE_CONSOLE:
res.evType = SE_CONSOLE;
res.evPtrLength = ( intptr_t )ev.user.data1;
res.evPtr = ev.user.data2;
return res;
default:
common->Warning( "unknown user event %u", ev.user.code );
return res_none;
}
default:
common->Warning( "unknown event %u", ev.type );
return res_none;
}
}
return res_none;
}
/*
================
Sys_ClearEvents
================
*/
void Sys_ClearEvents()
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
;
kbd_polls.SetNum( 0, false );
mouse_polls.SetNum( 0, false );
}
/*
================
Sys_GenerateEvents
================
*/
void Sys_GenerateEvents()
{
char* s = Sys_ConsoleInput();
if( s )
PushConsoleEvent( s );
SDL_PumpEvents();
}
/*
================
Sys_PollKeyboardInputEvents
================
*/
int Sys_PollKeyboardInputEvents()
{
return kbd_polls.Num();
}
/*
================
Sys_ReturnKeyboardInputEvent
================
*/
int Sys_ReturnKeyboardInputEvent( const int n, int& key, bool& state )
{
if( n >= kbd_polls.Num() )
return 0;
key = kbd_polls[n].key;
state = kbd_polls[n].state;
return 1;
}
/*
================
Sys_EndKeyboardInputEvents
================
*/
void Sys_EndKeyboardInputEvents()
{
kbd_polls.SetNum( 0, false );
}
/*
================
Sys_PollMouseInputEvents
================
*/
int Sys_PollMouseInputEvents()
{
return mouse_polls.Num();
}
/*
================
Sys_ReturnMouseInputEvent
================
*/
int Sys_ReturnMouseInputEvent( const int n, int& action, int& value )
{
if( n >= mouse_polls.Num() )
return 0;
action = mouse_polls[n].action;
value = mouse_polls[n].value;
return 1;
}
/*
================
Sys_EndMouseInputEvents
================
*/
void Sys_EndMouseInputEvents()
{
mouse_polls.SetNum( 0, false );
}

341
neo/sys/sdl/sdl_glimp.cpp Normal file
View file

@ -0,0 +1,341 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 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 3 of the License, or
(at your option) any later version.
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include <SDL.h>
#include <SDL_syswm.h>
#include "sys/platform.h"
#include "framework/Licensee.h"
#include "renderer/tr_local.h"
idCVar in_nograb( "in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing" );
idCVar r_waylandcompat( "r_waylandcompat", "0", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "wayland compatible framebuffer" );
static bool grabbed = false;
#if SDL_VERSION_ATLEAST(2, 0, 0)
static SDL_Window* window = NULL;
static SDL_GLContext context = NULL;
#else
static SDL_Surface* window = NULL;
#define SDL_WINDOW_OPENGL SDL_OPENGL
#define SDL_WINDOW_FULLSCREEN SDL_FULLSCREEN
#endif
/*
===================
GLimp_Init
===================
*/
bool GLimp_Init( glimpParms_t parms )
{
common->Printf( "Initializing OpenGL subsystem\n" );
assert( SDL_WasInit( SDL_INIT_VIDEO ) );
Uint32 flags = SDL_WINDOW_OPENGL;
if( parms.fullScreen )
flags |= SDL_WINDOW_FULLSCREEN;
int colorbits = 24;
int depthbits = 24;
int stencilbits = 8;
for( int i = 0; i < 16; i++ )
{
// 0 - default
// 1 - minus colorbits
// 2 - minus depthbits
// 3 - minus stencil
if( ( i % 4 ) == 0 && i )
{
// one pass, reduce
switch( i / 4 )
{
case 2 :
if( colorbits == 24 )
colorbits = 16;
break;
case 1 :
if( depthbits == 24 )
depthbits = 16;
else if( depthbits == 16 )
depthbits = 8;
case 3 :
if( stencilbits == 24 )
stencilbits = 16;
else if( stencilbits == 16 )
stencilbits = 8;
}
}
int tcolorbits = colorbits;
int tdepthbits = depthbits;
int tstencilbits = stencilbits;
if( ( i % 4 ) == 3 )
{
// reduce colorbits
if( tcolorbits == 24 )
tcolorbits = 16;
}
if( ( i % 4 ) == 2 )
{
// reduce depthbits
if( tdepthbits == 24 )
tdepthbits = 16;
else if( tdepthbits == 16 )
tdepthbits = 8;
}
if( ( i % 4 ) == 1 )
{
// reduce stencilbits
if( tstencilbits == 24 )
tstencilbits = 16;
else if( tstencilbits == 16 )
tstencilbits = 8;
else
tstencilbits = 0;
}
int channelcolorbits = 4;
if( tcolorbits == 24 )
channelcolorbits = 8;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, channelcolorbits );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, channelcolorbits );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, channelcolorbits );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits );
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits );
if( r_waylandcompat.GetBool() )
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 0 );
else
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, channelcolorbits );
SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples );
#if SDL_VERSION_ATLEAST(2, 0, 0)
window = SDL_CreateWindow( GAME_NAME,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
parms.width, parms.height, flags );
context = SDL_GL_CreateContext( window );
if( !window )
{
common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s",
channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() );
continue;
}
if( SDL_GL_SetSwapInterval( r_swapInterval.GetInteger() ) < 0 )
common->Warning( "SDL_GL_SWAP_CONTROL not supported" );
SDL_GetWindowSize( window, &glConfig.vidWidth, &glConfig.vidHeight );
glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) == SDL_WINDOW_FULLSCREEN;
#else
SDL_WM_SetCaption( GAME_NAME, GAME_NAME );
if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger() ) < 0 )
common->Warning( "SDL_GL_SWAP_CONTROL not supported" );
window = SDL_SetVideoMode( parms.width, parms.height, colorbits, flags );
if( !window )
{
common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s",
channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() );
continue;
}
glConfig.vidWidth = window->w;
glConfig.vidHeight = window->h;
glConfig.isFullscreen = ( window->flags & SDL_FULLSCREEN ) == SDL_FULLSCREEN;
#endif
common->Printf( "Using %d color bits, %d depth, %d stencil display\n",
channelcolorbits, tdepthbits, tstencilbits );
glConfig.colorBits = tcolorbits;
glConfig.depthBits = tdepthbits;
glConfig.stencilBits = tstencilbits;
glConfig.displayFrequency = 0;
break;
}
if( !window )
{
common->Warning( "No usable GL mode found: %s", SDL_GetError() );
return false;
}
return true;
}
/*
===================
GLimp_SetScreenParms
===================
*/
bool GLimp_SetScreenParms( glimpParms_t parms )
{
common->DPrintf( "TODO: GLimp_ActivateContext\n" );
return true;
}
/*
===================
GLimp_Shutdown
===================
*/
void GLimp_Shutdown()
{
common->Printf( "Shutting down OpenGL subsystem\n" );
#if SDL_VERSION_ATLEAST(2, 0, 0)
if( context )
{
SDL_GL_DeleteContext( context );
context = NULL;
}
if( window )
{
SDL_DestroyWindow( window );
window = NULL;
}
#endif
}
/*
===================
GLimp_SwapBuffers
===================
*/
void GLimp_SwapBuffers()
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_SwapWindow( window );
#else
SDL_GL_SwapBuffers();
#endif
}
/*
=================
GLimp_SetGamma
=================
*/
void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] )
{
if( !window )
{
common->Warning( "GLimp_SetGamma called without window" );
return;
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
if( SDL_SetWindowGammaRamp( window, red, green, blue ) )
#else
if( SDL_SetGammaRamp( red, green, blue ) )
#endif
common->Warning( "Couldn't set gamma ramp: %s", SDL_GetError() );
}
/*
=================
GLimp_ActivateContext
=================
*/
void GLimp_ActivateContext()
{
common->DPrintf( "TODO: GLimp_ActivateContext\n" );
}
/*
=================
GLimp_DeactivateContext
=================
*/
void GLimp_DeactivateContext()
{
common->DPrintf( "TODO: GLimp_DeactivateContext\n" );
}
/*
===================
GLimp_ExtensionPointer
===================
*/
GLExtension_t GLimp_ExtensionPointer( const char* name )
{
assert( SDL_WasInit( SDL_INIT_VIDEO ) );
return ( GLExtension_t )SDL_GL_GetProcAddress( name );
}
void GLimp_GrabInput( int flags )
{
bool grab = flags & GRAB_ENABLE;
if( grab && ( flags & GRAB_REENABLE ) )
grab = false;
if( flags & GRAB_SETSTATE )
grabbed = grab;
if( in_nograb.GetBool() )
grab = false;
if( !window )
{
common->Warning( "GLimp_GrabInput called without window" );
return;
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_ShowCursor( flags & GRAB_HIDECURSOR ? SDL_DISABLE : SDL_ENABLE );
SDL_SetRelativeMouseMode( flags & GRAB_HIDECURSOR ? SDL_TRUE : SDL_FALSE );
SDL_SetWindowGrab( window, grab ? SDL_TRUE : SDL_FALSE );
#else
SDL_ShowCursor( flags & GRAB_HIDECURSOR ? SDL_DISABLE : SDL_ENABLE );
SDL_WM_GrabInput( grab ? SDL_GRAB_ON : SDL_GRAB_OFF );
#endif
}