Initial commit

This commit is contained in:
Brian Harris
2012-11-26 12:58:24 -06:00
parent a5214f79ef
commit 5016f605b8
1115 changed files with 587266 additions and 0 deletions

109
neo/sys/win32/rc/doom.rc Normal file
View File

@@ -0,0 +1,109 @@
// Microsoft Visual C++ generated resource script.
//
#include "doom_resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"doom_resource.h\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "res\\doom.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "id Software LLC, a ZeniMax Media company"
VALUE "FileDescription", "DOOM 3: BFG Edition"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "Doom3BFG"
VALUE "LegalCopyright", "© 1993-2012 id Software LLC, a ZeniMax Media company"
VALUE "OriginalFilename", "Doom3BFG"
VALUE "ProductName", "DOOM® 3: BFG Edition™"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,18 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by doom.rc
//
#define IDI_ICON1 4001
#define IDR_IDR_USYSGZPS11 4002
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 4003
#define _APS_NEXT_COMMAND_VALUE 24000
#define _APS_NEXT_CONTROL_VALUE 4200
#define _APS_NEXT_SYMED_VALUE 4002
#endif
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,103 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "win_achievements.h"
#include "../sys_session_local.h"
extern idCVar achievements_Verbose;
#define STEAM_ACHIEVEMENT_PREFIX "ach_"
/*
========================
idAchievementSystemWin::idAchievementSystemWin
========================
*/
idAchievementSystemWin::idAchievementSystemWin() {
}
/*
========================
idAchievementSystemWin::IsInitialized
========================
*/
bool idAchievementSystemWin::IsInitialized() {
return false;
}
/*
================================
idAchievementSystemWin::AchievementUnlock
================================
*/
void idAchievementSystemWin::AchievementUnlock( idLocalUser * user, int achievementID ) {
}
/*
========================
idAchievementSystemWin::AchievementLock
========================
*/
void idAchievementSystemWin::AchievementLock( idLocalUser * user, const int achievementID ) {
}
/*
========================
idAchievementSystemWin::AchievementLockAll
========================
*/
void idAchievementSystemWin::AchievementLockAll( idLocalUser * user, const int maxId ) {
}
/*
========================
idAchievementSystemWin::GetAchievementDescription
========================
*/
bool idAchievementSystemWin::GetAchievementDescription( idLocalUser * user, const int achievementID, achievementDescription_t & data ) const {
return false;
}
/*
========================
idAchievementSystemWin::GetAchievementState
========================
*/
bool idAchievementSystemWin::GetAchievementState( idLocalUser * user, idArray< bool, idAchievementSystem::MAX_ACHIEVEMENTS > & achievements ) const {
return false;
}
/*
================================
idAchievementSystemWin::Pump
================================
*/
void idAchievementSystemWin::Pump() {
}

View File

@@ -0,0 +1,49 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#ifndef __WIN_ACHIEVEMENTS_H__
#define __WIN_ACHIEVEMENTS_H__
/*
================================================
idAchievementSystemWin
================================================
*/
class idAchievementSystemWin : public idAchievementSystem {
public:
idAchievementSystemWin();
bool IsInitialized();
void AchievementUnlock( idLocalUser * user, const int achievementID );
void AchievementLock( idLocalUser * user, const int achievementID );
void AchievementLockAll( idLocalUser * user, const int maxId );
void Pump();
bool GetAchievementDescription( idLocalUser * user, const int id, achievementDescription_t & data ) const;
bool GetAchievementState( idLocalUser * user, idArray< bool, idAchievementSystem::MAX_ACHIEVEMENTS > & achievements ) const;
};
#endif // __WIN_ACHIEVEMENTS_H__

1105
neo/sys/win32/win_cpu.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
/*
** WIN_GAMMA.C
*/
#include <assert.h>
#include "win_local.h"
#include "../../renderer/tr_local.h"
static unsigned short s_oldHardwareGamma[3][256];
/*
** WG_GetOldGammaRamp
**
*/
void WG_GetOldGammaRamp( void )
{
HDC hDC;
hDC = GetDC( GetDesktopWindow() );
GetDeviceGammaRamp( hDC, s_oldHardwareGamma );
ReleaseDC( GetDesktopWindow(), hDC );
/*
** GLimp_SetGamma
**
*/
void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
{
unsigned short table[3][256];
int i;
if ( !glw_state.hDC )
{
return;
}
for ( i = 0; i < 256; i++ )
{
table[0][i] = ( ( ( unsigned short ) red[i] ) << 8 ) | red[i];
table[1][i] = ( ( ( unsigned short ) green[i] ) << 8 ) | green[i];
table[2][i] = ( ( ( unsigned short ) blue[i] ) << 8 ) | blue[i];
}
if ( !SetDeviceGammaRamp( glw_state.hDC, table ) ) {
common->Printf( "WARNING: SetDeviceGammaRamp failed.\n" );
}
}
/*
** WG_RestoreGamma
*/
void WG_RestoreGamma( void )
{
HDC hDC;
// if we never read in a reasonable looking
// table, don't write it out
if ( s_oldHardwareGamma[0][255] == 0 ) {
return;
}
hDC = GetDC( GetDesktopWindow() );
SetDeviceGammaRamp( hDC, s_oldHardwareGamma );
ReleaseDC( GetDesktopWindow(), hDC );
}

1562
neo/sys/win32/win_glimp.cpp Normal file

File diff suppressed because it is too large Load Diff

967
neo/sys/win32/win_input.cpp Normal file
View File

@@ -0,0 +1,967 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "../sys_session_local.h"
#include "win_local.h"
#define DINPUT_BUFFERSIZE 256
/*
============================================================
DIRECT INPUT KEYBOARD CONTROL
============================================================
*/
bool IN_StartupKeyboard() {
HRESULT hr;
bool bExclusive;
bool bForeground;
bool bImmediate;
bool bDisableWindowsKey;
DWORD dwCoopFlags;
if (!win32.g_pdi) {
common->Printf("keyboard: DirectInput has not been started\n");
return false;
}
if (win32.g_pKeyboard) {
win32.g_pKeyboard->Release();
win32.g_pKeyboard = NULL;
}
// Detrimine where the buffer would like to be allocated
bExclusive = false;
bForeground = true;
bImmediate = false;
bDisableWindowsKey = true;
if( bExclusive )
dwCoopFlags = DISCL_EXCLUSIVE;
else
dwCoopFlags = DISCL_NONEXCLUSIVE;
if( bForeground )
dwCoopFlags |= DISCL_FOREGROUND;
else
dwCoopFlags |= DISCL_BACKGROUND;
// Disabling the windows key is only allowed only if we are in foreground nonexclusive
if( bDisableWindowsKey && !bExclusive && bForeground )
dwCoopFlags |= DISCL_NOWINKEY;
// Obtain an interface to the system keyboard device.
if( FAILED( hr = win32.g_pdi->CreateDevice( GUID_SysKeyboard, &win32.g_pKeyboard, NULL ) ) ) {
common->Printf("keyboard: couldn't find a keyboard device\n");
return false;
}
// Set the data format to "keyboard format" - a predefined data format
//
// A data format specifies which controls on a device we
// are interested in, and how they should be reported.
//
// This tells DirectInput that we will be passing an array
// of 256 bytes to IDirectInputDevice::GetDeviceState.
if( FAILED( hr = win32.g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
return false;
// Set the cooperativity level to let DirectInput know how
// this device should interact with the system and with other
// DirectInput applications.
hr = win32.g_pKeyboard->SetCooperativeLevel( win32.hWnd, dwCoopFlags );
if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive ) {
common->Printf("keyboard: SetCooperativeLevel() returned DIERR_UNSUPPORTED.\nFor security reasons, background exclusive keyboard access is not allowed.\n");
return false;
}
if( FAILED(hr) ) {
return false;
}
if( !bImmediate ) {
// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
//
// DirectInput uses unbuffered I/O (buffer size = 0) by default.
// If you want to read buffered data, you need to set a nonzero
// buffer size.
//
// Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
//
// The buffer size is a DWORD property associated with the device.
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = DINPUT_BUFFERSIZE; // Arbitary buffer size
if( FAILED( hr = win32.g_pKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) )
return false;
}
// Acquire the newly created device
win32.g_pKeyboard->Acquire();
common->Printf( "keyboard: DirectInput initialized.\n");
return true;
}
/*
==========================
IN_DeactivateKeyboard
==========================
*/
void IN_DeactivateKeyboard() {
if (!win32.g_pKeyboard) {
return;
}
win32.g_pKeyboard->Unacquire( );
}
/*
============================================================
DIRECT INPUT MOUSE CONTROL
============================================================
*/
/*
========================
IN_InitDirectInput
========================
*/
void IN_InitDirectInput() {
HRESULT hr;
common->Printf( "Initializing DirectInput...\n" );
if ( win32.g_pdi != NULL ) {
win32.g_pdi->Release(); // if the previous window was destroyed we need to do this
win32.g_pdi = NULL;
}
// Register with the DirectInput subsystem and get a pointer
// to a IDirectInput interface we can use.
// Create the base DirectInput object
if ( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&win32.g_pdi, NULL ) ) ) {
common->Printf ("DirectInputCreate failed\n");
}
}
/*
========================
IN_InitDIMouse
========================
*/
bool IN_InitDIMouse() {
HRESULT hr;
if ( win32.g_pdi == NULL) {
return false;
}
// obtain an interface to the system mouse device.
hr = win32.g_pdi->CreateDevice( GUID_SysMouse, &win32.g_pMouse, NULL);
if (FAILED(hr)) {
common->Printf ("mouse: Couldn't open DI mouse device\n");
return false;
}
// Set the data format to "mouse format" - a predefined data format
//
// A data format specifies which controls on a device we
// are interested in, and how they should be reported.
//
// This tells DirectInput that we will be passing a
// DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
if( FAILED( hr = win32.g_pMouse->SetDataFormat( &c_dfDIMouse2 ) ) ) {
common->Printf ("mouse: Couldn't set DI mouse format\n");
return false;
}
// set the cooperativity level.
hr = win32.g_pMouse->SetCooperativeLevel( win32.hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
if (FAILED(hr)) {
common->Printf ("mouse: Couldn't set DI coop level\n");
return false;
}
// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
//
// DirectInput uses unbuffered I/O (buffer size = 0) by default.
// If you want to read buffered data, you need to set a nonzero
// buffer size.
//
// Set the buffer size to SAMPLE_BUFFER_SIZE (defined above) elements.
//
// The buffer size is a DWORD property associated with the device.
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = DINPUT_BUFFERSIZE; // Arbitary buffer size
if( FAILED( hr = win32.g_pMouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) ) {
common->Printf ("mouse: Couldn't set DI buffersize\n");
return false;
}
IN_ActivateMouse();
// clear any pending samples
int mouseEvents[MAX_MOUSE_EVENTS][2];
Sys_PollMouseInputEvents( mouseEvents );
common->Printf( "mouse: DirectInput initialized.\n");
return true;
}
/*
==========================
IN_ActivateMouse
==========================
*/
void IN_ActivateMouse() {
int i;
HRESULT hr;
if ( !win32.in_mouse.GetBool() || win32.mouseGrabbed || !win32.g_pMouse ) {
return;
}
win32.mouseGrabbed = true;
for ( i = 0; i < 10; i++ ) {
if ( ::ShowCursor( false ) < 0 ) {
break;
}
}
// we may fail to reacquire if the window has been recreated
hr = win32.g_pMouse->Acquire();
if (FAILED(hr)) {
return;
}
// set the cooperativity level.
hr = win32.g_pMouse->SetCooperativeLevel( win32.hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
}
/*
==========================
IN_DeactivateMouse
==========================
*/
void IN_DeactivateMouse() {
int i;
if (!win32.g_pMouse || !win32.mouseGrabbed ) {
return;
}
win32.g_pMouse->Unacquire();
for ( i = 0; i < 10; i++ ) {
if ( ::ShowCursor( true ) >= 0 ) {
break;
}
}
win32.mouseGrabbed = false;
}
/*
==========================
IN_DeactivateMouseIfWindowed
==========================
*/
void IN_DeactivateMouseIfWindowed() {
if ( !win32.cdsFullscreen ) {
IN_DeactivateMouse();
}
}
/*
============================================================
MOUSE CONTROL
============================================================
*/
/*
===========
Sys_ShutdownInput
===========
*/
void Sys_ShutdownInput() {
IN_DeactivateMouse();
IN_DeactivateKeyboard();
if ( win32.g_pKeyboard ) {
win32.g_pKeyboard->Release();
win32.g_pKeyboard = NULL;
}
if ( win32.g_pMouse ) {
win32.g_pMouse->Release();
win32.g_pMouse = NULL;
}
if ( win32.g_pdi ) {
win32.g_pdi->Release();
win32.g_pdi = NULL;
}
}
/*
===========
Sys_InitInput
===========
*/
void Sys_InitInput() {
common->Printf ("\n------- Input Initialization -------\n");
IN_InitDirectInput();
if ( win32.in_mouse.GetBool() ) {
IN_InitDIMouse();
// don't grab the mouse on initialization
Sys_GrabMouseCursor( false );
} else {
common->Printf ("Mouse control not active.\n");
}
IN_StartupKeyboard();
common->Printf ("------------------------------------\n");
win32.in_mouse.ClearModified();
}
/*
==================
IN_Frame
Called every frame, even if not generating commands
==================
*/
void IN_Frame() {
bool shouldGrab = true;
if ( !win32.in_mouse.GetBool() ) {
shouldGrab = false;
}
// if fullscreen, we always want the mouse
if ( !win32.cdsFullscreen ) {
if ( win32.mouseReleased ) {
shouldGrab = false;
}
if ( win32.movingWindow ) {
shouldGrab = false;
}
if ( !win32.activeApp ) {
shouldGrab = false;
}
}
if ( shouldGrab != win32.mouseGrabbed ) {
if ( usercmdGen != NULL ) {
usercmdGen->Clear();
}
if ( win32.mouseGrabbed ) {
IN_DeactivateMouse();
} else {
IN_ActivateMouse();
#if 0 // if we can't reacquire, try reinitializing
if ( !IN_InitDIMouse() ) {
win32.in_mouse.SetBool( false );
return;
}
#endif
}
}
}
void Sys_GrabMouseCursor( bool grabIt ) {
win32.mouseReleased = !grabIt;
if ( !grabIt ) {
// release it right now
IN_Frame();
}
}
//=====================================================================================
static DIDEVICEOBJECTDATA polled_didod[ DINPUT_BUFFERSIZE ]; // Receives buffered data
static int diFetch;
static byte toggleFetch[2][ 256 ];
#if 1
// I tried doing the full-state get to address a keyboard problem on one system,
// but it didn't make any difference
/*
====================
Sys_PollKeyboardInputEvents
====================
*/
int Sys_PollKeyboardInputEvents() {
DWORD dwElements;
HRESULT hr;
if( win32.g_pKeyboard == NULL ) {
return 0;
}
dwElements = DINPUT_BUFFERSIZE;
hr = win32.g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
polled_didod, &dwElements, 0 );
if( hr != DI_OK )
{
// We got an error or we got DI_BUFFEROVERFLOW.
//
// Either way, it means that continuous contact with the
// device has been lost, either due to an external
// interruption, or because the buffer overflowed
// and some events were lost.
hr = win32.g_pKeyboard->Acquire();
// nuke the garbage
if (!FAILED(hr)) {
//Bug 951: The following command really clears the garbage input.
//The original will still process keys in the buffer and was causing
//some problems.
win32.g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), NULL, &dwElements, 0 );
dwElements = 0;
}
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
}
if( FAILED(hr) ) {
return 0;
}
return dwElements;
}
#else
/*
====================
Sys_PollKeyboardInputEvents
Fake events by getting the entire device state
and checking transitions
====================
*/
int Sys_PollKeyboardInputEvents() {
HRESULT hr;
if( win32.g_pKeyboard == NULL ) {
return 0;
}
hr = win32.g_pKeyboard->GetDeviceState( sizeof( toggleFetch[ diFetch ] ), toggleFetch[ diFetch ] );
if( hr != DI_OK )
{
// We got an error or we got DI_BUFFEROVERFLOW.
//
// Either way, it means that continuous contact with the
// device has been lost, either due to an external
// interruption, or because the buffer overflowed
// and some events were lost.
hr = win32.g_pKeyboard->Acquire();
// nuke the garbage
if (!FAILED(hr)) {
hr = win32.g_pKeyboard->GetDeviceState( sizeof( toggleFetch[ diFetch ] ), toggleFetch[ diFetch ] );
}
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
}
if( FAILED(hr) ) {
return 0;
}
// build faked events
int numChanges = 0;
for ( int i = 0 ; i < 256 ; i++ ) {
if ( toggleFetch[0][i] != toggleFetch[1][i] ) {
polled_didod[ numChanges ].dwOfs = i;
polled_didod[ numChanges ].dwData = toggleFetch[ diFetch ][i] ? 0x80 : 0;
numChanges++;
}
}
diFetch ^= 1;
return numChanges;
}
#endif
/*
====================
Sys_PollKeyboardInputEvents
====================
*/
int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state ) {
ch = polled_didod[ n ].dwOfs;
state = ( polled_didod[ n ].dwData & 0x80 ) == 0x80;
if ( ch == K_PRINTSCREEN || ch == K_LCTRL || ch == K_LALT || ch == K_RCTRL || ch == K_RALT ) {
// for windows, add a keydown event for print screen here, since
// windows doesn't send keydown events to the WndProc for this key.
// ctrl and alt are handled here to get around windows sending ctrl and
// alt messages when the right-alt is pressed on non-US 102 keyboards.
Sys_QueEvent( SE_KEY, ch, state, 0, NULL, 0 );
}
return ch;
}
void Sys_EndKeyboardInputEvents() {
}
//=====================================================================================
int Sys_PollMouseInputEvents( int mouseEvents[MAX_MOUSE_EVENTS][2] ) {
DWORD dwElements;
HRESULT hr;
if ( !win32.g_pMouse || !win32.mouseGrabbed ) {
return 0;
}
dwElements = DINPUT_BUFFERSIZE;
hr = win32.g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), polled_didod, &dwElements, 0 );
if( hr != DI_OK ) {
hr = win32.g_pMouse->Acquire();
// clear the garbage
if (!FAILED(hr)) {
win32.g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), polled_didod, &dwElements, 0 );
}
}
if( FAILED(hr) ) {
return 0;
}
if ( dwElements > MAX_MOUSE_EVENTS ) {
dwElements = MAX_MOUSE_EVENTS;
}
for( DWORD i = 0; i < dwElements; i++ ) {
mouseEvents[i][0] = M_INVALID;
mouseEvents[i][1] = 0;
if ( polled_didod[i].dwOfs >= DIMOFS_BUTTON0 && polled_didod[i].dwOfs <= DIMOFS_BUTTON7 ) {
const int mouseButton = ( polled_didod[i].dwOfs - DIMOFS_BUTTON0 );
const bool mouseDown = (polled_didod[i].dwData & 0x80) == 0x80;
mouseEvents[i][0] = M_ACTION1 + mouseButton;
mouseEvents[i][1] = mouseDown;
Sys_QueEvent( SE_KEY, K_MOUSE1 + mouseButton, mouseDown, 0, NULL, 0 );
} else {
switch (polled_didod[i].dwOfs) {
case DIMOFS_X:
mouseEvents[i][0] = M_DELTAX;
mouseEvents[i][1] = polled_didod[i].dwData;
Sys_QueEvent( SE_MOUSE, polled_didod[i].dwData, 0, 0, NULL, 0 );
break;
case DIMOFS_Y:
mouseEvents[i][0] = M_DELTAY;
mouseEvents[i][1] = polled_didod[i].dwData;
Sys_QueEvent( SE_MOUSE, 0, polled_didod[i].dwData, 0, NULL, 0 );
break;
case DIMOFS_Z:
mouseEvents[i][0] = M_DELTAZ;
mouseEvents[i][1] = (int)polled_didod[i].dwData / WHEEL_DELTA;
{
const int value = (int)polled_didod[i].dwData / WHEEL_DELTA;
const int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP;
const int iterations = abs( value );
for ( int i = 0; i < iterations; i++ ) {
Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 );
}
}
break;
}
}
}
return dwElements;
}
//=====================================================================================
// Joystick Input Handling
//=====================================================================================
void Sys_SetRumble( int device, int low, int hi ) {
return win32.g_Joystick.SetRumble( device, low, hi );
}
int Sys_PollJoystickInputEvents( int deviceNum ) {
return win32.g_Joystick.PollInputEvents( deviceNum );
}
int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ) {
return win32.g_Joystick.ReturnInputEvent( n, action, value );
}
void Sys_EndJoystickInputEvents() {
}
/*
========================
JoystickSamplingThread
========================
*/
static int threadTimeDeltas[256];
static int threadPacket[256];
static int threadCount;
void JoystickSamplingThread( void *data ) {
static int prevTime = 0;
static uint64 nextCheck[MAX_JOYSTICKS] = { 0 };
const uint64 waitTime = 5000000; // poll every 5 seconds to see if a controller was connected
while( 1 ) {
// hopefully we see close to 4000 usec each loop
int now = Sys_Microseconds();
int delta;
if ( prevTime == 0 ) {
delta = 4000;
} else {
delta = now - prevTime;
}
prevTime = now;
threadTimeDeltas[threadCount&255] = delta;
threadCount++;
{
XINPUT_STATE joyData[MAX_JOYSTICKS];
bool validData[MAX_JOYSTICKS];
for ( int i = 0 ; i < MAX_JOYSTICKS ; i++ ) {
if ( now >= nextCheck[i] ) {
// XInputGetState might block... for a _really_ long time..
validData[i] = XInputGetState( i, &joyData[i] ) == ERROR_SUCCESS;
// allow an immediate data poll if the input device is connected else
// wait for some time to see if another device was reconnected.
// Checking input state infrequently for newly connected devices prevents
// severe slowdowns on PC, especially on WinXP64.
if ( validData[i] ) {
nextCheck[i] = 0;
} else {
nextCheck[i] = now + waitTime;
}
}
}
// do this short amount of processing inside a critical section
idScopedCriticalSection cs( win32.g_Joystick.mutexXis );
for ( int i = 0 ; i < MAX_JOYSTICKS ; i++ ) {
controllerState_t * cs = &win32.g_Joystick.controllers[i];
if ( !validData[i] ) {
cs->valid = false;
continue;
}
cs->valid = true;
XINPUT_STATE& current = joyData[i];
cs->current = current;
// Switch from using cs->current to current to reduce chance of Load-Hit-Store on consoles
threadPacket[threadCount&255] = current.dwPacketNumber;
#if 0
if ( xis.dwPacketNumber == oldXis[ inputDeviceNum ].dwPacketNumber ) {
return numEvents;
}
#endif
cs->buttonBits |= current.Gamepad.wButtons;
}
}
// we want this to be processed at least 250 times a second
WaitForSingleObject( win32.g_Joystick.timer, INFINITE );
}
}
/*
========================
idJoystickWin32::idJoystickWin32
========================
*/
idJoystickWin32::idJoystickWin32() {
numEvents = 0;
memset( &events, 0, sizeof( events ) );
memset( &controllers, 0, sizeof( controllers ) );
memset( buttonStates, 0, sizeof( buttonStates ) );
memset( joyAxis, 0, sizeof( joyAxis ) );
}
/*
========================
idJoystickWin32::Init
========================
*/
bool idJoystickWin32::Init() {
idJoystick::Init();
// setup the timer that the high frequency thread will wait on
// to fire every 4 msec
timer = CreateWaitableTimer( NULL, FALSE, "JoypadTimer" );
LARGE_INTEGER dueTime;
dueTime.QuadPart = -1;
if ( !SetWaitableTimer( timer, &dueTime, 4, NULL, NULL, FALSE ) ) {
idLib::FatalError( "SetWaitableTimer for joystick failed" );
}
// spawn the high frequency joystick reading thread
Sys_CreateThread( (xthread_t)JoystickSamplingThread, NULL, THREAD_HIGHEST, "Joystick", CORE_1A );
return false;
}
/*
========================
idJoystickWin32::SetRumble
========================
*/
void idJoystickWin32::SetRumble( int inputDeviceNum, int rumbleLow, int rumbleHigh ) {
if ( inputDeviceNum < 0 || inputDeviceNum >= MAX_JOYSTICKS ) {
return;
}
if ( !controllers[inputDeviceNum].valid ) {
return;
}
XINPUT_VIBRATION vibration;
vibration.wLeftMotorSpeed = idMath::ClampInt( 0, 65535, rumbleLow );
vibration.wRightMotorSpeed = idMath::ClampInt( 0, 65535, rumbleHigh );
DWORD err = XInputSetState( inputDeviceNum, &vibration );
if ( err != ERROR_SUCCESS ) {
idLib::Warning( "XInputSetState error: 0x%x", err );
}
}
/*
========================
idJoystickWin32::PostInputEvent
========================
*/
void idJoystickWin32::PostInputEvent( int inputDeviceNum, int event, int value, int range ) {
// These events are used for GUI button presses
if ( ( event >= J_ACTION1 ) && ( event <= J_ACTION_MAX ) ) {
PushButton( inputDeviceNum, K_JOY1 + ( event - J_ACTION1 ), value != 0 );
} else if ( event == J_AXIS_LEFT_X ) {
PushButton( inputDeviceNum, K_JOY_STICK1_LEFT, ( value < -range ) );
PushButton( inputDeviceNum, K_JOY_STICK1_RIGHT, ( value > range ) );
} else if ( event == J_AXIS_LEFT_Y ) {
PushButton( inputDeviceNum, K_JOY_STICK1_UP, ( value < -range ) );
PushButton( inputDeviceNum, K_JOY_STICK1_DOWN, ( value > range ) );
} else if ( event == J_AXIS_RIGHT_X ) {
PushButton( inputDeviceNum, K_JOY_STICK2_LEFT, ( value < -range ) );
PushButton( inputDeviceNum, K_JOY_STICK2_RIGHT, ( value > range ) );
} else if ( event == J_AXIS_RIGHT_Y ) {
PushButton( inputDeviceNum, K_JOY_STICK2_UP, ( value < -range ) );
PushButton( inputDeviceNum, K_JOY_STICK2_DOWN, ( value > range ) );
} else if ( ( event >= J_DPAD_UP ) && ( event <= J_DPAD_RIGHT ) ) {
PushButton( inputDeviceNum, K_JOY_DPAD_UP + ( event - J_DPAD_UP ), value != 0 );
} else if ( event == J_AXIS_LEFT_TRIG ) {
PushButton( inputDeviceNum, K_JOY_TRIGGER1, ( value > range ) );
} else if ( event == J_AXIS_RIGHT_TRIG ) {
PushButton( inputDeviceNum, K_JOY_TRIGGER2, ( value > range ) );
}
if ( event >= J_AXIS_MIN && event <= J_AXIS_MAX ) {
int axis = event - J_AXIS_MIN;
int percent = ( value * 16 ) / range;
if ( joyAxis[inputDeviceNum][axis] != percent ) {
joyAxis[inputDeviceNum][axis] = percent;
Sys_QueEvent( SE_JOYSTICK, axis, percent, 0, NULL, inputDeviceNum );
}
}
// These events are used for actual game input
events[numEvents].event = event;
events[numEvents].value = value;
numEvents++;
}
/*
========================
idJoystickWin32::PollInputEvents
========================
*/
int idJoystickWin32::PollInputEvents( int inputDeviceNum ) {
numEvents = 0;
if ( !win32.activeApp ) {
return numEvents;
}
assert( inputDeviceNum < 4 );
// if ( inputDeviceNum > in_joystick.GetInteger() ) {
// return numEvents;
// }
controllerState_t *cs = &controllers[ inputDeviceNum ];
// grab the current packet under a critical section
XINPUT_STATE xis;
XINPUT_STATE old;
int orBits;
{
idScopedCriticalSection crit( mutexXis );
xis = cs->current;
old = cs->previous;
cs->previous = xis;
// fetch or'd button bits
orBits = cs->buttonBits;
cs->buttonBits = 0;
}
#if 0
if ( XInputGetState( inputDeviceNum, &xis ) != ERROR_SUCCESS ) {
return numEvents;
}
#endif
for ( int i = 0 ; i < 32 ; i++ ) {
int bit = 1<<i;
if ( ( ( xis.Gamepad.wButtons | old.Gamepad.wButtons ) & bit ) == 0
&& ( orBits & bit ) ) {
idLib::Printf( "Dropped button press on bit %i\n", i );
}
}
if ( session->IsSystemUIShowing() ) {
// memset xis so the current input does not get latched if the UI is showing
memset( &xis, 0, sizeof( XINPUT_STATE ) );
}
int joyRemap[16] = {
J_DPAD_UP, J_DPAD_DOWN, // Up, Down
J_DPAD_LEFT, J_DPAD_RIGHT, // Left, Right
J_ACTION9, J_ACTION10, // Start, Back
J_ACTION7, J_ACTION8, // Left Stick Down, Right Stick Down
J_ACTION5, J_ACTION6, // Black, White (Left Shoulder, Right Shoulder)
0, 0, // Unused
J_ACTION1, J_ACTION2, // A, B
J_ACTION3, J_ACTION4, // X, Y
};
// Check the digital buttons
for ( int i = 0; i < 16; i++ ) {
int mask = ( 1 << i );
if ( ( xis.Gamepad.wButtons & mask ) != ( old.Gamepad.wButtons & mask ) ) {
PostInputEvent( inputDeviceNum, joyRemap[i], ( xis.Gamepad.wButtons & mask ) > 0 );
}
}
// Check the triggers
if ( xis.Gamepad.bLeftTrigger != old.Gamepad.bLeftTrigger ) {
PostInputEvent( inputDeviceNum, J_AXIS_LEFT_TRIG, xis.Gamepad.bLeftTrigger * 128 );
}
if ( xis.Gamepad.bRightTrigger != old.Gamepad.bRightTrigger ) {
PostInputEvent( inputDeviceNum, J_AXIS_RIGHT_TRIG, xis.Gamepad.bRightTrigger * 128 );
}
if ( xis.Gamepad.sThumbLX != old.Gamepad.sThumbLX ) {
PostInputEvent( inputDeviceNum, J_AXIS_LEFT_X, xis.Gamepad.sThumbLX );
}
if ( xis.Gamepad.sThumbLY != old.Gamepad.sThumbLY ) {
PostInputEvent( inputDeviceNum, J_AXIS_LEFT_Y, -xis.Gamepad.sThumbLY );
}
if ( xis.Gamepad.sThumbRX != old.Gamepad.sThumbRX ) {
PostInputEvent( inputDeviceNum, J_AXIS_RIGHT_X, xis.Gamepad.sThumbRX );
}
if ( xis.Gamepad.sThumbRY != old.Gamepad.sThumbRY ) {
PostInputEvent( inputDeviceNum, J_AXIS_RIGHT_Y, -xis.Gamepad.sThumbRY );
}
return numEvents;
}
/*
========================
idJoystickWin32::ReturnInputEvent
========================
*/
int idJoystickWin32::ReturnInputEvent( const int n, int & action, int &value ) {
if ( ( n < 0 ) || ( n >= MAX_JOY_EVENT ) ) {
return 0;
}
action = events[ n ].event;
value = events[ n ].value;
return 1;
}
/*
========================
idJoystickWin32::PushButton
========================
*/
void idJoystickWin32::PushButton( int inputDeviceNum, int key, bool value ) {
// So we don't keep sending the same SE_KEY message over and over again
if ( buttonStates[inputDeviceNum][key] != value ) {
buttonStates[inputDeviceNum][key] = value;
Sys_QueEvent( SE_KEY, key, value, 0, NULL, inputDeviceNum );
}
}

