Создание и настройка окна OpenGL

На этом уроке вы узнаете, как инициализировать OpenGL в Dev C++

На этом уроке вы узнаете, как создавать и настраивать окно OpenGL. Оно может быть полноэкранным, с любым разрешением и глубиной цвета. Код, который мы напишем в этом уроке, очень гибкий и может быть использован для всех ваших проектов OpenGL. Все мои уроки будут основаны на этом коде.

Первая вещь, которой вы должны сделать, - создать проект в Dev C++.
Заходим в меню File, New, выбираем Project. В открывшемся окне выбираем вкладку Multimedia. И создаем OpenGL проект, пишем название проекта и сохраняем его. 

Итак, перед нами готовый шаблон OpenGL программы. Нажимаем F9. И любуемся полученным результатом.

В окошке, размер которого указывается в коде программы, на черном фоне вращается треугольник каждая сторона которого, окрашена в свой цвет.

Если мы зайдем  в Project, выберем Project Options, затем щелкнем на вкладку Parameters. Увидим, что в списке Linker уже добавлен один параметр -OpenGL32. Сразу добавим туда остальные параметры, которые понадобятся нам в дальнейшей работе: -lopengl32 -lglu32 -lglaux -lwinmm

После того как вы добавите нужные параметры, необходимо скопировать файлы glaux.dll и glaux.h в папку с проектом.

Теперь всё готово к работе. Для того чтобы разобраться во всем, мы начнем все с пустого листа. Удаляем весь код, генерируемый по умолчанию, и начинаем писать свой.

Первые строки, которые вы введете, сообщают компилятору какие библиотечные файлы использовать. Они должны выглядят так:

#include <windows.h>                 // Заголовочный файл для Windows
#include <gl\gl.h>                   // Заголовочный файл для OpenGL32 библиотеки
#include <gl\glu.h>                      // Заголовочный файл для GLu32 библиотеки
#include “glaux.h”                     // Заголовочный файл для GLaux библиотеки, которой мы скопировали в папку с проектом

Далее, необходимо инициализировать все переменные, которые будут использованы в вашей программе. Мы создаем пустое OpenGL окно, поэтому большое количество переменных нам не понадобятся. Переменные, которые мы опишем, будут использоваться в каждой программе с OpenGL, которую вы будите писать.

Первые четыре строчки устанавливают Контексты Рендеринга, которые связывает вызовы OpenGL с окном Windows. Контекст Рендеринга OpenGL определен как hRC. Для того чтобы рисовать в окне, вам необходимо создать Контекст Устройства Windows, который определен как hDC. DC соединяет окно с GDI. RC соединяет OpenGL с DC.

HGLRC           hRC=NULL;    // Постоянный контекст рендеринга
HDC             hDC=NULL;    // Приватный контекст устройства GDI
HWND            hWnd=NULL;   
HINSTANCE       hInstance;   

Впишем ещё две переменные:

bool active=TRUE; // Переменная активности окна
bool fullscreen=TRUE; // Переменная полноэкранного режима

Последняя переменная, в которой мы будем нуждаться, это массив, который мы будем использовать для отслеживания нажатий клавиш на клавиатуре. Есть много методов следить за нажатиями на клавиатуре, но я буду использовать этот метод, потому что он позволяет отслеживать нажатие более чем одной клавиши одновременно.

BOOL    keys[256];              // Массив для процедуры обработки клавиатуры

Теперь мы должны объявить WndProc(). Мы должны это сделать потому, что CreateGLWindow(), имеет ссылку на WndProc() но WndProc(), стоит после CreateGLWindow(). В C если мы хотим иметь доступ к процедуре, которая написана после секции кода, мы должны объявить процедуру, к которой мы хотим иметь доступ с начала нашей программы.  И так, на следующей строчке, мы объявляем WndProc() чтобы CreateGLWindow(), мог ссылаться на WndProc().

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) ;

