Mouse Motion Event
GLUT 는 Mouse 를 Window 위에서 움직여 Window 상에 있는 물체에 움직임을 줄 수 있는 다음 2개의 callback 함수를 제공하고 있다.
void glutMotionFunc( void (*func)(int x, int y) ); |
위 두 개의 함수중 위의 것은 Mouse 를 눌렀을때의 Window 상의 위치 (x, y), 아래의 함수는 Mouse를 누르지 않았을 때의 위치를 기억한다. 위의 함수는 Mouse callback 함수 glutMouseFunc() 과 함께 사용하여, 필요한 실행에 대해 명령을 하게된다.
앞절의 프로그램에서 다음을 수정하여 보자.
전역지역에 다음의 변수와 함수의 prototype 을 새로 더한다.
. . enum actions { MOVE_OBJECT, ROTATE_OBJECT, ZOOM_OBJECT, DO_NONE };
// function prototypes . void motion( int, int ); . . |
main() 함수:
. .
// idle function registration for animation . . |
display() 함수:
. . // draw a point on the center of window
/* Translate & rotate the image */ . . |
mouse() 함수: 왼쪽 Mouse 를 물체의 회전을 실행하는 것 대신에 물체의 이동에 대한 실행을 하고, 대신 중간 Mouse button 을 눌렀을 때 물체의 회전이 서로 toggling 하도록 다음과 같이 새로 작성한다.
void mouse( int button, int state, int x, int y ) /* Update the saved mouse position */ |
motion() 함수:
void motion( int x, int y ) /* Update the stored mouse position for later use */
glutPostRedisplay(); |
위의 두 함수를 분석해 보면, mouse() 함수에서는 Mouse button 을 눌렀는지, 해지했는지에 대한 정보와 Mouse 를 눌렀을 때의 초기위치를 기억한다. motion() 함수에서는 현재의 Mouse 위치를 찾아 Mouse 가 움직인 거리를 계산하고, 항상 Mouse 위치를 초기화 시킨다. glutPostRedisplay() 함수를 통해 화면을 다시 정리하고 있다. 주의 깊게 보아야 할 점은 두 함수 모두 초기값을 기억하도록 하고 있는데, 이는 두 함수 모두에게 초기치를 기억시켜 mouse 에 대한 정확한 위치계산을 하기 위한 것이다. 두 함수 중에 하나에 대한 초기화를 하지 않았을 경우 움직임을 살펴보면, 사용자가 의도한 정확한 거리계산에 에러가 생기게 된다. motion() 함수에 대한 변수들은 항상 전역변수화 되어 전체 Program 에 영향을 주도록 하는것이 일반적이다.
Mouse 를 누르지 않은 상태에서 어떤 움직임에 대한 실행을 하고자 한다면, 위 두 함수의 Up, Down 의 조건을 서로 바꾸어 주고, glMotionFunc() 대신 glPassiveMotionFunc() callback 함수 를 사용하면 된다. 이 경우는 Mouse button 을 눌렀을 시 요구하는 명령을 실행하지 않게 된다.
Program 을 컴파일 한 후 화면내의 Image 를 Mouse 로 이리저리 Drag 해보면 Image 가 순조롭게 이동하는 것을 볼 수 있다. 화면의 중앙의 위치를 보여주기 위하여, 흰색 점을 하나 추가 하였다. 화살표나 Page Up, Down key, 또는 Space bar 를 사용하여 삼각형을 회전 시켰을 경우 Mouse 의 이동에 대한 물체의 이동 방향이 서로 바꾸어 지는것은 물체의 회전에 따라 좌표축이 회전하고, 그에 따라 Window 의 (x, y) 위치가 서로 뒤집어져 나타나는 현상이다. Program 을 분석하여 보면 그 이유를 이해를 할 수 있을 것이다. 따라서 Home key 를 눌러 회전위치를 원위치로 돌려놓은 후에 Mouse 을 이동 시키면 물체가 Mouse 의 이동방향에 따라 움직이게 된다.
응용 Program:
1장 3 절에 있는 advanced_keyboard 프로그램을 수정하면서 Mouse Motion 에 대한 부분을 좀 더 살펴보자. 이 프로그램은 화살표 Key 를 좌우로 움직여 360 도로 보는 방향을 회전시키고, 상하 화살표 Key 로 물체를 화면의 전후로 이동 (Zoom In & Out) 시키도록 구성되어 있었다. Special key 에 의한 작동을 Mouse 의 왼쪽 과 오른쪽 Button 으로 대체 하여 보는 시각을 이동시키도록 수정하여 보자. Mouse 의 왼쪽 Button 은 시각의 회전, 오른쪽 Button 은 Zoon In/Out 의 역할을 맡는다.
전역 지역에 다음의 변수와 함수의 Prototype 을 첨가한다.
. . GLsizei xini = 0, yini = 0; . // void pressKey( int, int, int ); // 2개의 함수 주석처리 void motion( int, int ); // 새로운 함수 추가 . |
main() 함수:
. .
// enter GLUT event processing cycle . . |
display() 함수: 아래 2개의 함수는 keyboard 를 통해서 들어오는 값은 처리하는 함수이므로 주석처리한다.
. // if (dmov) computePos( dmov ); // 주석처리 . |
pressKey() 와 releaseKey() 함수를 지운 후에, 다음의 motion() 과 mouse() 함수를 만든다.
mouse() 함수:
void mouse( int button, int state, int x, int y ) |
motion() 함수:
void motion( int x, int y ) // update camera's direction dmov = (GLfloat)(yini - y) * 0.05f; |
여기서 보면, Mouse 위치에 대한 초기값과, 최종적인 계산값 angle 에 대한 함수의 위치가, 위에서 설명한 것과 조금 다름을 엿볼 수 있다. 이는 변수 angle 이 motion() 함수에서보다 mouse() 함수에 있을 때 움직임이 좀더 부드럽기 때문이다 (motion() 함수에서 사용하려면 drot 값을 아주 낮게 잡아주어야 함). 이와 같이 Mouse motion 에 대한 것은 mouse() 함수 와 motion() 함수가 전역변수를 통하여 서로 밀접하게 연계되므로, 프로그램하기에 따라 여러 형태로 구성을 할 수 있다.
이제는 좌우 화살표 Key 대신에 Mouse 의 좌우 Button을 누른다음 커서를 이동시켜가며 화면의 물체를 시각을 달리하여 볼 수 있게 되었다.
Source Code: 01_6 - motion.zip
01_6 - advanced_motion.zip
'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글
1장 5절 - Mouse Event (0) | 2013.01.22 |
---|---|
1장 4절 - Animation by Idling (0) | 2013.01.21 |
1장 3절 - Keyboard Event (0) | 2013.01.20 |
1장 2절 - Resize OpenGL Window (0) | 2013.01.20 |
1장 1절 - Create a Simple OpenGL Window (0) | 2013.01.19 |