96
neo/sys/win32/win_input.h Normal file
View File

@@ -0,0 +1,96 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
//#if defined( ID_VS2010 )
//#include "../../../libs/dxsdk_June2010/include/xinput.h"
//#else
#include <Xinput.h>
//#endif
static const int MAX_JOYSTICKS = 4;
/*
================================================================================================
Joystick Win32
================================================================================================
*/
struct controllerState_t {
// the current states are updated by the input thread at 250 hz
XINPUT_STATE current;
// the previous state is latched at polling time
XINPUT_STATE previous;
// The current button bits are or'd into this at the high sampling rate, then
// zero'd by the main thread when a usercmd_t is created. This prevents the
// complete missing of a button press that went down and up between two usercmd_t
// creations, although it can add sn extra frame of latency to sensing a release.
int buttonBits;
// Only valid controllers will have their rumble set
bool valid;
};
class idJoystickWin32 : idJoystick {
public:
idJoystickWin32();
virtual bool Init();
virtual void SetRumble( int deviceNum, int rumbleLow, int rumbleHigh );
virtual int PollInputEvents( int inputDeviceNum );
virtual int ReturnInputEvent( const int n, int &action, int &value );
virtual void EndInputEvents() {}
protected:
friend void JoystickSamplingThread( void *data );
void PushButton( int inputDeviceNum, int key, bool value );
void PostInputEvent( int inputDeviceNum, int event, int value, int range = 16384 );
idSysMutex mutexXis; // lock this before using currentXis or stickIntegrations
HANDLE timer; // fire every 4 msec
int numEvents;
struct {
int event;
int value;
} events[ MAX_JOY_EVENT ];
controllerState_t controllers[ MAX_JOYSTICKS ];
// should these be per-controller?
bool buttonStates[MAX_INPUT_DEVICES][K_LAST_KEY]; // For keeping track of button up/down events
int joyAxis[MAX_INPUT_DEVICES][MAX_JOYSTICK_AXIS]; // For keeping track of joystick axises
};

166
neo/sys/win32/win_local.h Normal file
View File

@@ -0,0 +1,166 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#ifndef __WIN_LOCAL_H__
#define __WIN_LOCAL_H__
#include <windows.h>
#include "../../renderer/OpenGL/wglext.h" // windows OpenGL extensions
#include "win_input.h"
// WGL_ARB_extensions_string
extern PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
// WGL_EXT_swap_interval
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
// WGL_ARB_pixel_format
extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
extern PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
// WGL_ARB_pbuffer
extern PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
extern PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
extern PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
extern PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
extern PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB;
// WGL_ARB_render_texture
extern PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
extern PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
extern PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB;
#define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE | WS_THICKFRAME)
void Sys_QueEvent( sysEventType_t type, int value, int value2, int ptrLength, void *ptr, int inputDeviceNum );
void Sys_CreateConsole();
void Sys_DestroyConsole();
char *Sys_ConsoleInput ();
char *Sys_GetCurrentUser();
void Win_SetErrorText( const char *text );
cpuid_t Sys_GetCPUId();
// Input subsystem
void IN_Init ();
void IN_Shutdown ();
// add additional non keyboard / non mouse movement on top of the keyboard move cmd
void IN_DeactivateMouseIfWindowed();
void IN_DeactivateMouse();
void IN_ActivateMouse();
void IN_Frame();
void DisableTaskKeys( BOOL bDisable, BOOL bBeep, BOOL bTaskMgr );
uint64 Sys_Microseconds();
// window procedure
LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Conbuf_AppendText( const char *msg );
typedef struct {
HWND hWnd;
HINSTANCE hInstance;
bool activeApp; // changed with WM_ACTIVATE messages
bool mouseReleased; // when the game has the console down or is doing a long operation
bool movingWindow; // inhibit mouse grab when dragging the window
bool mouseGrabbed; // current state of grab and hide
OSVERSIONINFOEX osversion;
cpuid_t cpuid;
// when we get a windows message, we store the time off so keyboard processing
// can know the exact time of an event (not really needed now that we use async direct input)
int sysMsgTime;
bool windowClassRegistered;
WNDPROC wndproc;
HDC hDC; // handle to device context
HGLRC hGLRC; // handle to GL rendering context
PIXELFORMATDESCRIPTOR pfd;
int pixelformat;
HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library
int desktopBitsPixel;
int desktopWidth, desktopHeight;
int cdsFullscreen; // 0 = not fullscreen, otherwise monitor number
idFileHandle log_fp;
unsigned short oldHardwareGamma[3][256];
// desktop gamma is saved here for restoration at exit
static idCVar sys_arch;
static idCVar sys_cpustring;
static idCVar in_mouse;
static idCVar win_allowAltTab;
static idCVar win_notaskkeys;
static idCVar win_username;
static idCVar win_outputEditString;
static idCVar win_viewlog;
static idCVar win_timerUpdate;
static idCVar win_allowMultipleInstances;
CRITICAL_SECTION criticalSections[MAX_CRITICAL_SECTIONS];
HINSTANCE hInstDI; // direct input
LPDIRECTINPUT8 g_pdi;
LPDIRECTINPUTDEVICE8 g_pMouse;
LPDIRECTINPUTDEVICE8 g_pKeyboard;
idJoystickWin32 g_Joystick;
HANDLE renderCommandsEvent;
HANDLE renderCompletedEvent;
HANDLE renderActiveEvent;
HANDLE renderThreadHandle;
unsigned long renderThreadId;
void (*glimpRenderThread)();
void *smpData;
int wglErrors;
// SMP acceleration vars
} Win32Vars_t;
extern Win32Vars_t win32;
#endif /* !__WIN_LOCAL_H__ */

View File

