Files
itgmania212121/stepmania/src/StepMania.cpp
T
Chris Danford 044ac127da no message
2002-03-06 08:25:09 +00:00

777 lines
20 KiB
C++

#include "stdafx.h"
/*
-----------------------------------------------------------------------------
File: StepMania.cpp
Desc:
Copyright (c) 2001 Chris Danford. All rights reserved.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "resource.h"
#include "RageScreen.h"
#include "RageTextureManager.h"
#include "RageSound.h"
#include "RageMusic.h"
#include "RageInput.h"
#include "PrefsManager.h"
#include "SongManager.h"
#include "ThemeManager.h"
#include "WindowManager.h"
#include "WindowSandbox.h"
#include "WindowLoading.h"
#include "WindowMenuResults.h"
#include "WindowTitleMenu.h"
#include "WindowPlayerOptions.h"
#include "ScreenDimensions.h"
#include "DXUtil.h"
#include <Afxdisp.h>
//-----------------------------------------------------------------------------
// Links
//-----------------------------------------------------------------------------
#pragma comment(lib, "d3dx8.lib")
#pragma comment(lib, "d3d8.lib")
//-----------------------------------------------------------------------------
// Application globals
//-----------------------------------------------------------------------------
const CString g_sAppName = "StepMania";
const CString g_sAppClassName = "StepMania Class";
HWND g_hWndMain; // Main Window Handle
HINSTANCE g_hInstance; // The Handle to Window Instance
HANDLE g_hMutex; // Used to check if an instance of our app is already
const DWORD g_dwWindowStyle = WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU;
BOOL g_bIsActive = FALSE; // Whether the focus is on our app
//LPRageMovieTexture g_pMovieTexture = NULL;
//-----------------------------------------------------------------------------
// Function prototypes
//-----------------------------------------------------------------------------
// Main game functions
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
BOOL CALLBACK ErrorWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
void Update(); // Update the game logic
void Render(); // Render a frame
void ShowFrame(); // Display the contents of the back buffer to the screen
// Functions that work with game objects
HRESULT CreateObjects( HWND hWnd ); // allocate and initialize game objects
HRESULT InvalidateObjects(); // invalidate game objects before a display mode change
HRESULT RestoreObjects(); // restore game objects after a display mode change
VOID DestroyObjects(); // deallocate game objects when we're done with them
BOOL SwitchDisplayMode();// BOOL bWindowed, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP );
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Application entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
{
AfxEnableControlContainer();
#ifndef DEBUG // don't use error handler in Release mode
try
{
#endif
// Check to see if the app is already running.
g_hMutex = CreateMutex( NULL, TRUE, g_sAppName );
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
CloseHandle( g_hMutex );
RageError( "StepMania is already running!" );
}
// Make sure the current directory is the root program directory
if( !DoesFileExist("Songs") )
{
// change dir to path of the execuctable
TCHAR szFullAppPath[MAX_PATH];
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
// strip off executable name
LPSTR pLastBackslash = strrchr(szFullAppPath, '\\');
*pLastBackslash = '\0'; // terminate the string
SetCurrentDirectory(szFullAppPath);
}
CoInitialize (NULL); // Initialize COM
// Register the window class
WNDCLASS wndClass = {
0,
WndProc, // callback handler
0, // cbClsExtra;
0, // cbWndExtra;
hInstance,
LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON) ),
LoadCursor( hInstance, IDC_ARROW),
(HBRUSH)GetStockObject( BLACK_BRUSH ),
NULL, // lpszMenuName;
g_sAppClassName // lpszClassName;
};
RegisterClass( &wndClass );
// Set the window's initial width
RECT rcWnd;
SetRect( &rcWnd, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
AdjustWindowRect( &rcWnd, g_dwWindowStyle, FALSE );
// Create our main window
g_hWndMain = CreateWindow(
g_sAppClassName,// pointer to registered class name
g_sAppName, // pointer to window name
g_dwWindowStyle, // window style
CW_USEDEFAULT, // horizontal position of window
CW_USEDEFAULT, // vertical position of window
RECTWIDTH(rcWnd), // window width
RECTHEIGHT(rcWnd),// window height
NULL, // handle to parent or owner window
NULL, // handle to menu, or child-window identifier
hInstance, // handle to application instance
NULL // pointer to window-creation data
);
if( NULL == g_hWndMain )
exit(1);
// Load keyboard accelerators
HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
// run the game
CreateObjects( g_hWndMain ); // Create the game objects
// Now we're ready to recieve and process Windows messages.
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( WM_QUIT != msg.message )
{
// Look for messages, if none are found then
// update the state and display it
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
GetMessage(&msg, NULL, 0, 0 );
// Translate and dispatch the message
if( 0 == TranslateAccelerator( g_hWndMain, hAccel, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else // No messages are waiting. Render a frame during idle time.
{
Update();
Render();
//if( !g_bFullscreen )
::Sleep(0 ); // give some time for the movie decoding thread
}
} // end while( WM_QUIT != msg.message )
// clean up after a normal exit
CloseHandle( g_hMutex );
DestroyObjects(); // deallocate our game objects and leave fullscreen
DestroyWindow( g_hWndMain );
UnregisterClass( g_sAppClassName, hInstance );
CoUninitialize(); // Uninitialize COM
#ifndef DEBUG // only use pretty error handler in RELEASE build
}
catch(...) // catch all exceptions
{
CloseHandle( g_hMutex );
DestroyObjects(); // deallocate our game objects and leave fullscreen
ShowWindow( g_hWndMain, SW_HIDE );
// throw up a pretty error dialog
DialogBox(
hInstance,
MAKEINTRESOURCE(IDD_ERROR_DIALOG),
NULL,
ErrorWndProc
);
exit( 1 );
}
#endif
return 0L;
}
//-----------------------------------------------------------------------------
// Name: ErrorWndProc()
// Desc: Callback for all Windows messages
//-----------------------------------------------------------------------------
BOOL CALLBACK ErrorWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
{
CString sError;
CStdioFile file;
if( file.Open("error.txt", CFile::modeRead) )
{
CString sBuffer;
while( file.ReadString(sBuffer) )
{
sError += sBuffer + "\r\n";
}
}
sError.TrimRight();
if( sError == "" )
sError = "Program Crash. Click 'View Log' for trace.";
SendDlgItemMessage(
hWnd,
IDC_EDIT_ERROR,
WM_SETTEXT,
0,
(LPARAM)(LPCTSTR)sError
);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BUTTON_VIEW_LOG:
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
CreateProcess(
NULL, // pointer to name of executable module
"notepad.exe log.txt", // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
false, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
}
break;
case IDC_BUTTON_REPORT:
GotoURL( "Docs/report.htm" );
break;
case IDC_BUTTON_RESTART:
{
// Launch StepMania
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
CreateProcess(
NULL, // pointer to name of executable module
"stepmania.exe", // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
false, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
}
EndDialog( hWnd, 0 );
break;
// fall through
case IDOK:
EndDialog( hWnd, 0 );
break;
}
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: WndProc()
// Desc: Callback for all Windows messages
//-----------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_ACTIVATEAPP:
// Check to see if we are losing our window...
g_bIsActive = (BOOL)wParam;
break;
case WM_SIZE:
// Check to see if we are losing our window...
if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
g_bIsActive = FALSE;
else
g_bIsActive = TRUE;
break;
case WM_GETMINMAXINFO:
{
// Don't allow the window to be resized smaller than the screen resolution.
// This should snap to multiples of the screen size two!
RECT rcWnd;
SetRect( &rcWnd, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
DWORD dwWindowStyle = GetWindowLong( g_hWndMain, GWL_STYLE );
AdjustWindowRect( &rcWnd, dwWindowStyle, FALSE );
((MINMAXINFO*)lParam)->ptMinTrackSize.x = RECTWIDTH(rcWnd);
((MINMAXINFO*)lParam)->ptMinTrackSize.y = RECTHEIGHT(rcWnd);
}
break;
case WM_SETCURSOR:
// Turn off Windows cursor in fullscreen mode
if( SCREEN && !SCREEN->IsWindowed() )
{
SetCursor( NULL );
return TRUE; // prevent Windows from setting the cursor
}
break;
case WM_SYSCOMMAND:
// Prevent moving/sizing and power loss
switch( wParam )
{
case SC_MOVE:
case SC_SIZE:
case SC_KEYMENU:
case SC_MONITORPOWER:
return 1;
case SC_MAXIMIZE:
//SendMessage( g_hWndMain, WM_COMMAND, IDM_TOGGLEFULLSCREEN, 0 );
//return 1;
break;
}
break;
case WM_COMMAND:
{
GameOptions &go = PREFS->m_GameOptions;
switch( LOWORD(wParam) )
{
case IDM_TOGGLEFULLSCREEN:
go.m_bWindowed = !go.m_bWindowed;
SwitchDisplayMode();// !SCREEN->IsWindowed(), SCREEN_WIDTH, SCREEN_HEIGHT, 16 );
return 0;
case IDM_CHANGERESOLUTION:
go.m_iResolution = (go.m_iResolution==640) ? 320 : 640;
SwitchDisplayMode();
return 0;
case IDM_CHANGEDISPLAYCOLOR:
go.m_iDisplayColor = (go.m_iDisplayColor==16) ? 32 : 16;
SwitchDisplayMode();
return 0;
case IDM_CHANGETEXTURECOLOR:
go.m_iTextureColor = (go.m_iTextureColor==16) ? 32 : 16;
SwitchDisplayMode();
return 0;
case IDM_TOGGLESTATISTICS:
go.m_bShowFPS = !go.m_bShowFPS;
SwitchDisplayMode();
return 0;
case IDM_EXIT:
// Recieved key/menu command to exit app
SendMessage( hWnd, WM_CLOSE, 0, 0 );
return 0;
}
break;
}
case WM_NCHITTEST:
// Prevent the user from selecting the menu in fullscreen mode
if( SCREEN && !SCREEN->IsWindowed() )
return HTCLIENT;
break;
case WM_PAINT:
// redisplay the contents of the back buffer if the window needs to be redrawn
ShowFrame();
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: CreateObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CreateObjects( HWND hWnd )
{
////////////////////////////////
// Draw a splash bitmap so the user isn't looking at a black screen
////////////////////////////////
HBITMAP hSplashBitmap = (HBITMAP)LoadImage(
GetModuleHandle( NULL ),
TEXT("SPLASH"),
IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION );
BITMAP bmp;
RECT rc;
GetClientRect( hWnd, &rc );
// Display the splash bitmap in the window
HDC hDCWindow = GetDC( hWnd );
HDC hDCImage = CreateCompatibleDC( NULL );
SelectObject( hDCImage, hSplashBitmap );
GetObject( hSplashBitmap, sizeof(bmp), &bmp );
StretchBlt( hDCWindow, 0, 0, rc.right, rc.bottom,
hDCImage, 0, 0,
bmp.bmWidth, bmp.bmHeight, SRCCOPY );
DeleteDC( hDCImage );
ReleaseDC( hWnd, hDCWindow );
// Delete the bitmap
DeleteObject( hSplashBitmap );
/////////////////////////////////
// Create game objects
/////////////////////////////////
srand( (unsigned)time(NULL) ); // seed number generator
RageLogStart();
SOUND = new RageSound( hWnd );
MUSIC = new RageSoundStream;
INPUT = new RageInput( hWnd );
PREFS = new PrefsManager;
SONGS = new SongManager;
SCREEN = new RageScreen( hWnd );
BringWindowToTop( hWnd );
SetForegroundWindow( hWnd );
// switch the screen resolution according to user's prefs
SwitchDisplayMode();
// go.m_bWindowed,
// go.m_iResolution,
// go.m_iResolution==640 ? 480 : 240,
// go.m_iDisplayColor
// );
TM = new RageTextureManager( SCREEN );
THEME = new ThemeManager;
WM = new WindowManager;
// Ugly... Switch the screen resolution again so that the system message will display
SwitchDisplayMode();
// go.m_bWindowed,
// go.m_iResolution,
// go.m_iResolution==640 ? 480 : 240,
// go.m_iDisplayColor
// );
WM->SystemMessage( ssprintf("Found %d songs.", SONGS->m_pSongs.GetSize()) );
//WM->SetNewWindow( new WindowLoading );
//WM->SetNewWindow( new WindowSandbox );
//WM->SetNewWindow( new WindowMenuResults );
//WM->SetNewWindow( new WindowPlayerOptions );
WM->SetNewWindow( new WindowTitleMenu );
DXUtil_Timer( TIMER_START ); // Start the accurate timer
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DestroyObjects()
// Desc:
//-----------------------------------------------------------------------------
void DestroyObjects()
{
DXUtil_Timer( TIMER_STOP );
SAFE_DELETE( WM );
SAFE_DELETE( PREFS );
SAFE_DELETE( SONGS );
SAFE_DELETE( INPUT );
SAFE_DELETE( MUSIC );
SAFE_DELETE( SOUND );
SAFE_DELETE( TM );
SAFE_DELETE( SCREEN );
}
//-----------------------------------------------------------------------------
// Name: RestoreObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT RestoreObjects()
{
/////////////////////
// Restore the window
/////////////////////
// Set window size
RECT rcWnd;
if( SCREEN->IsWindowed() )
{
SetRect( &rcWnd, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
AdjustWindowRect( &rcWnd, g_dwWindowStyle, FALSE );
}
else // if fullscreen
{
SetRect( &rcWnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) );
}
// Bring the window to the foreground
SetWindowPos( g_hWndMain,
HWND_NOTOPMOST,
0,
0,
RECTWIDTH(rcWnd),
RECTHEIGHT(rcWnd),
0 );
///////////////////////////
// Restore all game objects
///////////////////////////
SCREEN->Restore();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InvalidateObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT InvalidateObjects()
{
SCREEN->Invalidate();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Update()
// Desc:
//-----------------------------------------------------------------------------
void Update()
{
float fDeltaTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
// This was a hack to fix timing issues with the old WindowSelectSong
//
if( fDeltaTime > 0.050f ) // we dropped > 5 frames
fDeltaTime = 0.050f;
MUSIC->Update( fDeltaTime );
WM->Update( fDeltaTime );
static DeviceInputArray diArray;
diArray.RemoveAll();
INPUT->GetDeviceInputs( diArray );
DeviceInput DeviceI;
PadInput PadI;
PlayerInput PlayerI;
for( int i=0; i<diArray.GetSize(); i++ )
{
DeviceI = diArray[i];
PREFS->DeviceToPad( DeviceI, PadI );
PREFS->PadToPlayer( PadI, PlayerI );
WM->Input( DeviceI, PadI, PlayerI );
}
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc:
//-----------------------------------------------------------------------------
void Render()
{
HRESULT hr = SCREEN->BeginFrame();
switch( hr )
{
case D3DERR_DEVICELOST:
// The user probably alt-tabbed out of fullscreen.
// Do not render a frame until we re-acquire the device
break;
case D3DERR_DEVICENOTRESET:
InvalidateObjects();
// Resize the device
if( SUCCEEDED( hr = SCREEN->Reset() ) )
{
// Initialize the app's device-dependent objects
RestoreObjects();
return;
}
else
{
RageErrorHr( "Failed to SCREEN->Reset()", hr );
}
break;
case S_OK:
{
// set texture and alpha properties
LPDIRECT3DDEVICE8 pd3dDevice = SCREEN->GetDevice();
// calculate view and projection transforms
D3DXMATRIX matProj;
D3DXMatrixOrthoOffCenterLH( &matProj, 0, 640, 480, 0, -100, 100 );
pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
D3DXMATRIX matView;
D3DXMatrixIdentity( &matView );
pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
SCREEN->ResetMatrixStack();
// draw the game
WM->Draw();
SCREEN->EndFrame();
}
break;
}
ShowFrame();
}
//-----------------------------------------------------------------------------
// Name: ShowFrame()
// Desc:
//-----------------------------------------------------------------------------
void ShowFrame()
{
// display the contents of the back buffer to the front
if( SCREEN )
SCREEN->ShowFrame();
}
//-----------------------------------------------------------------------------
// Name: SwitchDisplayMode()
// Desc:
//-----------------------------------------------------------------------------
BOOL SwitchDisplayMode()//( BOOL bWindowed, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP )
{
InvalidateObjects();
// use GameOptions to get the display settings
GameOptions &go = PREFS->m_GameOptions;
bool bWindowed = go.m_bWindowed;
DWORD dwWidth = go.m_iResolution;
DWORD dwHeight = go.m_iResolution==640 ? 480 : 240;
DWORD dwBPP = go.m_iDisplayColor;
// If the requested resolution doesn't work, keep switching until we find one that does.
if( !SCREEN->SwitchDisplayMode( bWindowed, dwWidth, dwHeight, dwBPP ) )
{
// We failed. Try full screen with same params.
bWindowed = false;
if( !SCREEN->SwitchDisplayMode( bWindowed, dwWidth, dwHeight, dwBPP ) )
{
// Failed again. Try 16 BPP
dwBPP = 16;
if( !SCREEN->SwitchDisplayMode( bWindowed, dwWidth, dwHeight, dwBPP ) )
{
// Failed again. Try 640x480
dwWidth = 640;
dwHeight = 480;
if( !SCREEN->SwitchDisplayMode( bWindowed, dwWidth, dwHeight, dwBPP ) )
{
// Failed again. Try 640x480
dwWidth = 320;
dwHeight = 240;
if( !SCREEN->SwitchDisplayMode( bWindowed, dwWidth, dwHeight, dwBPP ) )
{
RageError( "Tried every possible display mode, and couldn't change to any of them." );
return false;
}
}
}
}
}
RestoreObjects();
if( PREFS )
{
PREFS->m_GameOptions.m_bWindowed = bWindowed;
PREFS->m_GameOptions.m_iDisplayColor = dwBPP;
PREFS->m_GameOptions.m_iResolution = dwWidth;
PREFS->SavePrefsToDisk();
}
if( WM )
{
WM->SystemMessage( ssprintf("%s - %ux%u - %u bits", bWindowed ? "Windowed" : "FullScreen", dwWidth, dwHeight, dwBPP) );
}
return true;
}