2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright ( C ) 1999 - 2011 id Software LLC , a ZeniMax Media company .
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ( " Doom 3 Source Code " ) .
2011-11-22 21:28:15 +00:00
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"
# pragma hdrstop
# include <errno.h>
# include <float.h>
# include <fcntl.h>
# include <direct.h>
# include <io.h>
# include <conio.h>
# include <mapi.h>
# include <ShellAPI.h>
# ifndef __MRC__
# include <sys/types.h>
# include <sys/stat.h>
# endif
# include "../sys_local.h"
# include "win_local.h"
# include "rc/CreateResourceIDs.h"
# include "../../renderer/tr_local.h"
idCVar Win32Vars_t : : sys_arch ( " sys_arch " , " " , CVAR_SYSTEM | CVAR_INIT , " " ) ;
idCVar Win32Vars_t : : sys_cpustring ( " sys_cpustring " , " detect " , CVAR_SYSTEM | CVAR_INIT , " " ) ;
idCVar Win32Vars_t : : in_mouse ( " in_mouse " , " 1 " , CVAR_SYSTEM | CVAR_BOOL , " enable mouse input " ) ;
idCVar Win32Vars_t : : win_allowAltTab ( " win_allowAltTab " , " 0 " , CVAR_SYSTEM | CVAR_BOOL , " allow Alt-Tab when fullscreen " ) ;
idCVar Win32Vars_t : : win_notaskkeys ( " win_notaskkeys " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " disable windows task keys " ) ;
idCVar Win32Vars_t : : win_username ( " win_username " , " " , CVAR_SYSTEM | CVAR_INIT , " windows user name " ) ;
idCVar Win32Vars_t : : win_xpos ( " win_xpos " , " 3 " , CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER , " horizontal position of window " ) ;
idCVar Win32Vars_t : : win_ypos ( " win_ypos " , " 22 " , CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER , " vertical position of window " ) ;
idCVar Win32Vars_t : : win_outputDebugString ( " win_outputDebugString " , " 0 " , CVAR_SYSTEM | CVAR_BOOL , " " ) ;
idCVar Win32Vars_t : : win_outputEditString ( " win_outputEditString " , " 1 " , CVAR_SYSTEM | CVAR_BOOL , " " ) ;
idCVar Win32Vars_t : : win_viewlog ( " win_viewlog " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " " ) ;
idCVar Win32Vars_t : : win_timerUpdate ( " win_timerUpdate " , " 0 " , CVAR_SYSTEM | CVAR_BOOL , " allows the game to be updated while dragging the window " ) ;
idCVar Win32Vars_t : : win_allowMultipleInstances ( " win_allowMultipleInstances " , " 0 " , CVAR_SYSTEM | CVAR_BOOL , " allow multiple instances running concurrently " ) ;
Win32Vars_t win32 ;
static char sys_cmdline [ MAX_STRING_CHARS ] ;
// not a hard limit, just what we keep track of for debugging
xthreadInfo * g_threads [ MAX_THREADS ] ;
int g_thread_count = 0 ;
static sysMemoryStats_t exeLaunchMemoryStats ;
static xthreadInfo threadInfo ;
static HANDLE hTimer ;
/*
= = = = = = = = = = = = = = = =
Sys_GetExeLaunchMemoryStatus
= = = = = = = = = = = = = = = =
*/
void Sys_GetExeLaunchMemoryStatus ( sysMemoryStats_t & stats ) {
stats = exeLaunchMemoryStats ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_Createthread
= = = = = = = = = = = = = = = = = =
*/
void Sys_CreateThread ( xthread_t function , void * parms , xthreadPriority priority , xthreadInfo & info , const char * name , xthreadInfo * threads [ MAX_THREADS ] , int * thread_count ) {
HANDLE temp = CreateThread ( NULL , // LPSECURITY_ATTRIBUTES lpsa,
0 , // DWORD cbStack,
2011-12-01 17:01:13 +00:00
function , // LPTHREAD_START_ROUTINE lpStartAddr,
2011-11-22 21:28:15 +00:00
parms , // LPVOID lpvThreadParm,
0 , // DWORD fdwCreate,
& info . threadId ) ;
2011-12-01 17:01:13 +00:00
info . threadHandle = ( intptr_t ) temp ;
2011-11-22 21:28:15 +00:00
if ( priority = = THREAD_HIGHEST ) {
SetThreadPriority ( ( HANDLE ) info . threadHandle , THREAD_PRIORITY_HIGHEST ) ; // we better sleep enough to do this
} else if ( priority = = THREAD_ABOVE_NORMAL ) {
SetThreadPriority ( ( HANDLE ) info . threadHandle , THREAD_PRIORITY_ABOVE_NORMAL ) ;
}
info . name = name ;
if ( * thread_count < MAX_THREADS ) {
threads [ ( * thread_count ) + + ] = & info ;
} else {
common - > DPrintf ( " WARNING: MAX_THREADS reached \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
Sys_DestroyThread
= = = = = = = = = = = = = = = = = =
*/
void Sys_DestroyThread ( xthreadInfo & info ) {
WaitForSingleObject ( ( HANDLE ) info . threadHandle , INFINITE ) ;
CloseHandle ( ( HANDLE ) info . threadHandle ) ;
info . threadHandle = 0 ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_Sentry
= = = = = = = = = = = = = = = = = =
*/
void Sys_Sentry ( ) {
int j = 0 ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_GetThreadName
= = = = = = = = = = = = = = = = = =
*/
const char * Sys_GetThreadName ( int * index ) {
2011-12-01 17:01:13 +00:00
size_t id = GetCurrentThreadId ( ) ;
2011-11-22 21:28:15 +00:00
for ( int i = 0 ; i < g_thread_count ; i + + ) {
if ( id = = g_threads [ i ] - > threadId ) {
if ( index ) {
* index = i ;
}
return g_threads [ i ] - > name ;
}
}
if ( index ) {
* index = - 1 ;
}
return " main " ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_EnterCriticalSection
= = = = = = = = = = = = = = = = = =
*/
void Sys_EnterCriticalSection ( int index ) {
assert ( index > = 0 & & index < MAX_CRITICAL_SECTIONS ) ;
if ( TryEnterCriticalSection ( & win32 . criticalSections [ index ] ) = = 0 ) {
EnterCriticalSection ( & win32 . criticalSections [ index ] ) ;
// Sys_DebugPrintf( "busy lock '%s' in thread '%s'\n", lock->name, Sys_GetThreadName() );
}
}
/*
= = = = = = = = = = = = = = = = = =
Sys_LeaveCriticalSection
= = = = = = = = = = = = = = = = = =
*/
void Sys_LeaveCriticalSection ( int index ) {
assert ( index > = 0 & & index < MAX_CRITICAL_SECTIONS ) ;
LeaveCriticalSection ( & win32 . criticalSections [ index ] ) ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_WaitForEvent
= = = = = = = = = = = = = = = = = =
*/
void Sys_WaitForEvent ( int index ) {
assert ( index = = 0 ) ;
if ( ! win32 . backgroundDownloadSemaphore ) {
win32 . backgroundDownloadSemaphore = CreateEvent ( NULL , TRUE , FALSE , NULL ) ;
}
WaitForSingleObject ( win32 . backgroundDownloadSemaphore , INFINITE ) ;
ResetEvent ( win32 . backgroundDownloadSemaphore ) ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_TriggerEvent
= = = = = = = = = = = = = = = = = =
*/
void Sys_TriggerEvent ( int index ) {
assert ( index = = 0 ) ;
SetEvent ( win32 . backgroundDownloadSemaphore ) ;
}
# pragma optimize( "", on )
# ifdef DEBUG
static unsigned int debug_total_alloc = 0 ;
static unsigned int debug_total_alloc_count = 0 ;
static unsigned int debug_current_alloc = 0 ;
static unsigned int debug_current_alloc_count = 0 ;
static unsigned int debug_frame_alloc = 0 ;
static unsigned int debug_frame_alloc_count = 0 ;
idCVar sys_showMallocs ( " sys_showMallocs " , " 0 " , CVAR_SYSTEM , " " ) ;
// _HOOK_ALLOC, _HOOK_REALLOC, _HOOK_FREE
typedef struct CrtMemBlockHeader
{
struct _CrtMemBlockHeader * pBlockHeaderNext ; // Pointer to the block allocated just before this one:
struct _CrtMemBlockHeader * pBlockHeaderPrev ; // Pointer to the block allocated just after this one
char * szFileName ; // File name
int nLine ; // Line number
size_t nDataSize ; // Size of user block
int nBlockUse ; // Type of block
long lRequest ; // Allocation number
byte gap [ 4 ] ; // Buffer just before (lower than) the user's memory:
} CrtMemBlockHeader ;
# include <crtdbg.h>
/*
= = = = = = = = = = = = = = = = = =
Sys_AllocHook
called for every malloc / new / free / delete
= = = = = = = = = = = = = = = = = =
*/
2011-12-06 18:20:15 +00:00
int Sys_AllocHook ( int nAllocType , void * pvData , size_t nSize , int nBlockUse , long lRequest , const unsigned char * szFileName , int nLine )
2011-11-22 21:28:15 +00:00
{
CrtMemBlockHeader * pHead ;
byte * temp ;
if ( nBlockUse = = _CRT_BLOCK )
{
2011-12-06 18:20:15 +00:00
return ( TRUE ) ;
2011-11-22 21:28:15 +00:00
}
// get a pointer to memory block header
temp = ( byte * ) pvData ;
temp - = 32 ;
pHead = ( CrtMemBlockHeader * ) temp ;
switch ( nAllocType ) {
case _HOOK_ALLOC :
debug_total_alloc + = nSize ;
debug_current_alloc + = nSize ;
debug_frame_alloc + = nSize ;
debug_total_alloc_count + + ;
debug_current_alloc_count + + ;
debug_frame_alloc_count + + ;
break ;
case _HOOK_FREE :
assert ( pHead - > gap [ 0 ] = = 0xfd & & pHead - > gap [ 1 ] = = 0xfd & & pHead - > gap [ 2 ] = = 0xfd & & pHead - > gap [ 3 ] = = 0xfd ) ;
debug_current_alloc - = pHead - > nDataSize ;
debug_current_alloc_count - - ;
debug_total_alloc_count + + ;
debug_frame_alloc_count + + ;
break ;
case _HOOK_REALLOC :
assert ( pHead - > gap [ 0 ] = = 0xfd & & pHead - > gap [ 1 ] = = 0xfd & & pHead - > gap [ 2 ] = = 0xfd & & pHead - > gap [ 3 ] = = 0xfd ) ;
debug_current_alloc - = pHead - > nDataSize ;
debug_total_alloc + = nSize ;
debug_current_alloc + = nSize ;
debug_frame_alloc + = nSize ;
debug_total_alloc_count + + ;
debug_current_alloc_count - - ;
debug_frame_alloc_count + + ;
break ;
}
return ( TRUE ) ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_DebugMemory_f
= = = = = = = = = = = = = = = = = =
*/
void Sys_DebugMemory_f ( void ) {
2011-12-06 18:20:15 +00:00
common - > Printf ( " Total allocation %8dk in %d blocks \n " , debug_total_alloc / 1024 , debug_total_alloc_count ) ;
common - > Printf ( " Current allocation %8dk in %d blocks \n " , debug_current_alloc / 1024 , debug_current_alloc_count ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
Sys_MemFrame
= = = = = = = = = = = = = = = = = =
*/
void Sys_MemFrame ( void ) {
if ( sys_showMallocs . GetInteger ( ) ) {
common - > Printf ( " Frame: %8dk in %5d blocks \n " , debug_frame_alloc / 1024 , debug_frame_alloc_count ) ;
}
debug_frame_alloc = 0 ;
debug_frame_alloc_count = 0 ;
}
# endif
/*
= = = = = = = = = = = = = = = = = =
Sys_FlushCacheMemory
On windows , the vertex buffers are write combined , so they
don ' t need to be flushed from the cache
= = = = = = = = = = = = = = = = = =
*/
void Sys_FlushCacheMemory ( void * base , int bytes ) {
}
/*
= = = = = = = = = = = = =
Sys_Error
Show the early console as an error dialog
= = = = = = = = = = = = =
*/
void Sys_Error ( const char * error , . . . ) {
va_list argptr ;
char text [ 4096 ] ;
2011-12-06 18:20:15 +00:00
MSG msg ;
2011-11-22 21:28:15 +00:00
va_start ( argptr , error ) ;
vsprintf ( text , error , argptr ) ;
va_end ( argptr ) ;
Conbuf_AppendText ( text ) ;
Conbuf_AppendText ( " \n " ) ;
Win_SetErrorText ( text ) ;
Sys_ShowConsole ( 1 , true ) ;
timeEndPeriod ( 1 ) ;
Sys_ShutdownInput ( ) ;
GLimp_Shutdown ( ) ;
// wait for the user to quit
while ( 1 ) {
if ( ! GetMessage ( & msg , NULL , 0 , 0 ) ) {
common - > Quit ( ) ;
}
TranslateMessage ( & msg ) ;
2011-12-06 18:20:15 +00:00
DispatchMessage ( & msg ) ;
2011-11-22 21:28:15 +00:00
}
Sys_DestroyConsole ( ) ;
exit ( 1 ) ;
}
/*
= = = = = = = = = = = = = =
Sys_Quit
= = = = = = = = = = = = = =
*/
void Sys_Quit ( void ) {
timeEndPeriod ( 1 ) ;
Sys_ShutdownInput ( ) ;
Sys_DestroyConsole ( ) ;
ExitProcess ( 0 ) ;
}
/*
= = = = = = = = = = = = = =
Sys_Printf
= = = = = = = = = = = = = =
*/
# define MAXPRINTMSG 4096
void Sys_Printf ( const char * fmt , . . . ) {
char msg [ MAXPRINTMSG ] ;
va_list argptr ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( msg , MAXPRINTMSG - 1 , fmt , argptr ) ;
va_end ( argptr ) ;
msg [ sizeof ( msg ) - 1 ] = ' \0 ' ;
if ( win32 . win_outputDebugString . GetBool ( ) ) {
OutputDebugString ( msg ) ;
}
if ( win32 . win_outputEditString . GetBool ( ) ) {
Conbuf_AppendText ( msg ) ;
}
}
/*
= = = = = = = = = = = = = =
Sys_DebugPrintf
= = = = = = = = = = = = = =
*/
# define MAXPRINTMSG 4096
void Sys_DebugPrintf ( const char * fmt , . . . ) {
char msg [ MAXPRINTMSG ] ;
va_list argptr ;
va_start ( argptr , fmt ) ;
idStr : : vsnPrintf ( msg , MAXPRINTMSG - 1 , fmt , argptr ) ;
msg [ sizeof ( msg ) - 1 ] = ' \0 ' ;
va_end ( argptr ) ;
OutputDebugString ( msg ) ;
}
/*
= = = = = = = = = = = = = =
Sys_DebugVPrintf
= = = = = = = = = = = = = =
*/
void Sys_DebugVPrintf ( const char * fmt , va_list arg ) {
char msg [ MAXPRINTMSG ] ;
idStr : : vsnPrintf ( msg , MAXPRINTMSG - 1 , fmt , arg ) ;
msg [ sizeof ( msg ) - 1 ] = ' \0 ' ;
OutputDebugString ( msg ) ;
}
/*
= = = = = = = = = = = = = =
Sys_Sleep
= = = = = = = = = = = = = =
*/
void Sys_Sleep ( int msec ) {
Sleep ( msec ) ;
}
/*
= = = = = = = = = = = = = =
Sys_ShowWindow
= = = = = = = = = = = = = =
*/
void Sys_ShowWindow ( bool show ) {
: : ShowWindow ( win32 . hWnd , show ? SW_SHOW : SW_HIDE ) ;
}
/*
= = = = = = = = = = = = = =
Sys_IsWindowVisible
= = = = = = = = = = = = = =
*/
bool Sys_IsWindowVisible ( void ) {
return ( : : IsWindowVisible ( win32 . hWnd ) ! = 0 ) ;
}
/*
= = = = = = = = = = = = = =
Sys_Mkdir
= = = = = = = = = = = = = =
*/
void Sys_Mkdir ( const char * path ) {
_mkdir ( path ) ;
}
/*
= = = = = = = = = = = = = = = = =
Sys_FileTimeStamp
= = = = = = = = = = = = = = = = =
*/
ID_TIME_T Sys_FileTimeStamp ( FILE * fp ) {
struct _stat st ;
_fstat ( _fileno ( fp ) , & st ) ;
return ( long ) st . st_mtime ;
}
/*
= = = = = = = = = = = = = =
Sys_Cwd
= = = = = = = = = = = = = =
*/
const char * Sys_Cwd ( void ) {
static char cwd [ MAX_OSPATH ] ;
_getcwd ( cwd , sizeof ( cwd ) - 1 ) ;
cwd [ MAX_OSPATH - 1 ] = 0 ;
return cwd ;
}
/*
= = = = = = = = = = = = = =
Sys_DefaultCDPath
= = = = = = = = = = = = = =
*/
const char * Sys_DefaultCDPath ( void ) {
return " " ;
}
/*
= = = = = = = = = = = = = =
Sys_DefaultBasePath
= = = = = = = = = = = = = =
*/
const char * Sys_DefaultBasePath ( void ) {
return Sys_Cwd ( ) ;
}
/*
= = = = = = = = = = = = = =
Sys_DefaultSavePath
= = = = = = = = = = = = = =
*/
const char * Sys_DefaultSavePath ( void ) {
return cvarSystem - > GetCVarString ( " fs_basepath " ) ;
}
/*
= = = = = = = = = = = = = =
Sys_EXEPath
= = = = = = = = = = = = = =
*/
const char * Sys_EXEPath ( void ) {
static char exe [ MAX_OSPATH ] ;
GetModuleFileName ( NULL , exe , sizeof ( exe ) - 1 ) ;
return exe ;
}
/*
= = = = = = = = = = = = = =
Sys_ListFiles
= = = = = = = = = = = = = =
*/
int Sys_ListFiles ( const char * directory , const char * extension , idStrList & list ) {
idStr search ;
struct _finddata_t findinfo ;
int findhandle ;
int flag ;
if ( ! extension ) {
extension = " " ;
}
// passing a slash as extension will find directories
if ( extension [ 0 ] = = ' / ' & & extension [ 1 ] = = 0 ) {
extension = " " ;
flag = 0 ;
} else {
flag = _A_SUBDIR ;
}
sprintf ( search , " %s \\ *%s " , directory , extension ) ;
// search
list . Clear ( ) ;
findhandle = _findfirst ( search , & findinfo ) ;
if ( findhandle = = - 1 ) {
return - 1 ;
}
do {
if ( flag ^ ( findinfo . attrib & _A_SUBDIR ) ) {
list . Append ( findinfo . name ) ;
}
} while ( _findnext ( findhandle , & findinfo ) ! = - 1 ) ;
_findclose ( findhandle ) ;
return list . Num ( ) ;
}
/*
= = = = = = = = = = = = = = = =
Sys_GetClipboardData
= = = = = = = = = = = = = = = =
*/
char * Sys_GetClipboardData ( void ) {
char * data = NULL ;
char * cliptext ;
if ( OpenClipboard ( NULL ) ! = 0 ) {
HANDLE hClipboardData ;
if ( ( hClipboardData = GetClipboardData ( CF_TEXT ) ) ! = 0 ) {
if ( ( cliptext = ( char * ) GlobalLock ( hClipboardData ) ) ! = 0 ) {
data = ( char * ) Mem_Alloc ( GlobalSize ( hClipboardData ) + 1 ) ;
strcpy ( data , cliptext ) ;
GlobalUnlock ( hClipboardData ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
strtok ( data , " \n \r \b " ) ;
}
}
CloseClipboard ( ) ;
}
return data ;
}
/*
= = = = = = = = = = = = = = = =
Sys_SetClipboardData
= = = = = = = = = = = = = = = =
*/
void Sys_SetClipboardData ( const char * string ) {
HGLOBAL HMem ;
char * PMem ;
// allocate memory block
HMem = ( char * ) : : GlobalAlloc ( GMEM_MOVEABLE | GMEM_DDESHARE , strlen ( string ) + 1 ) ;
if ( HMem = = NULL ) {
return ;
}
// lock allocated memory and obtain a pointer
PMem = ( char * ) : : GlobalLock ( HMem ) ;
if ( PMem = = NULL ) {
return ;
}
// copy text into allocated memory block
lstrcpy ( PMem , string ) ;
// unlock allocated memory
: : GlobalUnlock ( HMem ) ;
// open Clipboard
if ( ! OpenClipboard ( 0 ) ) {
: : GlobalFree ( HMem ) ;
return ;
}
// remove current Clipboard contents
EmptyClipboard ( ) ;
// supply the memory handle to the Clipboard
SetClipboardData ( CF_TEXT , HMem ) ;
HMem = 0 ;
// close Clipboard
CloseClipboard ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DLL Loading
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = =
Sys_DLL_Load
= = = = = = = = = = = = = = = = = = = = =
*/
2011-12-01 09:40:40 +00:00
uintptr_t Sys_DLL_Load ( const char * dllName ) {
2011-11-22 21:28:15 +00:00
HINSTANCE libHandle ;
libHandle = LoadLibrary ( dllName ) ;
if ( libHandle ) {
// since we can't have LoadLibrary load only from the specified path, check it did the right thing
char loadedPath [ MAX_OSPATH ] ;
GetModuleFileName ( libHandle , loadedPath , sizeof ( loadedPath ) - 1 ) ;
if ( idStr : : IcmpPath ( dllName , loadedPath ) ) {
Sys_Printf ( " ERROR: LoadLibrary '%s' wants to load '%s' \n " , dllName , loadedPath ) ;
Sys_DLL_Unload ( ( int ) libHandle ) ;
return 0 ;
}
}
2011-12-01 09:40:40 +00:00
return ( uintptr_t ) libHandle ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = =
Sys_DLL_GetProcAddress
= = = = = = = = = = = = = = = = = = = = =
*/
2011-12-01 09:40:40 +00:00
void * Sys_DLL_GetProcAddress ( uintptr_t dllHandle , const char * procName ) {
2011-12-06 18:20:15 +00:00
return GetProcAddress ( ( HINSTANCE ) dllHandle , procName ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = =
Sys_DLL_Unload
= = = = = = = = = = = = = = = = = = = = =
*/
2011-12-01 09:40:40 +00:00
void Sys_DLL_Unload ( uintptr_t dllHandle ) {
2011-11-22 21:28:15 +00:00
if ( ! dllHandle ) {
return ;
}
if ( FreeLibrary ( ( HINSTANCE ) dllHandle ) = = 0 ) {
int lastError = GetLastError ( ) ;
LPVOID lpMsgBuf ;
FormatMessage (
FORMAT_MESSAGE_ALLOCATE_BUFFER ,
NULL ,
lastError ,
MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , // Default language
( LPTSTR ) & lpMsgBuf ,
0 ,
2011-12-06 18:20:15 +00:00
NULL
2011-11-22 21:28:15 +00:00
) ;
Sys_Error ( " Sys_DLL_Unload: FreeLibrary failed - %s (%d) " , lpMsgBuf , lastError ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
EVENT LOOP
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define MAX_QUED_EVENTS 256
# define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
sysEvent_t eventQue [ MAX_QUED_EVENTS ] ;
int eventHead = 0 ;
int eventTail = 0 ;
/*
= = = = = = = = = = = = = = = =
Sys_QueEvent
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 ;
ev = & eventQue [ eventHead & MASK_QUED_EVENTS ] ;
if ( eventHead - eventTail > = MAX_QUED_EVENTS ) {
common - > Printf ( " Sys_QueEvent: overflow \n " ) ;
// we are discarding an event, but don't leak memory
if ( ev - > evPtr ) {
Mem_Free ( ev - > evPtr ) ;
}
eventTail + + ;
}
eventHead + + ;
ev - > evType = type ;
ev - > evValue = value ;
ev - > evValue2 = value2 ;
ev - > evPtrLength = ptrLength ;
ev - > evPtr = ptr ;
}
/*
= = = = = = = = = = = = =
Sys_PumpEvents
This allows windows to be moved during renderbump
= = = = = = = = = = = = =
*/
void Sys_PumpEvents ( void ) {
2011-12-06 18:20:15 +00:00
MSG msg ;
2011-11-22 21:28:15 +00:00
// pump the message loop
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_NOREMOVE ) ) {
if ( ! GetMessage ( & msg , NULL , 0 , 0 ) ) {
common - > Quit ( ) ;
}
// save the msg time, because wndprocs don't have access to the timestamp
if ( win32 . sysMsgTime & & win32 . sysMsgTime > ( int ) msg . time ) {
2011-12-06 18:20:15 +00:00
// don't ever let the event times run backwards
2011-11-22 21:28:15 +00:00
// common->Printf( "Sys_PumpEvents: win32.sysMsgTime (%i) > msg.time (%i)\n", win32.sysMsgTime, msg.time );
} else {
win32 . sysMsgTime = msg . time ;
}
# ifdef ID_ALLOW_TOOLS
2011-12-06 18:20:15 +00:00
if ( GUIEditorHandleMessage ( & msg ) ) {
2011-11-22 21:28:15 +00:00
continue ;
}
# endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
TranslateMessage ( & msg ) ;
2011-12-06 18:20:15 +00:00
DispatchMessage ( & msg ) ;
2011-11-22 21:28:15 +00:00
}
}
/*
= = = = = = = = = = = = = = = =
Sys_GenerateEvents
= = = = = = = = = = = = = = = =
*/
void Sys_GenerateEvents ( void ) {
static int entered = false ;
char * s ;
if ( entered ) {
return ;
}
entered = true ;
// pump the message loop
Sys_PumpEvents ( ) ;
// make sure mouse and joystick are only called once a frame
IN_Frame ( ) ;
// check for console commands
s = Sys_ConsoleInput ( ) ;
if ( s ) {
char * b ;
int len ;
len = strlen ( s ) + 1 ;
b = ( char * ) Mem_Alloc ( len ) ;
strcpy ( b , s ) ;
Sys_QueEvent ( 0 , SE_CONSOLE , 0 , 0 , len , b ) ;
}
entered = false ;
}
/*
= = = = = = = = = = = = = = = =
Sys_ClearEvents
= = = = = = = = = = = = = = = =
*/
void Sys_ClearEvents ( void ) {
eventHead = eventTail = 0 ;
}
/*
= = = = = = = = = = = = = = = =
Sys_GetEvent
= = = = = = = = = = = = = = = =
*/
sysEvent_t Sys_GetEvent ( void ) {
sysEvent_t ev ;
// return if we have data
if ( eventHead > eventTail ) {
eventTail + + ;
return eventQue [ ( eventTail - 1 ) & MASK_QUED_EVENTS ] ;
}
2011-12-06 18:20:15 +00:00
// return the empty event
2011-11-22 21:28:15 +00:00
memset ( & ev , 0 , sizeof ( ev ) ) ;
return ev ;
}
//================================================================
/*
= = = = = = = = = = = = = = = = =
Sys_In_Restart_f
Restart the input subsystem
= = = = = = = = = = = = = = = = =
*/
void Sys_In_Restart_f ( const idCmdArgs & args ) {
Sys_ShutdownInput ( ) ;
Sys_InitInput ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
Sys_AsyncThread
= = = = = = = = = = = = = = = = = =
*/
2011-12-01 17:01:13 +00:00
static THREAD_RETURN_TYPE Sys_AsyncThread ( void * parm ) {
2011-11-22 21:28:15 +00:00
int wakeNumber ;
int startTime ;
startTime = Sys_Milliseconds ( ) ;
wakeNumber = 0 ;
while ( 1 ) {
2011-12-06 18:20:15 +00:00
# ifdef WIN32
2011-11-22 21:28:15 +00:00
// this will trigger 60 times a second
int r = WaitForSingleObject ( hTimer , 100 ) ;
if ( r ! = WAIT_OBJECT_0 ) {
OutputDebugString ( " idPacketServer::PacketServerInterrupt: bad wait return " ) ;
}
# endif
#if 0
wakeNumber + + ;
int msec = Sys_Milliseconds ( ) ;
int deltaTime = msec - startTime ;
startTime = msec ;
char str [ 1024 ] ;
sprintf ( str , " %i " , deltaTime ) ;
OutputDebugString ( str ) ;
# endif
common - > Async ( ) ;
}
2011-12-01 17:01:13 +00:00
return ( THREAD_RETURN_TYPE ) 0 ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = =
Sys_StartAsyncThread
Start the thread that will call idCommon : : Async ( )
= = = = = = = = = = = = = =
*/
void Sys_StartAsyncThread ( void ) {
// create an auto-reset event that happens 60 times a second
hTimer = CreateWaitableTimer ( NULL , false , NULL ) ;
if ( ! hTimer ) {
common - > Error ( " idPacketServer::Spawn: CreateWaitableTimer failed " ) ;
}
LARGE_INTEGER t ;
t . HighPart = t . LowPart = 0 ;
SetWaitableTimer ( hTimer , & t , USERCMD_MSEC , NULL , NULL , TRUE ) ;
2011-12-01 17:01:13 +00:00
Sys_CreateThread ( Sys_AsyncThread , NULL , THREAD_ABOVE_NORMAL , threadInfo , " Async " , g_threads , & g_thread_count ) ;
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
# ifdef SET_THREAD_AFFINITY
2011-11-22 21:28:15 +00:00
// give the async thread an affinity for the second cpu
SetThreadAffinityMask ( ( HANDLE ) threadInfo . threadHandle , 2 ) ;
# endif
if ( ! threadInfo . threadHandle ) {
common - > Error ( " Sys_StartAsyncThread: failed " ) ;
}
}
/*
= = = = = = = = = = = = = = = =
Sys_AlreadyRunning
returns true if there is a copy of D3 running already
= = = = = = = = = = = = = = = =
*/
bool Sys_AlreadyRunning ( void ) {
# ifndef DEBUG
if ( ! win32 . win_allowMultipleInstances . GetBool ( ) ) {
HANDLE hMutexOneInstance = : : CreateMutex ( NULL , FALSE , " DOOM3 " ) ;
if ( : : GetLastError ( ) = = ERROR_ALREADY_EXISTS | | : : GetLastError ( ) = = ERROR_ACCESS_DENIED ) {
return true ;
}
}
# endif
return false ;
}
/*
= = = = = = = = = = = = = = = =
Sys_Init
The cvar system must already be setup
= = = = = = = = = = = = = = = =
*/
# define OSR2_BUILD_NUMBER 1111
# define WIN98_BUILD_NUMBER 1998
void Sys_Init ( void ) {
CoInitialize ( NULL ) ;
// make sure the timer is high precision, otherwise
// NT gets 18ms resolution
timeBeginPeriod ( 1 ) ;
// get WM_TIMER messages pumped every millisecond
// SetTimer( NULL, 0, 100, NULL );
cmdSystem - > AddCommand ( " in_restart " , Sys_In_Restart_f , CMD_FL_SYSTEM , " restarts the input system " ) ;
# ifdef DEBUG
cmdSystem - > AddCommand ( " createResourceIDs " , CreateResourceIDs_f , CMD_FL_TOOL , " assigns resource IDs in _resouce.h files " ) ;
# endif
#if 0
cmdSystem - > AddCommand ( " setAsyncSound " , Sys_SetAsyncSound_f , CMD_FL_SYSTEM , " set the async sound option " ) ;
# endif
//
// Windows user name
//
win32 . win_username . SetString ( Sys_GetCurrentUser ( ) ) ;
//
// Windows version
//
win32 . osversion . dwOSVersionInfoSize = sizeof ( win32 . osversion ) ;
if ( ! GetVersionEx ( ( LPOSVERSIONINFO ) & win32 . osversion ) )
Sys_Error ( " Couldn't get OS info " ) ;
if ( win32 . osversion . dwMajorVersion < 4 ) {
Sys_Error ( GAME_NAME " requires Windows version 4 (NT) or greater " ) ;
}
if ( win32 . osversion . dwPlatformId = = VER_PLATFORM_WIN32s ) {
Sys_Error ( GAME_NAME " doesn't run on Win32s " ) ;
}
if ( win32 . osversion . dwPlatformId = = VER_PLATFORM_WIN32_NT ) {
if ( win32 . osversion . dwMajorVersion < = 4 ) {
win32 . sys_arch . SetString ( " WinNT (NT) " ) ;
} else if ( win32 . osversion . dwMajorVersion = = 5 & & win32 . osversion . dwMinorVersion = = 0 ) {
win32 . sys_arch . SetString ( " Win2K (NT) " ) ;
} else if ( win32 . osversion . dwMajorVersion = = 5 & & win32 . osversion . dwMinorVersion = = 1 ) {
win32 . sys_arch . SetString ( " WinXP (NT) " ) ;
} else if ( win32 . osversion . dwMajorVersion = = 6 ) {
win32 . sys_arch . SetString ( " Vista " ) ;
} else {
win32 . sys_arch . SetString ( " Unknown NT variant " ) ;
}
} else if ( win32 . osversion . dwPlatformId = = VER_PLATFORM_WIN32_WINDOWS ) {
if ( win32 . osversion . dwMajorVersion = = 4 & & win32 . osversion . dwMinorVersion = = 0 ) {
// Win95
if ( win32 . osversion . szCSDVersion [ 1 ] = = ' C ' ) {
win32 . sys_arch . SetString ( " Win95 OSR2 (95) " ) ;
} else {
win32 . sys_arch . SetString ( " Win95 (95) " ) ;
}
} else if ( win32 . osversion . dwMajorVersion = = 4 & & win32 . osversion . dwMinorVersion = = 10 ) {
// Win98
if ( win32 . osversion . szCSDVersion [ 1 ] = = ' A ' ) {
win32 . sys_arch . SetString ( " Win98SE (95) " ) ;
} else {
win32 . sys_arch . SetString ( " Win98 (95) " ) ;
}
} else if ( win32 . osversion . dwMajorVersion = = 4 & & win32 . osversion . dwMinorVersion = = 90 ) {
// WinMe
2011-12-06 18:20:15 +00:00
win32 . sys_arch . SetString ( " WinMe (95) " ) ;
2011-11-22 21:28:15 +00:00
} else {
2011-12-06 18:20:15 +00:00
win32 . sys_arch . SetString ( " Unknown 95 variant " ) ;
2011-11-22 21:28:15 +00:00
}
} else {
win32 . sys_arch . SetString ( " unknown Windows variant " ) ;
}
//
// CPU type
//
if ( ! idStr : : Icmp ( win32 . sys_cpustring . GetString ( ) , " detect " ) ) {
idStr string ;
common - > Printf ( " %1.0f MHz " , Sys_ClockTicksPerSecond ( ) / 1000000.0f ) ;
win32 . cpuid = Sys_GetCPUId ( ) ;
string . Clear ( ) ;
if ( win32 . cpuid & CPUID_AMD ) {
string + = " AMD CPU " ;
} else if ( win32 . cpuid & CPUID_INTEL ) {
string + = " Intel CPU " ;
} else if ( win32 . cpuid & CPUID_UNSUPPORTED ) {
string + = " unsupported CPU " ;
} else {
string + = " generic CPU " ;
}
string + = " with " ;
if ( win32 . cpuid & CPUID_MMX ) {
string + = " MMX & " ;
}
if ( win32 . cpuid & CPUID_3DNOW ) {
string + = " 3DNow! & " ;
}
if ( win32 . cpuid & CPUID_SSE ) {
string + = " SSE & " ;
}
if ( win32 . cpuid & CPUID_SSE2 ) {
2011-12-06 18:20:15 +00:00
string + = " SSE2 & " ;
2011-11-22 21:28:15 +00:00
}
if ( win32 . cpuid & CPUID_SSE3 ) {
string + = " SSE3 & " ;
}
if ( win32 . cpuid & CPUID_HTT ) {
string + = " HTT & " ;
}
string . StripTrailing ( " & " ) ;
string . StripTrailing ( " with " ) ;
win32 . sys_cpustring . SetString ( string ) ;
} else {
common - > Printf ( " forcing CPU type to " ) ;
idLexer src ( win32 . sys_cpustring . GetString ( ) , idStr : : Length ( win32 . sys_cpustring . GetString ( ) ) , " sys_cpustring " ) ;
idToken token ;
int id = CPUID_NONE ;
while ( src . ReadToken ( & token ) ) {
if ( token . Icmp ( " generic " ) = = 0 ) {
id | = CPUID_GENERIC ;
} else if ( token . Icmp ( " intel " ) = = 0 ) {
id | = CPUID_INTEL ;
} else if ( token . Icmp ( " amd " ) = = 0 ) {
id | = CPUID_AMD ;
} else if ( token . Icmp ( " mmx " ) = = 0 ) {
id | = CPUID_MMX ;
} else if ( token . Icmp ( " 3dnow " ) = = 0 ) {
id | = CPUID_3DNOW ;
} else if ( token . Icmp ( " sse " ) = = 0 ) {
id | = CPUID_SSE ;
} else if ( token . Icmp ( " sse2 " ) = = 0 ) {
id | = CPUID_SSE2 ;
} else if ( token . Icmp ( " sse3 " ) = = 0 ) {
id | = CPUID_SSE3 ;
} else if ( token . Icmp ( " htt " ) = = 0 ) {
id | = CPUID_HTT ;
}
}
if ( id = = CPUID_NONE ) {
common - > Printf ( " WARNING: unknown sys_cpustring '%s' \n " , win32 . sys_cpustring . GetString ( ) ) ;
id = CPUID_GENERIC ;
}
win32 . cpuid = ( cpuid_t ) id ;
}
common - > Printf ( " %s \n " , win32 . sys_cpustring . GetString ( ) ) ;
common - > Printf ( " %d MB System Memory \n " , Sys_GetSystemRam ( ) ) ;
common - > Printf ( " %d MB Video Memory \n " , Sys_GetVideoRam ( ) ) ;
}
/*
= = = = = = = = = = = = = = = =
Sys_Shutdown
= = = = = = = = = = = = = = = =
*/
void Sys_Shutdown ( void ) {
CoUninitialize ( ) ;
}
/*
= = = = = = = = = = = = = = = =
Sys_GetProcessorId
= = = = = = = = = = = = = = = =
*/
cpuid_t Sys_GetProcessorId ( void ) {
2011-12-06 18:20:15 +00:00
return win32 . cpuid ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = =
Sys_GetProcessorString
= = = = = = = = = = = = = = = =
*/
const char * Sys_GetProcessorString ( void ) {
return win32 . sys_cpustring . GetString ( ) ;
}
//=======================================================================
//#define SET_THREAD_AFFINITY
/*
= = = = = = = = = = = = = = = = = = = =
Win_Frame
= = = = = = = = = = = = = = = = = = = =
*/
void Win_Frame ( void ) {
// if "viewlog" has been modified, show or hide the log console
if ( win32 . win_viewlog . IsModified ( ) ) {
if ( ! com_skipRenderer . GetBool ( ) & & idAsyncNetwork : : serverDedicated . GetInteger ( ) ! = 1 ) {
Sys_ShowConsole ( win32 . win_viewlog . GetInteger ( ) , false ) ;
}
win32 . win_viewlog . ClearModified ( ) ;
}
}
extern " C " { void _chkstk ( int size ) ; } ;
void clrstk ( void ) ;
/*
= = = = = = = = = = = = = = = = = = = =
TestChkStk
= = = = = = = = = = = = = = = = = = = =
*/
void TestChkStk ( void ) {
int buffer [ 0x1000 ] ;
buffer [ 0 ] = 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = =
HackChkStk
= = = = = = = = = = = = = = = = = = = =
*/
void HackChkStk ( void ) {
DWORD old ;
VirtualProtect ( _chkstk , 6 , PAGE_EXECUTE_READWRITE , & old ) ;
* ( byte * ) _chkstk = 0xe9 ;
* ( int * ) ( ( int ) _chkstk + 1 ) = ( int ) clrstk - ( int ) _chkstk - 5 ;
TestChkStk ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
GetExceptionCodeInfo
= = = = = = = = = = = = = = = = = = = =
*/
const char * GetExceptionCodeInfo ( UINT code ) {
switch ( code ) {
case EXCEPTION_ACCESS_VIOLATION : return " The thread tried to read from or write to a virtual address for which it does not have the appropriate access. " ;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED : return " The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking. " ;
case EXCEPTION_BREAKPOINT : return " A breakpoint was encountered. " ;
case EXCEPTION_DATATYPE_MISALIGNMENT : return " The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on. " ;
case EXCEPTION_FLT_DENORMAL_OPERAND : return " One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value. " ;
case EXCEPTION_FLT_DIVIDE_BY_ZERO : return " The thread tried to divide a floating-point value by a floating-point divisor of zero. " ;
case EXCEPTION_FLT_INEXACT_RESULT : return " The result of a floating-point operation cannot be represented exactly as a decimal fraction. " ;
case EXCEPTION_FLT_INVALID_OPERATION : return " This exception represents any floating-point exception not included in this list. " ;
case EXCEPTION_FLT_OVERFLOW : return " The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type. " ;
case EXCEPTION_FLT_STACK_CHECK : return " The stack overflowed or underflowed as the result of a floating-point operation. " ;
case EXCEPTION_FLT_UNDERFLOW : return " The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type. " ;
case EXCEPTION_ILLEGAL_INSTRUCTION : return " The thread tried to execute an invalid instruction. " ;
case EXCEPTION_IN_PAGE_ERROR : return " The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network. " ;
case EXCEPTION_INT_DIVIDE_BY_ZERO : return " The thread tried to divide an integer value by an integer divisor of zero. " ;
case EXCEPTION_INT_OVERFLOW : return " The result of an integer operation caused a carry out of the most significant bit of the result. " ;
case EXCEPTION_INVALID_DISPOSITION : return " An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception. " ;
case EXCEPTION_NONCONTINUABLE_EXCEPTION : return " The thread tried to continue execution after a noncontinuable exception occurred. " ;
case EXCEPTION_PRIV_INSTRUCTION : return " The thread tried to execute an instruction whose operation is not allowed in the current machine mode. " ;
case EXCEPTION_SINGLE_STEP : return " A trace trap or other single-instruction mechanism signaled that one instruction has been executed. " ;
case EXCEPTION_STACK_OVERFLOW : return " The thread used up its stack. " ;
default : return " Unknown exception " ;
}
}
/*
= = = = = = = = = = = = = = = = = = = =
EmailCrashReport
emailer originally from Raven / Quake 4
= = = = = = = = = = = = = = = = = = = =
*/
void EmailCrashReport ( LPSTR messageText ) {
LPMAPISENDMAIL MAPISendMail ;
MapiMessage message ;
static int lastEmailTime = 0 ;
if ( Sys_Milliseconds ( ) < lastEmailTime + 10000 ) {
return ;
}
lastEmailTime = Sys_Milliseconds ( ) ;
2011-12-06 18:20:15 +00:00
HINSTANCE mapi = LoadLibrary ( " MAPI32.DLL " ) ;
2011-11-22 21:28:15 +00:00
if ( mapi ) {
MAPISendMail = ( LPMAPISENDMAIL ) GetProcAddress ( mapi , " MAPISendMail " ) ;
if ( MAPISendMail ) {
MapiRecipDesc toProgrammers =
{
0 , // ulReserved
MAPI_TO , // ulRecipClass
" DOOM 3 Crash " , // lpszName
" SMTP:programmers@idsoftware.com " , // lpszAddress
0 , // ulEIDSize
0 // lpEntry
} ;
memset ( & message , 0 , sizeof ( message ) ) ;
message . lpszSubject = " DOOM 3 Fatal Error " ;
message . lpszNoteText = messageText ;
message . nRecipCount = 1 ;
message . lpRecips = & toProgrammers ;
MAPISendMail (
0 , // LHANDLE lhSession
0 , // ULONG ulUIParam
& message , // lpMapiMessage lpMessage
MAPI_DIALOG , // FLAGS flFlags
0 // ULONG ulReserved
) ;
}
FreeLibrary ( mapi ) ;
}
}
int Sys_FPU_PrintStateFlags ( char * ptr , int ctrl , int stat , int tags , int inof , int inse , int opof , int opse ) ;
/*
= = = = = = = = = = = = = = = = = = = =
_except_handler
= = = = = = = = = = = = = = = = = = = =
*/
EXCEPTION_DISPOSITION __cdecl _except_handler ( struct _EXCEPTION_RECORD * ExceptionRecord , void * EstablisherFrame ,
struct _CONTEXT * ContextRecord , void * DispatcherContext ) {
static char msg [ 8192 ] ;
char FPUFlags [ 2048 ] ;
Sys_FPU_PrintStateFlags ( FPUFlags , ContextRecord - > FloatSave . ControlWord ,
ContextRecord - > FloatSave . StatusWord ,
ContextRecord - > FloatSave . TagWord ,
ContextRecord - > FloatSave . ErrorOffset ,
ContextRecord - > FloatSave . ErrorSelector ,
ContextRecord - > FloatSave . DataOffset ,
ContextRecord - > FloatSave . DataSelector ) ;
2011-12-06 18:20:15 +00:00
sprintf ( msg ,
2011-11-22 21:28:15 +00:00
" Please describe what you were doing when DOOM 3 crashed! \n "
" If this text did not pop into your email client please copy and email it to programmers@idsoftware.com \n "
" \n "
" -= FATAL EXCEPTION =- \n "
" \n "
" %s \n "
" \n "
" 0x%x at address 0x%08x \n "
" \n "
" %s \n "
" \n "
" EAX = 0x%08x EBX = 0x%08x \n "
" ECX = 0x%08x EDX = 0x%08x \n "
" ESI = 0x%08x EDI = 0x%08x \n "
" EIP = 0x%08x ESP = 0x%08x \n "
" EBP = 0x%08x EFL = 0x%08x \n "
" \n "
" CS = 0x%04x \n "
" SS = 0x%04x \n "
" DS = 0x%04x \n "
" ES = 0x%04x \n "
" FS = 0x%04x \n "
" GS = 0x%04x \n "
" \n "
" %s \n " ,
com_version . GetString ( ) ,
ExceptionRecord - > ExceptionCode ,
ExceptionRecord - > ExceptionAddress ,
GetExceptionCodeInfo ( ExceptionRecord - > ExceptionCode ) ,
ContextRecord - > Eax , ContextRecord - > Ebx ,
ContextRecord - > Ecx , ContextRecord - > Edx ,
ContextRecord - > Esi , ContextRecord - > Edi ,
ContextRecord - > Eip , ContextRecord - > Esp ,
ContextRecord - > Ebp , ContextRecord - > EFlags ,
ContextRecord - > SegCs ,
ContextRecord - > SegSs ,
ContextRecord - > SegDs ,
ContextRecord - > SegEs ,
ContextRecord - > SegFs ,
ContextRecord - > SegGs ,
FPUFlags
) ;
EmailCrashReport ( msg ) ;
common - > FatalError ( msg ) ;
2011-12-06 18:20:15 +00:00
// Tell the OS to restart the faulting instruction
return ExceptionContinueExecution ;
2011-11-22 21:28:15 +00:00
}
# define TEST_FPU_EXCEPTIONS /* FPU_EXCEPTION_INVALID_OPERATION | */ \
/* FPU_EXCEPTION_DENORMALIZED_OPERAND | */ \
/* FPU_EXCEPTION_DIVIDE_BY_ZERO | */ \
/* FPU_EXCEPTION_NUMERIC_OVERFLOW | */ \
/* FPU_EXCEPTION_NUMERIC_UNDERFLOW | */ \
/* FPU_EXCEPTION_INEXACT_RESULT | */ \
0
/*
= = = = = = = = = = = = = = = = = =
WinMain
= = = = = = = = = = = = = = = = = =
*/
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow ) {
const HCURSOR hcurSave = : : SetCursor ( LoadCursor ( 0 , IDC_WAIT ) ) ;
Sys_SetPhysicalWorkMemory ( 192 < < 20 , 1024 < < 20 ) ;
Sys_GetCurrentMemoryStatus ( exeLaunchMemoryStats ) ;
#if 0
2011-12-06 18:20:15 +00:00
DWORD handler = ( DWORD ) _except_handler ;
__asm
{ // Build EXCEPTION_REGISTRATION record:
push handler // Address of handler function
push FS : [ 0 ] // Address of previous handler
mov FS : [ 0 ] , ESP // Install new EXECEPTION_REGISTRATION
}
2011-11-22 21:28:15 +00:00
# endif
win32 . hInstance = hInstance ;
idStr : : Copynz ( sys_cmdline , lpCmdLine , sizeof ( sys_cmdline ) ) ;
// done before Com/Sys_Init since we need this for error output
Sys_CreateConsole ( ) ;
// no abort/retry/fail errors
SetErrorMode ( SEM_FAILCRITICALERRORS ) ;
for ( int i = 0 ; i < MAX_CRITICAL_SECTIONS ; i + + ) {
InitializeCriticalSection ( & win32 . criticalSections [ i ] ) ;
}
// get the initial time base
Sys_Milliseconds ( ) ;
# ifdef DEBUG
// disable the painfully slow MS heap check every 1024 allocs
_CrtSetDbgFlag ( 0 ) ;
# endif
// Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
Sys_FPU_SetPrecision ( FPU_PRECISION_DOUBLE_EXTENDED ) ;
common - > Init ( 0 , NULL , lpCmdLine ) ;
# if TEST_FPU_EXCEPTIONS != 0
common - > Printf ( Sys_FPU_GetState ( ) ) ;
# endif
# ifndef ID_DEDICATED
if ( win32 . win_notaskkeys . GetInteger ( ) ) {
DisableTaskKeys ( TRUE , FALSE , /*( win32.win_notaskkeys.GetInteger() == 2 )*/ FALSE ) ;
}
# endif
Sys_StartAsyncThread ( ) ;
// hide or show the early console as necessary
if ( win32 . win_viewlog . GetInteger ( ) | | com_skipRenderer . GetBool ( ) | | idAsyncNetwork : : serverDedicated . GetInteger ( ) ) {
Sys_ShowConsole ( 1 , true ) ;
} else {
Sys_ShowConsole ( 0 , false ) ;
}
2011-12-06 18:20:15 +00:00
# ifdef SET_THREAD_AFFINITY
2011-11-22 21:28:15 +00:00
// give the main thread an affinity for the first cpu
SetThreadAffinityMask ( GetCurrentThread ( ) , 1 ) ;
# endif
: : SetCursor ( hcurSave ) ;
// Launch the script debugger
if ( strstr ( lpCmdLine , " +debugger " ) ) {
// DebuggerClientInit( lpCmdLine );
return 0 ;
}
: : SetFocus ( win32 . hWnd ) ;
2011-12-06 18:20:15 +00:00
// main game loop
2011-11-22 21:28:15 +00:00
while ( 1 ) {
Win_Frame ( ) ;
# ifdef DEBUG
Sys_MemFrame ( ) ;
# endif
// set exceptions, even if some crappy syscall changes them!
Sys_FPU_EnableExceptions ( TEST_FPU_EXCEPTIONS ) ;
# ifdef ID_ALLOW_TOOLS
if ( com_editors ) {
if ( com_editors & EDITOR_GUI ) {
// GUI editor
GUIEditorRun ( ) ;
} else if ( com_editors & EDITOR_RADIANT ) {
// Level Editor
RadiantRun ( ) ;
}
else if ( com_editors & EDITOR_MATERIAL ) {
//BSM Nerve: Add support for the material editor
MaterialEditorRun ( ) ;
}
else {
if ( com_editors & EDITOR_LIGHT ) {
// in-game Light Editor
LightEditorRun ( ) ;
}
if ( com_editors & EDITOR_SOUND ) {
// in-game Sound Editor
SoundEditorRun ( ) ;
}
if ( com_editors & EDITOR_DECL ) {
// in-game Declaration Browser
DeclBrowserRun ( ) ;
}
if ( com_editors & EDITOR_AF ) {
// in-game Articulated Figure Editor
AFEditorRun ( ) ;
}
if ( com_editors & EDITOR_PARTICLE ) {
// in-game Particle Editor
ParticleEditorRun ( ) ;
}
if ( com_editors & EDITOR_SCRIPT ) {
// in-game Script Editor
ScriptEditorRun ( ) ;
}
if ( com_editors & EDITOR_PDA ) {
// in-game PDA Editor
PDAEditorRun ( ) ;
}
}
}
# endif
// run the game
common - > Frame ( ) ;
}
// never gets here
return 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = =
clrstk
I tried to get the run time to call this at every function entry , but
= = = = = = = = = = = = = = = = = = = =
*/
static int parmBytes ;
__declspec ( naked ) void clrstk ( void ) {
// eax = bytes to add to stack
__asm {
mov [ parmBytes ] , eax
2011-12-06 18:20:15 +00:00
neg eax ; compute new stack pointer in eax
add eax , esp
add eax , 4
xchg eax , esp
mov eax , dword ptr [ eax ] ; copy the return address
push eax
; clear to zero
push edi
push ecx
mov edi , esp
add edi , 12
mov ecx , [ parmBytes ]
2011-11-22 21:28:15 +00:00
shr ecx , 2
2011-12-06 18:20:15 +00:00
xor eax , eax
2011-11-22 21:28:15 +00:00
cld
2011-12-06 18:20:15 +00:00
rep stosd
pop ecx
pop edi
ret
2011-11-22 21:28:15 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = =
idSysLocal : : OpenURL
= = = = = = = = = = = = = = = = = =
*/
void idSysLocal : : OpenURL ( const char * url , bool doexit ) {
static bool doexit_spamguard = false ;
HWND wnd ;
if ( doexit_spamguard ) {
common - > DPrintf ( " OpenURL: already in an exit sequence, ignoring %s \n " , url ) ;
return ;
}
common - > Printf ( " Open URL: %s \n " , url ) ;
if ( ! ShellExecute ( NULL , " open " , url , NULL , NULL , SW_RESTORE ) ) {
common - > Error ( " Could not open url: '%s' " , url ) ;
return ;
}
wnd = GetForegroundWindow ( ) ;
if ( wnd ) {
ShowWindow ( wnd , SW_MAXIMIZE ) ;
}
if ( doexit ) {
doexit_spamguard = true ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " quit \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idSysLocal : : StartProcess
= = = = = = = = = = = = = = = = = =
*/
void idSysLocal : : StartProcess ( const char * exePath , bool doexit ) {
TCHAR szPathOrig [ _MAX_PATH ] ;
STARTUPINFO si ;
PROCESS_INFORMATION pi ;
ZeroMemory ( & si , sizeof ( si ) ) ;
si . cb = sizeof ( si ) ;
strncpy ( szPathOrig , exePath , _MAX_PATH ) ;
if ( ! CreateProcess ( NULL , szPathOrig , NULL , NULL , FALSE , 0 , NULL , NULL , & si , & pi ) ) {
2011-12-06 18:20:15 +00:00
common - > Error ( " Could not start process: '%s' " , szPathOrig ) ;
2011-11-22 21:28:15 +00:00
return ;
}
if ( doexit ) {
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " quit \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
Sys_SetFatalError
= = = = = = = = = = = = = = = = = =
*/
void Sys_SetFatalError ( const char * error ) {
}
/*
= = = = = = = = = = = = = = = = = =
Sys_DoPreferences
= = = = = = = = = = = = = = = = = =
*/
void Sys_DoPreferences ( void ) {
}