@@ -0,0 +1,121 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "win_localuser.h"
extern idCVar win_userPersistent;
extern idCVar win_userOnline;
extern idCVar win_isInParty;
extern idCVar win_partyCount;
/*
========================
idLocalUserWin::Init
========================
*/
void idLocalUserWin::Init( int inputDevice_, const char * gamertag_, int numLocalUsers ) {
if ( numLocalUsers == 1 ) { // Check for 1, since this is now incremented before we get in here
// This is the master user
gamertag = gamertag_;
} else {
// On steam, we need to generate a name based off the master user for split-screen users.
// We use the number of users on the system to generate the name rather than the device
// number so that it is always consistently "username (2)" for the second player.
gamertag.Format( "%s (%i)", gamertag_, numLocalUsers );
}
inputDevice = inputDevice_;
}
/*
========================
idLocalUserWin::IsProfileReady
========================
*/
bool idLocalUserWin::IsProfileReady() const {
#ifdef _DEBUG
return win_userPersistent.GetBool();
#else
return true;
#endif
}
/*
========================
idLocalUserWin::IsOnline
========================
*/
bool idLocalUserWin::IsOnline() const {
#ifdef _DEBUG
return win_userOnline.GetBool();
#else
return true;
#endif
}
/*
========================
idLocalUserWin::IsInParty
========================
*/
bool idLocalUserWin::IsInParty() const {
#ifdef _DEBUG
return win_isInParty.GetBool();
#else
return false;
#endif
}
/*
========================
idLocalUserWin::GetPartyCount
========================
*/
int idLocalUserWin::GetPartyCount() const {
// TODO: Implement
#ifdef _DEBUG
return win_partyCount.GetInteger();
#else
return 0;
#endif
}
/*
========================
idLocalUserWin::VerifyUserState
========================
*/
bool idLocalUserWin::VerifyUserState( winUserState_t & state ) {
if ( state.inputDevice != inputDevice ) {
return false;
}
return true;
}

View File

@@ -0,0 +1,75 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#ifndef __WIN_LOCALUSER_H__
#define __WIN_LOCALUSER_H__
// This is to quickly get/set the data needed for disc-swapping
typedef struct {
int inputDevice;
} winUserState_t;
/*
================================================
idLocalUserWin
================================================
*/
class idLocalUserWin : public idLocalUser {
public:
static const int MAX_GAMERTAG = 64; // max number of bytes for a gamertag
static const int MAX_GAMERTAG_CHARS = 16; // max number of UTF-8 characters to show
idLocalUserWin() : inputDevice( 0 ) {}
//==========================================================================================
// idLocalUser interface
//==========================================================================================
virtual bool IsProfileReady() const;
virtual bool IsOnline() const;
virtual bool IsInParty() const;
virtual int GetPartyCount() const;
virtual uint32 GetOnlineCaps() const { return ( IsPersistent() && IsOnline() ) ? ( CAP_IS_ONLINE | CAP_CAN_PLAY_ONLINE ) : 0; }
virtual int GetInputDevice() const { return inputDevice; }
virtual const char * GetGamerTag() const { return gamertag.c_str(); }
virtual void PumpPlatform() {}
//==========================================================================================
// idLocalUserWin interface
//==========================================================================================
void SetInputDevice( int inputDevice_ ) { inputDevice = inputDevice_; }
void SetGamerTag( const char * gamerTag_ ) { gamertag = gamerTag_; }
winUserState_t GetUserState() { winUserState_t a = { inputDevice }; return a; }
bool VerifyUserState( winUserState_t & state );
void Init( int inputDevice_, const char * gamertag_, int numLocalUsers );
private:
idStrStatic< MAX_GAMERTAG > gamertag;
int inputDevice;
};
#endif // __WIN_LOCALUSER_H__

1661
neo/sys/win32/win_main.cpp Normal file

File diff suppressed because it is too large Load Diff

987
neo/sys/win32/win_net.cpp Normal file
View File

