Home Map Index Search News Archives Links About LF
[Top Bar]
[Bottom
Bar]
[Photo of the
Author]
Miguel Angel Sepúlveda
필자 소개: 1993년에 워싱턴대학(미국)을 졸업했다. 스페인, 이스라엘, 일본, 미국에서 과학연구 분야에서 일한다. 커널 0.98쯤부터 리눅스를 알게 되었다. (첫눈에 반했다) 현재는 자유 시간에 리눅스 포커스의 편집장으로 일한다.

필자에게 연락하기

들어가는글

초기화

이벤트 처리

에니매이션 보기



GLUT 홈페이지
GLUT저자
GLUT-3.6 소스코드

창과 애니메이션

요약: --




들어가는 글

OpenGL의 설계상의 이유로 윈도우시스템에 의존성이 있는 기능들은 규약에 빠져있다. 그 덕분에 높은 이식성과 간결하면서 효율적인 2차원/3차원 랜더링 라이브러리가 나올 수 있었다. 창을 열고 다루는 것은 고유의 윈도우 시스템에 달려 있다. OpenGL라이브러리는 추가적인 부가라이브러리를 통하여 고유의 윈도우 시스템과 통신을 수행한다. 예를 들자면 GLX부가라이브러리는 OpenGL과 X윈도우시스템사이의 상호동작을 담당한다.

OpenGL 유틸리티 툴킷(GLUT)은 OpenGL프로그램을 윈도우시스템과는 독립적으로 작동하도록 개발하게 해주는 부가라이브러리로 ANSI C언어와 FORTRAN을 지원한다. Mark J.Kilgard씨에 의해 작성되었으며 OpenGL규약에 있는 큰 결점을 보완해 준다. GLUT개발자 덕분에 원하는 플랫폼에 독립적으로 작동하는 공통된 윈도우 시스템 인터페이스를 사용할 수 있다. GLUT를 사용하는 OpenGL응용프로그램은 소스코드를 많이 바꿀 필요도 없이 플랫폼 이식이 쉽게 가능하다. GLUT는 OpenGL코드를 간단하게 만들어 줄 뿐만 아니라 OpenGL라이브러리를 보완해 준다.

GLUT는 상대적으로 작고 배우기 쉽다.매우 설계가 잘되어 있으며 또한 저자가 이미 환상적인 관련문서를 작성해 두었다. 그러므로 리눅스포커스에서 또다시 다룰 필요가 없다고 생각한다.Mark의 문서들을 꼭 읽어보기 바란다. GLUT의 문서가 매우 잘 되어 있는데 왜 이 연재에서 GLUT를 다루는가? 필자는 OpenGL연재와 함께 읽으면서 GLUT라이브러리를 살펴보고 단계단계별로 각 예를 따라 독자 여러분이 직접 따라해보면서 실력이 늘기를 바란다. 또한 OpenGL을 환상적인 리눅스에서 사용하는 프로그래머들에게 도움을 주고 이런 프로그래머들이 많이 퍼지는데 도움이 되었으면 한다. 어떤 경우든지간에 여러분은 Mark의 문서를 좋은 참고문서로 가지고 있는 것이 좋다.

GLUT API는 OpenGL과 마찬가지로 상태기술방식이다. 즉 응용프로그램이 실행되는 동안 GLUT가 많은 상태변수를 가지고 있다는 것을 의미한다. GLUT의 초기상태는 대부분의 응용프로그램에 알맞은 값을 가지고 있다. 그러나 사용자가 원하는 상태변수의 값을 변경할 수도 있다. GLUT의 함수들은 상태변수들의 값에 따라 취하는 행동이 약간 달라진다. GLUT함수는 간단하며 몇개의 파라메터들을 취한다. 돌려주는 포인터는 없으며 단지 GLUT의 함수로 전달되는 포인터는 문자열과 불확실한 글꼴을 다루기 위한 포인터뿐이다.

GLUT의 함수들은 그 기능에 따라 몇개의 하위 API들로 나누어진다.:

  • 초기화 
  • 이벤트 처리시작 
  • 윈도우 관리 
  • 오버레이 관리 
  • 메뉴 관리 
  • 콜백함수 등록 
  • 색상 인덱스 컬러맵 관리 
  • 상태 복구 
  • 글꼴 랜더링 
  • 기하학적 형상 랜더링 
