본문 바로가기
전공/컴퓨터 그래픽스

OpenGL 기본틀 : Callback 프로그래밍 (2)Menu Callback, Idle Callback, Timer Callback

by 임 낭 만 2023. 4. 11.

Menu Callback

Menu Callback

#include <GL/freeglut.h>

GLboolean IsSphere = true;
//IsSphere 변수 선언하고 True로 초기화 : 메뉴에서 선택된 도형을 결정하는데 사용
void MyDisplay() {	//화면에 도형을 그리는 함수
    glClear(GL_COLOR_BUFFER_BIT);	//컬러버퍼 초기화
    glColor3f(0.5, 0.0, 0.5);		//그릴 도형의 색상 지정
    if (IsSphere)			//IsSphere가 참이면 구 그리기
        glutWireSphere(0.2, 15, 15);
    else				//거짓이면 도넛을 그리기
        glutWireTorus(0.1, 0.3, 40, 20);
    glFlush();		//그리기 명령 실행
}
void MyMainMenu(int entryID) {	//메뉴 아이템이 선택될 때마다 호출됨, 전달된 아이디에 따라...
    if (entryID == 1)		//"Draw Sphere" 아이템 선택되어 IsSphere 변수 true로 설정
        IsSphere = true;
    else if (entryID == 2)	//"Draw Torus" 아이템 선택되어 IsSphere 변수 false로 설정
        IsSphere = false;
    else if (entryID == 3)	//"Exit" 아이템 선택되어 프로그램 종료
        exit(0);
    glutPostRedisplay();
    //다른 콜백 함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때..
}
int main(int argc, char** argv) {
    glutInit(&argc,argv);			//GLUT 라이브러리를 초기화함
    glutInitDisplayMode(GLUT_RGB);		//디스플레이 모드를 RGB 컬러 모드로 설정함
    glutInitWindowSize(300, 300);		//윈도우 크기 설정
    glutInitWindowPosition(0, 0);		//윈도우 위치 설정
    glutCreateWindow("OpenGL Example Drawing"); //윈도우 생성

    glClearColor(1.0, 1.0, 1.0, 1.0);   	//초기화 색은 백색
    glMatrixMode(GL_PROJECTION);		//행렬 모드를 GL_PROJECTION으로 설정
    glLoadIdentity();				//현재의 행렬 상태 초기화함.
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);	//뷰포트의 좌표계 설정

    GLint MyMainMenuID = glutCreateMenu(MyMainMenu); //메뉴 콜백 함수를 등록, 그 결과 등록된 메뉴 아이디 값이 리턴됨
    //현 메뉴에 메뉴 항목을 추가함
    glutAddMenuEntry("Draw Sphere", 1);
    glutAddMenuEntry("Draw Torus", 2);
    glutAddMenuEntry("Exit", 3);
    glutAttachMenu(GLUT_RIGHT_BUTTON);		//지정한 마우스 버튼에 현 메뉴를 할당함 : 우클릭 버튼
    glutDisplayFunc(MyDisplay);			//디스플레이 콜백 함수 등록
    glutMainLoop();				//이벤트 루프 실행
    return 0;
}

Cascaded Menu

#include <GL/freeglut.h>
#include <iostream>