@@ -0,0 +1,987 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
/*
================================================================================================
Contains the NetworkSystem implementation specific to Win32.
================================================================================================
*/
#include <iptypes.h>
#include <iphlpapi.h>
static WSADATA winsockdata;
static bool winsockInitialized = false;
static bool usingSocks = false;
//lint -e569 ioctl macros trigger this
// force these libs to be included, so users of idLib don't need to add them to every project
#pragma comment(lib, "iphlpapi.lib" )
#pragma comment(lib, "wsock32.lib" )
/*
================================================================================================
Network CVars
================================================================================================
*/
idCVar net_socksServer( "net_socksServer", "", CVAR_ARCHIVE, "" );
idCVar net_socksPort( "net_socksPort", "1080", CVAR_ARCHIVE | CVAR_INTEGER, "" );
idCVar net_socksUsername( "net_socksUsername", "", CVAR_ARCHIVE, "" );
idCVar net_socksPassword( "net_socksPassword", "", CVAR_ARCHIVE, "" );
idCVar net_ip( "net_ip", "localhost", 0, "local IP address" );
static struct sockaddr_in socksRelayAddr;
static SOCKET ip_socket;
static SOCKET socks_socket;
static char socksBuf[4096];
typedef struct {
unsigned long ip;
unsigned long mask;
char addr[16];
} net_interface;
#define MAX_INTERFACES 32
int num_interfaces = 0;
net_interface netint[MAX_INTERFACES];
/*
================================================================================================
Free Functions
================================================================================================
*/
/*
========================
NET_ErrorString
========================
*/
char *NET_ErrorString() {
int code;
code = WSAGetLastError();
switch( code ) {
case WSAEINTR: return "WSAEINTR";
case WSAEBADF: return "WSAEBADF";
case WSAEACCES: return "WSAEACCES";
case WSAEDISCON: return "WSAEDISCON";
case WSAEFAULT: return "WSAEFAULT";
case WSAEINVAL: return "WSAEINVAL";
case WSAEMFILE: return "WSAEMFILE";
case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
case WSAEINPROGRESS: return "WSAEINPROGRESS";
case WSAEALREADY: return "WSAEALREADY";
case WSAENOTSOCK: return "WSAENOTSOCK";
case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
case WSAEMSGSIZE: return "WSAEMSGSIZE";
case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
case WSAEADDRINUSE: return "WSAEADDRINUSE";
case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
case WSAENETDOWN: return "WSAENETDOWN";
case WSAENETUNREACH: return "WSAENETUNREACH";
case WSAENETRESET: return "WSAENETRESET";
case WSAECONNABORTED: return "WSAECONNABORTED";
case WSAECONNRESET: return "WSAECONNRESET";
case WSAENOBUFS: return "WSAENOBUFS";
case WSAEISCONN: return "WSAEISCONN";
case WSAENOTCONN: return "WSAENOTCONN";
case WSAESHUTDOWN: return "WSAESHUTDOWN";
case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
case WSAETIMEDOUT: return "WSAETIMEDOUT";
case WSAECONNREFUSED: return "WSAECONNREFUSED";
case WSAELOOP: return "WSAELOOP";
case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
case WSASYSNOTREADY: return "WSASYSNOTREADY";
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
case WSANOTINITIALISED: return "WSANOTINITIALISED";
case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
case WSATRY_AGAIN: return "WSATRY_AGAIN";
case WSANO_RECOVERY: return "WSANO_RECOVERY";
case WSANO_DATA: return "WSANO_DATA";
default: return "NO ERROR";
}
}
/*
========================
Net_NetadrToSockadr
========================
*/
void Net_NetadrToSockadr( const netadr_t *a, sockaddr_in *s ) {
memset( s, 0, sizeof(*s) );
if ( a->type == NA_BROADCAST ) {
s->sin_family = AF_INET;
s->sin_addr.s_addr = INADDR_BROADCAST;
} else if ( a->type == NA_IP || a->type == NA_LOOPBACK ) {
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(int *)a->ip;
}
s->sin_port = htons( (short)a->port );
}
/*
========================
Net_SockadrToNetadr
========================
*/
void Net_SockadrToNetadr( sockaddr_in *s, netadr_t *a ) {
unsigned int ip;
if ( s->sin_family == AF_INET ) {
ip = s->sin_addr.s_addr;
*(unsigned int *)a->ip = ip;
a->port = htons( 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;
}
}
}
/*
========================
Net_ExtractPort
========================
*/
static bool Net_ExtractPort( const char *src, char *buf, int bufsize, int *port ) {
char *p;
strncpy( buf, src, bufsize );
p = buf; p += Min( bufsize - 1, idStr::Length( src ) ); *p = '\0';
p = strchr( buf, ':' );
if ( !p ) {
return false;
}
*p = '\0';
*port = strtol( p+1, NULL, 10 );
if ( errno == ERANGE ) {
return false;
}
return true;
}
/*
========================
Net_StringToSockaddr
========================
*/
static bool Net_StringToSockaddr( const char *s, 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' ) {
unsigned long ret = inet_addr(s);
if ( ret != INADDR_NONE ) {
*(int *)&sadr->sin_addr = ret;
} else {
// check for port
if ( !Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
return false;
}
ret = inet_addr( buf );
if ( ret == INADDR_NONE ) {
return false;
}
*(int *)&sadr->sin_addr = ret;
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 ( Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
sadr->sin_port = htons( port );
}
h = gethostbyname( buf );
if ( h == 0 ) {
return false;
}
*(int *)&sadr->sin_addr = *(int *)h->h_addr_list[0];
}
return true;
}
/*
========================
NET_IPSocket
========================
*/
int NET_IPSocket( const char *net_interface, int port, netadr_t *bound_to ) {
SOCKET newsocket;
sockaddr_in address;
unsigned long _true = 1;
int i = 1;
int err;
if ( port != PORT_ANY ) {
if( net_interface ) {
idLib::Printf( "Opening IP socket: %s:%i\n", net_interface, port );
} else {
idLib::Printf( "Opening IP socket: localhost:%i\n", port );
}
}
if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
err = WSAGetLastError();
if( err != WSAEAFNOSUPPORT ) {
idLib::Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() );
}
return 0;
}
// make it non-blocking
if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
idLib::Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
closesocket( newsocket );
return 0;
}
// make it broadcast capable
if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {
idLib::Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
closesocket( newsocket );
return 0;
}
if( !net_interface || !net_interface[0] || !idStr::Icmp( net_interface, "localhost" ) ) {
address.sin_addr.s_addr = INADDR_ANY;
}
else {
Net_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 sockaddr *)&address, sizeof(address) ) == SOCKET_ERROR ) {
idLib::Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() );
closesocket( newsocket );
return 0;
}
// if the port was PORT_ANY, we need to query again to know the real port we got bound to
// ( this used to be in idUDP::InitForPort )
if ( bound_to ) {
int len = sizeof( address );
getsockname( newsocket, (sockaddr *)&address, &len );
Net_SockadrToNetadr( &address, bound_to );
}
return newsocket;
}
/*
========================
NET_OpenSocks
========================
*/
void NET_OpenSocks( int port ) {
sockaddr_in address;
struct hostent *h;
int len;
bool rfc1929;
unsigned char buf[64];
usingSocks = false;
idLib::Printf( "Opening connection to SOCKS server.\n" );
if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
idLib::Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
return;
}
h = gethostbyname( net_socksServer.GetString() );
if ( h == NULL ) {
idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
return;
}
if ( h->h_addrtype != AF_INET ) {
idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
return;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
address.sin_port = htons( (short)net_socksPort.GetInteger() );
if ( connect( socks_socket, (sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
return;
}
// send socks authentication handshake
if ( *net_socksUsername.GetString() || *net_socksPassword.GetString() ) {
rfc1929 = true;
}
else {
rfc1929 = false;
}
buf[0] = 5; // SOCKS version
// method count
if ( rfc1929 ) {
buf[1] = 2;
len = 4;
}
else {
buf[1] = 1;
len = 3;
}
buf[2] = 0; // method #1 - method id #00: no authentication
if ( rfc1929 ) {
buf[2] = 2; // method #2 - method id #02: username/password
}
if ( send( socks_socket, (const char *)buf, len, 0 ) == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
return;
}
// get the response
len = recv( socks_socket, (char *)buf, 64, 0 );
if ( len == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
return;
}
if ( len != 2 || buf[0] != 5 ) {
idLib::Printf( "NET_OpenSocks: bad response\n" );
return;
}
switch( buf[1] ) {
case 0: // no authentication
break;
case 2: // username/password authentication
break;
default:
idLib::Printf( "NET_OpenSocks: request denied\n" );
return;
}
// do username/password authentication if needed
if ( buf[1] == 2 ) {
int ulen;
int plen;
// build the request
ulen = idStr::Length( net_socksUsername.GetString() );
plen = idStr::Length( net_socksPassword.GetString() );
buf[0] = 1; // username/password authentication version
buf[1] = ulen;
if ( ulen ) {
memcpy( &buf[2], net_socksUsername.GetString(), ulen );
}
buf[2 + ulen] = plen;
if ( plen ) {
memcpy( &buf[3 + ulen], net_socksPassword.GetString(), plen );
}
// send it
if ( send( socks_socket, (const char *)buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
return;
}
// get the response
len = recv( socks_socket, (char *)buf, 64, 0 );
if ( len == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
return;
}
if ( len != 2 || buf[0] != 1 ) {
idLib::Printf( "NET_OpenSocks: bad response\n" );
return;
}
if ( buf[1] != 0 ) {
idLib::Printf( "NET_OpenSocks: authentication failed\n" );
return;
}
}
// send the UDP associate request
buf[0] = 5; // SOCKS version
buf[1] = 3; // command: UDP associate
buf[2] = 0; // reserved
buf[3] = 1; // address type: IPV4
*(int *)&buf[4] = INADDR_ANY;
*(short *)&buf[8] = htons( (short)port ); // port
if ( send( socks_socket, (const char *)buf, 10, 0 ) == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
return;
}
// get the response
len = recv( socks_socket, (char *)buf, 64, 0 );
if( len == SOCKET_ERROR ) {
idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
return;
}
if( len < 2 || buf[0] != 5 ) {
idLib::Printf( "NET_OpenSocks: bad response\n" );
return;
}
// check completion code
if( buf[1] != 0 ) {
idLib::Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
return;
}
if( buf[3] != 1 ) {
idLib::Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
return;
}
socksRelayAddr.sin_family = AF_INET;
socksRelayAddr.sin_addr.s_addr = *(int *)&buf[4];
socksRelayAddr.sin_port = *(short *)&buf[8];
memset( socksRelayAddr.sin_zero, 0, sizeof( socksRelayAddr.sin_zero ) );
usingSocks = true;
}
/*
========================
Net_WaitForData
========================
*/
bool Net_WaitForData( int netSocket, int timeout ) {
int ret;
fd_set set;
struct timeval tv;
if ( !netSocket ) {
return false;
}
if ( timeout < 0 ) {
return true;
}
FD_ZERO( &set );
FD_SET( static_cast<unsigned int>( netSocket ), &set );
tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;
ret = select( netSocket + 1, &set, NULL, NULL, &tv );
if ( ret == -1 ) {
idLib::Printf( "Net_WaitForData select(): %s\n", strerror( errno ) );
return false;
}
// timeout with no data
if ( ret == 0 ) {
return false;
}
return true;
}
/*
========================
Net_GetUDPPacket
========================
*/
bool Net_GetUDPPacket( int netSocket, netadr_t &net_from, char *data, int &size, int maxSize ) {
int ret;
sockaddr_in from;
int fromlen;
int err;
if ( !netSocket ) {
return false;
}
fromlen = sizeof(from);
ret = recvfrom( netSocket, data, maxSize, 0, (sockaddr *)&from, &fromlen );
if ( ret == SOCKET_ERROR ) {
err = WSAGetLastError();
if ( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {
return false;
}
char buf[1024];
sprintf( buf, "Net_GetUDPPacket: %s\n", NET_ErrorString() );
idLib::Printf( buf );
return false;
}
if ( static_cast<unsigned int>( netSocket ) == ip_socket ) {
memset( from.sin_zero, 0, sizeof( from.sin_zero ) );
}
if ( usingSocks && static_cast<unsigned int>( netSocket ) == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
if ( ret < 10 || data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 1 ) {
return false;
}
net_from.type = NA_IP;
net_from.ip[0] = data[4];
net_from.ip[1] = data[5];
net_from.ip[2] = data[6];
net_from.ip[3] = data[7];
net_from.port = *(short *)&data[8];
memmove( data, &data[10], ret - 10 );
} else {
Net_SockadrToNetadr( &from, &net_from );
}
if ( ret > maxSize ) {
char buf[1024];
sprintf( buf, "Net_GetUDPPacket: oversize packet from %s\n", Sys_NetAdrToString( net_from ) );
idLib::Printf( buf );
return false;
}
size = ret;
return true;
}
/*
========================
Net_SendUDPPacket
========================
*/
void Net_SendUDPPacket( int netSocket, int length, const void *data, const netadr_t to ) {
int ret;
sockaddr_in addr;
if ( !netSocket ) {
return;
}
Net_NetadrToSockadr( &to, &addr );
if ( usingSocks && to.type == NA_IP ) {
socksBuf[0] = 0; // reserved
socksBuf[1] = 0;
socksBuf[2] = 0; // fragment (not fragmented)
socksBuf[3] = 1; // address type: IPV4
*(int *)&socksBuf[4] = addr.sin_addr.s_addr;
*(short *)&socksBuf[8] = addr.sin_port;
memcpy( &socksBuf[10], data, length );
ret = sendto( netSocket, socksBuf, length+10, 0, (sockaddr *)&socksRelayAddr, sizeof(socksRelayAddr) );
} else {
ret = sendto( netSocket, (const char *)data, length, 0, (sockaddr *)&addr, sizeof(addr) );
}
if ( ret == SOCKET_ERROR ) {
int err = WSAGetLastError();
// some PPP links do not allow broadcasts and return an error
if ( ( err == WSAEADDRNOTAVAIL ) && ( to.type == NA_BROADCAST ) ) {
return;
}
// NOTE: WSAEWOULDBLOCK used to be silently ignored,
// but that means the packet will be dropped so I don't feel it's a good thing to ignore
idLib::Printf( "UDP sendto error - packet dropped: %s\n", NET_ErrorString() );
}
}
/*
========================
Sys_InitNetworking
========================
*/
void Sys_InitNetworking() {
int r;
if ( winsockInitialized ) {
return;
}
r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
if( r ) {
idLib::Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
return;
}
winsockInitialized = true;
idLib::Printf( "Winsock Initialized\n" );
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
PIP_ADDR_STRING pIPAddrString;
ULONG ulOutBufLen;
bool foundloopback;
num_interfaces = 0;
foundloopback = false;
pAdapterInfo = (IP_ADAPTER_INFO *)malloc( sizeof( IP_ADAPTER_INFO ) );
if( !pAdapterInfo ) {
idLib::FatalError( "Sys_InitNetworking: Couldn't malloc( %d )", sizeof( IP_ADAPTER_INFO ) );
}
ulOutBufLen = sizeof( IP_ADAPTER_INFO );
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if( GetAdaptersInfo( pAdapterInfo, &ulOutBufLen ) == ERROR_BUFFER_OVERFLOW ) {
free( pAdapterInfo );
pAdapterInfo = (IP_ADAPTER_INFO *)malloc( ulOutBufLen );
if( !pAdapterInfo ) {
idLib::FatalError( "Sys_InitNetworking: Couldn't malloc( %ld )", ulOutBufLen );
}
}
if( ( dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) ) != NO_ERROR ) {
// happens if you have no network connection
idLib::Printf( "Sys_InitNetworking: GetAdaptersInfo failed (%ld).\n", dwRetVal );
} else {
pAdapter = pAdapterInfo;
while( pAdapter ) {
idLib::Printf( "Found interface: %s %s - ", pAdapter->AdapterName, pAdapter->Description );
pIPAddrString = &pAdapter->IpAddressList;
while( pIPAddrString ) {
unsigned long ip_a, ip_m;
if( !idStr::Icmp( "127.0.0.1", pIPAddrString->IpAddress.String ) ) {
foundloopback = true;
}
ip_a = ntohl( inet_addr( pIPAddrString->IpAddress.String ) );
ip_m = ntohl( inet_addr( pIPAddrString->IpMask.String ) );
//skip null netmasks
if( !ip_m ) {
idLib::Printf( "%s NULL netmask - skipped\n", pIPAddrString->IpAddress.String );
pIPAddrString = pIPAddrString->Next;
continue;
}
idLib::Printf( "%s/%s\n", pIPAddrString->IpAddress.String, pIPAddrString->IpMask.String );
netint[num_interfaces].ip = ip_a;
netint[num_interfaces].mask = ip_m;
idStr::Copynz( netint[num_interfaces].addr, pIPAddrString->IpAddress.String, sizeof( netint[num_interfaces].addr ) );
num_interfaces++;
if( num_interfaces >= MAX_INTERFACES ) {
idLib::Printf( "Sys_InitNetworking: MAX_INTERFACES(%d) hit.\n", MAX_INTERFACES );
free( pAdapterInfo );
return;
}
pIPAddrString = pIPAddrString->Next;
}
pAdapter = pAdapter->Next;
}
}
// for some retarded reason, win32 doesn't count loopback as an adapter...
if( !foundloopback && num_interfaces < MAX_INTERFACES ) {
idLib::Printf( "Sys_InitNetworking: adding loopback interface\n" );
netint[num_interfaces].ip = ntohl( inet_addr( "127.0.0.1" ) );
netint[num_interfaces].mask = ntohl( inet_addr( "255.0.0.0" ) );
num_interfaces++;
}
free( pAdapterInfo );
}
/*
========================
Sys_ShutdownNetworking
========================
*/
void Sys_ShutdownNetworking() {
if ( !winsockInitialized ) {
return;
}
WSACleanup();
winsockInitialized = false;
}
/*
========================
Sys_StringToNetAdr
========================
*/
bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ) {
sockaddr_in sadr;
if ( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) {
return false;
}
Net_SockadrToNetadr( &sadr, a );
return true;
}
/*
========================
Sys_NetAdrToString
========================
*/
const char *Sys_NetAdrToString( const netadr_t a ) {
static int index = 0;
static char buf[ 4 ][ 64 ]; // flip/flop
char *s;
s = buf[index];
index = (index + 1) & 3;
if ( a.type == NA_LOOPBACK ) {
if ( a.port ) {
idStr::snPrintf( s, 64, "localhost:%i", a.port );
} else {
idStr::snPrintf( s, 64, "localhost" );
}
} else if ( a.type == NA_IP ) {
idStr::snPrintf( s, 64, "%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 ) {
if ( adr.type == NA_LOOPBACK ) {
return true;
}
if ( adr.type != NA_IP ) {
return false;
}
if ( num_interfaces ) {
int i;
unsigned long *p_ip;
unsigned long ip;
p_ip = (unsigned long *)&adr.ip[0];
ip = ntohl( *p_ip );
for( i = 0; i < num_interfaces; i++ ) {
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 ) {
if ( a.port == b.port ) {
return true;
}
return false;
}
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;
}
idLib::Printf( "Sys_CompareNetAdrBase: bad address type\n" );
return false;
}
/*
========================
Sys_GetLocalIPCount
========================
*/
int Sys_GetLocalIPCount() {
return num_interfaces;
}
/*
========================
Sys_GetLocalIP
========================
*/
const char * Sys_GetLocalIP( int i ) {
if ( ( i < 0 ) || ( i >= num_interfaces ) ) {
return NULL;
}
return netint[i].addr;
}
/*
================================================================================================
idUDP
================================================================================================
*/
/*
========================
idUDP::idUDP
========================
*/
idUDP::idUDP() {
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
silent = false;
packetsRead = 0;
bytesRead = 0;
packetsWritten = 0;
bytesWritten = 0;
}
/*
========================
idUDP::~idUDP
========================
*/
idUDP::~idUDP() {
Close();
}
/*
========================
idUDP::InitForPort
========================
*/
bool idUDP::InitForPort( int portNumber ) {
netSocket = NET_IPSocket( net_ip.GetString(), portNumber, &bound_to );
if ( netSocket <= 0 ) {
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
return false;
}
return true;
}
/*
========================
idUDP::Close
========================
*/
void idUDP::Close() {
if ( netSocket ) {
closesocket( netSocket );
netSocket = 0;
memset( &bound_to, 0, sizeof( bound_to ) );
}
}
/*
========================
idUDP::GetPacket
========================
*/
bool idUDP::GetPacket( netadr_t &from, void *data, int &size, int maxSize ) {
bool ret;
while ( 1 ) {
ret = Net_GetUDPPacket( netSocket, from, (char *)data, size, maxSize );
if ( !ret ) {
break;
}
packetsRead++;
bytesRead += size;
break;
}
return ret;
}
/*
========================
idUDP::GetPacketBlocking
========================
*/
bool idUDP::GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ) {
if ( !Net_WaitForData( netSocket, timeout ) ) {
return false;
}
if ( GetPacket( from, data, size, maxSize ) ) {
return true;
}
return false;
}
/*
========================
idUDP::SendPacket
========================
*/
void idUDP::SendPacket( const netadr_t to, const void *data, int size ) {
if ( to.type == NA_BAD ) {
idLib::Warning( "idUDP::SendPacket: bad address type NA_BAD - ignored" );
return;
}
packetsWritten++;
bytesWritten += size;
if ( silent ) {
return;
}
Net_SendUDPPacket( netSocket, size, data, to );
}

2011
neo/sys/win32/win_qgl.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,698 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "../sys_session_local.h"
#include "../sys_savegame.h"
idCVar savegame_winInduceDelay( "savegame_winInduceDelay", "0", CVAR_INTEGER, "on windows, this is a delay induced before any file operation occurs" );
extern idCVar fs_savepath;
extern idCVar saveGame_checksum;
extern idCVar savegame_error;
#define SAVEGAME_SENTINAL 0x12358932
/*
========================
void Sys_ExecuteSavegameCommandAsync
========================
*/
void Sys_ExecuteSavegameCommandAsyncImpl( idSaveLoadParms * savegameParms ) {
assert( savegameParms != NULL );
session->GetSaveGameManager().GetSaveGameThread().data.saveLoadParms = savegameParms;
if ( session->GetSaveGameManager().GetSaveGameThread().GetThreadHandle() == 0 ) {
session->GetSaveGameManager().GetSaveGameThread().StartWorkerThread( "Savegame", CORE_ANY );
}
session->GetSaveGameManager().GetSaveGameThread().SignalWork();
}
/*
========================
idLocalUser * GetLocalUserFromUserId
========================
*/
idLocalUserWin * GetLocalUserFromSaveParms( const saveGameThreadArgs_t & data ) {
if ( ( data.saveLoadParms != NULL) && ( data.saveLoadParms->inputDeviceId >= 0 ) ) {
idLocalUser * user = session->GetSignInManager().GetLocalUserByInputDevice( data.saveLoadParms->inputDeviceId );
if ( user != NULL ) {
idLocalUserWin * userWin = static_cast< idLocalUserWin * >( user );
if ( userWin != NULL && data.saveLoadParms->userId == idStr::Hash( userWin->GetGamerTag() ) ) {
return userWin;
}
}
}
return NULL;
}
/*
========================
idSaveGameThread::SaveGame
========================
*/
int idSaveGameThread::Save() {
idLocalUserWin * user = GetLocalUserFromSaveParms( data );
if ( user == NULL ) {
data.saveLoadParms->errorCode = SAVEGAME_E_INVALID_USER;
return -1;
}
idSaveLoadParms * callback = data.saveLoadParms;
idStr saveFolder = "savegame";
saveFolder.AppendPath( callback->directory );
// Check for the required storage space.
int64 requiredSizeBytes = 0;
{
for ( int i = 0; i < callback->files.Num(); i++ ) {
idFile_SaveGame * file = callback->files[i];
requiredSizeBytes += ( file->Length() + sizeof( unsigned int ) ); // uint for checksum
if ( file->type == SAVEGAMEFILE_PIPELINED ) {
requiredSizeBytes += MIN_SAVEGAME_SIZE_BYTES;
}
}
}
int ret = ERROR_SUCCESS;
// Check size of previous files if needed
// ALL THE FILES RIGHT NOW---- could use pattern later...
idStrList filesToDelete;
if ( ( callback->mode & SAVEGAME_MBF_DELETE_FILES ) && !callback->cancelled ) {
if ( fileSystem->IsFolder( saveFolder.c_str(), "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFilesTree( saveFolder.c_str(), "*.*" );
for ( int i = 0; i < files->GetNumFiles(); i++ ) {
requiredSizeBytes -= fileSystem->GetFileLength( files->GetFile( i ) );
filesToDelete.Append( files->GetFile( i ) );
}
fileSystem->FreeFileList( files );
}
}
// Inform user about size required if necessary
if ( requiredSizeBytes > 0 && !callback->cancelled ) {
user->StorageSizeAvailable( requiredSizeBytes, callback->requiredSpaceInBytes );
if ( callback->requiredSpaceInBytes > 0 ) {
// check to make sure savepath actually exists before erroring
idStr directory = fs_savepath.GetString();
directory += "\\"; // so it doesn't think the last part is a file and ignores in the directory creation
fileSystem->CreateOSPath( directory ); // we can't actually check FileExists in production builds, so just try to create it
user->StorageSizeAvailable( requiredSizeBytes, callback->requiredSpaceInBytes );
if ( callback->requiredSpaceInBytes > 0 ) {
callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM;
// safe to return, haven't written any files yet
return -1;
}
}
}
// Delete all previous files if needed
// ALL THE FILES RIGHT NOW---- could use pattern later...
for ( int i = 0; i < filesToDelete.Num() && !callback->cancelled; i++ ) {
fileSystem->RemoveFile( filesToDelete[i].c_str() );
}
// Save the raw files.
for ( int i = 0; i < callback->files.Num() && ret == ERROR_SUCCESS && !callback->cancelled; i++ ) {
idFile_SaveGame * file = callback->files[i];
idStr fileName = saveFolder;
fileName.AppendPath( file->GetName() );
idStr tempFileName = va( "%s.temp", fileName.c_str() );
idFile * outputFile = fileSystem->OpenFileWrite( tempFileName, "fs_savePath" );
if ( outputFile == NULL ) {
idLib::Warning( "[%s]: Couldn't open file for writing, %s. Error = %08x", __FUNCTION__, tempFileName.c_str(), GetLastError() );
file->error = true;
callback->errorCode = SAVEGAME_E_UNKNOWN;
ret = -1;
continue;
}
if ( ( file->type & SAVEGAMEFILE_PIPELINED ) != 0 ) {
idFile_SaveGamePipelined * inputFile = dynamic_cast< idFile_SaveGamePipelined * >( file );
assert( inputFile != NULL );
blockForIO_t block;
while ( inputFile->NextWriteBlock( & block ) ) {
if ( (size_t)outputFile->Write( block.data, block.bytes ) != block.bytes ) {
idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() );
file->error = true;
callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM;
ret = -1;
break;
}
}
} else {
if ( ( file->type & SAVEGAMEFILE_BINARY ) || ( file->type & SAVEGAMEFILE_COMPRESSED ) ) {
if ( saveGame_checksum.GetBool() ) {
unsigned int checksum = MD5_BlockChecksum( file->GetDataPtr(), file->Length() );
size_t size = outputFile->WriteBig( checksum );
if ( size != sizeof( checksum ) ) {
idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() );
file->error = true;
callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM;
ret = -1;
}
}
}
size_t size = outputFile->Write( file->GetDataPtr(), file->Length() );
if ( size != (size_t)file->Length() ) {
idLib::Warning( "[%s]: Write failed. Error = %08x", __FUNCTION__, GetLastError() );
file->error = true;
callback->errorCode = SAVEGAME_E_INSUFFICIENT_ROOM;
ret = -1;
} else {
idLib::PrintfIf( saveGame_verbose.GetBool(), "Saved %s (%s)\n", fileName.c_str(), outputFile->GetFullPath() );
}
}
delete outputFile;
if ( ret == ERROR_SUCCESS ) {
// Remove the old file
if ( !fileSystem->RenameFile( tempFileName, fileName, "fs_savePath" ) ) {
idLib::Warning( "Could not start to rename temporary file %s to %s.", tempFileName.c_str(), fileName.c_str() );
}
} else {
fileSystem->RemoveFile( tempFileName );
idLib::Warning( "Invalid write to temporary file %s.", tempFileName.c_str() );
}
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
// Removed because it seemed a bit drastic
#if 0
// If there is an error, delete the partially saved folder
if ( callback->errorCode != SAVEGAME_E_NONE ) {
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFilesTree( saveFolder, "/|*" );
for ( int i = 0; i < files->GetNumFiles(); i++ ) {
fileSystem->RemoveFile( files->GetFile( i ) );
}
fileSystem->FreeFileList( files );
fileSystem->RemoveDir( saveFolder );
}
}
#endif
return ret;
}
/*
========================
idSessionLocal::LoadGame
========================
*/
int idSaveGameThread::Load() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr saveFolder = "savegame";
saveFolder.AppendPath( callback->directory );
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) != FOLDER_YES ) {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
return -1;
}
int ret = ERROR_SUCCESS;
for ( int i = 0; i < callback->files.Num() && ret == ERROR_SUCCESS && !callback->cancelled; i++ ) {
idFile_SaveGame * file = callback->files[i];
idStr filename = saveFolder;
filename.AppendPath( file->GetName() );
idFile * inputFile = fileSystem->OpenFileRead( filename.c_str() );
if ( inputFile == NULL ) {
file->error = true;
if ( !( file->type & SAVEGAMEFILE_OPTIONAL ) ) {
callback->errorCode = SAVEGAME_E_CORRUPTED;
ret = -1;
}
continue;
}
if ( ( file->type & SAVEGAMEFILE_PIPELINED ) != 0 ) {
idFile_SaveGamePipelined * outputFile = dynamic_cast< idFile_SaveGamePipelined * >( file );
assert( outputFile != NULL );
size_t lastReadBytes = 0;
blockForIO_t block;
while ( outputFile->NextReadBlock( &block, lastReadBytes ) && !callback->cancelled ) {
lastReadBytes = inputFile->Read( block.data, block.bytes );
if ( lastReadBytes != block.bytes ) {
// Notify end-of-file to the save game file which will cause all reads on the
// other end of the pipeline to return zero bytes after the pipeline is drained.
outputFile->NextReadBlock( NULL, lastReadBytes );
break;
}
}
} else {
size_t size = inputFile->Length();
unsigned int originalChecksum = 0;
if ( ( file->type & SAVEGAMEFILE_BINARY ) != 0 || ( file->type & SAVEGAMEFILE_COMPRESSED ) != 0 ) {
if ( saveGame_checksum.GetBool() ) {
if ( size >= sizeof( originalChecksum ) ) {
inputFile->ReadBig( originalChecksum );
size -= sizeof( originalChecksum );
}
}
}
file->SetLength( size );
size_t sizeRead = inputFile->Read( (void *)file->GetDataPtr(), size );
if ( sizeRead != size ) {
file->error = true;
callback->errorCode = SAVEGAME_E_CORRUPTED;
ret = -1;
}
if ( ( file->type & SAVEGAMEFILE_BINARY ) != 0 || ( file->type & SAVEGAMEFILE_COMPRESSED ) != 0 ) {
if ( saveGame_checksum.GetBool() ) {
unsigned int checksum = MD5_BlockChecksum( file->GetDataPtr(), file->Length() );
if ( checksum != originalChecksum ) {
file->error = true;
callback->errorCode = SAVEGAME_E_CORRUPTED;
ret = -1;
}
}
}
}
delete inputFile;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::Delete
This deletes a complete savegame directory
========================
*/
int idSaveGameThread::Delete() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr saveFolder = "savegame";
saveFolder.AppendPath( callback->directory );
int ret = ERROR_SUCCESS;
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFilesTree( saveFolder, "/|*" );
for ( int i = 0; i < files->GetNumFiles() && !callback->cancelled; i++ ) {
fileSystem->RemoveFile( files->GetFile( i ) );
}
fileSystem->FreeFileList( files );
fileSystem->RemoveDir( saveFolder );
} else {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
ret = -1;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::Enumerate
========================
*/
int idSaveGameThread::Enumerate() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr saveFolder = "savegame";
callback->detailList.Clear();
int ret = ERROR_SUCCESS;
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFilesTree( saveFolder, SAVEGAME_DETAILS_FILENAME );
const idStrList & fileList = files->GetList();
for ( int i = 0; i < fileList.Num() && !callback->cancelled; i++ ) {
idSaveGameDetails * details = callback->detailList.Alloc();
// We have more folders on disk than we have room in our save detail list, stop trying to read them in and continue with what we have
if ( details == NULL ) {
break;
}
idStr directory = fileList[i];
idFile * file = fileSystem->OpenFileRead( directory.c_str() );
if ( file != NULL ) {
// Read the DETAIL file for the enumerated data
if ( callback->mode & SAVEGAME_MBF_READ_DETAILS ) {
if ( !SavegameReadDetailsFromFile( file, *details ) ) {
details->damaged = true;
ret = -1;
}
}
// Use the date from the directory
WIN32_FILE_ATTRIBUTE_DATA attrData;
BOOL attrRet = GetFileAttributesEx( file->GetFullPath(), GetFileExInfoStandard, &attrData );
delete file;
if ( attrRet == TRUE ) {
FILETIME lastWriteTime = attrData.ftLastWriteTime;
const ULONGLONG second = 10000000L; // One second = 10,000,000 * 100 nsec
SYSTEMTIME base_st = { 1970, 1, 0, 1, 0, 0, 0, 0 };
ULARGE_INTEGER itime;
FILETIME base_ft;
BOOL success = SystemTimeToFileTime( &base_st, &base_ft );
itime.QuadPart = ((ULARGE_INTEGER *)&lastWriteTime)->QuadPart;
if ( success ) {
itime.QuadPart -= ((ULARGE_INTEGER *)&base_ft)->QuadPart;
} else {
// Hard coded number of 100-nanosecond units from 1/1/1601 to 1/1/1970
itime.QuadPart -= 116444736000000000LL;
}
itime.QuadPart /= second;
details->date = itime.QuadPart;
}
} else {
details->damaged = true;
}
// populate the game details struct
directory = directory.StripFilename();
details->slotName = directory.c_str() + saveFolder.Length() + 1; // Strip off the prefix too
// JDC: I hit this all the time assert( fileSystem->IsFolder( directory.c_str(), "fs_savePath" ) == FOLDER_YES );
}
fileSystem->FreeFileList( files );
} else {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
ret = -3;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::EnumerateFiles
========================
*/
int idSaveGameThread::EnumerateFiles() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr folder = "savegame";
folder.AppendPath( callback->directory );
callback->files.Clear();
int ret = ERROR_SUCCESS;
if ( fileSystem->IsFolder( folder, "fs_savePath" ) == FOLDER_YES ) {
// get listing of all the files, but filter out below
idFileList * files = fileSystem->ListFilesTree( folder, "*.*" );
// look for the instance pattern
for ( int i = 0; i < files->GetNumFiles() && ret == 0 && !callback->cancelled; i++ ) {
idStr fullFilename = files->GetFile( i );
idStr filename = fullFilename;
filename.StripPath();
if ( filename.IcmpPrefix( callback->pattern ) != 0 ) {
continue;
}
if ( !callback->postPattern.IsEmpty() && filename.Right( callback->postPattern.Length() ).IcmpPrefix( callback->postPattern ) != 0 ) {
continue;
}
// Read the DETAIL file for the enumerated data
if ( callback->mode & SAVEGAME_MBF_READ_DETAILS ) {
idSaveGameDetails & details = callback->description;
idFile * uncompressed = fileSystem->OpenFileRead( fullFilename.c_str() );
if ( uncompressed == NULL ) {
details.damaged = true;
} else {
if ( !SavegameReadDetailsFromFile( uncompressed, details ) ) {
ret = -1;
}
delete uncompressed;
}
// populate the game details struct
details.slotName = callback->directory;
assert( fileSystem->IsFolder( details.slotName, "fs_savePath" ) == FOLDER_YES );
}
idFile_SaveGame * file = new (TAG_SAVEGAMES) idFile_SaveGame( filename, SAVEGAMEFILE_AUTO_DELETE );
callback->files.Append( file );
}
fileSystem->FreeFileList( files );
} else {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
ret = -3;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::DeleteFiles
========================
*/
int idSaveGameThread::DeleteFiles() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr folder = "savegame";
folder.AppendPath( callback->directory );
// delete the explicitly requested files first
for ( int j = 0; j < callback->files.Num() && !callback->cancelled; ++j ) {
idFile_SaveGame * file = callback->files[j];
idStr fullpath = folder;
fullpath.AppendPath( file->GetName() );
fileSystem->RemoveFile( fullpath );
}
int ret = ERROR_SUCCESS;
if ( fileSystem->IsFolder( folder, "fs_savePath" ) == FOLDER_YES ) {
// get listing of all the files, but filter out below
idFileList * files = fileSystem->ListFilesTree( folder, "*.*" );
// look for the instance pattern
for ( int i = 0; i < files->GetNumFiles() && !callback->cancelled; i++ ) {
idStr filename = files->GetFile( i );
filename.StripPath();
// If there are post/pre patterns to match, make sure we adhere to the patterns
if ( callback->pattern.IsEmpty() || ( filename.IcmpPrefix( callback->pattern ) != 0 ) ) {
continue;
}
if ( callback->postPattern.IsEmpty() || ( filename.Right( callback->postPattern.Length() ).IcmpPrefix( callback->postPattern ) != 0 ) ) {
continue;
}
fileSystem->RemoveFile( files->GetFile( i ) );
}
fileSystem->FreeFileList( files );
} else {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
ret = -3;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::DeleteAll
This deletes all savegame directories
========================
*/
int idSaveGameThread::DeleteAll() {
idSaveLoadParms * callback = data.saveLoadParms;
idStr saveFolder = "savegame";
int ret = ERROR_SUCCESS;
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFilesTree( saveFolder, "/|*" );
// remove directories after files
for ( int i = 0; i < files->GetNumFiles() && !callback->cancelled; i++ ) {
// contained files should always be first
if ( fileSystem->IsFolder( files->GetFile( i ), "fs_savePath" ) == FOLDER_YES ) {
fileSystem->RemoveDir( files->GetFile( i ) );
} else {
fileSystem->RemoveFile( files->GetFile( i ) );
}
}
fileSystem->FreeFileList( files );
} else {
callback->errorCode = SAVEGAME_E_FOLDER_NOT_FOUND;
ret = -3;
}
if ( data.saveLoadParms->cancelled ) {
data.saveLoadParms->errorCode = SAVEGAME_E_CANCELLED;
}
return ret;
}
/*
========================
idSaveGameThread::Run
========================
*/
int idSaveGameThread::Run() {
int ret = ERROR_SUCCESS;
try {
idLocalUserWin * user = GetLocalUserFromSaveParms( data );
if ( user != NULL && !user->IsStorageDeviceAvailable() ) {
data.saveLoadParms->errorCode = SAVEGAME_E_UNABLE_TO_SELECT_STORAGE_DEVICE;
}
if ( savegame_winInduceDelay.GetInteger() > 0 ) {
Sys_Sleep( savegame_winInduceDelay.GetInteger() );
}
if ( data.saveLoadParms->mode & SAVEGAME_MBF_SAVE ) {
ret = Save();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_LOAD ) {
ret = Load();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_ENUMERATE ) {
ret = Enumerate();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_DELETE_FOLDER ) {
ret = Delete();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_DELETE_ALL_FOLDERS ) {
ret = DeleteAll();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_DELETE_FILES ) {
ret = DeleteFiles();
} else if ( data.saveLoadParms->mode & SAVEGAME_MBF_ENUMERATE_FILES ) {
ret = EnumerateFiles();
}
// if something failed and no one set an error code, do it now.
if ( ret != 0 && data.saveLoadParms->errorCode == SAVEGAME_E_NONE ) {
data.saveLoadParms->errorCode = SAVEGAME_E_UNKNOWN;
}
} catch ( ... ) {
// if anything horrible happens, leave it up to the savegame processors to handle in PostProcess().
data.saveLoadParms->errorCode = SAVEGAME_E_UNKNOWN;
}
// Make sure to cancel any save game file pipelines.
if ( data.saveLoadParms->errorCode != SAVEGAME_E_NONE ) {
data.saveLoadParms->CancelSaveGameFilePipelines();
}
// Override error if cvar set
if ( savegame_error.GetInteger() != 0 ) {
data.saveLoadParms->errorCode = (saveGameError_t)savegame_error.GetInteger();
}
// Tell the waiting caller that we are done
data.saveLoadParms->callbackSignal.Raise();
return ret;
}
/*
========================
Sys_SaveGameCheck
========================
*/
void Sys_SaveGameCheck( bool & exists, bool & autosaveExists ) {
exists = false;
autosaveExists = false;
const idStr autosaveFolderStr = AddSaveFolderPrefix( SAVEGAME_AUTOSAVE_FOLDER, idSaveGameManager::PACKAGE_GAME );
const char * autosaveFolder = autosaveFolderStr.c_str();
const char * saveFolder = "savegame";
if ( fileSystem->IsFolder( saveFolder, "fs_savePath" ) == FOLDER_YES ) {
idFileList * files = fileSystem->ListFiles( saveFolder, "/" );
const idStrList & fileList = files->GetList();
idLib::PrintfIf( saveGame_verbose.GetBool(), "found %d savegames\n", fileList.Num() );
for ( int i = 0; i < fileList.Num(); i++ ) {
const char * directory = va( "%s/%s", saveFolder, fileList[i].c_str() );
if ( fileSystem->IsFolder( directory, "fs_savePath" ) == FOLDER_YES ) {
exists = true;
idLib::PrintfIf( saveGame_verbose.GetBool(), "found savegame: %s\n", fileList[i].c_str() );
if ( idStr::Icmp( fileList[i].c_str(), autosaveFolder ) == 0 ) {
autosaveExists = true;
break;
}
}
}
fileSystem->FreeFileList( files );
}
}

View File

@@ -0,0 +1,668 @@
/*
================================================================================================
CONFIDENTIAL AND PROPRIETARY INFORMATION/NOT FOR DISCLOSURE WITHOUT WRITTEN PERMISSION
Copyright 2010 id Software LLC, a ZeniMax Media company. All Rights Reserved.
================================================================================================
*/
/*
================================================================================================
Contains the windows implementation of the network session
================================================================================================
*/
#pragma hdrstop
#include "../../idlib/precompiled.h"
#include "../../framework/Common_local.h"
#include "../sys_session_local.h"
#include "../sys_stats.h"
#include "../sys_savegame.h"
#include "../sys_lobby_backend_direct.h"
#include "../sys_voicechat.h"
#include "win_achievements.h"
#include "win_local.h"
/*
========================
Global variables
========================
*/
extern idCVar net_port;
/*
========================
idSessionLocalWin::idSessionLocalWin
========================
*/
class idSessionLocalWin : public idSessionLocal {
friend class idLobbyToSessionCBLocal;
public:
idSessionLocalWin();
virtual ~idSessionLocalWin();
// idSessionLocal interface
virtual void Initialize();
virtual void Shutdown();
virtual void InitializeSoundRelatedSystems();
virtual void ShutdownSoundRelatedSystems();
virtual void PlatformPump();
virtual void InviteFriends();
virtual void InviteParty();
virtual void ShowPartySessions();
virtual void ShowSystemMarketplaceUI() const;
virtual void ListServers( const idCallback & callback );
virtual void CancelListServers();
virtual int NumServers() const;
virtual const serverInfo_t * ServerInfo( int i ) const;
virtual void ConnectToServer( int i );
virtual void ShowServerGamerCardUI( int i );
virtual void ShowLobbyUserGamerCardUI( lobbyUserID_t lobbyUserID );
virtual void ShowOnlineSignin() {}
virtual void UpdateRichPresence() {}
virtual void CheckVoicePrivileges() {}
virtual bool ProcessInputEvent( const sysEvent_t * ev );
// System UI
virtual bool IsSystemUIShowing() const;
virtual void SetSystemUIShowing( bool show );
// Invites
virtual void HandleBootableInvite( int64 lobbyId = 0 );
virtual void ClearBootableInvite();
virtual void ClearPendingInvite();
virtual bool HasPendingBootableInvite();
virtual void SetDiscSwapMPInvite( void * parm );
virtual void * GetDiscSwapMPInviteParms();
virtual void EnumerateDownloadableContent();
virtual void HandleServerQueryRequest( lobbyAddress_t & remoteAddr, idBitMsg & msg, int msgType );
virtual void HandleServerQueryAck( lobbyAddress_t & remoteAddr, idBitMsg & msg );
// Leaderboards
virtual void LeaderboardUpload( lobbyUserID_t lobbyUserID, const leaderboardDefinition_t * leaderboard, const column_t * stats, const idFile_Memory * attachment = NULL );
virtual void LeaderboardDownload( int sessionUserIndex, const leaderboardDefinition_t * leaderboard, int startingRank, int numRows, const idLeaderboardCallback & callback );
virtual void LeaderboardDownloadAttachment( int sessionUserIndex, const leaderboardDefinition_t * leaderboard, int64 attachmentID );
// Scoring (currently just for TrueSkill)
virtual void SetLobbyUserRelativeScore( lobbyUserID_t lobbyUserID, int relativeScore, int team ) {}
virtual void LeaderboardFlush();
virtual idNetSessionPort & GetPort( bool dedicated = false );
virtual idLobbyBackend * CreateLobbyBackend( const idMatchParameters & p, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType );
virtual idLobbyBackend * FindLobbyBackend( const idMatchParameters & p, int numPartyUsers, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType );
virtual idLobbyBackend * JoinFromConnectInfo( const lobbyConnectInfo_t & connectInfo , idLobbyBackend::lobbyBackendType_t lobbyType );
virtual void DestroyLobbyBackend( idLobbyBackend * lobbyBackend );
virtual void PumpLobbies();
virtual void JoinAfterSwap( void * joinID );
virtual bool GetLobbyAddressFromNetAddress( const netadr_t & netAddr, lobbyAddress_t & outAddr ) const;
virtual bool GetNetAddressFromLobbyAddress( const lobbyAddress_t & lobbyAddress, netadr_t & outNetAddr ) const;
public:
void Connect_f( const idCmdArgs &args );
private:
void EnsurePort();
idLobbyBackend * CreateLobbyInternal( idLobbyBackend::lobbyBackendType_t lobbyType );
idArray< idLobbyBackend *, 3 > lobbyBackends;
idNetSessionPort port;
bool canJoinLocalHost;
idLobbyToSessionCBLocal * lobbyToSessionCB;
};
idSessionLocalWin sessionLocalWin;
idSession * session = &sessionLocalWin;
/*
========================
idLobbyToSessionCBLocal
========================
*/
class idLobbyToSessionCBLocal : public idLobbyToSessionCB {
public:
idLobbyToSessionCBLocal( idSessionLocalWin * sessionLocalWin_ ) : sessionLocalWin( sessionLocalWin_ ) { }
virtual bool CanJoinLocalHost() const { sessionLocalWin->EnsurePort(); return sessionLocalWin->canJoinLocalHost; }
virtual class idLobbyBackend * GetLobbyBackend( idLobbyBackend::lobbyBackendType_t type ) const { return sessionLocalWin->lobbyBackends[ type ]; }
private:
idSessionLocalWin * sessionLocalWin;
};
idLobbyToSessionCBLocal lobbyToSessionCBLocal( &sessionLocalWin );
idLobbyToSessionCB * lobbyToSessionCB = &lobbyToSessionCBLocal;
class idVoiceChatMgrWin : public idVoiceChatMgr {
public:
virtual bool GetLocalChatDataInternal( int talkerIndex, byte * data, int & dataSize ) { return false; }
virtual void SubmitIncomingChatDataInternal( int talkerIndex, const byte * data, int dataSize ) { }
virtual bool TalkerHasData( int talkerIndex ) { return false; }
virtual bool RegisterTalkerInternal( int index ) { return true; }
virtual void UnregisterTalkerInternal( int index ) { }
};
/*
========================
idSessionLocalWin::idSessionLocalWin
========================
*/
idSessionLocalWin::idSessionLocalWin() {
signInManager = new (TAG_SYSTEM) idSignInManagerWin;
saveGameManager = new (TAG_SAVEGAMES) idSaveGameManager();
voiceChat = new (TAG_SYSTEM) idVoiceChatMgrWin();
lobbyToSessionCB = new (TAG_SYSTEM) idLobbyToSessionCBLocal( this );
canJoinLocalHost = false;
lobbyBackends.Zero();
}
/*
========================
idSessionLocalWin::idSessionLocalWin
========================
*/
idSessionLocalWin::~idSessionLocalWin() {
delete voiceChat;
delete lobbyToSessionCB;
}
/*
========================
idSessionLocalWin::Initialize
========================
*/
void idSessionLocalWin::Initialize() {
idSessionLocal::Initialize();
// The shipping path doesn't load title storage
// Instead, we inject values through code which is protected through steam DRM
titleStorageVars.Set( "MAX_PLAYERS_ALLOWED", "8" );
titleStorageLoaded = true;
// First-time check for downloadable content once game is launched
EnumerateDownloadableContent();
GetPartyLobby().Initialize( idLobby::TYPE_PARTY, sessionCallbacks );
GetGameLobby().Initialize( idLobby::TYPE_GAME, sessionCallbacks );
GetGameStateLobby().Initialize( idLobby::TYPE_GAME_STATE, sessionCallbacks );
achievementSystem = new (TAG_SYSTEM) idAchievementSystemWin();
achievementSystem->Init();
}
/*
========================
idSessionLocalWin::Shutdown
========================
*/
void idSessionLocalWin::Shutdown() {
NET_VERBOSE_PRINT( "NET: Shutdown\n" );
idSessionLocal::Shutdown();
MoveToMainMenu();
// Wait until we fully shutdown
while ( localState != STATE_IDLE && localState != STATE_PRESS_START ) {
Pump();
}
if ( achievementSystem != NULL ) {
achievementSystem->Shutdown();
delete achievementSystem;
achievementSystem = NULL;
}
}
/*
========================
idSessionLocalWin::InitializeSoundRelatedSystems
========================
*/
void idSessionLocalWin::InitializeSoundRelatedSystems() {
if ( voiceChat != NULL ) {
voiceChat->Init( NULL );
}
}
/*
========================
idSessionLocalWin::ShutdownSoundRelatedSystems
========================
*/
void idSessionLocalWin::ShutdownSoundRelatedSystems() {
if ( voiceChat != NULL ) {
voiceChat->Shutdown();
}
}
/*
========================
idSessionLocalWin::PlatformPump
========================
*/
void idSessionLocalWin::PlatformPump() {
}
/*
========================
idSessionLocalWin::InviteFriends
========================
*/
void idSessionLocalWin::InviteFriends() {
}
/*
========================
idSessionLocalWin::InviteParty
========================
*/
void idSessionLocalWin::InviteParty() {
}
/*
========================
idSessionLocalWin::ShowPartySessions
========================
*/
void idSessionLocalWin::ShowPartySessions() {
}
/*
========================
idSessionLocalWin::ShowSystemMarketplaceUI
========================
*/
void idSessionLocalWin::ShowSystemMarketplaceUI() const {
}
/*
========================
idSessionLocalWin::ListServers
========================
*/
void idSessionLocalWin::ListServers( const idCallback & callback ) {
ListServersCommon();
}
/*
========================
idSessionLocalWin::CancelListServers
========================
*/
void idSessionLocalWin::CancelListServers() {
}
/*
========================
idSessionLocalWin::NumServers
========================
*/
int idSessionLocalWin::NumServers() const {
return 0;
}
/*
========================
idSessionLocalWin::ServerInfo
========================
*/
const serverInfo_t * idSessionLocalWin::ServerInfo( int i ) const {
return NULL;
}
/*
========================
idSessionLocalWin::ConnectToServer
========================
*/
void idSessionLocalWin::ConnectToServer( int i ) {
}
/*
========================
idSessionLocalWin::Connect_f
========================
*/
void idSessionLocalWin::Connect_f( const idCmdArgs &args ) {
if ( args.Argc() < 2 ) {
idLib::Printf( "Usage: Connect to IP. Use with net_port. \n");
return;
}
Cancel();
if ( signInManager->GetMasterLocalUser() == NULL ) {
signInManager->RegisterLocalUser( 0 );
}
lobbyConnectInfo_t connectInfo;
Sys_StringToNetAdr( args.Argv(1), &connectInfo.netAddr, true );
connectInfo.netAddr.port = net_port.GetInteger();
ConnectAndMoveToLobby( GetPartyLobby(), connectInfo, false );
}
/*
========================
void Connect_f
========================
*/
CONSOLE_COMMAND( connect, "Connect to the specified IP", NULL ) {
sessionLocalWin.Connect_f( args );
}
/*
========================
idSessionLocalWin::ShowServerGamerCardUI
========================
*/
void idSessionLocalWin::ShowServerGamerCardUI( int i ) {
}
/*
========================
idSessionLocalWin::ShowLobbyUserGamerCardUI(
========================
*/
void idSessionLocalWin::ShowLobbyUserGamerCardUI( lobbyUserID_t lobbyUserID ) {
}
/*
========================
idSessionLocalWin::ProcessInputEvent
========================
*/
bool idSessionLocalWin::ProcessInputEvent( const sysEvent_t * ev ) {
if ( GetSignInManager().ProcessInputEvent( ev ) ) {
return true;
}
return false;
}
/*
========================
idSessionLocalWin::IsSystemUIShowing
========================
*/
bool idSessionLocalWin::IsSystemUIShowing() const {
return !win32.activeApp || isSysUIShowing; // If the user alt+tabs away, treat it the same as bringing up the steam overlay
}
/*
========================
idSessionLocalWin::SetSystemUIShowing
========================
*/
void idSessionLocalWin::SetSystemUIShowing( bool show ) {
isSysUIShowing = show;
}
/*
========================
idSessionLocalWin::HandleServerQueryRequest
========================
*/
void idSessionLocalWin::HandleServerQueryRequest( lobbyAddress_t & remoteAddr, idBitMsg & msg, int msgType ) {
NET_VERBOSE_PRINT( "HandleServerQueryRequest from %s\n", remoteAddr.ToString() );
}
/*
========================
idSessionLocalWin::HandleServerQueryAck
========================
*/
void idSessionLocalWin::HandleServerQueryAck( lobbyAddress_t & remoteAddr, idBitMsg & msg ) {
NET_VERBOSE_PRINT( "HandleServerQueryAck from %s\n", remoteAddr.ToString() );
}
/*
========================
idSessionLocalWin::ClearBootableInvite
========================
*/
void idSessionLocalWin::ClearBootableInvite() {
}
/*
========================
idSessionLocalWin::ClearPendingInvite
========================
*/
void idSessionLocalWin::ClearPendingInvite() {
}
/*
========================
idSessionLocalWin::HandleBootableInvite
========================
*/
void idSessionLocalWin::HandleBootableInvite( int64 lobbyId ) {
}
/*
========================
idSessionLocalWin::HasPendingBootableInvite
========================
*/
bool idSessionLocalWin::HasPendingBootableInvite() {
return false;
}
/*
========================
idSessionLocal::SetDiscSwapMPInvite
========================
*/
void idSessionLocalWin::SetDiscSwapMPInvite( void * parm ) {
}
/*
========================
idSessionLocal::GetDiscSwapMPInviteParms
========================
*/
void * idSessionLocalWin::GetDiscSwapMPInviteParms() {
return NULL;
}
/*
========================
idSessionLocalWin::EnumerateDownloadableContent
========================
*/
void idSessionLocalWin::EnumerateDownloadableContent() {
}
/*
========================
idSessionLocalWin::LeaderboardUpload
========================
*/
void idSessionLocalWin::LeaderboardUpload( lobbyUserID_t lobbyUserID, const leaderboardDefinition_t * leaderboard, const column_t * stats, const idFile_Memory * attachment ) {
}
/*
========================
idSessionLocalWin::LeaderboardFlush
========================
*/
void idSessionLocalWin::LeaderboardFlush() {
}
/*
========================
idSessionLocalWin::LeaderboardDownload
========================
*/
void idSessionLocalWin::LeaderboardDownload( int sessionUserIndex, const leaderboardDefinition_t * leaderboard, int startingRank, int numRows, const idLeaderboardCallback & callback ) {
}
/*
========================
idSessionLocalWin::LeaderboardDownloadAttachment
========================
*/
void idSessionLocalWin::LeaderboardDownloadAttachment( int sessionUserIndex, const leaderboardDefinition_t * leaderboard, int64 attachmentID ) {
}
/*
========================
idSessionLocalWin::EnsurePort
========================
*/
void idSessionLocalWin::EnsurePort() {
// Init the port using reqular windows sockets
if ( port.IsOpen() ) {
return; // Already initialized
}
if ( port.InitPort( net_port.GetInteger(), false ) ) {
canJoinLocalHost = false;
} else {
// Assume this is another instantiation on the same machine, and just init using any available port
port.InitPort( PORT_ANY, false );
canJoinLocalHost = true;
}
}
/*
========================
idSessionLocalWin::GetPort
========================
*/
idNetSessionPort & idSessionLocalWin::GetPort( bool dedicated ) {
EnsurePort();
return port;
}
/*
========================
idSessionLocalWin::CreateLobbyBackend
========================
*/
idLobbyBackend * idSessionLocalWin::CreateLobbyBackend( const idMatchParameters & p, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) {
idLobbyBackend * lobbyBackend = CreateLobbyInternal( lobbyType );
lobbyBackend->StartHosting( p, skillLevel, lobbyType );
return lobbyBackend;
}
/*
========================
idSessionLocalWin::FindLobbyBackend
========================
*/
idLobbyBackend * idSessionLocalWin::FindLobbyBackend( const idMatchParameters & p, int numPartyUsers, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) {
idLobbyBackend * lobbyBackend = CreateLobbyInternal( lobbyType );
lobbyBackend->StartFinding( p, numPartyUsers, skillLevel );
return lobbyBackend;
}
/*
========================
idSessionLocalWin::JoinFromConnectInfo
========================
*/
idLobbyBackend * idSessionLocalWin::JoinFromConnectInfo( const lobbyConnectInfo_t & connectInfo, idLobbyBackend::lobbyBackendType_t lobbyType ) {
idLobbyBackend * lobbyBackend = CreateLobbyInternal( lobbyType );
lobbyBackend->JoinFromConnectInfo( connectInfo );
return lobbyBackend;
}
/*
========================
idSessionLocalWin::DestroyLobbyBackend
========================
*/
void idSessionLocalWin::DestroyLobbyBackend( idLobbyBackend * lobbyBackend ) {
assert( lobbyBackend != NULL );
assert( lobbyBackends[lobbyBackend->GetLobbyType()] == lobbyBackend );
lobbyBackends[lobbyBackend->GetLobbyType()] = NULL;
lobbyBackend->Shutdown();
delete lobbyBackend;
}
/*
========================
idSessionLocalWin::PumpLobbies
========================
*/
void idSessionLocalWin::PumpLobbies() {
assert( lobbyBackends[idLobbyBackend::TYPE_PARTY] == NULL || lobbyBackends[idLobbyBackend::TYPE_PARTY]->GetLobbyType() == idLobbyBackend::TYPE_PARTY );
assert( lobbyBackends[idLobbyBackend::TYPE_GAME] == NULL || lobbyBackends[idLobbyBackend::TYPE_GAME]->GetLobbyType() == idLobbyBackend::TYPE_GAME );
assert( lobbyBackends[idLobbyBackend::TYPE_GAME_STATE] == NULL || lobbyBackends[idLobbyBackend::TYPE_GAME_STATE]->GetLobbyType() == idLobbyBackend::TYPE_GAME_STATE );
// Pump lobbyBackends
for ( int i = 0; i < lobbyBackends.Num(); i++ ) {
if ( lobbyBackends[i] != NULL ) {
lobbyBackends[i]->Pump();
}
}
}
/*
========================
idSessionLocalWin::CreateLobbyInternal
========================
*/
idLobbyBackend * idSessionLocalWin::CreateLobbyInternal( idLobbyBackend::lobbyBackendType_t lobbyType ) {
EnsurePort();
idLobbyBackend * lobbyBackend = new (TAG_NETWORKING) idLobbyBackendDirect();
lobbyBackend->SetLobbyType( lobbyType );
assert( lobbyBackends[lobbyType] == NULL );
lobbyBackends[lobbyType] = lobbyBackend;
return lobbyBackend;
}
/*
========================
idSessionLocalWin::JoinAfterSwap
========================
*/
void idSessionLocalWin::JoinAfterSwap( void * joinID ) {
}
/*
========================
idSessionLocalWin::GetLobbyAddressFromNetAddress
========================
*/
bool idSessionLocalWin::GetLobbyAddressFromNetAddress( const netadr_t & netAddr, lobbyAddress_t & outAddr ) const {
return false;
}
/*
========================
idSessionLocalWin::GetNetAddressFromLobbyAddress
========================
*/
bool idSessionLocalWin::GetNetAddressFromLobbyAddress( const lobbyAddress_t & lobbyAddress, netadr_t & outNetAddr ) const {
return false;
}

View File

@@ -0,0 +1,800 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "win_local.h"
#include <lmerr.h>
#include <lmcons.h>
#include <lmwksta.h>
#include <errno.h>
#include <fcntl.h>
#include <direct.h>
#include <io.h>
#include <conio.h>
#undef StrCmpN
#undef StrCmpNI
#undef StrCmpI
#include <atlbase.h>
#include <comdef.h>
#include <comutil.h>
#include <Wbemidl.h>
#pragma comment (lib, "wbemuuid.lib")
#pragma warning(disable:4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
/*
================
Sys_Milliseconds
================
*/
int Sys_Milliseconds() {
static DWORD sys_timeBase = timeGetTime();
return timeGetTime() - sys_timeBase;
}
/*
========================
Sys_Microseconds
========================
*/
uint64 Sys_Microseconds() {
static uint64 ticksPerMicrosecondTimes1024 = 0;
if ( ticksPerMicrosecondTimes1024 == 0 ) {
ticksPerMicrosecondTimes1024 = ( (uint64)Sys_ClockTicksPerSecond() << 10 ) / 1000000;
assert( ticksPerMicrosecondTimes1024 > 0 );
}
return ((uint64)( (int64)Sys_GetClockTicks() << 10 )) / ticksPerMicrosecondTimes1024;
}
/*
================
Sys_GetSystemRam
returns amount of physical memory in MB
================
*/
int Sys_GetSystemRam() {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof ( statex );
GlobalMemoryStatusEx (&statex);
int physRam = statex.ullTotalPhys / ( 1024 * 1024 );
// HACK: For some reason, ullTotalPhys is sometimes off by a meg or two, so we round up to the nearest 16 megs
physRam = ( physRam + 8 ) & ~15;
return physRam;
}
/*
================
Sys_GetDriveFreeSpace
returns in megabytes
================
*/
int Sys_GetDriveFreeSpace( const char *path ) {
DWORDLONG lpFreeBytesAvailable;
DWORDLONG lpTotalNumberOfBytes;
DWORDLONG lpTotalNumberOfFreeBytes;
int ret = 26;
//FIXME: see why this is failing on some machines
if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
ret = ( double )( lpFreeBytesAvailable ) / ( 1024.0 * 1024.0 );
}
return ret;
}
/*
========================
Sys_GetDriveFreeSpaceInBytes
========================
*/
int64 Sys_GetDriveFreeSpaceInBytes( const char * path ) {
DWORDLONG lpFreeBytesAvailable;
DWORDLONG lpTotalNumberOfBytes;
DWORDLONG lpTotalNumberOfFreeBytes;
int64 ret = 1;
//FIXME: see why this is failing on some machines
if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
ret = lpFreeBytesAvailable;
}
return ret;
}
/*
================
Sys_GetVideoRam
returns in megabytes
================
*/
int Sys_GetVideoRam() {
unsigned int retSize = 64;
CComPtr<IWbemLocator> spLoc = NULL;
HRESULT hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, ( LPVOID * ) &spLoc );
if ( hr != S_OK || spLoc == NULL ) {
return retSize;
}
CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
CComPtr<IWbemServices> spServices;
// Connect to CIM
hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
if ( hr != WBEM_S_NO_ERROR ) {
return retSize;
}
// Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.
hr = CoSetProxyBlanket( spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
if ( hr != S_OK ) {
return retSize;
}
// Get the vid controller
CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst );
if ( hr != WBEM_S_NO_ERROR || spEnumInst == NULL ) {
return retSize;
}
ULONG uNumOfInstances = 0;
CComPtr<IWbemClassObject> spInstance = NULL;
hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
if ( hr == S_OK && spInstance ) {
// Get properties from the object
CComVariant varSize;
hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
if ( hr == S_OK ) {
retSize = varSize.intVal / ( 1024 * 1024 );
if ( retSize == 0 ) {
retSize = 64;
}
}
}
return retSize;
}
/*
================
Sys_GetCurrentMemoryStatus
returns OS mem info
all values are in kB except the memoryload
================
*/
void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
MEMORYSTATUSEX statex = {};
unsigned __int64 work;
statex.dwLength = sizeof( statex );
GlobalMemoryStatusEx( &statex );
memset( &stats, 0, sizeof( stats ) );
stats.memoryLoad = statex.dwMemoryLoad;
work = statex.ullTotalPhys >> 20;
stats.totalPhysical = *(int*)&work;
work = statex.ullAvailPhys >> 20;
stats.availPhysical = *(int*)&work;
work = statex.ullAvailPageFile >> 20;
stats.availPageFile = *(int*)&work;
work = statex.ullTotalPageFile >> 20;
stats.totalPageFile = *(int*)&work;
work = statex.ullTotalVirtual >> 20;
stats.totalVirtual = *(int*)&work;
work = statex.ullAvailVirtual >> 20;
stats.availVirtual = *(int*)&work;
work = statex.ullAvailExtendedVirtual >> 20;
stats.availExtendedVirtual = *(int*)&work;
}
/*
================
Sys_LockMemory
================
*/
bool Sys_LockMemory( void *ptr, int bytes ) {
return ( VirtualLock( ptr, (SIZE_T)bytes ) != FALSE );
}
/*
================
Sys_UnlockMemory
================
*/
bool Sys_UnlockMemory( void *ptr, int bytes ) {
return ( VirtualUnlock( ptr, (SIZE_T)bytes ) != FALSE );
}
/*
================
Sys_SetPhysicalWorkMemory
================
*/
void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
::SetProcessWorkingSetSize( GetCurrentProcess(), minBytes, maxBytes );
}
/*
================
Sys_GetCurrentUser
================
*/
char *Sys_GetCurrentUser() {
static char s_userName[1024];
unsigned long size = sizeof( s_userName );
if ( !GetUserName( s_userName, &size ) ) {
strcpy( s_userName, "player" );
}
if ( !s_userName[0] ) {
strcpy( s_userName, "player" );
}
return s_userName;
}
/*
===============================================================================
Call stack
===============================================================================
*/
#define PROLOGUE_SIGNATURE 0x00EC8B55
#include <dbghelp.h>
const int UNDECORATE_FLAGS = UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS |
UNDNAME_NO_FUNCTION_RETURNS |
UNDNAME_NO_ALLOCATION_MODEL |
UNDNAME_NO_ALLOCATION_LANGUAGE |
UNDNAME_NO_MEMBER_TYPE;
#if defined(_DEBUG) && 1
typedef struct symbol_s {
int address;
char * name;
struct symbol_s * next;
} symbol_t;
typedef struct module_s {
int address;
char * name;
symbol_t * symbols;
struct module_s * next;
} module_t;
module_t *modules;
/*
==================
SkipRestOfLine
==================
*/
void SkipRestOfLine( const char **ptr ) {
while( (**ptr) != '\0' && (**ptr) != '\n' && (**ptr) != '\r' ) {
(*ptr)++;
}
while( (**ptr) == '\n' || (**ptr) == '\r' ) {
(*ptr)++;
}
}
/*
==================
SkipWhiteSpace
==================
*/
void SkipWhiteSpace( const char **ptr ) {
while( (**ptr) == ' ' ) {
(*ptr)++;
}
}
/*
==================
ParseHexNumber
==================
*/
int ParseHexNumber( const char **ptr ) {
int n = 0;
while( (**ptr) >= '0' && (**ptr) <= '9' || (**ptr) >= 'a' && (**ptr) <= 'f' ) {
n <<= 4;
if ( **ptr >= '0' && **ptr <= '9' ) {
n |= ( (**ptr) - '0' );
} else {
n |= 10 + ( (**ptr) - 'a' );
}
(*ptr)++;
}
return n;
}
/*
==================
Sym_Init
==================
*/
void Sym_Init( long addr ) {
TCHAR moduleName[MAX_STRING_CHARS];
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
char *ext = moduleName + strlen( moduleName );
while( ext > moduleName && *ext != '.' ) {
ext--;
}
if ( ext == moduleName ) {
strcat( moduleName, ".map" );
} else {
strcpy( ext, ".map" );
}
module_t *module = (module_t *) malloc( sizeof( module_t ) );
module->name = (char *) malloc( strlen( moduleName ) + 1 );
strcpy( module->name, moduleName );
module->address = (int)mbi.AllocationBase;
module->symbols = NULL;
module->next = modules;
modules = module;
FILE * fp = fopen( moduleName, "rb" );
if ( fp == NULL ) {
return;
}
int pos = ftell( fp );
fseek( fp, 0, SEEK_END );
int length = ftell( fp );
fseek( fp, pos, SEEK_SET );
char *text = (char *) malloc( length+1 );
fread( text, 1, length, fp );
text[length] = '\0';
fclose( fp );
const char *ptr = text;
// skip up to " Address" on a new line
while( *ptr != '\0' ) {
SkipWhiteSpace( &ptr );
if ( idStr::Cmpn( ptr, "Address", 7 ) == 0 ) {
SkipRestOfLine( &ptr );
break;
}
SkipRestOfLine( &ptr );
}
int symbolAddress;
int symbolLength;
char symbolName[MAX_STRING_CHARS];
symbol_t *symbol;
// parse symbols
while( *ptr != '\0' ) {
SkipWhiteSpace( &ptr );
ParseHexNumber( &ptr );
if ( *ptr == ':' ) {
ptr++;
} else {
break;
}
ParseHexNumber( &ptr );
SkipWhiteSpace( &ptr );
// parse symbol name
symbolLength = 0;
while( *ptr != '\0' && *ptr != ' ' ) {
symbolName[symbolLength++] = *ptr++;
if ( symbolLength >= sizeof( symbolName ) - 1 ) {
break;
}
}
symbolName[symbolLength++] = '\0';
SkipWhiteSpace( &ptr );
// parse symbol address
symbolAddress = ParseHexNumber( &ptr );
SkipRestOfLine( &ptr );
symbol = (symbol_t *) malloc( sizeof( symbol_t ) );
symbol->name = (char *) malloc( symbolLength );
strcpy( symbol->name, symbolName );
symbol->address = symbolAddress;
symbol->next = module->symbols;
module->symbols = symbol;
}
free( text );
}
/*
==================
Sym_Shutdown
==================
*/
void Sym_Shutdown() {
module_t *m;
symbol_t *s;
for ( m = modules; m != NULL; m = modules ) {
modules = m->next;
for ( s = m->symbols; s != NULL; s = m->symbols ) {
m->symbols = s->next;
free( s->name );
free( s );
}
free( m->name );
free( m );
}
modules = NULL;
}
/*
==================
Sym_GetFuncInfo
==================
*/
void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
MEMORY_BASIC_INFORMATION mbi;
module_t *m;
symbol_t *s;
VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
for ( m = modules; m != NULL; m = m->next ) {
if ( m->address == (int) mbi.AllocationBase ) {
break;
}
}
if ( !m ) {
Sym_Init( addr );
m = modules;
}
for ( s = m->symbols; s != NULL; s = s->next ) {
if ( s->address == addr ) {
char undName[MAX_STRING_CHARS];
if ( UnDecorateSymbolName( s->name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
funcName = undName;
} else {
funcName = s->name;
}
for ( int i = 0; i < funcName.Length(); i++ ) {
if ( funcName[i] == '(' ) {
funcName.CapLength( i );
break;
}
}
module = m->name;
return;
}
}
sprintf( funcName, "0x%08x", addr );
module = "";
}
#elif defined(_DEBUG)
DWORD lastAllocationBase = -1;
HANDLE processHandle;
idStr lastModule;
/*
==================
Sym_Init
==================
*/
void Sym_Init( long addr ) {
TCHAR moduleName[MAX_STRING_CHARS];
TCHAR modShortNameBuf[MAX_STRING_CHARS];
MEMORY_BASIC_INFORMATION mbi;
if ( lastAllocationBase != -1 ) {
Sym_Shutdown();
}
VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
_splitpath( moduleName, NULL, NULL, modShortNameBuf, NULL );
lastModule = modShortNameBuf;
processHandle = GetCurrentProcess();
if ( !SymInitialize( processHandle, NULL, FALSE ) ) {
return;
}
if ( !SymLoadModule( processHandle, NULL, moduleName, NULL, (DWORD)mbi.AllocationBase, 0 ) ) {
SymCleanup( processHandle );
return;
}
SymSetOptions( SymGetOptions() & ~SYMOPT_UNDNAME );
lastAllocationBase = (DWORD) mbi.AllocationBase;
}
/*
==================
Sym_Shutdown
==================
*/
void Sym_Shutdown() {
SymUnloadModule( GetCurrentProcess(), lastAllocationBase );
SymCleanup( GetCurrentProcess() );
lastAllocationBase = -1;
}
/*
==================
Sym_GetFuncInfo
==================
*/
void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
if ( (DWORD) mbi.AllocationBase != lastAllocationBase ) {
Sym_Init( addr );
}
BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + MAX_STRING_CHARS ];
PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)&symbolBuffer[0];
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
pSymbol->MaxNameLength = 1023;
pSymbol->Address = 0;
pSymbol->Flags = 0;
pSymbol->Size =0;
DWORD symDisplacement = 0;
if ( SymGetSymFromAddr( processHandle, addr, &symDisplacement, pSymbol ) ) {
// clean up name, throwing away decorations that don't affect uniqueness
char undName[MAX_STRING_CHARS];
if ( UnDecorateSymbolName( pSymbol->Name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
funcName = undName;
} else {
funcName = pSymbol->Name;
}
module = lastModule;
}
else {
LPVOID lpMsgBuf;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
LocalFree( lpMsgBuf );
// Couldn't retrieve symbol (no debug info?, can't load dbghelp.dll?)
sprintf( funcName, "0x%08x", addr );
module = "";
}
}
#else
/*
==================
Sym_Init
==================
*/
void Sym_Init( long addr ) {
}
/*
==================
Sym_Shutdown
==================
*/
void Sym_Shutdown() {
}
/*
==================
Sym_GetFuncInfo
==================
*/
void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
module = "";
sprintf( funcName, "0x%08x", addr );
}
#endif
/*
==================
GetFuncAddr
==================
*/
address_t GetFuncAddr( address_t midPtPtr ) {
long temp;
do {
temp = (long)(*(long*)midPtPtr);
if ( (temp&0x00FFFFFF) == PROLOGUE_SIGNATURE ) {
break;
}
midPtPtr--;
} while(true);
return midPtPtr;
}
/*
==================
GetCallerAddr
==================
*/
address_t GetCallerAddr( long _ebp ) {
long midPtPtr;
long res = 0;
__asm {
mov eax, _ebp
mov ecx, [eax] // check for end of stack frames list
test ecx, ecx // check for zero stack frame
jz label
mov eax, [eax+4] // get the ret address
test eax, eax // check for zero return address
jz label
mov midPtPtr, eax
}
res = GetFuncAddr( midPtPtr );
label:
return res;
}
/*
==================
Sys_GetCallStack
use /Oy option
==================
*/
void Sys_GetCallStack( address_t *callStack, const int callStackSize ) {
#if 1 //def _DEBUG
int i;
long m_ebp;
__asm {
mov eax, ebp
mov m_ebp, eax
}
// skip last two functions
m_ebp = *((long*)m_ebp);
m_ebp = *((long*)m_ebp);
// list functions
for ( i = 0; i < callStackSize; i++ ) {
callStack[i] = GetCallerAddr( m_ebp );
if ( callStack[i] == 0 ) {
break;
}
m_ebp = *((long*)m_ebp);
}
#else
int i = 0;
#endif
while( i < callStackSize ) {
callStack[i++] = 0;
}
}
/*
==================
Sys_GetCallStackStr
==================
*/
const char *Sys_GetCallStackStr( const address_t *callStack, const int callStackSize ) {
static char string[MAX_STRING_CHARS*2];
int index, i;
idStr module, funcName;
index = 0;
for ( i = callStackSize-1; i >= 0; i-- ) {
Sym_GetFuncInfo( callStack[i], module, funcName );
index += sprintf( string+index, " -> %s", funcName.c_str() );
}
return string;
}
/*
==================
Sys_GetCallStackCurStr
==================
*/
const char *Sys_GetCallStackCurStr( int depth ) {
address_t *callStack;
callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
Sys_GetCallStack( callStack, depth );
return Sys_GetCallStackStr( callStack, depth );
}
/*
==================
Sys_GetCallStackCurAddressStr
==================
*/
const char *Sys_GetCallStackCurAddressStr( int depth ) {
static char string[MAX_STRING_CHARS*2];
address_t *callStack;
int index, i;
callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
Sys_GetCallStack( callStack, depth );
index = 0;
for ( i = depth-1; i >= 0; i-- ) {
index += sprintf( string+index, " -> 0x%08x", callStack[i] );
}
return string;
}
/*
==================
Sys_ShutdownSymbols
==================
*/
void Sys_ShutdownSymbols() {
Sym_Shutdown();
}

