470 likes | 753 Views
입력과 상호작용. 입력과 상호작용 개요. 본 장의 내용 상호 작용을 위한 장치 물리적 입력 장치 논리적 입력 장치 클라이언트 - 서버 그래픽스 이벤트 - 구동 입력 페인트 프로그램 소개. 대화식 프로그램 개발. 입력과 상호작용. 상호작용 입력장치 클라이언트와 서버 디스플레이 리스트 이벤트 - 구동 입력의 프로그래밍 메뉴 지적 간단한 페인트 프로그램 대화식 프로그램의 설계. 상호 작용. 상호 작용
E N D
입력과 상호작용 개요 • 본 장의 내용 • 상호 작용을 위한 장치 • 물리적 입력 장치 • 논리적 입력 장치 • 클라이언트-서버 그래픽스 • 이벤트-구동 입력 • 페인트 프로그램 소개 대화식 프로그램 개발
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
상호 작용 • 상호 작용 • 화면상의 이미지에 사용자가 마우스와 같은 입력 장치로 반응하고 다시 이미지는 사용자의 입력에 반응하여 변화하는 과정의 반복 • OpenGL • 이식성을 높이기 위해 상호 작용을 직접 지원하지 않음 (GL 라이브러리에 포함되어 있지 않다는 의미) • GLUT 라이브러리에서 지원
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
입력 장치 • 물리적 입력 장치 • 마우스, 키보드와 같은 하드웨어적 기능에 대한 관점 • 논리적 입력 장치 • 응용프로그램 관점에서 특성이 명시됨 • 프로그래머는 대부분 물리적 입력 장치의 특성까지 알 필요가 없어야 함 • C언어의 printf 함수 • 출력이 나오는 물리적 입력 장치가 프린터, 모니터, 디스크 파일 등일 수 있음
물리적 입력 장치 • 지시 장치 • 상대위치 지정 장치 • 볼 마우스, 광학 마우스 , 트랙볼 등 • 장치의 움직임에 따라 x, y 방향의 두 값을 생성 • 절대 위치 지정 장치 • 데이터 태블릿, 터치 스크린 • 도면 트레이싱, 정교한 그림 편집 작업에 적합 마우스 트랙볼 태블릿
물리적 입력 장치 (con’t) • 조이스틱 • 가변-감도 장치 • 사용자에게 저항력을 줄 수 있어 시뮬레이션이나 게임에 적합 • 3차원 입력 장치 • 스페이스 볼(space ball) : 6-자유도를 가짐 • 세가지 힘 : 상하, 좌우, 전후 압력 감지 • 세가지 비틀림
물리적 입력 장치 (con’t) • 3차원 입력 장치 • 레이저-거리 측정 • 3차원 위치 추적 • 데이터 글러브
논리적 장치 • PHIGS, GKS등의 API에서의 분류 • 문자열 장치 • 위치 장치 • 지적(pick) 장치 : 객체의 식별자를 제공 • 선택(choice) 장치 : 선택사양중의 하나를 선택 • 다이얼 장치 : 아날로그 입력 • 획(stroke) 장치 : 위치의 배열을 제공 • OpenGL은 위의 6가지를 제공하지는 않음
측정치와 트리거 • 측정치 • 사용자 프로그램으로 장치가 반환하는 값 예) 지적(pick) 장치 : 객체의 식별자 + 상태 정보 키보드 : 문자열 • 트리거 • 사용자가 컴퓨터에게 신호를 주게 하는 입력 예) 위치 장치 : 버튼 키보드 : Enter 키
샘플 측정 프로세스 프로그램 측정치, 상태 입력 모드 • 요구 모드 : 장치가 트리거 될 때까지 측정치가 프로그램으로 반환되지 않음 (예) scanf() • 샘플 모드 : 트리거가 필요 없이 즉시 입력됨 (예) getc() 요구 트리거 측정 프로세스 트리거 프로세스 프로그램 측정치, 상태
트리거 대기 이벤트 큐 측정 프로세스 트리거 프로세스 프로그램 이벤트 측정치, 장치 ID 입력 모드 (con’t) • 이벤트 모드 • 장치가 트리거되면 이벤트가 생성되어 장치의 측정치와 식별자가 이벤트 큐에 저장됨 • 이벤트의 처리 • 답신(callback) 함수를 이벤트에 연결 • 이벤트 발생시에 답신 함수가 자동적으로 수행됨
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
디스플레이 리스트 • 간편한 그래픽스 구조 • 디스플레이 처리기 디스플레이 처리기 프레임 버퍼 주컴퓨터 화소 기본요소 디스플레이 리스트 클라이언트 서버
프레임 버퍼 클라이언트 서 버 객체들 화소 즉시 모드와 유지 모드 • 즉시모드 • 프로그램이 기본요소를 정의하는 문장을 실행하는 즉시 그 기본요소가 서버에 보내지고 시스템에는 메모리가 남지 않음 • 고도로 대화식인 프로그램에서 복잡한 객체의 경우, 클라이언트에서 서버로의 많은 데이터 양이 발생
객체들 화소 프레임 버퍼 클라이언트 서 버 디스플레이 객체들 디스플레이리스트 재 디스플레이 디스플레이 명령 즉시 모드와 유지 모드 (con’t) • 유지 모드 • 객체를 한번 정의하고 그것의 기술을 디스플레이 리스트에 저장 • 디스플레이 리스트는 서버에 저장되고 클라이언트로부터 서버에게 보내지는 간단한 함수호출로 재디스플레이
유지모드의 장단점 • 장점 • 클라이언트와 서버간의 통신량 절감 • 서버의 특수 하드웨어의 활용 • 단점 • 서버에 메모리 필요 • 디스플레이 리스트를 생성하는 부담 • 객체 자체가 변하는 경우에는 부적합
디스플레이 리스트의 정의와 실행 정수 ID 서버에 보내기만 함 • 정의 • 호출 glCallList(BOX); glNewList(BOX, GL_COMPILE); // Display List의 시작. BOX는 List의 ID // 비교 : GL_COMPILE_AND_EXECUTE glBegin(GL_POLYGON); // Polygon의 정의 glColor3f(1.0, 0.0., 0.0); // 색은 Red로.. glVertex2f(-1.0, -1.0); // 4개의 좌표 정의 glVertex2f( 1.0, -1.0); glVertex2f( 1.0, 1.0); glVertex2f(-1.0, 1.0); glEnd(); // Polygon 정의 끝 glEndList(); // List 정의 끝
속성 및 행렬 • 속성, 모델-관측 행렬, 투영 행렬 등의 시스템의 현재 상태의 적용을 받음 glMatrixMode(GL_PROJECTION); // View 설정 for (I=1; I < 5; I++) { glLoadIdentity(); // Matrix의 초기화 gluOrtho2D(-2.0*I, 2.0*I, -2.0*I, 2.0*I); // 절단 사각형 변경 glCallList(BOX); }
속성 및 행렬 저장 및 복원 • 디스플레이 리스트 내에서 상태 변환이 가능 디스플레이 리스트로 들어가기 전에 속성과 행렬을 저장하고 나올 때 복원하는 것이 좋음 • 스택을 사용하여 저장 glPushAttrib(GL_ALL_ATTRIB_BITS); glPushMatrix(); … glPopAttrib(); glPopMatrix();
다중 리스트 • 연속적인 식별자를 갖는 여러 개의 디스플레이 리스트 • glGenLists(number) : number 개의 연속된 리스트 ID를 확보하고 첫 ID를 반환 • glCallLists() : 여러 리스트를 실행
GLUT의 폰트 • 획 문자 출력 glTranslatef(100.0, 100.0, 0.0); glutStrokeCharacter(GLUT_STROKE_ROMAN, ‘A’); ‘A’문자 출력 • 래스터 문자 출력 glRasterPos2i(100,100); glutBitmapCharacter(GLUT_BITMAP_8_BY_13, ‘A’); • 각각 몇 개의 서체가 제공됨 (GLUT 매뉴얼 참조)
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
이벤트-구동 입력의 프로그래밍 • 3.5.1 지시장치의 사용 • 이벤트 종류 • 이동이벤트 • 버튼 중 하나가 눌린 채로 이동 시 • 답신 함수 : glutMotionFunc(callback_func) • 비활성 이동이벤트 • 버튼을 누르지 않고 이동 시 • 답신함수 : glutPassiveMotionFunc(callback_func) • 마우스 이벤트 • 버튼 중 하나가 눌려지거나 떼어졌을 때 • 답신 함수 : glutMouseFunc(callback_func)
사각형 그리기 프로그램 예(square.c) int main (int argc, char **argv) { glutInit (&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutCreateWindow (“square”); myinit(); glutReshapeFunc(myReshape); glutMouseFunc(mouse); glutMotionFunc(drawSquare); glutMainLoop(); } mouse (int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) drawSquare(x, y); if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) exit(0); } 윈도우 크기가 변할 경우호출 버튼을 누르고 마우스를 움직이면 사각형을 그림
초기화 /* 전역 변수 */ GLsizei wh = 500, ww = 500; /* 초기 윈도우 크기 */ GLfloat size = 3.0; /* 사각형의 한변의 절반크기 */ void myinit(void) { glViewport (0, 0, ww, wh); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluOrtho2D (0.0, (GLdouble) ww, 0.0, (GLdouble) wh); glMatrixMode (GL_MODELVIEW); glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glFlush(); }
사각형 그리기 void drawSquare( int x, int y) { y = wh -y; glColor3ub( (char)rand()%256, (char)rand()%256, (char) rand()%256); glBegin(GL_POLYGON); glVertex2f (x+size, y+size); glVertex2f (x-size, y+size); glVertex2f (x-size, y-size); glVertex2f (x+size, y-size); glEnd(); glFlush(); } 마우스 좌표 : 좌 상단 (0,0) 윈도우 좌표 : 좌 하단 (0,0)
윈도우 이벤트 • 재구성 이벤트 • 윈도우 크기가 변화되는 경우 • 답신 함수 : glutReshapeFunc() • 고려 사항 • 윈도우 내의 객체를 다시 그릴 것인가? • 종횡비가 달라지는 경우 어떻게 해야 하는가? • 기본 요소의 크기나 속성을 변화시켜야 하는가?
윈도우 이벤트 (con’t) void myReshape (GLsizei w, GLsizei h) { glMatrixMode (GL_PROJECTION); glLoadIdentity(); gluOrtho2D (0.0, (GLdouble)w, 0.0, (GLdouble)h); glMatrixMode (GL_MODELVIEW); glLoadIdentity(); glViewport (0, 0, w,h); glClearColor ( 0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glFlush(); ww = w; wh = h; } • 객체를 다시 그리지 않음 • 객체의 종횡비는 그대로 • 기본요소의 크기,속성 불변
키보드 이벤트 • 키가 눌렸을 때 이벤트 발생 main() { … glutKeyboardFunc(keyboard); … } void keyboard(unsigned char key, int x, int y) { if (key == ‘q’ || key == ‘Q’) exit(0); }
디스플레이 답신/휴지(idle) 답신 • 디스플레이 답신 • 윈도우가 다시 디스플레이되어야 할 때 예) 윈도우가 맨 처음 열릴 때 • 사용자와의 상호작용을 필요로 하지 않는 단순히 정보를 디스플레이 할 경우 사용. • 답신 함수 : glutDisplayFunc() • 이 답신 함수는 반드시 포함 되어야 함 • 다른 이벤트가 없을 때 발생 • 디폴트 : null 함수 • 답신 함수 : glutIdleFunc(idle_func)
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
메뉴 • GLUT는 팝업 메뉴를 제공 glutCreateMenu(demo_menu); // 메뉴 답신 함수 설정 glutAddMenuEntry(“quit”, 1); // 메뉴 항목 정의 glutAddMenuEntry(“Increase square size”, 2); // 메뉴 항목 정의 glutAddMenuEntry(“Decrease square size”, 3); // 메뉴 항목 정의 glutAttachMenu(GLUT_RIGHT_BUTTON); // 메뉴를 마우스 오른쪽 버튼에 연결 void demo_menu(int id) // 메뉴 답신 함수 { if (id == 1) exit(); // Quit 메뉴를 눌렀을 경우 else if (id == 2) size = 2 * size; // Increase square size 메뉴를 눌렀을 경우 else if (size > 1) size = size / 2; // Decrease square size 메뉴를 눌렀을 경우 glutPostRedisplay(); // 메뉴호출 이전 상태를 다시 그림. }
계층 메뉴 sub_menu = glutCreateMenu(size_menu); // 부메뉴 답신 함수 설정 glutAddmenuEntry(“Increase square size”, 2); // 메뉴 항목 정의 glutAddMenuEntry(“Decrease square size”, 3); // 메뉴 항목 정의 glutCreateMenu(top_menu); // 주메뉴 답신 함수 설정 glutAddMenuEntry(“quit”, 1); // 메뉴 항목 정의 glutAddSubMenu(“Resize”, sub_menu); // 부메뉴 항목 정의 glutAttachMenu(GLUT_RIGHT_BUTTON); // 마우스 오른쪽 버튼 연결
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
간단한 페인트 프로그램 편집 모드 왼쪽 버튼 : 편집 모드 선택, 정점 입력
함수 구성 void mouse(int btn, int state, int x, int y); // 마우스 답신 함수 void key(unsigned char c, int x, int y); // 키보드 답신 함수 void display(void); // Display 답신 함수 void drawSquare(int x, int y); // 4각형 함수 void myReshape(GLsizei, GLsizei); // Resizing 답신 함수 void myinit(void) // 초기화 함수 void screen_box(intx, int y, int s); // void right_menu(int id); // 각 메뉴의 답신 함수 void middle_menu(int id); void color_menu(int id); void pixel_menu(int id); void fill_menu(int id); int pick(int x, int y); // 편집 모드 선택
함수의 기능 main() : 메뉴 및 답신 함수들을 정의 myinit() : 윈도우를 지우고, 전역변수, 128 문자의 디스플레이 리스트를 생성하고 컴파일 display() : 화면을 흰색으로 초기화 뒤, 버튼을 출력 (버튼 크기 = 윈도우 크기의 10%) myReshape() : 3.5절에서 설명한 Reshape 답신 함수 이용 mouse() : 그림 그리기 작업 수행 pick() : 주어진 X, Y 좌표에 대응하는 스크린상의 영역을 결정 그리기 영역 = 0, 버튼 = 1, 2, 3, 4 메뉴 답신 함수 : 각 메뉴의 기능을 수행
입력과 상호작용 • 상호작용 • 입력장치 • 클라이언트와 서버 • 디스플레이 리스트 • 이벤트-구동 입력의 프로그래밍 • 메뉴 • 지적 • 간단한 페인트 프로그램 • 대화식 프로그램의 설계
대화식 프로그램의 애니메이션 • 회전하는 정사각형 • 각도 theta에 대하여 다음과 같은 값을 가지는 정점들이 정사각형을 이룸
대화식 프로그램의 애니메이션 (con’t) • 정사각형 디스플레이 • theta : 0 ~ 360도의 각도 • thetar : radian 각도 ( 2PI radian = 360도) void display(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); thetar = (theta * (2 * 3.14159)) / 360.0; glVertex2f(cos(thetar), sin(thetar)); glVertex2f(-sin(thetar), cos(thetar)); glVertex2f(-cos(thetar), -sin(thetar)); glVertex2f(sin(thetar), -cos(thetar)); glEnd(); glFlush(); }
대화식 프로그램의 애니메이션 (con’t) • 애니메이션 void idle() { theta += 2; if (theta >= 360.0) theta -= 360.0; glutPostRedisplay(); } void mouse(int btn, int state, int x, int y) { if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) glutIdleFunc(idle); if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) glutIdleFunc(NULL); }
대화식 프로그램의 애니메이션 (con’t) • Main 함수 void main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutCreateWindow("Rotating Rectangle"); myinit(); glutDisplayFunc(display); glutIdleFunc (idle); glutMouseFunc (mouse); glutMainLoop(); }
이중 버퍼링 • 페인트 프로그램에서 시계의 깜박임 • 화면 재생 : 초당 50-85번 프레임 버퍼의 내용을 초당 50-85번 화면에 표시 • 재생하는 동안 프레임 버퍼의 내용이 변경되면 문제 발생 • 화면 한 영역을 반복적으로 지우고 그리는 경우 • 화면이 복잡하여 한 재생주기 내에 그려질 수 없는 경우 이중 버퍼링으로 문제 해결
전면 버퍼 후면 버퍼 모니터 디스플레이 처리기 후면 버퍼 전면 버퍼 디스플레이 처리기 모니터 이중 버퍼링 (con’t) • 두 개의 버퍼 사용 • 전면 버퍼 : 화면에 보여주는 부분 • 후면 버퍼 : 화면에 보이기 전에 미리 그리는 부분 glutSwapBuffers()