GLboolean IsSphere = true;
GLboolean IsSmall = true;
//IsSphere와 IsSmall이라는 전역 변수가 선언됨. 도형의 종류와 크기 결정
void MyDisplay() {	//화면에 도형을 그리는 함수
    glClear(GL_COLOR_BUFFER_BIT);	//컬러버퍼 초기화
    glColor3f(0.5, 0.0, 0.5);		//그릴 도형의 색상 지정
    if ((IsSphere) && (IsSmall))
        glutWireSphere(0.2, 15, 15);        //작은 원구
    else if ((IsSphere) && (!IsSmall))
        glutWireSphere(0.4, 15, 15);        //큰 원구
    else if ((!IsSphere) && (IsSmall))
        glutWireTorus(0.1, 0.3, 40, 20);    //작은 원환체
    else
        glutWireTorus(0.2, 0.5, 40, 20);    //큰 원환체
    glFlush();		//그리기 명령 실행
}
void MyMainMenu(int entryID) {		//메뉴 아이템이 선택될 때마다 호출됨,
    if (entryID == 1)
        IsSphere = true;                //원구 그리기
    else if (entryID == 2)
        IsSphere = false;               //원환체 그리기
    else if (entryID == 3)
        exit(0);                        //프로그램 종료
    glutPostRedisplay();
    //다른 콜백 함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때..
}
void MySubMenu(int entryID) {
    if (entryID == 1)
        IsSmall = true;                 //작은 크기로 그리기
    else if (entryID == 2)
        IsSmall = false;                //큰 크기로 그리기
    glutPostRedisplay();
    //다른 콜백 함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때..
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);			//GLUT 라이브러리를 초기화함
    glutInitDisplayMode(GLUT_RGB);		//디스플레이 모드를 RGB 컬러 모드로 설정함
    glutInitWindowSize(300, 300);		//윈도우 크기 설정
    glutInitWindowPosition(0, 0);		//윈도우 위치 설정
    glutCreateWindow("OpenGL Example Drawing"); //윈도우 생성
    glClearColor(1.0, 1.0, 1.0, 1.0);   	//초기화 색은 백색
    glMatrixMode(GL_PROJECTION);		//행렬 모드를 GL_PROJECTION으로 설정
    glLoadIdentity();				//현재의 행렬 상태 초기화함.
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);	//뷰포트의 좌표계 설정
    
    GLint MySubMenuID = glutCreateMenu(MySubMenu);//서브 메뉴 콜백 함수를 등록, 그 결과 등록된 메뉴 아이디 값이 리턴됨
    //서브 메뉴 항목 추가
    glutAddMenuEntry("Small One", 1);
    glutAddMenuEntry("Big One", 2);
    GLint MyMainMenuID = glutCreateMenu(MyMainMenu);//메인 메뉴 콜백 함수를 등록, 그 결과 등록된 메뉴 아이디 값이 리턴됨
    //현 메뉴에 메뉴 항목을 추가함
    glutAddMenuEntry("Draw Sphere", 1);
    glutAddMenuEntry("Draw Torus", 2);
    glutAddSubMenu("Change Size", MySubMenuID);	//현 메뉴 중 하나로서 서브 메뉴 항목을 추가함
    glutAddMenuEntry("Exit", 3);
    glutAttachMenu(GLUT_RIGHT_BUTTON);		//지정한 마우스 버튼에 현 메뉴를 할당함 : 우클릭 버튼
    glutDisplayFunc(MyDisplay);			//디스플레이 콜백 함수 등록
    glutMainLoop();				//이벤트 루프 실행
    return 0;
}

더보기
  • int glutCreateMenu(void(*func)(int value)) : 새로운 메뉴를 생성하고 해당 메뉴에 대한 함수를 등록함.
  • void glutSetMenu(int id) : 현재 메뉴를 설정함.
  • void glutAddMenuEntry(char *name,int value) : 현재 메뉴에 새로운 항목을 추가. 항목 이름과 항목을 선택했을 때 호출될 값(value)을 지정함.
  • int glutAttachMenu(int button) : 마우스 버튼 이벤트와 현재 메뉴를 연결 예를 들어, GLUT_RIGHT_BUTTON을 인수로 전달하면 마우스 오른쪽 버튼 클릭시 메뉴가 나타남.
  • void glutaddSubMenu(char *name, int menu) : 하위 메뉴를 생성하고 현재 메뉴에 추가. name은 하위 메뉴 이름, menu는 하위 메뉴에 대한 메뉴 ID. 이 함수는 메뉴 계층 구조를 만드는 데 사용됨.

Idle Callback

#include <GL/freeglut.h>

GLfloat Delta = 0.0;	//사각형을 오른쪽으로 조금씩 옮기는데 사용함 (사각형이 이동하는 양)
void MyDisplay() {
    glClear(GL_COLOR_BUFFER_BIT);	//기존의 컬러 버퍼 내용을 지우라는 것. glClearColor(1.0, 1.0, 1.0, 1.0) 사용
    glColor3f(0.0, 0.5, 0.8);		//그리는 도형의 색상 설정	
    glBegin(GL_POLYGON);		//사각형 그리기
        glVertex3f(-1.0 + Delta, -0.5, 0.0);
        glVertex3f(0.0 + Delta, -0.5, 0.0);
        glVertex3f(0.0 + Delta, 0.5, 0.0);
        glVertex3f(-1.0 + Delta, 0.5, 0.0);
    glEnd();		//도형 그리기 종료
    glutSwapBuffers();
  //증가된 델타 값을 사용하여 새로이 그려질 사각형은 백 버퍼에 기록되며 그동한 현재 화면에 보이는 내용은 현재 프런트 버퍼에 있는 이전 사각형임
  //버퍼 스와핑 명령에 의해 새로 생성된 사각형을 보일 수 있게 됨
}
void MyIdle() {
    Delta = Delta + 0.001;	//Delta 값을 증가시킴
    glutPostRedisplay();
    //다른 콜백함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때, 화면을 다시 그리도록 하기
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);			//GLUT 라이브러리를 초기화함
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//디스플레이 모드를 RGB 컬러 모드로 설정 & 더블 버퍼링 활성화
    glutInitWindowSize(300, 300);		//윈도우 크기 설정
    glutInitWindowPosition(0, 0);		//윈도우 위치 설정
    glutCreateWindow("OpenGL Example Drawing"); //윈도우 생성
    glClearColor(1.0, 1.0, 1.0, 1.0);   	//초기화 색은 백색
    glMatrixMode(GL_PROJECTION);		//행렬 모드를 GL_PROJECTION으로 설정
    glLoadIdentity();				//현재의 행렬 상태 초기화함.
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);	//뷰포트의 좌표계 설정
    
    glutDisplayFunc(MyDisplay);			//디스플레이 콜백 함수 등록
    glutIdleFunc(MyIdle);			//아이들 콜백 함수 등록
    glutMainLoop();				//이벤트 루프 실행
    return 0;
}