View File

@@ -0,0 +1,146 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "../../framework/PlayerProfile.h"
#include "../sys_session_local.h"
#include "win_signin.h"
#ifdef _DEBUG
idCVar win_userPersistent( "win_userPersistent", "1", CVAR_BOOL, "debugging cvar for profile persistence status" );
idCVar win_userOnline( "win_userOnline", "1", CVAR_BOOL, "debugging cvar for profile online status" );
idCVar win_isInParty( "win_isInParty", "0", CVAR_BOOL, "debugging cvar for platform party status" );
idCVar win_partyCount( "win_partyCount", "0", CVAR_INTEGER, "debugginc var for platform party count" );
#endif
/*
========================
idSignInManagerWin::Shutdown
========================
*/
void idSignInManagerWin::Shutdown() {
}
/*
========================
idSignInManagerWin::Pump
========================
*/
void idSignInManagerWin::Pump() {
// If we have more users than we need, then set to the lower amount
// (don't remove the master user though)
if ( localUsers.Num() > 1 && localUsers.Num() > maxDesiredLocalUsers ) {
localUsers.SetNum( maxDesiredLocalUsers );
}
#ifndef ID_RETAIL
// If we don't have enough, then make sure we do
// NOTE - We always want at least one user on windows for now,
// and this master user will always use controller 0
while ( localUsers.Num() < minDesiredLocalUsers ) {
RegisterLocalUser( localUsers.Num() );
}
#endif
// See if we need to save settings on any of the profiles
for ( int i = 0; i < localUsers.Num(); i++ ) {
localUsers[i].Pump();
}
}
/*
========================
idSignInManagerWin::RemoveLocalUserByIndex
========================
*/
void idSignInManagerWin::RemoveLocalUserByIndex( int index ) {
session->OnLocalUserSignout( &localUsers[index] );
localUsers.RemoveIndex( index );
}
/*
========================
idSignInManagerWin::RegisterLocalUser
========================
*/
void idSignInManagerWin::RegisterLocalUser( int inputDevice ) {
if ( GetLocalUserByInputDevice( inputDevice ) != NULL ) {
return;
}
static char machineName[128];
DWORD len = 128;
::GetComputerName( machineName, &len );
const char * nameSource = machineName;
idStr name( nameSource );
int nameLength = name.Length();
if ( idStr::IsValidUTF8( nameSource, nameLength ) ) {
int nameIndex = 0;
int numChars = 0;
name.Empty();
while ( nameIndex < nameLength && numChars++ < idLocalUserWin::MAX_GAMERTAG_CHARS ) {
uint32 c = idStr::UTF8Char( nameSource, nameIndex );
name.AppendUTF8Char( c );
}
}
idLocalUserWin & localUser = *localUsers.Alloc();
localUser.Init( inputDevice, name.c_str(), localUsers.Num() );
localUser.SetLocalUserHandle( GetUniqueLocalUserHandle( localUser.GetGamerTag() ) );
session->OnLocalUserSignin( &localUser );
}
/*
========================
idSignInManagerWin::CreateNewUser
========================
*/
bool idSignInManagerWin::CreateNewUser( winUserState_t & state ) {
//idScopedGlobalHeap everythingHereGoesInTheGlobalHeap; // users obviously persist across maps
RemoveAllLocalUsers();
RegisterLocalUser( state.inputDevice );
if ( localUsers.Num() > 0 ) {
if ( !localUsers[0].VerifyUserState( state ) ) {
RemoveAllLocalUsers();
}
}
return true;
}
CONSOLE_COMMAND( testRemoveAllLocalUsers, "Forces removal of local users - mainly for PC testing", NULL ) {
session->GetSignInManager().RemoveAllLocalUsers();
}

