Quick Flow
glutInit → 버전·프로파일·표시 모드 지정 → glutCreateWindow
→ GL 함수 로딩 → display·reshape·입력 콜백 등록
→ glutMainLoop → 이벤트에 맞는 콜백 실행
→ display에서 그리기·glutSwapBuffersfreeglut은 창과 이벤트 흐름을 준비합니다. glutPostRedisplay는 다시 그리기를 요청하고, 실제 GL 그리기는 display 콜백에서 수행합니다. 기본 예제는 freeglut 3.x + GLAD 2 + GL 3.3 Core입니다.
시작 조건
원본 GLUT과 freeglut 개발 패키지는 구분합니다. GL/freeglut.h와 freeglut 라이브러리가 필요하며, Apple의 시스템 GLUT만 연결한 상태에서는 freeglut 전용 함수를 사용할 수 없습니다. 플랫폼에 따라 창 시스템 의존성도 필요합니다. 설치 패키지가 제공하는 백엔드를 확인합니다.
freeglut-frame.cpp를 기존 예제 빌드 파일 옆에 저장합니다. GLAD 생성과 기본 빌드를 준비한 뒤 다음 옵션을 켭니다. 이 공통 빌드 파일은 GLFW 예제도 함께 만들므로 GLFW 개발 패키지도 필요합니다.
cmake -S . -B build -DGLAD_DIR=./glad -DBUILD_FREEGLUT_SAMPLE=ON
cmake --build build --config ReleaseFindGLUT가 다른 GLUT 구현을 선택했다면 freeglut 개발 패키지의 검색 경로를 지정합니다. 창 생성 실패는 freeglut의 진단 메시지를 확인합니다. 일부 치명적 초기화 오류는 함수가 단순 실패값을 반환하는 대신 프로세스를 종료할 수 있습니다.
콜백의 책임
다음은 완결 예제에서 사용하는 콜백입니다. GL 함수 로딩을 마친 컨텍스트에서 호출되며, 함수 이름을 glutDisplayFunc, glutReshapeFunc, glutKeyboardFunc에 각각 등록합니다. 이 콜백의 Escape 경로가 main으로 돌아오도록 루프 진입 전에 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS)를 설정합니다. 기본 종료 동작을 그대로 두는 경우와 구분합니다.
void display() {
glClearColor(0.1f, 0.3f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();
}
void reshape(int width, int height) {
if (width > 0 && height > 0) glViewport(0, 0, width, height);
}
void keyboard(unsigned char key, int, int) {
if (key == 27) glutLeaveMainLoop();
else glutPostRedisplay();
}display는 파란 배경을 그립니다. reshape는 새 크기를 viewport에 반영하고, 키보드 콜백은 Escape에서 루프를 끝내거나 다른 키에서 재그리기를 요청합니다. 특수 키는 void special(int key, int x, int y) 형태의 콜백을 만들고 glutSpecialFunc(special)로 등록합니다. 예를 들어 방향키는 GLUT_KEY_LEFT 같은 상수로 분기하며 문자 콜백과 구분합니다.
애니메이션을 추가한다면 timer 또는 idle 콜백에서 시간을 계산하고 상태를 갱신한 뒤 재그리기를 요청합니다. timer는 정밀한 고정 주기 실행을 보장하지 않으며, 반복하려면 다음 호출을 다시 등록해야 합니다. idle은 가능한 자주 실행될 수 있으므로 고정 프레임 시간으로 간주하지 않습니다.
표시와 종료 설정
| 설정·호출 | 선택과 결과 | 잘못 연결했을 때 |
|---|---|---|
GLUT_RGBA | 색상 모드를 명시 | 색 인덱스 모드와 혼동하지 않음 |
GLUT_DOUBLE | 이중 버퍼를 요청 | 단일 버퍼 예제에 swap만 추가하지 않음 |
GLUT_DEPTH, GLUT_STENCIL | 해당 기본 버퍼가 필요한 경우 요청 | 상태를 켜도 버퍼 자체가 없을 수 있음 |
glutInitContextVersion/Profile | 창 생성 전에 Core 3.3을 요청 | 창 생성 뒤 호출해 기존 컨텍스트를 바꾸려 함 |
GLUT_ACTION_GLUTMAINLOOP_RETURNS | 창 닫힘 뒤 main으로 복귀 | 종료 이후 컨텍스트가 남아 있다고 가정 |
샘플은 GL 객체를 별도로 만들지 않으므로 main 복귀 뒤 GL 정리가 없습니다. 버퍼·텍스처를 추가한 앱은 해당 컨텍스트가 유효한 시점에 정리하는 책임을 설계해야 합니다. 창이 이미 닫힌 뒤 glDelete*를 몰아서 호출하는 방식은 안전하지 않습니다.
GLUT과 달라진 점
freeglut의 glutLeaveMainLoop, 한 번의 이벤트 처리를 수행하는 glutMainLoopEvent, 컨텍스트 버전·프로파일 요청은 원본 GLUT과 구분합니다. GLUT 코드가 glBegin을 쓴다면 창 라이브러리만 freeglut으로 바꾸고 Core 3.3을 요청해서는 실행되지 않습니다. 그리기 경로도 현대 API로 바꾸거나 지원되는 레거시 컨텍스트를 선택합니다.
GLFW는 애플리케이션이 루프를 직접 작성하는 예제를 기본으로 합니다. 두 방식의 프레임 역할은 프레임 실행과 화면 표시에서 비교합니다.
참고 링크
2 sources