더보기
  • 이벤트 루프를 돌 때마다 GLUT는 큐에 쌓인 이벤트를 검사함.
  • glClear()를 기존의 컬러 버퍼 내용을 다 지우라는 의미로, 이게 없다면 새로운 사각형이 이전 사각형이 위에 겹쳐서 기록 되므로 원하는 바가 아니다.  = 러버 밴딩 : 이전의 그림을 지우고, 배경색을 다시 칠하고.
  • 애니메이션 등의 동적인 변화를 위해 사용됨. glutIdleFunc() 함수를 사용하여 Idle 콜백 함수 등록

Timer Callback

Timer Callback 1

#include <GL/freeglut.h>

GLfloat Delta = 0.0;
//사각형을 오른쪽으로 조금씩 옮기는데 사용함 (사각형이 이동하는 양)
void MyDisplay() {	//도형 그리는 함수
    glClear(GL_COLOR_BUFFER_BIT);	//기존의 컬러 버퍼 내용을 지우라는 것. glClearColor(1.0, 1.0, 1.0, 1.0) 사용
    glColor3f(0.0, 0.5, 0.8);		//그리는 도형의 색상 설정	
    glBegin(GL_POLYGON);		//사각형 그리기
        glVertex3f(-1.0 + Delta, -0.5, 0.0);
        glVertex3f(0.0 + Delta, -0.5, 0.0);
        glVertex3f(0.0 + Delta, 0.5, 0.0);
        glVertex3f(-1.0 + Delta, 0.5, 0.0);
    glEnd();		//도형 그리기 종료
    glutSwapBuffers();
    //증가된 델타 값을 사용하여 새로이 그려질 사각형은 백 버퍼에 기록되며 그동한 현재 화면에 보이는 내용은 현재 프런트 버퍼에 있는 이전 사각형임
    //버퍼 스와핑 명령에 의해 새로 생성된 사각형을 보일 수 있게 됨
}
void MyTimer(int Value) {
    Delta = Delta + 0.001;	//Delta 값을 증가시킴
    glutPostRedisplay();
    //다른 콜백함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때, 화면을 다시 그리도록 하기
    glutTimerFunc(40, MyTimer, 1);
    /*일정한 시간간격이 지나면 발생하는 이벤트가 타이머 이벤트 이며, 타이머 콜백은 이 이벤트에 대응하는 콜백함수임
    40 msec 의미, 1은 넘겨줄 파라미터. GLUT 타이머는 타이머 함수가 등록되면 단 한번만 타이머 이벤트를 발생시킴.
    콜백함수의 마지막에 콜백등록함수를 다시 써 줌으로써 해결함*/
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);			//GLUT 라이브러리를 초기화함
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//디스플레이 모드를 RGB 컬러 모드로 설정 & 더블 버퍼링 활성화
    glutInitWindowSize(300, 300);		//윈도우 크기 설정
    glutInitWindowPosition(0, 0);		//윈도우 위치 설정
    glutCreateWindow("OpenGL Example Drawing"); //윈도우 생성
    glClearColor(1.0, 1.0, 1.0, 1.0);   	//초기화 색은 백색
    glMatrixMode(GL_PROJECTION);		//행렬 모드를 GL_PROJECTION으로 설정
    glLoadIdentity();				//현재의 행렬 상태 초기화함.
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);	//뷰포트의 좌표계 설정
    
    glutDisplayFunc(MyDisplay);			//디스플레이 콜백 함수 등록
    glutTimerFunc(40, MyTimer, 1);		//타이머 콜백 함수 등록
    glutMainLoop();				//이벤트 루프 실행
    return 0;
}