View File

@@ -0,0 +1,62 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#ifndef __WIN_SIGNIN_H__
#define __WIN_SIGNIN_H__
#include "win_localuser.h"
/*
================================================
idSignInManagerWin
================================================
*/
class idSignInManagerWin : public idSignInManagerBase {
public:
idSignInManagerWin() : dlcVersionChecked( false ) {}
virtual ~idSignInManagerWin() {}
//==========================================================================================
// idSignInManagerBase interface
//==========================================================================================
virtual void Pump();
virtual void Shutdown();
virtual int GetNumLocalUsers() const { return localUsers.Num(); }
virtual idLocalUser * GetLocalUserByIndex( int index ) { return &localUsers[index]; }
virtual const idLocalUser * GetLocalUserByIndex( int index ) const { return &localUsers[index]; }
virtual void RemoveLocalUserByIndex( int index );
virtual void RegisterLocalUser( int inputDevice ); // Register a local user to the passed in controller
bool CreateNewUser( winUserState_t & state );
private:
idStaticList< idLocalUserWin, MAX_INPUT_DEVICES > localUsers;
bool dlcVersionChecked;
};
#endif

37
neo/sys/win32/win_snd.cpp Normal file
View File

@@ -0,0 +1,37 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
// DirectX SDK
#include <DxErr.h>
#include <ks.h>
#include <ksmedia.h>
#include "../../sound/snd_local.h"
#include "win_local.h"