ReSizeGLScene() - функция масштабирования сцены, вызываемая OpenGL всякий раз, когда вы изменяете размер окна. Даже если вы не делаете изменение размеров окна (например, если вы находитесь в полноэкранном режиме), эта процедура все равно должна быть вызвана хоть один раз, обычно во время запуска программы. Замечу, что сцена масштабируется, основываясь на ширине и высоте окна, которое отображается.

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   
{
if (height==0)           
{
    height=1;                    
}

glViewport(0,0,width,height);

glMatrixMode(GL_PROJECTION) сообщает о том, что следующие команды будут воздействовать на матрицу проекции. glLoadIdentity() – это функция работает подобно сбросу. glMatrixMode(GL_MODELVIEW) сообщает, что любые новые трансформации будут воздействовать на матрицу просмотра модели. Не волнуйтесь, если вы что-то не понимаете в этом материале, я буду обучать всему этому в дальнейших уроках. Только запомните, что надо сделать, если вы хотите красивую сцену.
                     
// Сброс текущей области вывода и перспективных преобразований
glMatrixMode(GL_PROJECTION);       
glLoadIdentity();           
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
// Вычисление соотношений геометрических размеров для окна
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

В следующей секции кода будут произведены все настройки OpenGL. Мы установим цвет для очистки экрана, включим буфер глубины, разрешим плавное сглаживание цветов, и что наиболее важно, мы установим рендеринг на экран в перспективе, используя ширину и высоту окна.

int InitGL(GLvoid)    // Вызвать после создания окна GL
{

Следующая строчка задает плавное цветовое сглаживание.
 
glShadeModel(GL_SMOOTH);        // разрешить плавное цветовое сглаживание

В следующей строке устанавливается цвет, которым будет очищен экран. Для тех, кто не знает, как устроены цвета, я постараюсь кратко объяснять. Все значения могут быть в диапазоне от 0.0f до 1.0f, при этом 0.0 самый темный, а 1.0 самый светлый. Первое число в glClearColor - это интенсивность красного, второе – зеленного, третье – синего. Наибольшее значение – 1.0f, является самым ярким значением данного цвета. Последнее число - для альфа значения. Как его использовать, я объясню на другом уроке, а пока зададим ему значение равное 0.0f.

Итак, если вы вызвали glClearColor(0.0f,0.0f,1.0f,0.0f) вы произведете очистку экрана, с последующим закрашиванием его в ярко синий цвет. Если вы вызвали glClearColor(0.5f,0.0f,0.0f,0.0f) экран будет заполнен умеренно красным цветом. Не очень ярким (1.0f) и не темным (0.0f), а именно умеренно красным. Для того чтобы сделать белый фон, вы должны установить все цвета в (1.0f). Черный - как можно ниже (0.0f).

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);   // Очистка экрана в черный цвет

Следующие три строки создают Буфер Глубины. Буфер глубины указывает, как далеко объекты находятся от экрана. Мы не будем использовать буфер глубины в этой программе, но он нужен для любой программы с OpenGL, которая рисует на экране 3D объекты. Он позволяет сортировать объекты для отрисовки, поэтому квадрат, расположенный под кругом не будет изображен поверх круга. Буфер глубины очень важная часть OpenGL.

glClearDepth(1.0);                      // Разрешить очистку буфера глубины
glDepthFunc(GL_LESS);                   // Тип теста глубины
glEnable(GL_DEPTH_TEST);                // разрешить тест глубины

Затем мы сообщаем OpenGL, что мы хотим лучшую перспективную коррекцию, которую можно сделать.

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

return TRUE; // Инициализация прошла успешно
}

Далее идет та часть кода - где будут прорисовываться ваши объекты. Всё, что хотите изобразить на экране, описывается в этой части.

int DrawGLScene(GLvoid)    // Процедура отображения
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Отчистка экрана и буфера глубины
glLoadIdentity();        // Сброс просмотра
return TRUE;        // Все прошло успешно
}

