Pages

Saturday, October 17, 2009

Win32: Первая OpenGL программа


OpenGL добавили еще в Windows NT. Если кто-то собирается изучать OpenGL, то для начала хорошо бы посмотреть самую простую программу поддерживающую OpenGL:
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <WinGDI.h>
#include <GL/gl.h>

#pragma comment(lib, "opengl32.lib")

LPCWSTR s_szWndClassName = L"Window for Open GL Test application";

ATOM RegisterWndClass(HINSTANCE, LPCWSTR);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void ChangeSize(int cx, int cy);
BOOL SetPixelFormat(HDC);
void RenderScene();

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

HWND hWnd = NULL;
MSG msg = { 0 };

RegisterWndClass(hInstance, s_szWndClassName);

hWnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
s_szWndClassName, s_szWndClassName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);

if (hWnd != NULL)
{
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int)msg.wParam;
}

ATOM RegisterWndClass(HINSTANCE hInstance, LPCWSTR lpszWndClassName)
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = lpszWndClassName;
return RegisterClassEx(&wcex);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HGLRC hRC;
static HDC hDC;

switch (message)
{
case WM_CREATE:
hDC = GetDC(hWnd);
SetPixelFormat(hDC);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC,hRC);
break;

case WM_PAINT:
RenderScene();
SwapBuffers(hDC);
ValidateRect(hWnd, NULL);
break;

case WM_DESTROY:
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
break;

    default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

BOOL SetPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pfd = { 0 };
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat(hDC, &pfd);
if (nPixelFormat == 0)
return FALSE;
BOOL bResult = SetPixelFormat(hDC, nPixelFormat, &pfd);
return bResult;
}

void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
Эта апликация не более, чем шаблон. Она ничего не рисует, а просто создает окно и готовит рабочую среду для использования OpenGL. Рисование должно быть добавлено в функцию RenderScene:
void RenderScene()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(0.0f, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(-0.87f, -0.5f);
glEnd();
glPopMatrix();
}

Можна реагировать на изменения размеров окна:
case WM_SIZE:
ChangeSize(LOWORD(lParam), HIWORD(lParam));
break;

Ну и сама ChangeSize:
void ChangeSize(int cx, int cy)
{
glViewport(0, 0, cx, cy);
}

Можно добавить таймер и заставить нарисованый треугольник крутиться - SetTimer в обработку WM_CREATE сообщения, KillTimer в WM_DESTROY, добавить обработку WM_TIMER - просто вызвать InvalidateRect.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, 
WPARAM wParam, LPARAM lParam)
{
static HGLRC hRC; // Save the rendering context between calls
static HDC hDC; // Save the device context between calls


switch (message)
{
case WM_CREATE:
hDC = GetDC(hWnd);
SetPixelFormat(hDC);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC,hRC);
SetTimer(hWnd, 123, 100, NULL);
break;

case WM_PAINT:
RenderScene();
SwapBuffers(hDC);
ValidateRect(hWnd, NULL);
break;

case WM_TIMER:
InvalidateRect(hWnd, NULL, FALSE);
break;

case WM_SIZE:
ChangeSize(LOWORD(lParam), HIWORD(lParam));
break;

case WM_DESTROY:
KillTimer(hWnd, 123);
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
break;

    default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

И изменить функцию рисования:
void RenderScene()
{
static GLfloat angle = 0;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();
glRotatef(angle, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(-0.87f, -0.5f);
glEnd();
glPopMatrix();

angle += 1.0f;
}

И абсолютно без всякого смысла можно сделать окно полупрозрачным - WS_EX_LAYERED в вызов CreateWindowEx и вызвать SetLayeredWindowAttributes для дескриптора окна:
SetLayeredWindowAttributes(hWnd, 0, (255 * 70) / 100, LWA_ALPHA);

MSDN:OpenGL I: Quick Start
OpenGL Win32 Tutorial

No comments:

Post a Comment