You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1441 lines
36 KiB
1441 lines
36 KiB
//========= 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 > ¶ms ) |
|
{ |
|
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; |
|
}
|
|
|