Следующая часть кода работает при завершении программы. Она нужна для корректного завершения работы приложения. Я добавил много проверок на ошибки. Если программа - не в состоянии уничтожить любую часть Окна, то по сообщению об ошибке, можно определить в какой части кода ошибка.

GLvoid KillGLWindow(GLvoid)    // Правильно уничтожаем окно
{

Проверка на ошибки инициализации.

if (fullscreen)    // Если мы в полноэкранном режиме то?
{
    ChangeDisplaySettings(NULL,0); // Если оконный режим
    ShowCursor(TRUE);    // Включаем указатель мыши
}

if (hRC)            // Работает ли контекст рендеринга?
if (!wglMakeCurrent(NULL,NULL))    // Будут ли работать DC и RC Контексты?
{
MessageBox(NULL,"Не работают DC и RC контексты","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
    }

if (!wglDeleteContext(hRC))    // Способны ли мы завершить RC?
    {
    MessageBox(NULL,"Неудачное предоставление контекста","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
    }
    hRC=NULL;    // Устанавливаем RC To NULL
}

if (hDC && !ReleaseDC(hWnd,hDC)) // Способны ли мы установить DC
{
    MessageBox(NULL,"Контекст устройства не работает","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
    hDC=NULL;    // Устанавливаем DC в NULL
}

if (hWnd && !DestroyWindow(hWnd)) // Способны ли мы уничтожить окно?
{
    MessageBox(NULL,"Невозможно отобразить окно","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
    hWnd=NULL;                    // Set hWnd To NULL
}

if (!UnregisterClass("OpenGL",hInstance)) // Зарегистрирован ли класс ?
{
    MessageBox(NULL,"Незарегистрированный класс.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
    hInstance=NULL;    // Устанавливаем hInstance в NULL
}
}

В следуюшей секции кода создаем наше окно OpenGL.
Как вы видите следующая процедура имеет 5 параметров: название окна, ширина окна, высота окна, количество битов (16/24/32), fullscreenflag TRUE - для fullscreen или FALSE - для оконного режима.

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{

В переменную PixelFormat будет загружен результат поиска формата пикселя.

GLuint    PixelFormat; // Сохраняет результат

В wc будет сохранена наша структура класса Окна. Структура класса окна хранит информацию о нашем окне.

WNDCLASS        wc; // Структура класса Windows для установки типа окна

DWORD    dwExStyle; // Расширенный стиль
DWORD    dwStyle;       // Стиль окна

Мы используем следующие величины, чтобы настраивать наше окно. Границы окна будут настроены нами, мы создаем окно размером 1024x768 пикселей.

RECT WindowRect;           
WindowRect.left=(long)0;           
WindowRect.right=(long)width;           
WindowRect.top=(long)0;           
WindowRect.bottom=(long)height;           

На следующей линии кода, мы присваиваем переменной fullscreen значение fullscreenflag..

fullscreen=fullscreenflag;

Флаги стиля CS_HREDRAW и CS_VREDRAW принуждают перерисовать окно всякий раз, когда оно перемещается. CS_OWNDC создает скрытый DC для окна. Это означает, что DC не используется совместно нескольким приложениями. WndProc() - процедура, которая перехватывает сообщения для программы. hIcon установлен равным нулю, это означает, что мы не хотим иконку в окне. Для мыши используем стандартный указатель. Фоновый цвет не имеет значения (мы установим его в GL). Мы не хотим меню в этом окне, поэтому мы используем установку его в NULL, и имя класса – это любое имя которое вы хотите.

hInstance    = GetModuleHandle(NULL);   
wc.style    = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    // Обновление при перемещении, и DC для окна
wc.lpfnWndProc    = (WNDPROC) WndProc;       
wc.cbClsExtra    = 0;           
wc.cbWndExtra    = 0;           
wc.hInstance    = hInstance;       
wc.hIcon    = LoadIcon(NULL, IDI_WINLOGO);    // Загрузка иконки по умолчанию
wc.hCursor    = LoadCursor(NULL, IDC_ARROW);    // Загрузка стандартного указателя мыши
wc.hbrBackground = NULL;           
wc.lpszMenuName    = NULL;           
wc.lpszClassName = "OpenGL";       

Сейчас мы регистрируем класс. Если произошла ошибка, появится соответствующее сообщение.

if (!RegisterClass(&wc)) // Попытка зарегистрировать класс
{
    MessageBox(NULL,"Невозможно зарегистрировать класс",”ERROR”,MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}
Следующая часть кода вызывает у многих людей массу проблем. Переход в полноэкранный режим. Здесь важна одна вещь, которую вы должны запомнить, при переключении в полноэкранный режим – ширина и высота должна быть одинаковая.

if (fullscreen)                   
{

DEVMODE dmScreenSettings;        memset(&dmScreenSettings,0,sizeof(dmScreenSettings));    dmScreenSettings.dmSize=sizeof(dmScreenSettings);    dmScreenSettings.dmPelsWidth = width;    dmScreenSettings.dmPelsHeight = height;    dmScreenSettings.dmBitsPerPel = bits;    dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

В коде выше мы очищаем сцену, чтобы установить наши параметры. Мы устанавливаем ширину, высоту и количество битов, которое нам нужно. В коде ниже мы устанавливаем запрошенный полно экранный режим. Мы устанавливаем все параметры в dmScreenSettings. На линии ниже ChangeDisplaySettings мы переключаем на режим, который соответствует тому, что мы настроили в dmScreenSettings.

    // Устанока нужного режима
if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
    {
//Если режим не удается установить, выводим сообщение
    if (MessageBox(NULL,"Данный режим установить не удается","OpenGL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
    {
        fullscreen=FALSE;    // Режим установлен
    }
    else
    {
        // Выводим заключительное сообщение.
MessageBox(NULL,"Программа не может продолжать работу","ERROR",MB_OK|MB_ICONSTOP);
        return FALSE;                // Возвращаем FALSE
    }
    }
}

Теперь мы заново проверяем установлен ли полноэкранный режим

if (fullscreen)
{
Если мы все ещё в полноэкранном режиме, устанавливаем расширенный стиль на WS_EX_APPWINDOW. Для стиля окна, который мы создадим окно WS_POPUP. Этот тип окна не имеет границу вокруг, а это лучше для полноэкранного режима

Наконец, мы убираем указатель мыши.

dwExStyle=WS_EX_APPWINDOW;    // Устанавливаем расширенный стиль
dwStyle=WS_POPUP;    // Стиль окна
ShowCursor(FALSE);    // Убираем указатель мыши
}
else
{

Если мы используем окно вместо полноэкранного режима, мы добавим WS_EX_WINDOWEDGE к расширенному стилю. Это придает окну 3D вид. WS_OVERLAPPEDWINDOW создает окно с зоной названия, изменения размера, меню, и кнопками  минимизировать / расширять / закрыть.

dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Устанавливаем расширенный стиль
dwStyle=WS_OVERLAPPEDWINDOW;        // Стиль окна

}

Настраиваем окно в соответствии с указанными стилями.

AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
В следующей секции кода, мы создаем наше окно и проверяем было ли оно создано правильно. Мы передаем CreateWindowEx() все параметры которые требуется. Расширенный стиль, который мы решили использовать. Имя класса (который должен быть таким же, как и имя, которое вы использовали, когда регистрировали). Название окна. Стиль окна. Ширина и высота окна.

if (!(hWnd=CreateWindowEx( dwExStyle,   
        "OpenGL",       
        title,       
        WS_CLIPSIBLINGS |   
        WS_CLIPCHILDREN |   
        dwStyle,       
        0, 0,       
        WindowRect.right-WindowRect.left,
        WindowRect.bottom-WindowRect.top,
        NULL,       
        NULL,       
        hInstance,       
        NULL)))       

Затем мы проверяем, если наше окно создано правильно. Если окно не было создано появиться сообщение об ошибки и программа завершит свою работу.
   
{
    KillGLWindow();           
    MessageBox(NULL,"Ошибка создания окна","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Следующая секция кода описывает Формат Пикселя.

static PIXELFORMATDESCRIPTOR pfd=            {
    sizeof(PIXELFORMATDESCRIPTOR),       
    1,               
    PFD_DRAW_TO_WINDOW |           
    PFD_SUPPORT_OPENGL |           
    PFD_DOUBLEBUFFER,           
    PFD_TYPE_RGBA,           
    bits,               
    0, 0, 0, 0, 0, 0,           
    0,               
    0,               
    0,               
    0, 0, 0, 0,           
    16,               
    0,               
    0,               
    PFD_MAIN_PLANE,           
    0,               
    0, 0, 0               
};

Если не было никаких ошибок при создании окна, мы попытаемся получать Контекст Устройства OpenGL. Если мы не можем получать DC то покажется сообщение об ошибке и работа программы прекратиться.

if (!(hDC=GetDC(hWnd)))           
{
    KillGLWindow();           
    MessageBox(NULL,"Не возможно получить контекст устройства","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Если нам удалось получать Контекст Устройства для нашего окна OpenGL, мы попытаемся установить формат пикселя, который мы описывали выше. Если Windows не может найти подходящего формата пикселя, мы получим сообщение об ошибки и программа завершиться.

if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))       
{
    KillGLWindow();           
    MessageBox(NULL,"Проблема с форматом пикселся","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Если подходящий формат пикселя найден, мы попробуем установить его. Если формат пикселя не найден то мы получим сообщение об ошибки и программа завершиться.

if(!SetPixelFormat(hDC,PixelFormat,&pfd))        {
    KillGLWindow();            MessageBox(NULL,"Невозможно установить данный формат пикселя","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Если формат пикселя установился правильно, мы попытаемся получать Предоставляющий Контекст. Если мы не сможем получать Предоставляющий Контекст, мы получим сообщение об ошибки и программа завершиться.

if (!(hRC=wglCreateContext(hDC)))            {
    KillGLWindow();           
    MessageBox(NULL,"Ошибка получения контекста","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Если нет никаких ошибок, и удалось создать Контекст устройства и Предоставляющий контекст, то теперь нужно сделать Предоставляющий контекст активным. Если не получиться, то мы получим сообщение об ошибки и программа завершиться

if(!wglMakeCurrent(hDC,hRC))            {
    KillGLWindow();            MessageBox(NULL,"Не получается сделать пред. Контекст активным","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

Теперь если все прошло гладко, и наше окно OpenGL было создано. Мы вызываем его и устанавливаем фокус в это окно. Затем мы вызываем ReSizeGLScene(), передающую экранную ширину и высоту, чтобы установить перспективный экран OpenGL.

ShowWindow(hWnd,SW_SHOW);            // Вызываем окно
SetForegroundWindow(hWnd);            // Устанавливаем приоритет
SetFocus(hWnd);                // Устанавливаем фокус на это окно
ReSizeGLScene(width, height);           

Наконец мы переходим к InitGL() где мы можем установить освещение, текстуры, и что-нибудь еще, что должно быть установлено. Если процедуру выполнить не удалость то мы получим сообщение об ошибки и программа завершиться

if (!InitGL())               
{
    KillGLWindow();           
    MessageBox(NULL,"Ошибка инициализации","ERROR",MB_OK|MB_ICONEXCLAMATION);
    return FALSE;           
}

return TRUE;               
}

Следующая часть кода наиболее важная в этой программе. Это установка окна Windows, установка формата пикселя, обработка при изменении размеров, при нажатии на клавиатуру, и закрытие программы.

Первые четыре строки делают следующее: переменная hWnd – является указателем на окно. Переменная message – сообщения, передаваемые вашей программе системой. Переменные wParam и lParam содержат информацию, которая посылается вместе с сообщением, например такая как ширина и высота окна.

LRESULT CALLBACK WndProc( HWND hWnd,       
        UINT uMsg,       
        WPARAM wParam,       
        LPARAM lParam)       
{

switch (uMsg)           
{

case WM_ACTIVATE:           
    {
    if (!HIWORD(wParam))                {
        active=TRUE;       
    }
    else
    {
        active=FALSE;       
    }

    return 0;           
    }

case WM_SYSCOMMAND:   
    {
    switch (wParam)           
    {
        case SC_SCREENSAVE:                case SC_MONITORPOWER:        // Monitor Trying To Enter Powersave?
        return 0;       
    }
    break;           
    }
Если uMsg - WM_CLOSE окно закрыто. Мы посылаем сообщение выхода, что основной цикл прервет и программа закроется.

case WM_CLOSE:   
    {
    PostQuitMessage(0);       
    return 0;           
    }

Определяем нажаты ли клавиши на клавиатуре.
case WM_KEYDOWN:           
    {
    keys[wParam] = TRUE;       
    return 0;           
    }

case WM_KEYUP:           
    {
    keys[wParam] = FALSE;       
    return 0;           
    }

Всякий раз, когда мы меняем размеры нашего окна, uMsg становиться сообщением WM_SIZE. Мы читаем LOWORD и HIWORD величины lParam, чтобы обнаруживать новую ширину и высоту окна. Мы передаем новую ширину и высоту на ReSizeGLScene().

case WM_SIZE:                {
    ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));   
    return 0;           
    }
}

return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

Это - точка входа в наше Приложение. В этом месте мы вызываем нашу программу.

int WINAPI WinMain( HINSTANCE hInstance,       
    HINSTANCE hPrevInstance,       
    LPSTR    lpCmdLine,       
    int    nCmdShow)       
{

MSG msg;
BOOL done=FALSE;           

Следующая часть код выдает окно в котором спрашивается хотим ли мы загрузить приложение вполноэкранном режиме.

if (MessageBox(NULL,"Загрузить приложение в полноэкранном режиме?", "Полноэкранный режим",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
    fullscreen=FALSE;
}

if (!CreateGLWindow("OpenGL",1024,768,32,fullscreen))
{
    return 0;           
}

Создаем цикл. Который будет прерван если переменная done буден равна False.

while(!done)               
{

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //Проверяем есть ли ожидаемые сообщения?
    {
В следующей части, мы проверяем какое сообщение было получено. Если текущее сообщение является сообщением WM_QUIT вызванным PostQuitMessage(0) то завершаем цикл.

if (msg.message==WM_QUIT)       
    {
        done=TRUE;       
    }
    else           
    {

TranslateMessage(&msg);                DispatchMessage(&msg);        // Dispatch The Message
    }
    }
    else               
    {

Если не было никаких сообщений, мы переходим к созданию нашей сцены. Первая линия кода ниже проверяет, активно ли окно. Если клавиша ESC нажата, переменная установлена в True, что завершает работу программы.

    if (active)                {
        if (keys[VK_ESCAPE])        // Было ли нажато ESC?
        {
        done=TRUE;        // Завершение
        }
        else            // Обновление экрана
        {

Если программа активна и ESC не был нажат, мы рисуем сцену.
   
DrawGLScene();        // Процедура прорисовки
SwapBuffers(hDC);     // Swap Buffers двойная буферизация
        }
    }
Следующий код позволяет переключать режимы при помощи клавиши F1

if (keys[VK_F1])
    {
        keys[VK_F1]=FALSE;       
        KillGLWindow();       
        fullscreen=!fullscreen;       
if (!CreateGLWindow("OpenGL",1024,768,32,fullscreen))
        {
        return 0;   
        }
    }
    }
}

// Завершение работы
KillGLWindow();                // Убиваем окно
return (msg.wParam);            // Выходим из программы
}

Теперь нажимаем F9 и если всё сделано правильно, то мы увидим сообщение о выборе режима.

На этом наш первый урок по инициализации и сознанию окна OpenGL закончен. Все последующие уроки будут основаны на коде этой программы. Советую хорошенько разобраться в этом уроке.