Каркас Windows-приложения. Особенности нового каркаса. Перемещение в пространстве (с текстурированными стенами), страница 3

return 0;

}

break;

case WM_KEYDOWN:

if (wParam < 256)  // Is key code in a valid range?

{

gInfo.keys [wParam] = true;

return 0;

}

break;

case WM_KEYUP:

if (wParam < 256)

{

gInfo.keys [wParam] = false;

return 0;

}

break;

case WM_TOGGLEFULLSCREEN: // Toggle full screen mode On/Off

gInfo.bFull = !gInfo.bFull;

PostMessage (hWnd, WM_QUIT, 0, 0);

break;

}

return DefWindowProc (hWnd, msg, wParam, lParam);

}

bool RegisterWndClass ()

{

WNDCLASSEX wc;   ZeroMemory (&wc, sizeof(wc));

wc.lpszClassName= gInfo.cls;

wc.hInstance  = gInfo.hInst;

wc.lpfnWndProc   = (WNDPROC)WndProc;

wc.style    = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

wc.hbrBackground= (HBRUSH)COLOR_WINDOW + 1;

wc.hCursor    = LoadCursor (0, IDC_ARROW);

wc.cbSize   = sizeof (WNDCLASSEX);

if (RegisterClassEx (&wc) == 0)

{

MessageBox (HWND_DESKTOP, "RegisterClassEx Failed!",

"Error", MB_OK | MB_ICONEXCLAMATION);

return false;

}

return true;

}

bool ReCreate ()

{

if (CreateGLWindow () && Init ())

return true;

MessageBox (HWND_DESKTOP, "Error Creating OpenGL Window",

"Error", MB_OK | MB_ICONEXCLAMATION);

return false;

}

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE, LPSTR, int)

{

gInfo.hInst = hInst; // Store the application handle

if (!RegisterWndClass())

return 0;

if (MessageBox (HWND_DESKTOP, "Start FullScreen?",

"Display Mode", MB_YESNO | MB_ICONQUESTION) == IDNO)

gInfo.bFull = false;

while (!gInfo.bQuit) // Full-screen/Window toggling loop

{

if (!ReCreate ())  // Create a full-screen (or usual) window

break;      // and set it up to render OpenGL

MSG msg;

while (true)     // Windows message handling loop

{

if (PeekMessage (&msg, gInfo.hWnd, 0, 0, PM_REMOVE) != 0)

{

// Do not quit, but break and see if it is time to really quit (gInfo.bQuit)

if (msg.message == WM_QUIT)

break;

DispatchMessage (&msg);

}

else          // If there are no messages

{

if (!gInfo.bVisible)// If window is not visible

WaitMessage ();  // It is minimized - wait for a message

else

{

DWORD t = GetTickCount ();  // Get The Tick Count

Update (t - gInfo.ticks);   // Update The Counter

gInfo.ticks = t;

Draw ();

SwapBuffers (gInfo.hDC);

}

}

}

DestroyGLWindow ();  // Destroy The Active Window

}

Deinitialize();

UnregisterClass (gInfo.cls, gInfo.hInst);  // UnRegister Window Class

return 0;

}

Здесь вы, вероятно, встретили достаточно много новых (непонятных) элементов и технологических приемов. Новый каркас потребует значительного времени на освоение заложенных в него возможностей. Рекомендую не стараться уяснить все сразу. Вы постепенно к нему привыкните и поймете все детали, а сейчас постарайтесь понять необходимость двух циклов while (см. WinMain), вместо одного, используемого в традиционном каркасе. Они характеризуют новый подход, при котором мы можем переключать экранные режимы. Переключение требует разрушить и заново создать Windows-окно. Именно поэтому необходимо иметь не один цикл обработки сообщений, а два.

q  Первый, внешний цикл длится до тех пор, пока пользователь не нажмет клавишу Esc, ALT+F4 или не закроет окно приложения. Он позволяет переключать режимы и заново создавать главное окно (см. вызов функции ReCreate).

q  Второй цикл обычно завершается c приходом сообщения WM_QUIT (которое посылается при закрытии окна и обычно завершает приложение), но в нашем случае WM_QUIT не завершает приложение, а лишь позволяет произвести переключение режимов.

q  Действительное завершение приложения (внешнего цикла while) осуществляется путем установки в true флага bQuit. Мы делаем это в обработчике WM_CLOSE. Позже мы установим флаг bQuit и при нажатии клавиши Esc.

q  Особую роль играют функции Init, Update, Draw и Deinitialize, которые дают возможность другому, пользовательскому модулю управлять анимацией (Update), перерисовкой (Draw), а также ресурсами (Init и Deinitialize).

Особенности нового каркаса