-
Notifications
You must be signed in to change notification settings - Fork 0
/
WinMain.cpp
385 lines (329 loc) · 10.4 KB
/
WinMain.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
//////////////////////////////////////////////////////////////////////////////////////////////
// File : "WinMain.cpp"
//
// Author : David Brown (DB)
// Based in part on:
// -Window code from the book: "Physics for Game Developers" by David M. Bourg.
// -The previous WinMain.cpp by Jensen Rivera.
//
// Last Modified : 3/31/2009
//
// Purpose : To provide a basic window framework for student games.
//
//////////////////////////////////////////////////////////////////////////////////////////////
#include <windows.h> // Needed for Windows Applications.
// #define VLD_AGGREGATE_DUPLICATES
// #define VLD_MAX_DATA_DUMP 0
// #include <vld.h>
#include "CGame.h"
void ToggleFullscreenMode(HWND hWnd,
int iWidth, int iHeight, int iBpp, int iRefreshRate);
void SetDisplayMode(int iWidth, int iHeight, int iBpp, int iRefreshRate);
const char* g_szWINDOW_CLASS_NAME = "SGDWindowClass"; // Window Class Name.
const char* g_szWINDOW_TITLE = "Tile Engine Test"; // Window Title.
const int g_nWINDOW_WIDTH = 1024; // Window Width.
const int g_nWINDOW_HEIGHT = 768; // Window Height.
POINT mouse;
// Windowed or Full screen depending on project setting
#ifdef _DEBUG
const BOOL g_bIS_WINDOWED = TRUE;
#else
const BOOL g_bIS_WINDOWED = FALSE;
#endif
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// This is the main message handler of the system.
PAINTSTRUCT ps; // Used in WM_PAINT.
HDC hdc; // Handle to a device context.
// What is the message
switch(msg)
{
// To skip ALT pop up menu (system menu)
case WM_SYSKEYUP:
case WM_SYSCHAR:
return(0);
break;
// Handle ALT+F4
case WM_CLOSE:
{
// Sends us a WM_DESTROY
DestroyWindow(hWnd);
}
break;
case WM_MOUSEMOVE:
{
mouse.x = LOWORD(lParam);
mouse.y = HIWORD(lParam);
}
// and lose/gain focus
case WM_ACTIVATE:
{
// gaining focus
if (LOWORD(wParam) != WA_INACTIVE)
{
// unpause game code here
}
else // losing focus
{
// pause game code here
}
}
break;
case WM_CREATE:
{
// Do initialization here
return(0);
}
break;
case WM_PAINT:
{
// Start painting
hdc = BeginPaint(hWnd,&ps);
// End painting
EndPaint(hWnd,&ps);
return(0);
}
break;
case WM_DESTROY:
{
// Kill the application
PostQuitMessage(0);
return(0);
}
break;
default:
break;
}
// Process any messages that we didn't take care of
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
// Checks to see if the game was already running in another window.
//
// NOTE: Don't call this function if your game needs to have more
// than one instance running on the same computer (i.e. client/server)
BOOL CheckIfAlreadyRunning(void)
{
// Find a window of the same window class name and window title
HWND hWnd = FindWindow(g_szWINDOW_CLASS_NAME, g_szWINDOW_TITLE);
// If one was found
if (hWnd)
{
// If it was minimized
if (IsIconic(hWnd))
// restore it
ShowWindow(hWnd, SW_RESTORE);
// Bring it to the front
SetForegroundWindow(hWnd);
return TRUE;
}
// No other copies found running
return FALSE;
}
BOOL RegisterWindowClass(HINSTANCE hInstance)
{
WNDCLASSEX winClassEx; // This will describe the window class we will create.
// First fill in the window class structure
winClassEx.cbSize = sizeof(winClassEx);
winClassEx.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winClassEx.lpfnWndProc = WindowProc;
winClassEx.cbClsExtra = 0;
winClassEx.cbWndExtra = 0;
winClassEx.hInstance = hInstance;
winClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winClassEx.hIconSm = NULL;
winClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
winClassEx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClassEx.lpszMenuName = NULL;
winClassEx.lpszClassName = g_szWINDOW_CLASS_NAME;
mouse.x = 0;
mouse.y = 0;
// Register the window class
return RegisterClassEx(&winClassEx);
}
// Creates and sizes the window appropriately depending on if
// the application is windowed or full screen.
HWND MakeWindow(HINSTANCE hInstance)
{
// Setup window style flags
DWORD dwWindowStyleFlags = WS_VISIBLE;
if (g_bIS_WINDOWED)
{
dwWindowStyleFlags |= WS_OVERLAPPEDWINDOW;
}
else
{
dwWindowStyleFlags |= WS_POPUP;
ShowCursor(FALSE); // Stop showing the mouse cursor
}
// Setup the desired client area size
RECT rWindow;
rWindow.left = 0;
rWindow.top = 0;
rWindow.right = g_nWINDOW_WIDTH;
rWindow.bottom = g_nWINDOW_HEIGHT;
// Get the dimensions of a window that will have a client rect that
// will really be the resolution we're looking for.
AdjustWindowRectEx(&rWindow,
dwWindowStyleFlags,
FALSE,
WS_EX_APPWINDOW);
// Calculate the width/height of that window's dimensions
int nWindowWidth = rWindow.right - rWindow.left;
int nWindowHeight = rWindow.bottom - rWindow.top;
// Create the window
return CreateWindowEx(WS_EX_APPWINDOW, // Extended Style flags.
g_szWINDOW_CLASS_NAME, // Window Class Name.
g_szWINDOW_TITLE, // Title of the Window.
dwWindowStyleFlags, // Window Style Flags.
(GetSystemMetrics(SM_CXSCREEN)/2) - (nWindowWidth/2), // Window Start Point (x, y).
(GetSystemMetrics(SM_CYSCREEN)/2) - (nWindowHeight/2), // -Does the math to center the window over the desktop.
nWindowWidth, // Width of Window.
nWindowHeight, // Height of Window.
NULL, // Handle to parent window.
NULL, // Handle to menu.
hInstance, // Application Instance.
NULL); // Creation parameters.
}
//////////////////////////
// WinMain //
//////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; // Generic message.
HWND hWnd; // Main Window Handle.
// Don't let more than one instance of the application exist
//
// NOTE: Comment out the following section of code if your game needs to have more
// than one instance running on the same computer (i.e. client/server)
////////////////////////////////////////////////////////////////////////
if (!hPrevInstance)
{
if (CheckIfAlreadyRunning())
return FALSE;
}
////////////////////////////////////////////////////////////////////////
// Register the window class
if (!RegisterWindowClass(hInstance))
return 0;
// Create the window
hWnd = MakeWindow(hInstance);
if (!hWnd)
return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//////////////////////////////////////////
// Initialize Game here
//////////////////////////////////////////
CGame* pGame = CGame::GetInstance();
pGame->Initialize(hWnd, hInstance, g_nWINDOW_WIDTH, g_nWINDOW_HEIGHT, g_bIS_WINDOWED);
//////////////////////////////////////////
// Enter main event loop
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Test if this is a quit
if (msg.message == WM_QUIT)
break;
// Translate any accelerator keys
TranslateMessage(&msg);
// Send the message to the window proc
DispatchMessage(&msg);
}
if(GetAsyncKeyState(VK_MENU) && GetAsyncKeyState(VK_RETURN))
ToggleFullscreenMode(hWnd, g_nWINDOW_WIDTH, g_nWINDOW_HEIGHT, 32, 60);
//////////////////////////////////
// Put Game Logic Here
//////////////////////////////////
if(pGame->Main(mouse) == false)
break;
//////////////////////////////////
}
/////////////////////////////////////////
// Shutdown Game Here
/////////////////////////////////////////
pGame->Shutdown();
/////////////////////////////////////////
// Unregister the window class
UnregisterClass(g_szWINDOW_CLASS_NAME, hInstance);
// Return to Windows like this.
return (int)(msg.wParam);
}
void ToggleFullscreenMode(HWND hWnd,
int iWidth, int iHeight, int iBpp, int iRefreshRate)
{
static bool bFullScreen = true;
static RECT rWindow = {0,0,g_nWINDOW_WIDTH,g_nWINDOW_HEIGHT};
static HMENU hMenu = NULL;
if(bFullScreen)
{
// Remember the window position.
GetWindowRect(hWnd, &rWindow);
// Switch to the requested display mode.
SetDisplayMode(iWidth, iHeight, iBpp, iRefreshRate);
// Remember the menu, then remove it.
hMenu = GetMenu(hWnd);
SetMenu(hWnd, NULL);
// Remove the window's title bar.
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
// Put the changes to the window into effect.
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
// Size the window to cover the entire screen.
SetWindowPos(hWnd, 0,
0, 0,
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
SWP_NOZORDER);
// Remove the cursor.
ShowCursor(FALSE);
}
else
{
// Restore the display mode.
SetDisplayMode(0, 0, 0, 0);
// Restore the window's menu.
SetMenu(hWnd, hMenu);
// Restore the window's title bar.
SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
// Put the changes to the window into effect.
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
// Size the window to its original position.
int iWindowWidth = rWindow.right - rWindow.left;
int iWindowHeight = rWindow.bottom - rWindow.top;
SetWindowPos(hWnd, 0,
rWindow.left,
rWindow.top,
iWindowWidth, iWindowHeight,
SWP_NOZORDER);
// Restore the cursor.
ShowCursor(TRUE);
}
bFullScreen = !bFullScreen;
}
void SetDisplayMode(int iWidth, int iHeight, int iBpp, int iRefreshRate)
{
if(iWidth == 0 && iHeight == 0 && iBpp == 0 && iRefreshRate == 0)
{
// Restore display settings to those stored in the registry.
ChangeDisplaySettings(NULL, 0);
return;
}
DEVMODE dm;
dm.dmSize = sizeof(DEVMODE);
int i = 0;
while(EnumDisplaySettings(NULL, i++, &dm))
{
// Iterate through the display settings until a match is found.
if(dm.dmPelsWidth == iWidth && dm.dmPelsHeight == iHeight &&
dm.dmBitsPerPel == iBpp && dm.dmDisplayFrequency == iRefreshRate)
{
if(ChangeDisplaySettings(&dm, CDS_TEST) == DISP_CHANGE_SUCCESSFUL)
{
// Put the new settings into effect.
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
return;
}
}
}
}