Приветствую Вас ГостьВоскресенье, 13.07.2025, 21:36

Light Midnight Inc.


Каталог статей

Главная » Статьи » Программирование » С/С++/MFC

Каркас для OpenGL

В этом шаге мы создадим скелет приложения, который мы будем использовать во всех дальнейших проектах. Я, например, сделал проект skeleton и спрятал в надежное место ;)

Прежде всего создайте пустой проект Win32 Application. Назовем его skeleton. Добавьте в проект пустой файл skeleton.cpp ( или .c, поскольку мы пока не будем использовать с++)

Теперь настроим проект: Меню Project->Settings, заладка Link и в editbox "Object/Library Modules" добавим библиотеки: opengl32.lib, glu32.lib ( в принципе, можно обойтись и только opengl32.lib, но glu32.lib имеет несколько удобных функций для настроек ViewPort-а)

Нажимаем "Ok" и, как пишут в американских книжках, мы готовы пить кофе ;) Ну ладно, шутки в сторону.

Пишем заголовочные файлы:

#include <windows.h> // это, сами понимаете для того что б win заработало

#include <gl/gl.h> // OpenGL
#include <gl/glu.h> // GLU

Теперь объявим несколько глобальных переменных:

static HGLRC hRC; // Это контекст рендеринга
static HDC hDC; // А это стандартный контекст устройства windows

BOOL keys[256]; // это массивчик, который нам пригодится 
 // для обработки нажатия клавиш

Теперь объявляем функции:

GLvoid Initial(GLsizei Width, GLsizei Height); 
// по названию ясно, это инициализация всей страны (т.е. OpenGL)

GLvoid Resize(GLsizei Width, GLsizei Height);
// эта маленькая функция будет вызываться при получении окном сообщения WM_SIZE

GLvoid Draw(GLvoid); // это центр вселенной для OpenGL

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Ну это все и так знают. Функция окна в Win32

Переходим к реализации функций:

GLvoid Initial(GLsizei Width, GLsizei Height)
{
 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);// устанавливаем цвет для очистки буфера цвета
 glClearDepth(1.0); // устенавливаем параметр для очистки буфера глубины
 glDepthFunc(GL_LESS); // настройка Z буфера
 glEnable(GL_DEPTH_TEST); // и, наконец, включение

 glShadeModel(GL_SMOOTH); // выбираете режим затенения ( flat или smooth )

 glMatrixMode(GL_PROJECTION);// устанавливаем текушей матрицей матрицу проекта
 glLoadIdentity(); // обнуляем эту самую матрицу


 // настраиваем перспективу ( вот она, функция из glu32 )
 gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
 glMatrixMode(GL_MODELVIEW); // и переключаемся в модельную матрицу
}

Следующую функцию я комментировать не буду, мне кажется и так все понятно.

GLvoid Resize(GLsizei Width, GLsizei Height)
{
 if(Height==0)
 Height = 1;
 glViewport(0, 0, Width, Height);

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();

 gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);

 glMatrixMode(GL_MODELVIEW);
}

Функция Draw пока очень маленькая, но она будет расти, и будет это делать очень быстро:

GLvoid Draw(GLvoid)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // очищаем буферы
 glLoadIdentity(); // обнуляем модельную матрицу
}

А сейчас самое интересное. Функция WndProc. В ней мы должны установить формат пикселей и будем обрабатывать сообщения:

LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 RECT Screen; // Это структурка в которую мы поместим размеры области экрана
 GLuint PixelFormat; // формат пикселя

 static PIXELFORMATDESCRIPTOR pfd =
 {
 sizeof(PIXELFORMATDESCRIPTOR),// размер структуры
 1, // версия ?
 PFD_DRAW_TO_WINDOW| // format must support Window
 PFD_SUPPORT_OPENGL| // format must support OpenGL
 PFD_DOUBLEBUFFER, // must support double buffer
 PFD_TYPE_RGBA, // требуется RGBA формат
 16, // 16Bit color depth
 0, 0, 0, 0, 0, 0, // Color bits ignored ?
 0, // No Alpha buffer
 0, // shift bit ignored
 0, // no accumulation buffer
 0, 0, 0, 0, // accumulation buffer bits ignored
 16, // 16bit z-buffer (depth buffer)
 0, // no stencil buffer
 0, // no auxiliary buffer
 PFD_MAIN_PLANE, // main drawing layer
 0, // reserved
 0, 0, 0 // layer mask ignored
 };

 // Начинаем обрабатывать сообщения
 switch(msg)
 {
 case WM_CREATE: // на этапе создания приложения мы должны настроить 
 // формат пикселей и инициализироваит библиотеку
 hDC = GetDC(hWnd); // получаем контекст windows

 // Следующие несколько строк настраивают формат пикселей
 PixelFormat = ChoosePixelFormat(hDC, &pfd);

 if(!PixelFormat){
 MessageBox(0, "Can't find suitable PixelFormat",
 "Error", MB_OK|MB_ICONERROR);
 PostQuitMessage(0);
 break;
 }

 if(!SetPixelFormat(hDC, PixelFormat, &pfd)) {
 MessageBox(0, "Can't set The PixelFormat",
 "Error", MB_OK|MB_ICONERROR);
 PostQuitMessage(0);
 break;
 }
 hRC = wglCreateContext(hDC); // создаем контекст рендеринга
 if(!hRC) {
 MessageBox(0, "Can't Create Render Device Context",
 "Error",MB_OK|MB_ICONERROR);
 PostQuitMessage(0);
 break;
 }
 if(!wglMakeCurrent(hDC, hRC)) { // устанавливаем его текущим
 MessageBox(0, "Can't set current Render Device Context",
 "Error",MB_OK|MB_ICONERROR);
 PostQuitMessage(0);
 break;
 }

 GetClientRect(hWnd, &Screen); // получаем клиентскую область
 Initial(Screen.right, Screen.bottom);// инициализация OpenGL
 break;
 case WM_CLOSE:
 case WM_DESTROY: // по CLOSE и/или DESTROY
 ChangeDisplaySettings(NULL, 0); // восстанавливаем установки

 wglMakeCurrent(hDC, NULL); // устанавливаем обычный device context
 wglDeleteContext(hRC); // удаляем контекст рендеринга
 ReleaseDC(hWnd, hDC); // освобождаем device context

 PostQuitMessage(0);
 break;
 case WM_SIZE: // ну это для resize ( хотя как сделать resize
 // для fuulscreen application я не знаю ;) )
 Resize(LOWORD(lParam), HIWORD(lParam));
 break;
 default:
 return( DefWindowProc(hWnd, msg, wParam, lParam));
 }
 return(0);
}

Дальше все стандартно за исключением того, что заполняется структурка DEVMODE и устанавливаются DisplaySettings:

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShowCmd)
{
 MSG msg;
 WNDCLASS wc;
 HWND hWnd;

 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
 wc.lpfnWndProc = (WNDPROC)WndProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInst;
 wc.hIcon = NULL;
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = NULL;
 wc.lpszMenuName = NULL;
 wc.lpszClassName = "Lirik";

 if(!RegisterClass(&wc)) 
 {
 MessageBox(0,"Error Create window class","Error", MB_OK|MB_ICONERROR);
 return FALSE;
 }

 hWnd = CreateWindow("Skeleton",
 "Skeleton",
 WS_POPUP |
 WS_CLIPCHILDREN |
 WS_CLIPSIBLINGS,
 0, 
 0, 
 800, 
 600, 
 NULL, 
 NULL, 
 hInst, 
 NULL);

 if(!hWnd){
 MessageBox(0,"Error Create window","Error",MB_OK|MB_ICONERROR);
 return FALSE;
 }

 DEVMODE dmScreenSettings;

 memset(&dmScreenSettings, 0, sizeof(DEVMODE));
 dmScreenSettings.dmSize = sizeof(DEVMODE);
 dmScreenSettings.dmPelsWidth = 800;
 dmScreenSettings.dmPelsHeight = 600;
 dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
 ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

 ShowWindow(hWnd, SW_SHOW);
 UpdateWindow(hWnd);
 SetFocus(hWnd);

 while(1)
 {
 while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
 {
 if(GetMessage(&msg, NULL, 0, 0))
 {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
 }
 else
 {
 return TRUE;
 }
 }

 Draw();
 SwapBuffers(hDC);

 if(keys[VK_ESCAPE]) SendMessage(hWnd, WM_CLOSE, 0, 0);
 }
}

Теперь, если мы все правильно сделали, вы увидите просто черный экранчик и мышиный курсорчик.

Ну вы не расстраивайтесь.

В следующем шаге мы на этом черненьком экранчике сделаем беленькие фигурки, а потом цветные, а потом 3-х мерные, а потом : стоп, не все сразу.

Категория: С/С++/MFC | Добавил: Cromartie (22.08.2012)
Просмотров: 985 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Наш опрос
Оцените мой сайт
Всего ответов: 543
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Реклама
Cheсking
Часы
Мини-чат
200
Друзья Сайта
  • Light Midnight - Ваша Еда
  • Light Midnight - Anim as life style
  • Поиск