이 글에서는 간단한 OpenGL프로그램을 시작하는데 필요한 초기화, 이벤트 처리, 창관리와 관련된 몇가지 함수들을 살펴보기로 하자.

초기화

GLUT를 사용하는 모든 OpenGL프로그램은 반드시 GLUT 상태머신에 의하여 초기화시켜야 한다. glut초기화함수는 glutInit-로 시작하는 이름을 가지고 있다. 주요 초기화루틴은 glutInit이다.:
사용법 
  glutInit(int **argcp, char **argv); 
  argcp 는 main함수의 수정할 수 없는 argc변수를 가르키는 포인터이다. glutInit함수는 GLUT라이브러리를 위한 적절한 실행명령어 선택옵션을 골라내기 때문에 반환값에 따라 argcp가 가르키는 값이 변경된다. 예를 들어 X윈도우시스템 환경이라면 X윈도우에 적절한 옵션만이 GLUT창에 영향을 미친다.
  argv 는 main함수에 사용되는 수정할 수 없는 프로그램의 argv변수이다.

glutInit는 GLUT의 상태변수를 초기화하는 역할과 윈도우시스템의 세션을 처리하는 역할을 한다. glutInit보다 먼저 사용될 수 있는 명령어가 몇가지 있는데 이 루틴들은 모두 glutInit-로 시작되는 이름을 가진다. 이 루틴들은 기본 창을 초기 상태로 설정하는데 사용된다. 예를 들어보자.: 
사용법 
  glutInitWindowPosition(int x, int **y); 
  glutInitWindowSize(int width, int **height); 
  x,y  = 창의 왼쪽 윗꼭지점의 화면위치를 픽셀단위로 표현 
  width,height  창 크기를 픽셀단위로 나타낸 것 

모든 OpenGL프로그램에서 반드시 제공되는 초기화루틴인 glutInitDisplayMode()도 있다.: 
사용법 
  glutInitDisplayMode(unsigned int mode); 
  mode 는 디스플레이 모드를 나타내는데 이 값들은 GLUT의 디스플레이 모드를 나타내는 비트마스크값을 OR연산을 취한다. 가능한 비트마스크 값은 다음과 같다.: 
GLUT_RGBA  RGBA모드의 창을 선택한다. GLUT_RGBA나 GLUT_INDEX로 지정되지 않는다면 이 값이 기본설정값이 된다. 
GLUT_RGB  GLUT_RGBA와 동일하다. 
GLUT_INDEX  인덱스를 가진 색상만 지원하는 창모드를 선택한다. GLUT_RGBA위에 덮어 써진다.. 
GLUT_SINGLE  단일버퍼를 가진 창을 선택한다. 이값이 기본설정이다. 
GLUT_DOUBLE  이중버퍼를 가진 창을 선택한다. 이 값은 GLUT_SINGLE위에 덮어 써진다. 
GLUT_ACCUM  누적버퍼를 가진 창을 선택한다. 
GLUT_ALPHA  색상버퍼에 알파값을 가진 창을 선택한다. 
GLUT_DEPTH  깊이버퍼를 가진 창을 선택한다. 
GLUT_STENCIL  형판버퍼(stencil buffer)를 가진 창을 선택한다.
GLUT_MULTISAMPLE  다중맵플링(multismapling)을 지원하는 창을 선택한다.
GLUT_STEREO 입체창(stereo window)을 선택한다. 
GLUT_LUMINANCE 휘도를 가진 색상모델을 다루는 입체창을 선택한다.
여기에 설명된 몇가지 특징들이 낯선 것일지라도 걱정하지 마라. 빠른 시간안에 그러한 것들에 대해서도 이야기를 하게 될 것이다. 이제 몇가지 예를 살펴보자. 먼저 하나의 간단한 랜더링 애플리케이션을 만들기 위한 간단한 초기화를 살펴보자.: 

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* 창의 위치와 크기 설정 */ 
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* 디스플레이모드형식 선택:  
   Single buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); 

/* GLUT상태의 초기화 */ 
glutInit(&argcp, argv);  

.....코드 생략 

}; 

두번째는 애니메이션 프로그램을 위한 초기화부분이다.: 

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* 창의 크기와 위치 결정 */ 
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* 디스플레이 모드 형식 결정: 
   이중버퍼를 가지고 있으며 RGBA 색상 지원 */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 

