GLUT를 사용하지 않고 openGL을 사용하기 위한 가장 중요한 과정은 openGL의 context를 얻는것이다. Windows에서 rendering context라 불리는 이 context를 얻기 위해서는 먼저 device context를 가지고 있어야한다. device context는 GDI에서 정의하는 그래픽 오브젝트에 대한 여러 특성을 담고있는 구조체(핸들러)이며 다음과 같이 윈도우 핸들러에 대한 DC를 얻어올 수 있다.
설정 된 DC에 대한 RC를 가져온다.
이렇게 만들어진 context를 내 어플리케이션에서 사용하기 위해서는 생성된 context를 현재 사용되는 context로 설정해줘야한다.
이는 메모리가 굉장히 작던 시절 context에 대한 메모리 비용이 크기때문에 여러 프로세스에서 하나의 context를 공유하며 쓰던 방식이 남아있기 때문이다. 하지만 opengl의 api가 context를 문제 없이 사용하기 위해서는 윈도우에 DC를 온전히 할당해줄 필요가 있는데, 이를 위해서 윈도우의 스타일에 CS_OWNDC 속성을 반드시 추가시켜야 한다.
이제 context를 가졌으니 gl의 함수를 원하는 만큼 사용하면 된다. 픽셀 포멧에 더블 버퍼를 사용한다 하였으니 렌더링을 위해서
를 통해 버퍼를 스왑해주도록 한다.
context를 다 사용하고 난 후에는 제거해주는 과정이 필수적이다. RC는 더이상 사용하지 않으니 제거하고, DC는 윈도우에게 돌려준다.
위 내용을 기반으로 opengl application을 위한 코어를 구성해보았다.
접기
#include <Windows.h> #include <GL/GL.H> #include <GL/GLU.H>
#pragma comment(lib, "winmm") #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "glu32.lib")
class Core{ private: static Core* instance; HINSTANCE mhInst; HWND mhWnd; HDC mhDC; HGLRC mhRC;
bool bRunning; unsigned int wndWidth, wndHeight;
Core(){ mhInst = NULL; mhWnd = NULL; mhDC = NULL; mhRC = NULL;
bRunning = false; }
public: static Core* GetInstance(){ if (instance == NULL) instance = new Core(); return instance; }
bool InitializeApp(HINSTANCE hInstance, int nCmdShow, LPCWSTR lpszClassName, LPCWSTR lpszAppName){ mhInst = hInstance;
WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = lpszClassName; if (!RegisterClassEx(&wc)) return false;
wndWidth = 640; wndHeight = 480; mhWnd = CreateWindow(lpszClassName, lpszAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, wndWidth, wndHeight, NULL, (HMENU)NULL, hInstance, NULL); if (mhWnd == NULL) return false;
ShowWindow(mhWnd, nCmdShow);
if (!EnableGLContext()) return false;
SetupGL(); return true; }
void Run(){ bRunning = true; MSG msg;
unsigned long passTime = timeGetTime(); unsigned long curTime;
while (bRunning){ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ // handle or dispatch messages if (msg.message == WM_QUIT){ bRunning = false; } else{ TranslateMessage(&msg); DispatchMessage(&msg); } } else{ curTime = timeGetTime(); Update((float)(curTime - passTime) / 1000.0f); passTime = curTime;
Render(); } } }
void Update(float fDeltTime){
}
void Render(){ glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); static float theta = 0;
glPushMatrix(); glRotatef(theta, 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();
SwapBuffers(mhDC);
theta += 1.0f; }
void ReleaseApp(){ DisableGLContext(); }
void Resize(unsigned int width, unsigned int height){ wndWidth = width; wndHeight = height;
glViewport(0, 0, wndWidth, wndHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(60, (float)wndWidth / (float)wndHeight, 0.1f, 500.0f);
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } private: bool EnableGLContext(){ PIXELFORMATDESCRIPTOR pfd; int nPixelFormat;
mhDC = GetDC(mhWnd); memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; nPixelFormat = ChoosePixelFormat(mhDC, &pfd); SetPixelFormat(mhDC, nPixelFormat, &pfd);
mhRC = wglCreateContext(mhDC); return wglMakeCurrent(mhDC, mhRC); }
void DisableGLContext(){ wglMakeCurrent(NULL, NULL); wglDeleteContext(mhRC); ReleaseDC(mhWnd, mhDC); }
void SetupGL(){ glClearColor(0, 0, 0, 1.0f); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glPolygonMode(GL_FRONT_FACE, GL_FILL); }
public: static LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){ switch (iMessage){ case WM_DESTROY: Core::instance->bRunning = false; return 0;
case WM_SIZE: Core::instance->Resize(LOWORD(lParam), HIWORD(lParam)); return 0; }; return DefWindowProc(hWnd, iMessage, wParam, lParam); } }; Core* Core::instance = NULL;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){ Core::GetInstance()->InitializeApp(hInstance, nCmdShow, L"Test", L"Test"); Core::GetInstance()->Run(); Core::GetInstance()->ReleaseApp();
return 0; }
접기