View File

@@ -0,0 +1,29 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../framework/precompiled.h"

32
neo/sys/win32/win_stats.h Normal file
View File

@@ -0,0 +1,32 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#ifndef __WIN_STATS_H__
#define __WIN_STATS_H__
#endif // !__WIN_STATS_H__

View File

@@ -0,0 +1,553 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include <errno.h>
#include <float.h>
#include <fcntl.h>
#include <stdio.h>
#include <direct.h>
#include <io.h>
#include <conio.h>
#include "win_local.h"
#include "rc/doom_resource.h"
#define COPY_ID 1
#define QUIT_ID 2
#define CLEAR_ID 3
#define ERRORBOX_ID 10
#define ERRORTEXT_ID 11
#define EDIT_ID 100
#define INPUT_ID 101
#define COMMAND_HISTORY 64
typedef struct {
HWND hWnd;
HWND hwndBuffer;
HWND hwndButtonClear;
HWND hwndButtonCopy;
HWND hwndButtonQuit;
HWND hwndErrorBox;
HWND hwndErrorText;
HBITMAP hbmLogo;
HBITMAP hbmClearBitmap;
HBRUSH hbrEditBackground;
HBRUSH hbrErrorBackground;
HFONT hfBufferFont;
HFONT hfButtonFont;
HWND hwndInputLine;
char errorString[80];
char consoleText[512], returnedText[512];
bool quitOnClose;
int windowWidth, windowHeight;
WNDPROC SysInputLineWndProc;
idEditField historyEditLines[COMMAND_HISTORY];
int nextHistoryLine;// the last line in the history buffer, not masked
int historyLine; // the line being displayed from history buffer
// will be <= nextHistoryLine
idEditField consoleField;
} WinConData;
static WinConData s_wcd;
static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
char *cmdString;
static bool s_timePolarity;
switch (uMsg) {
case WM_ACTIVATE:
if ( LOWORD( wParam ) != WA_INACTIVE ) {
SetFocus( s_wcd.hwndInputLine );
}
break;
case WM_CLOSE:
if ( s_wcd.quitOnClose ) {
PostQuitMessage( 0 );
} else {
Sys_ShowConsole( 0, false );
win32.win_viewlog.SetBool( false );
}
return 0;
case WM_CTLCOLORSTATIC:
if ( ( HWND ) lParam == s_wcd.hwndBuffer ) {
SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0x80 ) );
SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );
return ( long ) s_wcd.hbrEditBackground;
} else if ( ( HWND ) lParam == s_wcd.hwndErrorBox ) {
if ( s_timePolarity & 1 ) {
SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );
} else {
SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );
}
return ( long ) s_wcd.hbrErrorBackground;
}
break;
case WM_SYSCOMMAND:
if ( wParam == SC_CLOSE ) {
PostQuitMessage( 0 );
}
break;
case WM_COMMAND:
if ( wParam == COPY_ID ) {
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );
} else if ( wParam == QUIT_ID ) {
if ( s_wcd.quitOnClose ) {
PostQuitMessage( 0 );
} else {
cmdString = Mem_CopyString( "quit" );
Sys_QueEvent( SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString, 0 );
}
} else if ( wParam == CLEAR_ID ) {
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" );
UpdateWindow( s_wcd.hwndBuffer );
}
break;
case WM_CREATE:
s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0x80 ) );
s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );
SetTimer( hWnd, 1, 1000, NULL );
break;
/*
case WM_ERASEBKGND:
HGDIOBJ oldObject;
HDC hdcScaled;
hdcScaled = CreateCompatibleDC( ( HDC ) wParam );
assert( hdcScaled != 0 );
if ( hdcScaled ) {
oldObject = SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo );
assert( oldObject != 0 );
if ( oldObject )
{
StretchBlt( ( HDC ) wParam, 0, 0, s_wcd.windowWidth, s_wcd.windowHeight,
hdcScaled, 0, 0, 512, 384,
SRCCOPY );
}
DeleteDC( hdcScaled );
hdcScaled = 0;
}
return 1;
*/
case WM_TIMER:
if ( wParam == 1 ) {
s_timePolarity = (bool)!s_timePolarity;
if ( s_wcd.hwndErrorBox ) {
InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );
}
}
break;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
int key, cursor;
switch ( uMsg ) {
case WM_KILLFOCUS:
if ( ( HWND ) wParam == s_wcd.hWnd || ( HWND ) wParam == s_wcd.hwndErrorBox ) {
SetFocus( hWnd );
return 0;
}
break;
case WM_KEYDOWN:
key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
// command history
if ( ( key == K_UPARROW ) || ( key == K_KP_8 ) ) {
if ( s_wcd.nextHistoryLine - s_wcd.historyLine < COMMAND_HISTORY && s_wcd.historyLine > 0 ) {
s_wcd.historyLine--;
}
s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ];
SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
return 0;
}
if ( ( key == K_DOWNARROW ) || ( key == K_KP_2 ) ) {
if ( s_wcd.historyLine == s_wcd.nextHistoryLine ) {
return 0;
}
s_wcd.historyLine++;
s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ];
SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
return 0;
}
break;
case WM_CHAR:
key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
GetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer(), MAX_EDIT_LINE );
SendMessage( s_wcd.hwndInputLine, EM_GETSEL, (WPARAM) NULL, (LPARAM) &cursor );
s_wcd.consoleField.SetCursor( cursor );
// enter the line
if ( key == K_ENTER || key == K_KP_ENTER ) {
strncat( s_wcd.consoleText, s_wcd.consoleField.GetBuffer(), sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 );
strcat( s_wcd.consoleText, "\n" );
SetWindowText( s_wcd.hwndInputLine, "" );
Sys_Printf( "]%s\n", s_wcd.consoleField.GetBuffer() );
// copy line to history buffer
s_wcd.historyEditLines[s_wcd.nextHistoryLine % COMMAND_HISTORY] = s_wcd.consoleField;
s_wcd.nextHistoryLine++;
s_wcd.historyLine = s_wcd.nextHistoryLine;
s_wcd.consoleField.Clear();
return 0;
}
// command completion
if ( key == K_TAB ) {
s_wcd.consoleField.AutoComplete();
SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
//s_wcd.consoleField.SetWidthInChars( strlen( s_wcd.consoleField.GetBuffer() ) );
SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
return 0;
}
// clear autocompletion buffer on normal key input
if ( ( key >= K_SPACE && key <= K_BACKSPACE ) ||
( key >= K_KP_SLASH && key <= K_KP_PLUS ) || ( key >= K_KP_STAR && key <= K_KP_EQUALS ) ) {
s_wcd.consoleField.ClearAutoComplete();
}
break;
}
return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );
}
/*
** Sys_CreateConsole
*/
void Sys_CreateConsole() {
HDC hDC;
WNDCLASS wc;
RECT rect;
const char *DEDCLASS = WIN32_CONSOLE_CLASS;
int nHeight;
int swidth, sheight;
int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;
int i;
memset( &wc, 0, sizeof( wc ) );
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) ConWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = win32.hInstance;
wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
wc.hbrBackground = (struct HBRUSH__ *)COLOR_WINDOW;
wc.lpszMenuName = 0;
wc.lpszClassName = DEDCLASS;
if ( !RegisterClass (&wc) ) {
return;
}
rect.left = 0;
rect.right = 540;
rect.top = 0;
rect.bottom = 450;
AdjustWindowRect( &rect, DEDSTYLE, FALSE );
hDC = GetDC( GetDesktopWindow() );
swidth = GetDeviceCaps( hDC, HORZRES );
sheight = GetDeviceCaps( hDC, VERTRES );
ReleaseDC( GetDesktopWindow(), hDC );
s_wcd.windowWidth = rect.right - rect.left + 1;
s_wcd.windowHeight = rect.bottom - rect.top + 1;
//s_wcd.hbmLogo = LoadBitmap( win32.hInstance, MAKEINTRESOURCE( IDB_BITMAP_LOGO) );
s_wcd.hWnd = CreateWindowEx( 0,
DEDCLASS,
GAME_NAME,
DEDSTYLE,
( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
NULL,
NULL,
win32.hInstance,
NULL );
if ( s_wcd.hWnd == NULL ) {
return;
}
//
// create fonts
//
hDC = GetDC( s_wcd.hWnd );
nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY ), 72 );
s_wcd.hfBufferFont = CreateFont( nHeight, 0, 0, 0, FW_LIGHT, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH, "Courier New" );
ReleaseDC( s_wcd.hWnd, hDC );
//
// create the input line
//
s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER |
ES_LEFT | ES_AUTOHSCROLL,
6, 400, 528, 20,
s_wcd.hWnd,
( HMENU ) INPUT_ID, // child window ID
win32.hInstance, NULL );
//
// create the buttons
//
s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
5, 425, 72, 24,
s_wcd.hWnd,
( HMENU ) COPY_ID, // child window ID
win32.hInstance, NULL );
SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" );
s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
82, 425, 72, 24,
s_wcd.hWnd,
( HMENU ) CLEAR_ID, // child window ID
win32.hInstance, NULL );
SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" );
s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
462, 425, 72, 24,
s_wcd.hWnd,
( HMENU ) QUIT_ID, // child window ID
win32.hInstance, NULL );
SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" );
//
// create the scrollbuffer
//
s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
6, 40, 526, 354,
s_wcd.hWnd,
( HMENU ) EDIT_ID, // child window ID
win32.hInstance, NULL );
SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc );
SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
// don't show it now that we have a splash screen up
if ( win32.win_viewlog.GetBool() ) {
ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);
UpdateWindow( s_wcd.hWnd );
SetForegroundWindow( s_wcd.hWnd );
SetFocus( s_wcd.hwndInputLine );
}
s_wcd.consoleField.Clear();
for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
s_wcd.historyEditLines[i].Clear();
}
}
/*
** Sys_DestroyConsole
*/
void Sys_DestroyConsole() {
if ( s_wcd.hWnd ) {
ShowWindow( s_wcd.hWnd, SW_HIDE );
CloseWindow( s_wcd.hWnd );
DestroyWindow( s_wcd.hWnd );
s_wcd.hWnd = 0;
}
}
/*
** Sys_ShowConsole
*/
void Sys_ShowConsole( int visLevel, bool quitOnClose ) {
s_wcd.quitOnClose = quitOnClose;
if ( !s_wcd.hWnd ) {
return;
}
switch ( visLevel ) {
case 0:
ShowWindow( s_wcd.hWnd, SW_HIDE );
break;
case 1:
ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );
SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
break;
case 2:
ShowWindow( s_wcd.hWnd, SW_MINIMIZE );
break;
default:
Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel );
break;
}
}
/*
** Sys_ConsoleInput
*/
char *Sys_ConsoleInput() {
if ( s_wcd.consoleText[0] == 0 ) {
return NULL;
}
strcpy( s_wcd.returnedText, s_wcd.consoleText );
s_wcd.consoleText[0] = 0;
return s_wcd.returnedText;
}
/*
** Conbuf_AppendText
*/
void Conbuf_AppendText( const char *pMsg )
{
#define CONSOLE_BUFFER_SIZE 16384
char buffer[CONSOLE_BUFFER_SIZE*2];
char *b = buffer;
const char *msg;
int bufLen;
int i = 0;
static unsigned long s_totalChars;
//
// if the message is REALLY long, use just the last portion of it
//
if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 ) {
msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;
} else {
msg = pMsg;
}
//
// copy into an intermediate buffer
//
while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) ) {
if ( msg[i] == '\n' && msg[i+1] == '\r' ) {
b[0] = '\r';
b[1] = '\n';
b += 2;
i++;
} else if ( msg[i] == '\r' ) {
b[0] = '\r';
b[1] = '\n';
b += 2;
} else if ( msg[i] == '\n' ) {
b[0] = '\r';
b[1] = '\n';
b += 2;
} else if ( idStr::IsColor( &msg[i] ) ) {
i++;
} else {
*b= msg[i];
b++;
}
i++;
}
*b = 0;
bufLen = b - buffer;
s_totalChars += bufLen;
//
// replace selection instead of appending if we're overflowing
//
if ( s_totalChars > 0x7000 ) {
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
s_totalChars = bufLen;
}
//
// put this text into the windows console
//
SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );
SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );
}
/*
** Win_SetErrorText
*/
void Win_SetErrorText( const char *buf ) {
idStr::Copynz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );
if ( !s_wcd.hwndErrorBox ) {
s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,
6, 5, 526, 30,
s_wcd.hWnd,
( HMENU ) ERRORBOX_ID, // child window ID
win32.hInstance, NULL );
SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );
DestroyWindow( s_wcd.hwndInputLine );
s_wcd.hwndInputLine = NULL;
}
}