/* GLUT 상태를 초기화한다. */ 
glutInit(&argcp, argv);  

....이하 생략 

}; 

이 두 예제를 비교하면서 계속 GLUT를 배워보자. 가장 큰 차이점은 두번째 예제가 이중버퍼로 초기화되었다는 것이다. 이 방법은 애니메이션처리에 이상적이며 애니메이션의 순서에 따라 프레임이 바뀔때 나타나는 깜빡거림 효과를 없애준다.

이벤트 처리

앞에서 말했듯이 GLUT는 상태를 다루는 라이브러리이다. 지금부터 이벤트들을 다루는 부분을 작성해 보자. 이것은 결국 적절하게 초기화시킨 다음 실행되는 무한루프나 타이머가 있다는 것이다. 이에 따라 초기화하는 동안 GLUT에 선언된 모든 이벤트들을 하나하나씩 모두 처리한다는 것이다. 마우스버튼 클릭, 창 닫기, 창 모양바꿈, 커서 이동, 키보드 눌러짐, 그리고 "아무런 입력도 없는 상태"임 등의 이벤트들에 대해 적절한 행동을 취할 수 있다. 이용할 수 있는 이벤트들의 각 이벤트들은 반드시 사용자에 의해 해당 이벤트가 발생했는지를 확인해보는 주기적인 GLUT이벤트 처리 루프나 타이머에 사용될 GLUT상태변수의 하나로 등록시켜야 한다.
 
예를 들어 "마우스버튼이 눌러짐" 이벤트를 GLUT가 계속 발생하는지 살펴봐야할 이벤트로 등록할 수 있다. 이벤트는 콜백등록 루틴으로 등록한다.. 이 함수는 모두 glut[특정이벤트]Func라는 규칙에 따라 이름을 가지며 마우스 클릭에 대한 이벤트처리는 glutMouseFunc가 될 것이다. 콜백등록은 GLUT엔진에게 어떤 특정한 이벤트가 발생하면 적절한 사용자정의함수를 실행하도록 해준다. 그래서 만약 마우스의 왼쪽버튼이 눌러졌을때 실행될 루틴을 MyMouse라 한다면(물론 오른쪽버튼도 가능하다.) 이 경우 main()함수에서 glutInit()다음에 "glutMouseFunc(MyMouse);"라 적어줌으로써 자신의 콜백함수를 등록할 수 있다.

GLUT에서 처리할 수 있는 콜백함수와 이벤트들은 뒤에 살펴보기로 하자. 지금 중요한 것은 우리들의 프로그램에서 중요한 이벤트들이 등록된 다음 glutMainLoop()라는 GLUT의 이벤트처리루틴을 반드시 호출해야 한다는 것이다. 이 함수를 한번 실행하면 프로그램은 기본적으로 무한루프상태로 들어간다. 이 함수는 이미 등록한 콜백함수를 필요에 따라 호출한다. 따라서 모든 OpenGL프로그램은 glutMainLoop()명령문으로 끝난다. 애니메이션의 경우를 살펴보자.

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* GLUT 상태 초기화*/ 
glutInit(&argcp, argv);  
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* 창을 연다. */ 
glutCreateWindow("My OpenGL Application"); 

/* 디스플레이 모드를 선택한다.:  
   이중버퍼 & RGBA 색상 */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
 

/* 콜백함수 등록 */ 
..... 

/* 이벤트 처리엔진 시작 */ 
glutMainLoop(); 
}; 

앞에서 설명하지 않은 몇가지 특별한 코드가 눈에 띌 것이다. glutCreateWindow(char **name)는 GLUT의 윈도우를 관리하는 루틴의 하나이다. 이 함수는 이름만 척보면 어떤 일을 하는지 바로 명확하게 알 수 있다. 이러한 함수이름은 OpenGL과 GLUT의 설계철학중에서 필자가 적극적으로 찬성하는 부분이다. 이 함수는 실제로 OpenGL응용프로그램에서 사용할 창을 사용자의 윈도우시스템에서 생성하도록 명령을 전달하는 역할을 담당한다. 이 창의 이름은 문자열"name"으로 전달된다. X윈도우 환경에서 이 이름은 창의 윗쪽 왼쪽 모서리에 쓰여진다. GLUT가 담당하는 창의 관리부분은 수시로 확인해야할 다양한 많은 함수를 가지고 있다. 지금까지동안 이야기한 것이면 충분하다. 이제 다시 glutInit()함수 뒤에 둘 수 있는 초기화루틴들을 다시 배치시키면 된다.

