summaryrefslogtreecommitdiff
path: root/utils/smp/smp.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/smp/smp.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/smp/smp.cpp')
-rw-r--r--utils/smp/smp.cpp1441
1 files changed, 1441 insertions, 0 deletions
diff --git a/utils/smp/smp.cpp b/utils/smp/smp.cpp
new file mode 100644
index 0000000..fb30df9
--- /dev/null
+++ b/utils/smp/smp.cpp
@@ -0,0 +1,1441 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// smp.cpp : Main window procedure
+//
+
+#include "stdafx.h"
+#include "resource.h"
+#include "initguid.h"
+#include "CWMPHost.h"
+#include <commctrl.h>
+#include <windows.h>
+#include <psapi.h>
+#include <math.h>
+#include <cstdio>
+#include <vector>
+#include <string>
+#include <strstream>
+#include <fstream>
+
+
+#include "IceKey.h"
+
+
+CComModule _Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+END_OBJECT_MAP()
+
+
+#define ID_SKIP_FADE_TIMER 1
+#define ID_DRAW_TIMER 2
+
+
+const float FADE_TIME = 1.0f;
+const int MAX_BLUR_STEPS = 100;
+
+HINSTANCE g_hInstance;
+HWND g_hBlackFadingWindow = 0;
+bool g_bFadeIn = true;
+bool g_bFrameCreated = false;
+CWMPHost g_frame;
+CWMPHost *g_pFrame = NULL;
+HDC g_hdcCapture = 0;
+HDC g_hdcBlend = 0;
+HBITMAP g_hbmCapture = 0;
+HBITMAP g_hbmBlend = 0;
+HMONITOR g_hMonitor = 0;
+
+int g_screenWidth = 0;
+int g_screenHeight = 0;
+
+LPTSTR g_lpCommandLine = NULL;
+std::string g_redirectTarget;
+std::string g_URL;
+bool g_bReportStats = false;
+bool g_bUseLocalSteamServer = false;
+
+double g_timeAtFadeStart = 0.0;
+int g_nBlurSteps = 0;
+
+
+void LogPlayerEvent( EventType_t e );
+
+
+enum OSVersion
+{
+ OSV_95,
+ OSV_95OSR2,
+ OSV_98,
+ OSV_98SE,
+ OSV_ME,
+ OSV_NT4,
+ OSV_2000,
+ OSV_SERVER2003,
+ OSV_XP,
+ OSV_XPSP1,
+ OSV_XPSP2,
+ OSV_XPSP3,
+ OSV_VISTA,
+ OSV_UNKNOWN,
+};
+
+OSVersion DetectOSVersion()
+{
+ OSVERSIONINFO version;
+ version.dwOSVersionInfoSize = sizeof( version );
+ GetVersionEx( &version );
+ if ( version.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( version.dwMajorVersion != 4 )
+ return OSV_UNKNOWN;
+
+ switch ( version.dwMinorVersion )
+ {
+ case 0:
+ return strstr( version.szCSDVersion, _TEXT( " C" ) ) == version.szCSDVersion ? OSV_95OSR2 : OSV_95;
+ case 10:
+ return ( strstr( version.szCSDVersion, _TEXT( " A" ) ) == version.szCSDVersion ) || ( strstr( version.szCSDVersion, _TEXT( " B" ) ) == version.szCSDVersion ) ? OSV_98SE : OSV_98;
+ case 90:
+ return OSV_ME;
+ }
+ }
+ else if ( version.dwPlatformId & VER_PLATFORM_WIN32_NT )
+ {
+ if ( version.dwMajorVersion == 4 )
+ return OSV_NT4; // or mabye NT3.5???
+
+ if ( version.dwMajorVersion == 6 )
+ return OSV_VISTA;
+
+ if ( version.dwMajorVersion != 5 )
+ return OSV_UNKNOWN;
+
+ switch ( version.dwMinorVersion )
+ {
+ case 0:
+ return OSV_2000;
+ case 1:
+ {
+ if ( version.szCSDVersion == NULL )
+ return OSV_XP;
+
+ if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 1" ) ) != NULL )
+ return OSV_XPSP1;
+
+ if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 2" ) ) != NULL )
+ return OSV_XPSP2;
+
+ if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 3" ) ) != NULL )
+ return OSV_XPSP3;
+ }
+ case 2:
+ return OSV_SERVER2003; // or maybe XP64???
+ }
+ }
+
+ return OSV_UNKNOWN;
+}
+
+const OSVersion g_osVersion = DetectOSVersion();
+
+
+
+#define BLUR
+
+#define USE_D3D8
+#ifdef USE_D3D8
+
+#include <d3d8.h>
+IDirect3D8* g_pD3D = NULL;
+IDirect3DDevice8* g_pd3dDevice = NULL;
+IDirect3DVertexBuffer8* g_pDrawVB = NULL;
+IDirect3DTexture8* g_pImg = NULL;
+int g_nDrawStride = 0;
+DWORD g_dwDrawFVF = 0;
+
+#ifdef BLUR
+
+int g_nBlurStride = 0;
+DWORD g_dwBlurFVF = 0;
+IDirect3DVertexBuffer8* g_pBlurVB = NULL;
+IDirect3DTexture8* g_pTex = NULL;
+IDirect3DTexture8* g_pRT = NULL;
+IDirect3DSurface8* g_pBackBuf = NULL;
+
+#endif // BLUR
+
+#endif // USE_D3D8
+
+
+DWORD g_dwUseVMROverlayOldValue = 0;
+bool g_bUseVMROverlayValueExists = false;
+
+
+void SetRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwValue, DWORD &dwOldValue, bool &bValueExisted )
+{
+ HKEY hKey = 0;
+ LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
+ if ( rval != ERROR_SUCCESS )
+ {
+ OutputDebugString( "unable to open registry key: " );
+ OutputDebugString( pKeyName );
+ OutputDebugString( "\n" );
+ return;
+ }
+
+ DWORD dwType = 0;
+ DWORD dwSize = sizeof( dwOldValue );
+
+ // amusingly enough, if pValueName doesn't exist, RegQueryValueEx returns ERROR_FILE_NOT_FOUND
+ rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )&dwOldValue, &dwSize );
+ bValueExisted = ( rval == ERROR_SUCCESS );
+
+ rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwValue, sizeof( dwValue ) );
+ if ( rval != ERROR_SUCCESS )
+ {
+ OutputDebugString( "unable to write registry value " );
+ OutputDebugString( pValueName );
+ OutputDebugString( " in key " );
+ OutputDebugString( pKeyName );
+ OutputDebugString( "\n" );
+ }
+
+ RegCloseKey( hKey );
+}
+
+void RestoreRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwOldValue, bool bValueExisted )
+{
+ HKEY hKey = 0;
+ LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
+ if ( rval != ERROR_SUCCESS )
+ {
+ OutputDebugString( "unable to open registry key: " );
+ OutputDebugString( pKeyName );
+ OutputDebugString( "\n" );
+ return;
+ }
+
+ if ( bValueExisted )
+ {
+ rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwOldValue, sizeof( dwOldValue ) );
+ }
+ else
+ {
+ rval = RegDeleteValue( hKey, pValueName );
+ }
+ if ( rval != ERROR_SUCCESS )
+ {
+ OutputDebugString( "SetRegistryValue FAILED!\n" );
+ }
+
+ RegCloseKey( hKey );
+}
+
+bool GetRegistryString( const char *pKeyName, const char *pValueName, const char *pValueString, int nValueLen )
+{
+ HKEY hKey = 0;
+ LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
+ if ( rval != ERROR_SUCCESS )
+ {
+ OutputDebugString( "unable to open registry key: " );
+ OutputDebugString( pKeyName );
+ OutputDebugString( "\n" );
+ return false;
+ }
+
+ DWORD dwType = 0;
+ rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )pValueString, ( DWORD* )&nValueLen );
+
+ RegCloseKey( hKey );
+
+ if ( rval != ERROR_SUCCESS || dwType != REG_SZ )
+ {
+ OutputDebugString( "unable to read registry string: " );
+ OutputDebugString( pValueName );
+ OutputDebugString( "\n" );
+ return false;
+ }
+
+ return true;
+}
+
+struct EventData_t
+{
+ EventData_t( int t, float pos, EventType_t e )
+ : time( t ), position( pos ), event( e )
+ {
+ }
+ int time; // real time
+ float position; // movie position
+ EventType_t event; // event type
+};
+
+const char *GetEventName( EventType_t event )
+{
+ switch ( event )
+ {
+ case ET_APPLAUNCH: return "al";
+ case ET_APPEXIT: return "ae";
+ case ET_CLOSE: return "cl";
+ case ET_FADEOUT: return "fo";
+
+ case ET_MEDIABEGIN: return "mb";
+ case ET_MEDIAEND: return "me";
+
+ case ET_JUMPHOME: return "jh";
+ case ET_JUMPEND: return "je";
+
+ case ET_PLAY: return "pl";
+ case ET_PAUSE: return "ps";
+ case ET_STOP: return "st";
+ case ET_SCRUBFROM: return "jf";
+ case ET_SCRUBTO: return "jt";
+ case ET_STEPFWD: return "sf";
+ case ET_STEPBCK: return "sb";
+ case ET_JUMPFWD: return "jf";
+ case ET_JUMPBCK: return "jb";
+ case ET_REPEAT: return "rp";
+
+ case ET_MAXIMIZE: return "mx";
+ case ET_MINIMIZE: return "mn";
+ case ET_RESTORE: return "rs";
+
+ default: return "<unknown>";
+ }
+}
+
+std::vector< EventData_t > g_events;
+
+void LogPlayerEvent( EventType_t e, float pos )
+{
+ if ( !g_bReportStats )
+ return;
+
+ static int s_firstTick = GetTickCount();
+ int time = GetTickCount() - s_firstTick;
+
+#if 0
+ char msg[ 256 ];
+ sprintf( msg, "event %s at time %d and pos %d\n", GetEventName( e ), time, int( 1000 * pos ) );
+ OutputDebugString( msg );
+#endif
+
+ bool bDropEvent = false;
+
+ int nEvents = g_events.size();
+ if ( ( e == ET_STEPFWD || e == ET_STEPBCK ) && nEvents >= 2 )
+ {
+ const EventData_t &e1 = g_events[ nEvents - 1 ];
+ const EventData_t &e2 = g_events[ nEvents - 2 ];
+ if ( ( e1.event == e || e1.event == ET_REPEAT ) && e2.event == e )
+ {
+ // only store starting and ending stepfwd or stepbck events, since there can be so many
+ // also keep events that are more than a second apart
+ if ( e1.event == ET_REPEAT )
+ {
+ // keep dropping events while e1 isn't before a gap
+ bDropEvent = time - e1.time < 1000;
+ }
+ else
+ {
+ // e2 was kept last time, so keep e1 if e2 was kept because it was before a gap
+ bDropEvent = e1.time - e2.time < 1000;
+ }
+ }
+ }
+
+ if ( bDropEvent )
+ {
+ g_events[ nEvents - 1 ] = EventData_t( time, pos, ET_REPEAT );
+ }
+ else
+ {
+ g_events.push_back( EventData_t( time, pos, e ) );
+ }
+}
+
+char C2M_UPLOADDATA = 'q';
+char C2M_UPLOADDATA_PROTOCOL_VERSION = 1;
+char C2M_UPLOADDATA_DATA_VERSION = 1;
+
+inline void WriteHexDigit( std::ostream &os, byte src )
+{
+ os.put( ( src <= 9 ) ? src + '0' : src - 10 + 'A' );
+}
+
+inline void WriteByte( std::ostream &os, byte src )
+{
+ WriteHexDigit( os, src >> 4 );
+ WriteHexDigit( os, src & 0xf );
+}
+
+inline void WriteShort( std::ostream &os, unsigned short src )
+{
+ WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
+ WriteByte( os, ( byte )( src & 0xff ) );
+}
+
+inline void WriteInt24( std::ostream &os, int src )
+{
+ WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) );
+ WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
+ WriteByte( os, ( byte )( src & 0xff ) );
+}
+
+inline void WriteInt( std::ostream &os, int src )
+{
+ WriteByte( os, ( byte )( ( src >> 24 ) & 0xff ) );
+ WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) );
+ WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
+ WriteByte( os, ( byte )( src & 0xff ) );
+}
+
+inline void WriteFloat( std::ostream &os, float src )
+{
+ WriteInt( os, *( int* )&src );
+}
+
+void WriteUUID( std::ostream &os, const UUID &uuid )
+{
+ WriteInt( os, uuid.Data1 );
+ WriteShort( os, uuid.Data2 );
+ WriteShort( os, uuid.Data3 );
+ for ( int i = 0; i < 8; ++i )
+ {
+ WriteByte( os, uuid.Data4[ i ] );
+ }
+}
+
+bool QueryOrGenerateUserID( UUID &userId )
+{
+ HKEY hKey = 0;
+ LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Steam", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
+ if ( rval != ERROR_SUCCESS )
+ {
+ UuidCreate( &userId );
+ return false;
+ }
+
+ DWORD dwType = 0;
+ unsigned char idstr[ 40 ];
+ DWORD dwSize = sizeof( idstr );
+
+ rval = RegQueryValueEx( hKey, "smpid", NULL, &dwType, ( LPBYTE )idstr, &dwSize );
+ if ( rval != ERROR_SUCCESS || dwType != REG_SZ )
+ {
+ UuidCreate( &userId );
+
+ unsigned char *outstring = NULL;
+ UuidToString( &userId, &outstring );
+ if ( outstring == NULL || *outstring == '\0' )
+ {
+ RegCloseKey( hKey );
+ return false;
+ }
+
+ rval = RegSetValueEx( hKey, "smpid", 0, REG_SZ, ( CONST BYTE* )outstring, sizeof( idstr ) );
+
+ RpcStringFree( &outstring );
+ RegCloseKey( hKey );
+
+ return rval == ERROR_SUCCESS;
+ }
+
+ if ( RPC_S_OK != UuidFromString( idstr, &userId ) )
+ return false;
+
+ RegCloseKey( hKey );
+ return true;
+}
+
+void PrintStats( const char *pStatsFilename )
+{
+ std::ofstream os( pStatsFilename, std::ios_base::out | std::ios_base::binary );
+
+ // user id
+ UUID userId;
+ QueryOrGenerateUserID( userId );
+ unsigned char *userIdStr;
+ UuidToStringA( &userId, &userIdStr );
+ os << userIdStr << "\n";
+ RpcStringFree( &userIdStr );
+
+ // filename
+ int nOffset = g_URL.find_last_of( "/\\" );
+ if ( nOffset == g_URL.npos )
+ nOffset = 0;
+ std::string filename = g_URL.substr( nOffset + 1 );
+ os << filename << '\n';
+
+ // number of events
+ int nEvents = g_events.size();
+ os << nEvents << "\n";
+
+ // event data (tab-delimited)
+ for ( int i = 0; i < nEvents; ++i )
+ {
+ os << GetEventName( g_events[ i ].event ) << "\t";
+ os << g_events[ i ].time << "\t";
+ os << int( 1000 * g_events[ i ].position ) << "\n";
+ }
+}
+
+void UploadStats()
+{
+ char pathname[ 256 ];
+ if ( !GetRegistryString( "Software\\Valve\\Steam", "SteamExe", pathname, sizeof( pathname ) ) )
+ return;
+
+ char *pExeName = strrchr( pathname, '/' );
+ if ( !pExeName )
+ return;
+
+ *pExeName = '\0'; // truncate exe filename to just pathname
+
+ char filename[ 256 ];
+ sprintf( filename, "%s/smpstats.txt", pathname );
+
+ PrintStats( filename );
+
+ ::ShellExecuteA( NULL, "open", "steam://smp/smpstats.txt", NULL, NULL, SW_SHOWNORMAL );
+}
+
+void RestoreRegistry()
+{
+ static bool s_bDone = false;
+ if ( s_bDone )
+ return;
+
+ s_bDone = true;
+ RestoreRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists );
+}
+
+
+#ifdef USE_D3D8
+
+void CleanupD3D()
+{
+ if ( g_pDrawVB )
+ {
+ g_pDrawVB->Release();
+ g_pDrawVB = NULL;
+ }
+ if ( g_pImg )
+ {
+ g_pImg->Release();
+ g_pImg = NULL;
+ }
+#ifdef BLUR
+ if ( g_pBackBuf )
+ {
+ g_pBackBuf->Release();
+ g_pBackBuf = NULL;
+ }
+ if ( g_pBlurVB )
+ {
+ g_pBlurVB->Release();
+ g_pBlurVB = NULL;
+ }
+ if ( g_pTex )
+ {
+ g_pTex->Release();
+ g_pTex = NULL;
+ }
+ if ( g_pRT )
+ {
+ g_pRT->Release();
+ g_pRT = NULL;
+ }
+#endif // BLUR
+ if ( g_pd3dDevice )
+ {
+ g_pd3dDevice->Release();
+ g_pd3dDevice = NULL;
+ }
+ if ( g_pD3D )
+ {
+ g_pD3D->Release();
+ g_pD3D = NULL;
+ }
+}
+
+void InitTextureStageState( int nStage, DWORD dwColorOp, DWORD dwColorArg1, DWORD dwColorArg2, DWORD dwColorArg0 = D3DTA_CURRENT )
+{
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLOROP, dwColorOp );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG1, dwColorArg1 );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG2, dwColorArg2 );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG0, dwColorArg0 );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
+ g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
+}
+
+bool InitD3D( HWND hWnd, bool blur )
+{
+ g_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
+ if ( !g_pD3D )
+ {
+ OutputDebugString( "Direct3DCreate8 FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ D3DDISPLAYMODE d3ddm;
+ bool bFound = false;
+ int nAdapters = g_pD3D->GetAdapterCount();
+ int nAdapterIndex = 0;
+ for ( ; nAdapterIndex < nAdapters; ++nAdapterIndex )
+ {
+ if ( g_pD3D->GetAdapterMonitor( nAdapterIndex ) == g_hMonitor )
+ {
+ if ( FAILED( g_pD3D->GetAdapterDisplayMode( nAdapterIndex, &d3ddm ) ) )
+ {
+ OutputDebugString( "GetAdapterDisplayMode FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ MONITORINFO mi;
+ mi.cbSize = sizeof( mi );
+ GetMonitorInfo( g_hMonitor, &mi );
+ bFound = true;
+ break;
+ }
+ }
+ if ( !bFound )
+ {
+ OutputDebugString( "Starting monitor not found when creating D3D device!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ D3DPRESENT_PARAMETERS d3dpp;
+ ZeroMemory( &d3dpp, sizeof( d3dpp ) );
+ d3dpp.BackBufferWidth = g_screenWidth;
+ d3dpp.BackBufferHeight = g_screenHeight;
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.BackBufferCount = 1;
+ d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.hDeviceWindow = NULL;
+ d3dpp.Windowed = FALSE;
+ d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
+ d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+
+ if ( FAILED( g_pD3D->CreateDevice( nAdapterIndex, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
+ {
+ OutputDebugString( "CreateDevice FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ // create and fill vertex buffer(s)
+ float du = 0.5f / g_screenWidth;
+ float dv = 0.5f / g_screenHeight;
+ float u0 = du;
+ float u1 = 1.0f + du;
+ float v0 = dv;
+ float v1 = 1.0f + dv;
+ float drawverts[] =
+ { // x, y, z, u, v
+ -1, -1, 0, u0, v0,
+ -1, 1, 0, u0, v1,
+ 1, -1, 0, u1, v0,
+ 1, 1, 0, u1, v1,
+ };
+ g_dwDrawFVF = D3DFVF_XYZ | D3DFVF_TEX1;
+ g_nDrawStride = sizeof( drawverts ) / 4;
+
+ if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( drawverts ), D3DUSAGE_WRITEONLY, g_dwDrawFVF, D3DPOOL_MANAGED, &g_pDrawVB ) ) )
+ {
+ OutputDebugString( "CreateVertexBuffer( g_pDrawVB ) FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ BYTE* pDrawVBMem;
+ if ( FAILED( g_pDrawVB->Lock( 0, sizeof( drawverts ), &pDrawVBMem, 0 ) ) )
+ {
+ OutputDebugString( "g_pDrawVB->Lock FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+ memcpy( pDrawVBMem, drawverts, sizeof( drawverts ) );
+ g_pDrawVB->Unlock();
+
+ g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride );
+ g_pd3dDevice->SetVertexShader( g_dwDrawFVF );
+#ifdef BLUR
+ if ( blur )
+ {
+ float f = 2.0f / ( 2.0f + sqrt( 2.0f ) );
+ float ds = 2.0f * f / g_screenWidth;
+ float dt = 2.0f * f / g_screenHeight;
+ float s0 = ( 0.5f - f ) / g_screenWidth;
+ float s1 = 1.0f + s0;
+ float t0 = ( 0.5f - f ) / g_screenHeight;
+ float t1 = 1.0f + t0;
+ float blurverts[] =
+ { // x, y, z, u, v
+ -1, -1, 0, s0, t1, s0+ds, t1, s0, t1+dt, s0+ds, t1+dt,
+ -1, 1, 0, s0, t0, s0+ds, t0, s0, t0+dt, s0+ds, t0+dt,
+ 1, -1, 0, s1, t1, s1+ds, t1, s1, t1+dt, s1+ds, t1+dt,
+ 1, 1, 0, s1, t0, s1+ds, t0, s1, t0+dt, s1+ds, t0+dt,
+ };
+ g_dwBlurFVF = D3DFVF_XYZ | D3DFVF_TEX4;
+ g_nBlurStride = sizeof( blurverts ) / 4;
+
+ if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( blurverts ), D3DUSAGE_WRITEONLY, g_dwBlurFVF, D3DPOOL_MANAGED, &g_pBlurVB ) ) )
+ {
+ OutputDebugString( "CreateVertexBuffer( g_pBlurVB ) FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ BYTE* pBlurVBMem;
+ if ( FAILED( g_pBlurVB->Lock( 0, sizeof( blurverts ), &pBlurVBMem, 0 ) ) )
+ {
+ OutputDebugString( "g_pBlurVB->Lock FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+ memcpy( pBlurVBMem, blurverts, sizeof( blurverts ) );
+ g_pBlurVB->Unlock();
+ }
+#endif // BLUR
+
+ // create and fill texture
+ if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &g_pImg ) ) )
+ {
+ OutputDebugString( "CreateTexture( g_pImg ) FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ D3DLOCKED_RECT lockedRect;
+ if ( FAILED( g_pImg->LockRect( 0, &lockedRect, NULL, 0 ) ) )
+ {
+ OutputDebugString( "g_pImg->LockRect FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader );
+ bitmapInfo.bmiHeader.biWidth = g_screenWidth;
+ bitmapInfo.bmiHeader.biHeight = g_screenHeight;
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ if ( GetDIBits( g_hdcCapture, g_hbmCapture, 0, g_screenHeight, lockedRect.pBits, &bitmapInfo, DIB_RGB_COLORS ) != g_screenHeight )
+ {
+ OutputDebugString( "GetDIBits FAILED to get the full image!\n" );
+ }
+
+ g_pImg->UnlockRect( 0 );
+
+#ifdef BLUR
+ if ( blur )
+ {
+ if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTex ) ) )
+ {
+ OutputDebugString( "CreateTexture( g_pTex ) FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pRT ) ) )
+ {
+ OutputDebugString( "CreateTexture( g_pRT ) FAILED!\n" );
+ CleanupD3D();
+ return false;
+ }
+
+ IDirect3DSurface8 *pTexSurf = NULL;
+ g_pTex->GetSurfaceLevel( 0, &pTexSurf );
+ IDirect3DSurface8 *pImgSurf = NULL;
+ g_pImg->GetSurfaceLevel( 0, &pImgSurf );
+
+ RECT rect = { 0, 0, g_screenWidth, g_screenHeight };
+ POINT pt = { 0, 0 };
+ g_pd3dDevice->CopyRects( pImgSurf, &rect, 1, pTexSurf, &pt );
+
+ pTexSurf->Release();
+ pImgSurf->Release();
+ }
+#endif // BLUR
+
+ g_pd3dDevice->SetTexture( 0, g_pImg );
+
+ InitTextureStageState( 0, D3DTOP_MODULATE, D3DTA_TEXTURE, D3DTA_TFACTOR );
+#ifdef BLUR
+ if ( blur )
+ {
+ g_pd3dDevice->SetTexture( 0, g_pTex );
+// g_pd3dDevice->SetTexture( 1, g_pTex );
+// g_pd3dDevice->SetTexture( 2, g_pTex );
+// g_pd3dDevice->SetTexture( 3, g_pTex );
+
+ DWORD op = D3DTOP_DISABLE; // D3DTOP_MULTIPLYADD;
+ InitTextureStageState( 1, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
+ InitTextureStageState( 2, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
+ InitTextureStageState( 3, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
+ }
+#endif // BLUR
+
+ return true;
+}
+
+void DrawD3DFade( BYTE fade, bool blur )
+{
+ if ( g_pd3dDevice )
+ {
+#ifdef BLUR
+ if ( g_pTex )
+ {
+ if ( blur )
+ {
+ IDirect3DSurface8 *pRTSurf = NULL;
+ g_pRT->GetSurfaceLevel( 0, &pRTSurf );
+ g_pd3dDevice->SetRenderTarget( pRTSurf, NULL );
+
+ if ( g_pBackBuf )
+ {
+ g_pBackBuf->Release();
+ g_pBackBuf = NULL;
+ }
+
+ g_pd3dDevice->BeginScene();
+
+ g_pd3dDevice->SetTexture( 0, g_pTex );
+ g_pd3dDevice->SetTexture( 1, g_pTex );
+ g_pd3dDevice->SetTexture( 2, g_pTex );
+ g_pd3dDevice->SetTexture( 3, g_pTex );
+
+ g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
+ g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
+ g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
+
+ g_pd3dDevice->SetStreamSource( 0, g_pBlurVB, g_nBlurStride );
+ g_pd3dDevice->SetVertexShader( g_dwBlurFVF );
+
+ DWORD quarter = 0x3f | ( 0x3f << 8 ) | ( 0x3f << 16 ) | ( 0x3f << 24 );
+ g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, quarter );
+ g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
+
+ g_pd3dDevice->EndScene();
+
+ pRTSurf->Release();
+
+ g_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackBuf );
+ g_pd3dDevice->SetRenderTarget( g_pBackBuf, NULL );
+
+ IDirect3DTexture8 *pTemp = g_pTex;
+ g_pTex = g_pRT;
+ g_pRT = pTemp;
+
+ g_pd3dDevice->SetTexture( 0, g_pTex );
+ g_pd3dDevice->SetTexture( 1, NULL );
+ g_pd3dDevice->SetTexture( 2, NULL );
+ g_pd3dDevice->SetTexture( 3, NULL );
+
+ g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
+ g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
+ g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_DISABLE );
+
+ g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride );
+ g_pd3dDevice->SetVertexShader( g_dwDrawFVF );
+ }
+ }
+#endif
+
+ g_pd3dDevice->BeginScene();
+
+ // DWORD factor = 0xff | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 );
+ DWORD factor = fade | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 );
+ g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, factor );
+ g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
+
+ g_pd3dDevice->EndScene();
+ g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
+ }
+}
+
+#endif // USE_D3D8
+
+int g_nTimingIndex = 0;
+double g_timings[ 65536 ];
+
+LRESULT CALLBACK WinProc( HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+ switch ( msg )
+ {
+ case WM_CREATE:
+ {
+ g_timeAtFadeStart = 0.0;
+ g_nBlurSteps = 0;
+
+ g_hBlackFadingWindow = hWnd;
+
+#ifndef USE_D3D8
+ MONITORINFO mi;
+ mi.cbSize = sizeof( mi );
+ if ( GetMonitorInfo( g_hMonitor, &mi ) )
+ {
+ SetWindowPos( hWnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, 0 );
+ }
+#endif
+
+#ifdef USE_D3D8
+ InitD3D( hWnd, true );
+#endif // USE_D3D8
+ if ( !g_bFadeIn )
+ {
+ g_pFrame->ShowWindow( SW_HIDE );
+ g_pFrame->PostMessage( WM_DESTROY, 0, 0 );
+ }
+
+ InvalidateRect( hWnd, NULL, TRUE );
+
+ SetTimer( hWnd, ID_SKIP_FADE_TIMER, 1000, NULL ); // if the fade doesn't start in 1 second, then just jump to the video
+ SetTimer( hWnd, ID_DRAW_TIMER, 10, NULL ); // draw timer
+ }
+ break;
+
+#ifdef USE_D3D8
+ case WM_TIMER: // WM_ERASEBKGND:
+#else
+ case WM_TIMER: // WM_ERASEBKGND:
+// case WM_NCPAINT:
+#endif
+ if ( wparam == ID_DRAW_TIMER )
+ {
+ static LARGE_INTEGER s_nPerformanceFrequency;
+ if ( g_timeAtFadeStart == 0.0 )
+ {
+ LARGE_INTEGER nTimeAtFadeStart;
+ QueryPerformanceCounter( &nTimeAtFadeStart );
+ QueryPerformanceFrequency( &s_nPerformanceFrequency );
+ g_timeAtFadeStart = nTimeAtFadeStart.QuadPart / double( s_nPerformanceFrequency.QuadPart );
+
+ KillTimer( hWnd, ID_SKIP_FADE_TIMER );
+ SetTimer( hWnd, ID_SKIP_FADE_TIMER, 100 + UINT( FADE_TIME * 1000 ), NULL ); // restart skip fade timer and give it an extra 100ms to allow the fade to draw fully black once
+ }
+
+ LARGE_INTEGER time;
+ QueryPerformanceCounter( &time );
+ g_timings[ g_nTimingIndex++ ] = time.QuadPart / double( s_nPerformanceFrequency.QuadPart );
+ float dt = ( float )( time.QuadPart / double( s_nPerformanceFrequency.QuadPart ) - g_timeAtFadeStart );
+
+ bool bFadeFinished = dt >= FADE_TIME;
+ float fraction = bFadeFinished ? 1.0f : dt / FADE_TIME;
+/*
+ char str[ 256 ];
+ sprintf( str, "A - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" );
+ OutputDebugString( str );
+*/
+ bool blur = g_bFadeIn && ( int( fraction * MAX_BLUR_STEPS ) > g_nBlurSteps );
+ if ( blur )
+ {
+ ++g_nBlurSteps;
+ }
+
+ BYTE fade = BYTE( fraction * 255.999f );
+ if ( g_bFadeIn )
+ {
+ fade = 255 - fade;
+ }
+/*
+ char str[ 256 ];
+ sprintf( str, "fade = %d\n", fade );
+ OutputDebugString( str );
+*/
+#ifdef USE_D3D8
+ DrawD3DFade( fade, blur );
+#else // USE_D3D8
+// HDC hdc = GetDCEx( hWnd, ( HRGN )wparam, DCX_WINDOW | DCX_INTERSECTRGN );
+
+ if ( !PatBlt( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, BLACKNESS ) )
+ {
+ OutputDebugString( "PatBlt FAILED!\n" );
+ }
+
+// fade = 128;
+ BLENDFUNCTION blendfunc = { AC_SRC_OVER, 0, fade, 0 };
+ if ( !::AlphaBlend( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, blendfunc ) )
+ {
+ OutputDebugString( "AlphaBlend FAILED!\n" );
+ }
+
+ if ( !BitBlt( ( HDC )wparam, 0, 0, g_screenWidth, g_screenHeight, g_hdcBlend, 0, 0, SRCCOPY ) )
+ {
+ OutputDebugString( "BitBlt FAILED!\n" );
+ }
+
+// ReleaseDC( hWnd, hdc );
+// RedrawWindow( hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE );
+#endif // USE_D3D8
+/*
+// char str[ 256 ];
+ sprintf( str, "B - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" );
+ OutputDebugString( str );
+*/
+ if ( !bFadeFinished )
+ break;
+
+ // fall-through intentional
+// OutputDebugString( "Fall-through from erase background\n" );
+ }
+
+// case WM_TIMER:
+ {
+ if ( msg == WM_TIMER )
+ {
+/*
+ char str[ 256 ];
+ sprintf( str, "Timer 0x%x triggered for window 0x%x\n", wparam, hWnd );
+ OutputDebugString( str );
+*/
+ if ( wparam == ID_DRAW_TIMER )
+ {
+// UpdateWindow( hWnd );
+// InvalidateRect( hWnd, NULL, TRUE );
+// break;
+ }
+ }
+
+ KillTimer( hWnd, ID_SKIP_FADE_TIMER );
+ KillTimer( hWnd, ID_DRAW_TIMER );
+
+ if ( !g_bFadeIn )
+ {
+// OutputDebugString( "closing fade window\n" );
+ ShowWindow( hWnd, SW_HIDE );
+ PostMessage( hWnd, WM_CLOSE, 0, 0 );
+ return 1;
+ }
+ else if ( !g_bFrameCreated )
+ {
+ g_bFrameCreated = true;
+#ifdef USE_D3D8
+// OutputDebugString( "Cleanup D3D\n" );
+ CleanupD3D();
+#endif
+ g_pFrame = &g_frame;
+ g_pFrame->GetWndClassInfo().m_wc.hIcon = LoadIcon( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDI_ICON ) );
+ RECT rcPos = { CW_USEDEFAULT, 0, 0, 0 };
+
+// OutputDebugString( "Create WMP frame\n" );
+
+ if ( g_osVersion < OSV_XP )
+ {
+ g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW, 0, ( UINT )0 );
+ }
+ else
+ {
+ g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, ( UINT )0 );
+
+ g_pFrame->ShowWindow( SW_SHOW );
+ }
+
+// OutputDebugString( "Create WMP frame - done\n" );
+ }
+
+ // close WMP window once we paint the fullscreen fade window
+ if ( !g_bFadeIn )
+ {
+ g_pFrame->ShowWindow( SW_HIDE );
+ }
+ }
+ return 1;
+
+ case WM_KEYDOWN:
+ if ( wparam == VK_ESCAPE )
+ {
+ ::DestroyWindow( hWnd );
+ }
+ break;
+
+ case WM_DESTROY:
+ g_hBlackFadingWindow = NULL;
+
+#ifdef USE_D3D8
+ CleanupD3D();
+#endif
+
+ if ( g_bFrameCreated )
+ {
+ g_bFrameCreated = false;
+
+ g_pFrame->DestroyWindow();
+ g_pFrame = NULL;
+ }
+
+ ::PostQuitMessage( 0 );
+ break;
+ }
+
+ return DefWindowProc( hWnd, msg, wparam, lparam );
+}
+
+bool ShowFadeWindow( bool bShow )
+{
+ if ( bShow )
+ {
+ g_timeAtFadeStart = 0.0;
+ g_bFadeIn = false;
+
+ SetTimer( g_hBlackFadingWindow, ID_DRAW_TIMER, 10, NULL );
+
+ if ( g_pFrame )
+ {
+ g_pFrame->ShowWindow( SW_HIDE );
+ }
+#ifdef USE_D3D8
+ if ( g_osVersion < OSV_XP )
+ {
+ ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
+ }
+ InitD3D( g_hBlackFadingWindow, false );
+#else // USE_D3D8
+ ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
+// ::ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
+#endif // USE_D3D8
+ InvalidateRect( g_hBlackFadingWindow, NULL, TRUE );
+ }
+ else
+ {
+ if ( g_osVersion < OSV_XP )
+ {
+// OutputDebugString( "hiding fade window\n" );
+ ShowWindow( g_hBlackFadingWindow, SW_HIDE );
+ }
+ else
+ {
+// OutputDebugString( "Deferring erase on fade window\n" );
+ ::SetWindowPos( g_hBlackFadingWindow, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_DEFERERASE );
+ }
+ }
+ return true;
+}
+
+HWND CreateFullscreenWindow( bool bFadeIn )
+{
+ if ( g_hBlackFadingWindow )
+ return g_hBlackFadingWindow;
+
+ static s_bRegistered = false;
+ if ( !s_bRegistered )
+ {
+ WNDCLASS wc;
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = ( WNDPROC )WinProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = g_hInstance;
+ wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "myclass";
+
+ if ( !RegisterClass( &wc ) )
+ return 0;
+
+ s_bRegistered = true;
+ }
+
+ g_bFadeIn = bFadeIn;
+ DWORD windowStyle = WS_POPUP;
+#ifndef USE_D3D8
+ windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE;
+#endif
+ if ( g_osVersion < OSV_XP )
+ {
+ windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE;
+ }
+
+ MONITORINFO mi;
+ mi.cbSize = sizeof( mi );
+ if ( !GetMonitorInfo( g_hMonitor, &mi ) )
+ {
+ GetClientRect( GetDesktopWindow(), &mi.rcMonitor );
+ }
+
+ g_hBlackFadingWindow = CreateWindow( "myclass", _T( "Steam Media Player" ), windowStyle, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, NULL, NULL, g_hInstance, NULL );
+#ifndef USE_D3D8
+ ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
+#endif
+ if ( g_osVersion < OSV_XP )
+ {
+ ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
+ }
+
+ while ( ShowCursor( FALSE ) >= 0 )
+ ;
+
+ return g_hBlackFadingWindow;
+}
+
+bool CreateDesktopBitmaps()
+{
+ MONITORINFOEX mi;
+ mi.cbSize = sizeof( mi );
+ if ( !GetMonitorInfo( g_hMonitor, &mi ) )
+ return false;
+
+ g_screenWidth = mi.rcMonitor.right - mi.rcMonitor.left;
+ g_screenHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
+
+ HDC hdcScreen = CreateDC( mi.szDevice, mi.szDevice, NULL, NULL );
+ if ( !hdcScreen )
+ return false;
+
+ g_hdcCapture = CreateCompatibleDC( hdcScreen );
+ g_hdcBlend = CreateCompatibleDC( hdcScreen );
+ if ( !g_hdcCapture || !g_hdcBlend )
+ return false;
+
+ if ( ( GetDeviceCaps( hdcScreen, SHADEBLENDCAPS ) & SB_CONST_ALPHA ) == 0 )
+ {
+ OutputDebugString( "display doesn't support AlphaBlend!\n" );
+ }
+
+ if ( ( GetDeviceCaps( hdcScreen, RASTERCAPS ) & RC_BITBLT ) == 0 )
+ {
+ OutputDebugString( "display doesn't support BitBlt!\n" );
+ }
+
+ if ( GetDeviceCaps( hdcScreen, BITSPIXEL ) < 32 )
+ {
+ OutputDebugString( "display doesn't support 32bpp!\n" );
+ }
+
+ if ( g_screenWidth != GetDeviceCaps( hdcScreen, HORZRES ) ||
+ g_screenHeight != GetDeviceCaps( hdcScreen, VERTRES ) )
+ {
+ OutputDebugString( "Screen DC size differs from monitor size!\n" );
+ }
+
+ g_hbmCapture = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight );
+ g_hbmBlend = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight );
+ if ( !g_hbmCapture || !g_hbmBlend )
+ return false;
+
+ HGDIOBJ oldCaptureObject = SelectObject( g_hdcCapture, g_hbmCapture );
+ HGDIOBJ oldBlendObject = SelectObject( g_hdcBlend, g_hbmBlend );
+
+ if ( !BitBlt( g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, hdcScreen, 0, 0, SRCCOPY ) )
+ return false;
+
+ SelectObject( g_hdcCapture, oldCaptureObject );
+ SelectObject( g_hdcBlend, oldBlendObject );
+
+ return true;
+}
+
+void PrintLastError( const char *pPrefix )
+{
+#ifdef _DEBUG
+ DWORD dw = GetLastError();
+
+ LPVOID lpMsgBuf;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, dw, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+ ( LPTSTR )&lpMsgBuf, 0, NULL );
+
+ OutputDebugString( pPrefix );
+ char msg[ 256 ];
+ sprintf( msg, "(%d) ", dw );
+ OutputDebugString( msg );
+ OutputDebugString( ( char * )lpMsgBuf );
+
+ LocalFree( lpMsgBuf );
+#endif
+}
+
+void KillOtherSMPs()
+{
+ DWORD nBytesReturned = 0;
+ DWORD procIds[ 1024 ];
+ if ( !EnumProcesses( procIds, sizeof( procIds ), &nBytesReturned ) )
+ {
+ PrintLastError( "EnumProcesses Error: " );
+ return;
+ }
+
+ DWORD dwCurrentProcessId = GetCurrentProcessId();
+
+ int nProcIds = nBytesReturned / sizeof( DWORD );
+ for ( int i = 0; i < nProcIds; ++i )
+ {
+ if ( procIds[ i ] == dwCurrentProcessId )
+ continue;
+
+ if ( procIds[ i ] == 0 ) // system idle process
+ continue;
+
+ HANDLE hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, procIds[ i ] );
+ if ( !hProcess )
+ {
+ PrintLastError( "OpenProcess Error: " );
+ continue;
+ }
+
+ HMODULE hMod[ 1 ];
+ DWORD cbNeeded;
+ if ( !EnumProcessModules( hProcess, hMod, sizeof( hMod ), &cbNeeded ) )
+ {
+ PrintLastError( "EnumProcessModules Error: " );
+ continue;
+ }
+
+ char processName[ 1024 ];
+ int nChars = GetModuleBaseName( hProcess, hMod[ 0 ], processName, sizeof( processName ) / sizeof( char ) );
+ if ( nChars >= sizeof( processName ) )
+ {
+ PrintLastError( "GetModuleBaseName Error: " );
+ continue;
+ }
+
+ if ( strcmp( processName, "smp.exe" ) == 0 )
+ {
+ OutputDebugString( "!!! Killing smp.exe !!!\n" );
+ TerminateProcess( hProcess, 0 );
+ }
+
+ if ( !CloseHandle( hProcess ) )
+ {
+ PrintLastError( "CloseHandle Error: " );
+ continue;
+ }
+ }
+}
+
+void ParseCommandLine( const char *cmdline, std::vector< std::string > &params )
+{
+ params.push_back( "" );
+
+ bool quoted = false;
+ for ( const char *cp = cmdline; *cp; ++cp )
+ {
+ if ( *cp == '\"' )
+ {
+ quoted = !quoted;
+ }
+ else if ( isspace( *cp ) && !quoted )
+ {
+ if ( !params.back().empty() )
+ {
+ params.push_back( "" );
+ }
+ }
+ else
+ {
+ params.back().push_back( *cp );
+ }
+ }
+
+ if ( params.back().empty() )
+ {
+ params.pop_back();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+extern "C" int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/ )
+{
+ g_hInstance = hInstance;
+
+ KillOtherSMPs();
+
+ g_lpCommandLine = lpCmdLine;
+ if ( lpCmdLine == NULL || *lpCmdLine == '\0' )
+ return 0;
+
+ std::vector< std::string > params;
+ ParseCommandLine( lpCmdLine, params );
+ int nParams = params.size();
+ for ( int i = 0; i < nParams; ++i )
+ {
+ if ( params[ i ][ 0 ] == '-' || params[ i ][ 0 ] == '/' )
+ {
+ const char *pOption = params[ i ].c_str() + 1;
+ if ( strcmp( pOption, "reportstats" ) == 0 )
+ {
+ g_bReportStats = true;
+ }
+ else if ( strcmp( pOption, "localsteamserver" ) == 0 )
+ {
+ g_bUseLocalSteamServer = true;
+ }
+ else if ( strcmp( pOption, "redirect" ) == 0 )
+ {
+ ++i;
+ g_redirectTarget = params[ i ];
+ }
+ }
+ else
+ {
+ g_URL = params[ i ];
+ }
+ }
+
+ SetRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", 0, g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists );
+ atexit( RestoreRegistry );
+
+ LogPlayerEvent( ET_APPLAUNCH, 0.0f );
+
+ lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
+
+ CoInitialize( 0 );
+ _Module.Init( ObjectMap, hInstance, &LIBID_ATLLib );
+
+ ::InitCommonControls();
+
+ POINT pt;
+ GetCursorPos( &pt );
+ g_hMonitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
+
+ if ( !CreateDesktopBitmaps() )
+ {
+ OutputDebugString( "CreateDesktopBitmaps FAILED!\n" );
+ }
+
+ ShowCursor( FALSE );
+ CreateFullscreenWindow( true );
+
+ MSG msg;
+ while ( GetMessage( &msg, 0, 0, 0 ) )
+ {
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+
+ LogPlayerEvent( ET_APPEXIT );
+ if ( g_bReportStats )
+ {
+ UploadStats();
+ }
+
+ if ( !g_redirectTarget.empty() )
+ {
+ ::ShellExecuteA( NULL, "open", g_redirectTarget.c_str(), NULL, NULL, SW_SHOWNORMAL );
+ }
+
+ _Module.Term();
+ CoUninitialize();
+
+ RestoreRegistry();
+
+ return 0;
+}