View File

@@ -0,0 +1,142 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
//
// This file implements the low-level keyboard hook that traps the task keys.
//
#include "win_local.h"
#define DLLEXPORT __declspec(dllexport)
// Magic registry key/value for "Remove Task Manager" policy.
LPCTSTR KEY_DisableTaskMgr = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
LPCTSTR VAL_DisableTaskMgr = "DisableTaskMgr";
// The section is SHARED among all instances of this DLL.
// A low-level keyboard hook is always a system-wide hook.
#pragma data_seg (".mydata")
HHOOK g_hHookKbdLL = NULL; // hook handle
BOOL g_bBeep = FALSE; // beep on illegal key
#pragma data_seg ()
#pragma comment(linker, "/SECTION:.mydata,RWS") // tell linker: make it shared
/*
================
MyTaskKeyHookLL
Low-level keyboard hook:
Trap task-switching keys by returning without passing along.
================
*/
LRESULT CALLBACK MyTaskKeyHookLL( int nCode, WPARAM wp, LPARAM lp ) {
KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT *) lp;
if ( nCode == HC_ACTION ) {
BOOL bCtrlKeyDown = GetAsyncKeyState( VK_CONTROL)>>((sizeof(SHORT) * 8) - 1 );
if ( ( pkh->vkCode == VK_ESCAPE && bCtrlKeyDown ) // Ctrl+Esc
|| ( pkh->vkCode == VK_TAB && pkh->flags & LLKHF_ALTDOWN ) // Alt+TAB
|| ( pkh->vkCode == VK_ESCAPE && pkh->flags & LLKHF_ALTDOWN ) // Alt+Esc
|| ( pkh->vkCode == VK_LWIN || pkh->vkCode == VK_RWIN ) // Start Menu
) {
if ( g_bBeep && ( wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN ) ) {
MessageBeep( 0 ); // beep on downstroke if requested
}
return 1; // return without processing the key strokes
}
}
return CallNextHookEx( g_hHookKbdLL, nCode, wp, lp );
}
/*
================
AreTaskKeysDisabled
Are task keys disabled--ie, is hook installed?
Note: This assumes there's no other hook that does the same thing!
================
*/
BOOL AreTaskKeysDisabled() {
return g_hHookKbdLL != NULL;
}
/*
================
IsTaskMgrDisabled
================
*/
BOOL IsTaskMgrDisabled() {
HKEY hk;
if ( RegOpenKey( HKEY_CURRENT_USER, KEY_DisableTaskMgr, &hk ) != ERROR_SUCCESS ) {
return FALSE; // no key ==> not disabled
}
DWORD val = 0;
DWORD len = 4;
return RegQueryValueEx( hk, VAL_DisableTaskMgr, NULL, NULL, (BYTE*)&val, &len ) == ERROR_SUCCESS && val == 1;
}
/*
================
DisableTaskKeys
================
*/
void DisableTaskKeys( BOOL bDisable, BOOL bBeep, BOOL bTaskMgr ) {
// task keys (Ctrl+Esc, Alt-Tab, etc.)
if ( bDisable ) {
if ( !g_hHookKbdLL ) {
g_hHookKbdLL = SetWindowsHookEx( WH_KEYBOARD_LL, MyTaskKeyHookLL, win32.hInstance, 0 );
}
} else if ( g_hHookKbdLL != NULL ) {
UnhookWindowsHookEx( g_hHookKbdLL );
g_hHookKbdLL = NULL;
}
g_bBeep = bBeep;
// task manager (Ctrl+Alt+Del)
if ( bTaskMgr ) {
HKEY hk;
if ( RegOpenKey( HKEY_CURRENT_USER, KEY_DisableTaskMgr, &hk ) != ERROR_SUCCESS ) {
RegCreateKey( HKEY_CURRENT_USER, KEY_DisableTaskMgr, &hk );
}
if ( bDisable ) {
// disable TM: set policy = 1
DWORD val = 1;
RegSetValueEx( hk, VAL_DisableTaskMgr, NULL, REG_DWORD, (BYTE*)&val, sizeof(val) );
} else {
// enable TM: remove policy
RegDeleteValue( hk,VAL_DisableTaskMgr );
}
}
}

View File

@@ -0,0 +1,429 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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 "../../idlib/precompiled.h"
#include "win_local.h"
#include "../../renderer/tr_local.h"
#include <Windowsx.h>
LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
static bool s_alttab_disabled;
extern idCVar r_windowX;
extern idCVar r_windowY;
extern idCVar r_windowWidth;
extern idCVar r_windowHeight;
static void WIN_DisableAltTab() {
if ( s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
return;
}
if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
} else {
BOOL old;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
}
s_alttab_disabled = true;
}
static void WIN_EnableAltTab() {
if ( !s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
return;
}
if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
UnregisterHotKey( 0, 0 );
} else {
BOOL old;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
}
s_alttab_disabled = false;
}
void WIN_Sizing(WORD side, RECT *rect)
{
if ( !R_IsInitialized() || renderSystem->GetWidth() <= 0 || renderSystem->GetHeight() <= 0 ) {
return;
}
// restrict to a standard aspect ratio
int width = rect->right - rect->left;
int height = rect->bottom - rect->top;
// Adjust width/height for window decoration
RECT decoRect = { 0, 0, 0, 0 };
AdjustWindowRect( &decoRect, WINDOW_STYLE|WS_SYSMENU, FALSE );
int decoWidth = decoRect.right - decoRect.left;
int decoHeight = decoRect.bottom - decoRect.top;
width -= decoWidth;
height -= decoHeight;
// Clamp to a minimum size
if ( width < SCREEN_WIDTH / 4 ) {
width = SCREEN_WIDTH / 4;
}
if ( height < SCREEN_HEIGHT / 4 ) {
height = SCREEN_HEIGHT / 4;
}
const int minWidth = height * 4 / 3;
const int maxHeight = width * 3 / 4;
const int maxWidth = height * 16 / 9;
const int minHeight = width * 9 / 16;
// Set the new size
switch ( side ) {
case WMSZ_LEFT:
rect->left = rect->right - width - decoWidth;
rect->bottom = rect->top + idMath::ClampInt( minHeight, maxHeight, height ) + decoHeight;
break;
case WMSZ_RIGHT:
rect->right = rect->left + width + decoWidth;
rect->bottom = rect->top + idMath::ClampInt( minHeight, maxHeight, height ) + decoHeight;
break;
case WMSZ_BOTTOM:
case WMSZ_BOTTOMRIGHT:
rect->bottom = rect->top + height + decoHeight;
rect->right = rect->left + idMath::ClampInt( minWidth, maxWidth, width ) + decoWidth;
break;
case WMSZ_TOP:
case WMSZ_TOPRIGHT:
rect->top = rect->bottom - height - decoHeight;
rect->right = rect->left + idMath::ClampInt( minWidth, maxWidth, width ) + decoWidth;
break;
case WMSZ_BOTTOMLEFT:
rect->bottom = rect->top + height + decoHeight;
rect->left = rect->right - idMath::ClampInt( minWidth, maxWidth, width ) - decoWidth;
break;
case WMSZ_TOPLEFT:
rect->top = rect->bottom - height - decoHeight;
rect->left = rect->right - idMath::ClampInt( minWidth, maxWidth, width ) - decoWidth;
break;
}
}
/*
====================
MainWndProc
main window procedure
====================
*/
LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
int key;
switch( uMsg ) {
case WM_WINDOWPOSCHANGED:
if (R_IsInitialized()) {
RECT rect;
if (::GetClientRect(win32.hWnd, &rect)) {
if ( rect.right > rect.left && rect.bottom > rect.top ) {
glConfig.nativeScreenWidth = rect.right - rect.left;
glConfig.nativeScreenHeight = rect.bottom - rect.top;
// save the window size in cvars if we aren't fullscreen
int style = GetWindowLong( hWnd, GWL_STYLE );
if ( ( style & WS_POPUP ) == 0 ) {
r_windowWidth.SetInteger( glConfig.nativeScreenWidth );
r_windowHeight.SetInteger( glConfig.nativeScreenHeight );
}
}
}
}
break;
case WM_MOVE: {
int xPos, yPos;
RECT r;
// save the window origin in cvars if we aren't fullscreen
int style = GetWindowLong( hWnd, GWL_STYLE );
if ( ( style & WS_POPUP ) == 0 ) {
xPos = (short) LOWORD(lParam); // horizontal position
yPos = (short) HIWORD(lParam); // vertical position
r.left = 0;
r.top = 0;
r.right = 1;
r.bottom = 1;
AdjustWindowRect( &r, style, FALSE );
r_windowX.SetInteger( xPos + r.left );
r_windowY.SetInteger( yPos + r.top );
}
break;
}
case WM_CREATE:
win32.hWnd = hWnd;
if ( win32.cdsFullscreen ) {
WIN_DisableAltTab();
} else {
WIN_EnableAltTab();
}
// do the OpenGL setup
void GLW_WM_CREATE( HWND hWnd );
GLW_WM_CREATE( hWnd );
break;
case WM_DESTROY:
// let sound and input know about this?
win32.hWnd = NULL;
if ( win32.cdsFullscreen ) {
WIN_EnableAltTab();
}
break;
case WM_CLOSE:
soundSystem->SetMute( true );
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
break;
case WM_ACTIVATE:
// if we got here because of an alt-tab or maximize,
// we should activate immediately. If we are here because
// the mouse was clicked on a title bar or drag control,
// don't activate until the mouse button is released
{
int fActive, fMinimized;
fActive = LOWORD(wParam);
fMinimized = (BOOL) HIWORD(wParam);
win32.activeApp = (fActive != WA_INACTIVE);
if ( win32.activeApp ) {
idKeyInput::ClearStates();
Sys_GrabMouseCursor( true );
if ( common->IsInitialized() ) {
SetCursor( NULL );
}
}
if ( fActive == WA_INACTIVE ) {
win32.movingWindow = false;
if ( common->IsInitialized() ) {
SetCursor( LoadCursor( 0, IDC_ARROW ) );
}
}
// start playing the game sound world
soundSystem->SetMute( !win32.activeApp );
// we do not actually grab or release the mouse here,
// that will be done next time through the main loop
}
break;
case WM_TIMER: {
if ( win32.win_timerUpdate.GetBool() ) {
common->Frame();
}
break;
}
case WM_SYSCOMMAND:
if ( wParam == SC_SCREENSAVE || wParam == SC_KEYMENU ) {
return 0;
}
break;
case WM_SYSKEYDOWN:
if ( wParam == 13 ) { // alt-enter toggles full-screen
cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
return 0;
}
// fall through for other keys
case WM_KEYDOWN:
key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
if ( key == K_LCTRL || key == K_LALT || key == K_RCTRL || key == K_RALT ) {
// let direct-input handle this because windows sends Alt-Gr
// as two events (ctrl then alt)
break;
}
// D
if ( key == K_NUMLOCK ) {
key = K_PAUSE;
} else if ( key == K_PAUSE ) {
key = K_NUMLOCK;
}
Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
break;
case WM_SYSKEYUP:
case WM_KEYUP:
key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
if ( key == K_PRINTSCREEN ) {
// don't queue printscreen keys. Since windows doesn't send us key
// down events for this, we handle queueing them with DirectInput
break;
} else if ( key == K_LCTRL || key == K_LALT || key == K_RCTRL || key == K_RALT ) {
// let direct-input handle this because windows sends Alt-Gr
// as two events (ctrl then alt)
break;
}
Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 );
break;
case WM_CHAR:
Sys_QueEvent( SE_CHAR, wParam, 0, 0, NULL, 0 );
break;
case WM_NCLBUTTONDOWN:
// win32.movingWindow = true;
break;
case WM_ENTERSIZEMOVE:
win32.movingWindow = true;
break;
case WM_EXITSIZEMOVE:
win32.movingWindow = false;
break;
case WM_SIZING:
WIN_Sizing(wParam, (RECT *)lParam);
break;
case WM_MOUSEMOVE: {
if ( !common->IsInitialized() ) {
break;
}
const bool isShellActive = ( game && ( game->Shell_IsActive() || game->IsPDAOpen() ) );
const bool isConsoleActive = console->Active();
if ( win32.activeApp ) {
if ( isShellActive ) {
// If the shell is active, it will display its own cursor.
SetCursor( NULL );
} else if ( isConsoleActive ) {
// The console is active but the shell is not.
// Show the Windows cursor.
SetCursor( LoadCursor( 0, IDC_ARROW ) );
} else {
// The shell not active and neither is the console.
// This is normal gameplay, hide the cursor.
SetCursor( NULL );
}
} else {
if ( !isShellActive ) {
// Always show the cursor when the window is in the background
SetCursor( LoadCursor( 0, IDC_ARROW ) );
} else {
SetCursor( NULL );
}
}
const int x = GET_X_LPARAM( lParam );
const int y = GET_Y_LPARAM( lParam );
// Generate an event
Sys_QueEvent( SE_MOUSE_ABSOLUTE, x, y, 0, NULL, 0 );
// Get a mouse leave message
TRACKMOUSEEVENT tme = {
sizeof( TRACKMOUSEEVENT ),
TME_LEAVE,
hWnd,
0
};
TrackMouseEvent( &tme );
return 0;
}
case WM_MOUSELEAVE: {
Sys_QueEvent( SE_MOUSE_LEAVE, 0, 0, 0, NULL, 0 );
return 0;
}
case WM_LBUTTONDOWN: {
Sys_QueEvent( SE_KEY, K_MOUSE1, 1, 0, NULL, 0 );
return 0;
}
case WM_LBUTTONUP: {
Sys_QueEvent( SE_KEY, K_MOUSE1, 0, 0, NULL, 0 );
return 0;
}
case WM_RBUTTONDOWN: {
Sys_QueEvent( SE_KEY, K_MOUSE2, 1, 0, NULL, 0 );
return 0;
}
case WM_RBUTTONUP: {
Sys_QueEvent( SE_KEY, K_MOUSE2, 0, 0, NULL, 0 );
return 0;
}
case WM_MBUTTONDOWN: {
Sys_QueEvent( SE_KEY, K_MOUSE3, 1, 0, NULL, 0 );
return 0;
}
case WM_MBUTTONUP: {
Sys_QueEvent( SE_KEY, K_MOUSE3, 0, 0, NULL, 0 );
return 0;
}
case WM_XBUTTONDOWN: {
int button = GET_XBUTTON_WPARAM( wParam );
if ( button == 1 ) {
Sys_QueEvent( SE_KEY, K_MOUSE4, 1, 0, NULL, 0 );
} else if ( button == 2 ) {
Sys_QueEvent( SE_KEY, K_MOUSE5, 1, 0, NULL, 0 );
}
return 0;
}
case WM_XBUTTONUP: {
int button = GET_XBUTTON_WPARAM( wParam );
if ( button == 1 ) {
Sys_QueEvent( SE_KEY, K_MOUSE4, 0, 0, NULL, 0 );
} else if ( button == 2 ) {
Sys_QueEvent( SE_KEY, K_MOUSE5, 0, 0, NULL, 0 );
}
return 0;
}
case WM_MOUSEWHEEL: {
int delta = GET_WHEEL_DELTA_WPARAM( wParam ) / WHEEL_DELTA;
int key = delta < 0 ? K_MWHEELDOWN : K_MWHEELUP;
delta = abs( delta );
while( delta-- > 0 ) {
Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 );
}
break;
}
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}