본론으로 돌아가서..필자는 애니메이션프로그램에서 매우 기본적인 두개의 콜백등록함수를 등록하는 방법을 소개할까 한다. glutDisplayFunc는 현재창을 실제로 보여주는 기능을 정의하고 있으며, glutIdleFunc는 아무런 입력이 없을 때 수행하는 기능을 정의하고 있다. 이 두 등록함수는 모두 void *(void)형의 함수이어야 한다. 먼저 애니메이션프로그램에 추가된 두개의 콜백함수를 이야기 하면 void MyDisplay(void)는 실제로 우리가 원하는 화면을 창에 그려주는 OpenGL명령어등을 호출하는 것을 담당하며 void MyIdle(void)는 사용자의 입력이 없을때 계속 호출되어진다. GLUT의 무한루프(glutMainLoop())하에서 이벤트처리는 계속 이루어지며 만약 아무런 새로운 이벤트도 발생하지 않는다면 그때는 MyIdle함수가 담당한다. 왜 애니메이션 프로그램에 아무런 입력이 없을때의 콜백함수를 등록시켜주어야 하는가? 만약 사용자의 입력과는 상관없이 계속해서 각 프레임의 그림을 바꿔그려주어야 하므로 OpenGL프로그램이 실행되고 있는 동안 Mydisplay()에서 그리기 전에 각 프레임을 바쭤주는 기능을 해주는 함수(쉬고있는 상태(idle) 콜백함수)가 필요한 것이다.

애니메이션 예

이제 하나로 깔끔하게 된 애니메이션코드를 살펴보자.: 
#include <GL/glut.h> 

void MyIdle(void){ 
/* 사용된 변수값을 다음 프레임의 상태로 수정해 주는부분*/ 
.... 
}; 

void MyDisplay(void){ 
/* 프레임에 실제 그림을 그리는 OpenGL명령어들이 들어간다. */ 
.... 
/* 프레임이 다 그려진 다음 버퍼를 교체한다. */ 
glutSwapBuffers(); 
}; 

void main(int argcp, char **argv){ 

/* GLUT상태를 초기화 한다. */ 
glutInit(&argcp, argv);  
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* 창을 연다. */ 
glutCreateWindow("My OpenGL Application"); 

/* 디스플레이모드를 선택한다.:  
   이중버퍼 & RGBA색상 */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 

/* 콜백함수들을 등록한다. */ 
glutDisplayFunc(MyDisplay) 
glutIdleFunc(MyIdle) 

/* 이벤트 처리엔진을 시작한다 */ 
glutMainLoop(); 
}; 

필자는 MyDisplay뒤에 새로운 GLUT함수인 glutSwapBuffers()를 추가하였다. 이 명령은 애니메이션에 대단히 유용하다. 이미 프로그램에서는 하나는 보여지고 하나는 숨겨진 이중버퍼모드의 창을 사용하고 있다. 이 경우 OpenGL의 그리는 명령어들은 항상 숨겨진 버퍼에 랜더링을 수행한다. glutSwapBuffers명령이 호출되면 완전히 다 그려진 숨겨져 있던 버퍼가 보여지게 되는 버퍼교환이 이루어진다. 이 기법은 애니메이션에서 사람들의 눈이 프레임단위로 그려지는 것을 눈치채지 못하도록 하기 때문에 컴퓨터애니메이션분야에서 일반적인 기법이다.

OpenGL응용프로그램개발을 시작하기 위한 충분한 정보들을 살펴보았다. 단 한가지 빠트린 것이 있다면 실제로 그림이 그려지는 MyDisplay내의 OpenGL명령어들이다...이것은 실제로 따른 이야기이다 ;-)

GLUT연재 다음회에서는 GLUT에서 사용할 수 있는 창 관리부분의 함수들을 좀더 깊이 다뤄보기로 하겠다. 그리고 동일한 창에 여러개의 장면을 어떻게 그리는가 하는 방법과 이식성 및 메뉴를 사용하는 방법을 살펴보겠다. 더 많은 정보가 필요하다면:




번역 : 이주호


본 웹사이트는 Miguel Angel Sepulveda씨에 의해 관리됩니다.
© Emre Demiralp 1998
LinuxFocus 1998