visual studio 2002 에서 openGL 예제 실행
맨날 리눅스에서만 하다가 노트북 바꾸기 귀찮아서(!!) 윈도우에서도 해보려고 발악중
일단은 visual studio 에서 콘솔앱으로는 안되서
Windows 데스크탑 애플리케이션으로 프로젝트를 생성
프로젝트 설정에 링커 - 입력 - 추가 종속성에
opengl32.lib 와 glu32.lib를 추가해주면 끝
[링크 : https://makingrobot.tistory.com/155]
F5 눌러서 빌드하니 잘 뜬다.
아래는 gemini가 생성해준 소스코드.
#include <windows.h> // Win32 API 헤더
#include <gl/gl.h> // OpenGL 핵심 헤더
#include <gl/glu.h> // GLU 유틸리티 헤더
// OpenGL 렌더링 컨텍스트 핸들
HGLRC g_hRC = NULL;
// 디바이스 컨텍스트 핸들
HDC g_hDC = NULL;
// 윈도우 핸들
HWND g_hWnd = NULL;
// 인스턴스 핸들
HINSTANCE g_hInstance = NULL;
// 창 클래스 이름 (유니코드 문자열)
LPCWSTR szWindowClass = L"OpenGLWindow";
// 창 제목 (유니코드 문자열)
LPCWSTR szTitle = L"Simple OpenGL Triangle (No GLUT)";
// OpenGL 초기화 함수
void InitOpenGL() {
// 배경색을 검정색으로 설정 (RGBA 값)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 현재 매트릭스를 프로젝션 매트릭스로 설정
glMatrixMode(GL_PROJECTION);
// 2D 직교 투영 설정 (좌표계: x=0.0~200.0, y=0.0~200.0)
gluOrtho2D(0.0, 200.0, 0.0, 200.0);
}
// 그리기 함수
void DrawScene() {
// 컬러 버퍼 클리어
glClear(GL_COLOR_BUFFER_BIT);
// 삼각형 그리기 시작
glBegin(GL_TRIANGLES);
// 첫 번째 꼭지점: 빨간색 (위쪽)
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2i(100, 150);
// 두 번째 꼭지점: 녹색 (왼쪽 아래)
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2i(50, 50);
// 세 번째 꼭지점: 파란색 (오른쪽 아래)
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2i(150, 50);
glEnd(); // 삼각형 그리기 끝
// 프론트 버퍼와 백 버퍼 교체 (더블 버퍼링 사용 시)
SwapBuffers(g_hDC);
}
// OpenGL 활성화 함수
// 창 핸들(hWnd), 디바이스 컨텍스트 포인터(hDC), 렌더링 컨텍스트 포인터(hRC)를 인자로 받음
void EnableOpenGL(HWND hWnd, HDC* hDC, HGLRC* hRC) {
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
// 픽셀 형식 기술자 구조체를 0으로 초기화
ZeroMemory(&pfd, sizeof(pfd));
// 픽셀 형식 기술자 구조체의 크기 설정
pfd.nSize = sizeof(pfd);
// 픽셀 형식 기술자 버전 설정
pfd.nVersion = 1;
// 픽셀 형식 플래그 설정: 윈도우에 그리기, OpenGL 지원, 더블 버퍼링 사용
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
// 픽셀 타입 설정: RGBA 색상 모드
pfd.iPixelType = PFD_TYPE_RGBA;
// 색상 비트 깊이 설정: 32비트 색상
pfd.cColorBits = 32;
// 깊이 버퍼 비트 깊이 설정: 16비트 깊이 버퍼
pfd.cDepthBits = 16;
// 레이어 타입 설정: 메인 평면
pfd.iLayerType = PFD_MAIN_PLANE;
// 윈도우의 디바이스 컨텍스트를 얻음
*hDC = GetDC(hWnd);
// 주어진 픽셀 형식 기술자에 가장 적합한 픽셀 형식을 찾음
iFormat = ChoosePixelFormat(*hDC, &pfd);
// 디바이스 컨텍스트에 픽셀 형식을 설정
SetPixelFormat(*hDC, iFormat, &pfd);
// OpenGL 렌더링 컨텍스트 생성
*hRC = wglCreateContext(*hDC);
// 현재 스레드의 디바이스 컨텍스트에 렌더링 컨텍스트를 연결
wglMakeCurrent(*hDC, *hRC);
// OpenGL 초기화 함수 호출
InitOpenGL();
}
// OpenGL 비활성화 함수
// 창 핸들(hWnd), 디바이스 컨텍스트(hDC), 렌더링 컨텍스트(hRC)를 인자로 받음
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) {
// 현재 렌더링 컨텍스트를 해제
wglMakeCurrent(NULL, NULL);
// 렌더링 컨텍스트를 삭제
wglDeleteContext(hRC);
// 디바이스 컨텍스트를 해제
ReleaseDC(hWnd, hDC);
}
// 윈도우 프로시저 (메시지 처리 콜백 함수)
// 윈도우 핸들, 메시지 코드, 추가 정보(wParam, lParam)를 인자로 받음
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
// 윈도우 생성 시 발생하는 메시지
case WM_CREATE:
// OpenGL 활성화 함수 호출
EnableOpenGL(hWnd, &g_hDC, &g_hRC);
break;
// 윈도우가 다시 그려져야 할 때 발생하는 메시지
case WM_PAINT:
// 그리기 함수 호출
DrawScene();
// WM_PAINT 메시지를 유효화 (반복적인 WM_PAINT 메시지 방지)
ValidateRect(hWnd, NULL);
break;
// 윈도우 크기 변경 시 발생하는 메시지
case WM_SIZE:
// 뷰포트 크기를 윈도우 크기에 맞게 조정 (선택 사항)
// L_PARAM에서 새 너비와 높이를 추출하여 glViewport 함수에 전달
// glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
break;
// 윈도우 닫기 버튼 클릭 시 발생하는 메시지
case WM_CLOSE:
// 윈도우 파괴 메시지를 보냄
DestroyWindow(hWnd);
break;
// 윈도우가 파괴될 때 발생하는 메시지
case WM_DESTROY:
// OpenGL 비활성화 함수 호출
DisableOpenGL(hWnd, g_hDC, g_hRC);
// 메시지 루프를 종료하는 메시지를 보냄
PostQuitMessage(0);
break;
// 처리하지 않는 다른 메시지들은 기본 윈도우 프로시저로 전달
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// WinMain 함수 (Windows 애플리케이션의 진입점)
// 인스턴스 핸들, 이전 인스턴스 핸들, 명령줄 문자열, 표시 상태 플래그를 인자로 받음
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc; // 윈도우 클래스 구조체
MSG msg; // 메시지 구조체
BOOL bDone = FALSE; // 메시지 루프 종료 플래그
g_hInstance = hInstance; // 현재 인스턴스 핸들 저장
// 윈도우 클래스 스타일 설정: 고유한 DC, 수평/수직 리드로우 시 다시 그리기
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
// 윈도우 프로시저 함수 포인터 설정
wc.lpfnWndProc = WndProc;
// 추가 클래스 메모리 (0)
wc.cbClsExtra = 0;
// 추가 윈도우 메모리 (0)
wc.cbWndExtra = 0;
// 인스턴스 핸들 설정
wc.hInstance = hInstance;
// 아이콘 설정 (기본 애플리케이션 아이콘)
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// 커서 설정 (기본 화살표 커서)
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// 배경 브러시 설정 (검정색 솔리드 브러시)
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
// 메뉴 이름 (없음)
wc.lpszMenuName = NULL;
// 윈도우 클래스 이름 설정 (LPCWSTR)
wc.lpszClassName = szWindowClass;
// 윈도우 클래스 등록 시도
if (!RegisterClass(&wc)) {
// 등록 실패 시 메시지 박스 표시 (유니코드 문자열 사용)
MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return 0; // 프로그램 종료
}
// 윈도우 생성 시도
g_hWnd = CreateWindowEx(
WS_EX_APPWINDOW, // 확장된 윈도우 스타일: 작업 표시줄에 앱으로 표시
szWindowClass, // 윈도우 클래스 이름 (LPCWSTR)
szTitle, // 윈도우 제목 (LPCWSTR)
// 윈도우 스타일: 오버랩된 창, 형제 윈도우 영역 클리핑, 자식 윈도우 영역 클리핑
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, // x, y 위치 (기본값 사용)
400, 400, // 윈도우 너비, 높이
NULL, // 부모 윈도우 핸들 (없음)
NULL, // 메뉴 핸들 (없음)
hInstance, // 인스턴스 핸들
NULL // 추가 생성 데이터 (없음)
);
// 윈도우 생성 실패 시
if (!g_hWnd) {
// 메시지 박스 표시 (유니코드 문자열 사용)
MessageBox(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return 0; // 프로그램 종료
}
// 윈도우를 화면에 표시
ShowWindow(g_hWnd, nCmdShow);
// 윈도우를 업데이트하여 WM_PAINT 메시지 발생
UpdateWindow(g_hWnd);
// 메시지 루프
while (!bDone) {
// 메시지 큐에서 메시지를 확인 (메시지가 없어도 즉시 반환)
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// 종료 메시지 (WM_QUIT) 수신 시
if (msg.message == WM_QUIT) {
bDone = TRUE; // 루프 종료 플래그 설정
}
else {
// 키보드 메시지를 번역 (예: VK_SHIFT -> WM_KEYDOWN)
TranslateMessage(&msg);
// 메시지를 해당 윈도우의 윈도우 프로시저로 디스패치
DispatchMessage(&msg);
}
}
else {
// 메시지가 없을 때 지속적으로 그리기 (게임 루프와 유사)
DrawScene();
}
}
// 프로그램 종료 코드 반환
return (int)msg.wParam;
}