Timer Callback 2

#include <GL/freeglut.h>
#include <time.h>

unsigned char PALETTE[16][3] = {	//팔레트 배열 : 16개의 색상 값(RGB)을 저장하는 배열
    { 255, 255, 255 },      // WHITE
    {   0, 255, 255 },      // CYAN
    { 255,   0, 255 },      // PURPLE
    {   0,   0, 255 },      // BLUE
    { 192, 192, 192 },      // LIGHT GRAY
    { 128, 128, 128 },      // DARK GRAY
    {   0, 128, 128 },      // DARK TEAL
    { 128,   0, 128 },      // DARK PURPLE
    {   0,   0, 128 },      // DARK BLUE
    { 255, 255,   0 },      // YELLOW
    {   0, 255,   0 },      // GREEN
    { 128, 128,   0 },      // DARK YELLOW
    {   0, 128,   0 },      // DARK GREEN
    { 255,   0,   0 },      // RED
    { 128,   0,   0 },      // DARK RED
    {   0,   0,   0 },      // BLACK
};
GLfloat Delta = 0.0;	//애니메이션에서 사용되는 변수. 각 라인이 얼마나 그려졌는지 나타냄
GLint   Index = 0;	//PALETTE 배열에서 현재 사용되는 색상의 인덱스를 저장하는 변수
//현재 사용되는 색상 값
GLfloat Red = 0.0;		
GLfloat Green = 0.0;
GLfloat Blue = 0.0;
void MyDisplay() {
//각 프레임마다 호출되어 그려지는 함수. 팔레트 배열에서 index에 해당하는 색상으로 두 개의 라인 그림
    Red   = PALETTE[Index][0] / 255.0f;
    Green = PALETTE[Index][1] / 255.0f;
    Blue  = PALETTE[Index][2] / 255.0f;

    glColor3f(Red, Green, Blue);		//그리는 선의 색상 설정
    glBegin(GL_LINES);				//선 그리기
        glVertex3f(-1.0 + Delta,  1.0, 0.0);	//Delta 변수를 사용해서 선을 회전시킴
        glVertex3f( 1.0 - Delta, -1.0, 0.0);
        glVertex3f(-1.0, -1.0 + Delta, 0.0);
        glVertex3f( 1.0,  1.0 - Delta, 0.0);
    glEnd();		//선 그리기 종료
    glutSwapBuffers();
}
void MyTimer(int Value) {	//일정 시간마다 호출되어 Delta 값을 변경하고, index 값이 변할 때마다 화면 지움
    if (Delta < 2.0f)
        Delta = Delta + 0.01;	//Delta 값을 증가시킴
    else {
        Delta = 0.0;
        if (++Index >= 15) {	//팔레트의 인덱스 값이 변경됨. 화면을 지우고 다시 그리기 위해 glClear 호출
            Index = 0;
            glClear(GL_COLOR_BUFFER_BIT);
        }
    }
    glutPostRedisplay();
    //다른 콜백함수에서 어떤 값을 바꾸고 바뀐 값을 기준으로 새로이 화면 디스플레이를 원할 때, 화면을 다시 그리도록 하기
    glutTimerFunc(10, MyTimer, 1);
    //첫 파라미터는 10msec를 의미하지만, 큐 프런트에 다른 이벤트가 있는 경우에는 그보다 늦어질 수 있음.
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);			//GLUT 라이브러리를 초기화함
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//디스플레이 모드를 RGB 컬러 모드로 설정 & 더블 버퍼링 활성화
    glutInitWindowSize(500, 500);		//윈도우 크기 설정
    glutInitWindowPosition(0, 0);		//윈도우 위치 설정
    glutCreateWindow("OpenGL Timer Animation Sample"); //윈도우 생성
    glClearColor(1.0, 1.0, 1.0, 1.0);   	//초기화 색은 백색
    glMatrixMode(GL_PROJECTION);		//행렬 모드를 GL_PROJECTION으로 설정
    glLoadIdentity();				//현재의 행렬 상태 초기화함.
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);	//뷰포트의 좌표계 설정
    
    glutTimerFunc(10, MyTimer, 1);		//타이머 콜백 함수 등록
    glutDisplayFunc(MyDisplay);			//디스플레이 콜백 함수 등록
    glutMainLoop();				//이벤트 루프 실행
    return 0;
}

더보기

타이머 이벤트 : 일정 시간이 지나면 발생하는 이벤트

댓글