창을 만들고 그 위에 상자(지만 육면체임)를 하나 그려봅니다.
참고로 윈도우 기준이고, NeHe의 튜토리얼을 따라하였습니다.
#include <windows.h>
#include <stdio.h>
#include <gl/GL.h>
#include <gl/GLU.h>
//#include <gl/glaux.h> // 삭제. 아직까진 없어도 됨
int windowWidth = 640; // 실제 창의 폭
int windowHeight = 360; // 실제 창의 높이
HGLRC hRC = NULL; // 렌더링 컨텍스트
HDC hDC = NULL; // 윈도우 GDI 디바이스 컨텍스트
HWND hWnd = NULL; // 윈도우 핸들
HINSTANCE hInstance;// 프로그램 인스턴스 핸들
bool keys[256]; // 키보드 루틴용
bool active = TRUE; // 윈도우가 최소화가 되었는지 판별
bool fullscreen = TRUE;// 전체화면인지 아닌지 (true 전체 false 윈도우)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // WndProc 선언
// 윈도우 크기 재조정시 리사이즈 (전체창 모드도 한 번은 실행됨) // glut의 리세이프 부분일듯
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) {
if(height == 0) {
height = 1;
}
glViewport(0, 0, width, height);// 뷰포트 설정
GLfloat aspect = (GLfloat)width / (GLfloat)height; // 종횡비 구하기
glMatrixMode(GL_PROJECTION); // 프로젝션 매트릭스 모드
glLoadIdentity(); // 매트릭스의 초기화
//gluPerspective(45.0f, aspect , 0.1f, 100.0f); // 원근투상 (45도 각도 시야, 윈도우의 종횡비 위에 투영, 전방절단면 0.1, 후방절단면 100.0)
// => 시선이 가시부피의 한가운데를 지나감
//glFrustum(0, 0.16f, 0, 0.09f, 0.1f, 10.0f); // 원근투상 (왼쪽, 오른쪽, 아래, 위, 전방절단면, 후방절단면)
//glFrustum(-2.0f, 2.0f, -1.125f, 1.125f, 2.0f, 10.0f); // 원근투상 (왼쪽, 오른쪽, 아래, 위, 전방절단면, 후방절단면)
glFrustum(-1.0f*aspect, 1.0f*aspect, -1.0f, 1.0f, 3.0f, 10.0f); // 원근투상 (왼쪽, 오른쪽, 아래, 위, 전방절단면, 후방절단면)
glMatrixMode(GL_MODELVIEW); // 모델뷰 매트릭스 모드
glLoadIdentity(); // 매트릭스의 초기화
}
// GL 초기화 // glut의 RenderContext 부분일듯?
int InitGL(GLvoid) {
glShadeModel(GL_SMOOTH); // 부드러운 쉐이딩
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 윈도우창 클리어 검정색
glClearDepth(1.0f); // 깊이 버퍼 셋업
glEnable(GL_DEPTH_TEST); // 깊이 테스트 활성
glDepthFunc(GL_LEQUAL); // 깊이 타입 실행
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 화면요청
return TRUE;
}
// 그리기 // glut의 Renderscene 부분일듯? (glutDisplayFunc())
int DrawGLScene(GLvoid) {
// 스크린 및 깊이 클리어
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // 매트릭스 초기화
// 여기에 그릴 내용이 들어감
gluLookAt(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f); // 시점변환 = 0, 0, 0위치의 카메라가 0, 0, -1 위치를 바라봄 카메라 상향벡터는 0, 1, 0
glTranslatef(0.0f, 0.0f, -5.0f);// 물체를 Z축으로 -5만큼 이동 - 모델변환
glBegin(GL_QUADS); // 사각형 모드 모델좌표
// top
glColor3f(1.0f, 1.0f, 0.0f); // 노란
glVertex3f(-0.5f, 0.5f, 0.5f); // 좌하단
glVertex3f( 0.5f, 0.5f, 0.5f); // 우하단
glVertex3f( 0.5f, 0.5f,-0.5f); // 우상단
glVertex3f(-0.5f, 0.5f,-0.5f); // 좌상단
// bottom
glColor3f(0.0f, 1.0f, 1.0f); // 청록
glVertex3f(-0.5f,-0.5f,-0.5f); // 좌하단
glVertex3f( 0.5f,-0.5f,-0.5f); // 우하단
glVertex3f( 0.5f,-0.5f, 0.5f); // 우상단
glVertex3f(-0.5f,-0.5f, 0.5f); // 좌상단
// front
glColor3f(1.0f, 0.0f, 0.0f); // 빨강
glVertex3f(-0.5f,-0.5f, 0.5f); // 좌하단
glVertex3f( 0.5f,-0.5f, 0.5f); // 우하단
glVertex3f( 0.5f, 0.5f, 0.5f); // 우상단
glVertex3f(-0.5f, 0.5f, 0.5f); // 좌상단
// back
glColor3f(0.0f, 0.0f, 1.0f); // 파랑
glVertex3f( 0.5f,-0.5f,-0.5f); // 좌하단
glVertex3f(-0.5f,-0.5f,-0.5f); // 우하단
glVertex3f(-0.5f, 0.5f,-0.5f); // 우상단
glVertex3f( 0.5f, 0.5f,-0.5f); // 좌상단
// left
glColor3f(1.0f, 0.0f, 1.0f); // 보라
glVertex3f(-0.5f,-0.5f,-0.5f); // 좌하단
glVertex3f(-0.5f,-0.5f, 0.5f); // 우하단
glVertex3f(-0.5f, 0.5f, 0.5f); // 우상단
glVertex3f(-0.5f, 0.5f,-0.5f); // 좌상단
// right
glColor3f(0.0f, 1.0f, 0.0f); // 녹색
glVertex3f( 0.5f,-0.5f, 0.5f); // 좌하단
glVertex3f( 0.5f,-0.5f,-0.5f); // 우하단
glVertex3f( 0.5f, 0.5f,-0.5f); // 우상단
glVertex3f( 0.5f, 0.5f, 0.5f); // 좌상단
glEnd(); // 모델좌표 끝
// 여기까지
return TRUE;
}
// 종료시 실행
GLvoid KillGLWindow(GLvoid) {
// 풀스크린 모드였는지 확인해서
if(fullscreen) {
ChangeDisplaySettings(NULL, 0); // 디스플레이 세팅 초기화
ShowCursor(TRUE); // 마우스 포인터 출력값 초기화
}
// 렌더링 콘텍스트를 가지고 있는지
if(hRC) {
// DC와 RC를 해제할 수 있는지 확인
if(!wglMakeCurrent(NULL, NULL)) {
// 메시지 박스로 에러메시지 출력
MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
// RC 삭제
if(!wglDeleteContext(hRC)) {
// 메시지 박스로 에러메시지 출력
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
hRC = NULL;
}
// DC 가지고 있는지 확인하고 삭제
if(hDC && !ReleaseDC(hWnd, hDC)) {
// 메시지 박스로 에러 메시지 출력
MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hDC = NULL; // DC를 NULL로
}
// 윈도우 핸들을 가지고 있는지 확인하고 해제
if(hWnd && !DestroyWindow(hWnd)) {
// 메시지 박스로 에러 메시지 출력
MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hWnd = NULL; // hWnd를 NULL로
}
// 윈도우 클래스 등록을 해제
if(!UnregisterClass("OpenGL", hInstance)) {
MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hInstance = NULL;
}
}
// 윈도우 생성
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) {
GLuint PixelFormat; // 픽셀포맷
WNDCLASS wc; // 윈도우 클래스
DWORD dwExStyle; // 윈도우 창 스타일
DWORD dwStyle; // 윈도우 창 스타일
RECT WindowRect; // 윈도우 크기
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom = (long)height;
fullscreen = fullscreenflag; // 풀스크린 확인
hInstance = GetModuleHandle(NULL);// 윈도우 인스턴스를 가져옴
// 윈도우 클래스 정의
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
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, "Failed To Register The Window Class.", "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;
// 전체화면 실행
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
// 전체화면 모드가 지원되지 않을경우 메시지 출력
if(MessageBox(NULL, "The Requested Fullscreen Mode Is Not supported By\n"
"Your Video Card. Use Windowed Mode nstead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
// 윈도우 창 모드로 변경
fullscreen = FALSE;
} else{
MessageBox(NULL, "Program Will Now close.", "ERROR", MB_OK | MB_ICONSTOP);
return FALSE;
}
}
}
if(fullscreen) {
dwExStyle = WS_EX_APPWINDOW; // 테스크바 삭제
dwStyle = WS_POPUP; // 보더 삭제
//ShowCursor(FALSE); // 마우스 커서 안보임
} else {
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
// 윈도우 크기 조정
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
// 윈도우 생성
if(!(hWnd = CreateWindowEx( dwExStyle, // 윈도우 스타일
"OpenGL", // 클래스 이름
title, // 윈도우 타이틀
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, // 윈도우 스타일
0, 0, // 윈도우 위치
WindowRect.right - WindowRect.left, // width
WindowRect.bottom - WindowRect.top, // height
NULL, // No parent window
NULL, // No menu
hInstance,
NULL)))
{
KillGLWindow(); // Reset the display
MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// 픽셀 포맷 기술
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // 크기
1, // 버전
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | // 윈도우, GL 포맷 지원
PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, // 더블버퍼링, RGBA포맷
bits, // Color depth
0, 0, 0, 0, 0, 0, // Color bits
0, // Alpha buffer
0, // Shift bit
0, // Accumulation buffer
0, 0, 0, 0, // Accumulation bits
16, // 16bit Z-buffer
0, // 스텐실 버퍼
0, // 보조 버퍼
PFD_MAIN_PLANE, // 메인 드로잉 레이어
0, // Reserved
0, 0, 0 // 레이어 마스크
};
// DC 얻기
if(!(hDC = GetDC(hWnd))) {
KillGLWindow();
MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// 픽셀 포맷 찾기
if(!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {
KillGLWindow();
MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// 필셀 포맷 설정
if(!SetPixelFormat(hDC, PixelFormat, &pfd)) {
KillGLWindow();
MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// RC 얻기
if(!(hRC = wglCreateContext(hDC))) {
KillGLWindow();
MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// RC 활성화
if(!wglMakeCurrent(hDC, hRC)) {
KillGLWindow();
MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hWnd, SW_SHOW); // 윈도우 보이기
SetForegroundWindow(hWnd); // 우선 순위
SetFocus(hWnd); // 포커스 설정
ReSizeGLScene(width, height);// GL화면 설정
if(!InitGL()) { // GL 초기화 함수
KillGLWindow();
MessageBox(NULL, "Initialization failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
}
// 윈도우 메시지 처리
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:
return 0;
}
break;
}
case WM_CLOSE: { // 윈도우 종료 메시지
PostQuitMessage(0);
return 0;
}
case WM_KEYDOWN: { // 키 눌림
keys[wParam] = TRUE;
return 0;
}
case WM_KEYUP: { // 키 떼임
keys[wParam] = FALSE;
return 0;
}
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, "Uould you like to run in fullscreen mode?", "Start FullScreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) {
fullscreen = FALSE;// 무조건 창모드로 실행하자
//}
// 윈도우 생성
if(!CreateGLWindow("OpenGL Framework", windowWidth, windowHeight, 16, fullscreen)) {
return 0;
}
// 루프
while(!done) {
// 메시지 확인
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if(msg.message == WM_QUIT) { // 종료 메시지 확인
done = TRUE; // 루프 종료
} else {
TranslateMessage(&msg); // 메시지 해석
DispatchMessage(&msg); // 메시지 디스패치
}
} else {
if(active) { // 액티브 상태인지 확인
if(keys[VK_ESCAPE]) { // ESC가 눌렸는지?
done = TRUE; // 루프 종료
} else {
DrawGLScene(); // GL신 그리기
SwapBuffers(hDC);// 버퍼 스왑
}
if(keys[VK_F1]) { // F1 키가 눌렸는지?
keys[VK_F1] = FALSE; // F1키 해제
KillGLWindow(); // 윈도우 종료
fullscreen = !fullscreen;// 전체화면 정보 바꿈
// 윈도우 생성
if(!CreateGLWindow("OpenGL Framework", windowWidth, windowHeight, 16, fullscreen)) {
return 0;
}
}
}
}
}
KillGLWindow(); // 윈도우 종료
return (msg.wParam);
}