1장 6절 - Mouse Motion Event

|

Mouse Motion Event

 

 

 

GLUT 는 Mouse 를 Window 위에서 움직여 Window 상에 있는 물체에 움직임을 줄 수 있는 다음 2개의 callback 함수를 제공하고 있다.

  

 void glutMotionFunc( void (*func)(int x, int y) );
 void glutPassiveMotionFunc( 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 };
GLsizei   action;
GLsizei   xini = 0,   yini = 0;
GLfloat   xmov = 0.0, ymov = 0.0;

 

// function prototypes

      .

void  motion( int, int );

      .

      .

 

main() 함수:

 

                     .

            . 
      // handling input events
      glutKeyboardFunc( keyboard );
      glutSpecialFunc( special );
      glutMotionFunc( motion );
      glutMouseFunc( mouse );

 

      // idle function registration for animation
   // glutIdleFunc( idle );   // 주석처리

           .

           .

 

display() 함수:

 

          .

          . 

     // draw a point on the center of window
      glColor4f( 1.0, 1.0, 1.0, 1.0 );
      glPointSize( 5.0 );
      glBegin( GL_POINTS );
            glVertex3f( 1.0, 1.0, 0.0 );
      glEnd();

 

      /*  Translate & rotate the image  */
      glPushMatrix();                       // Save the transformations performed
      glTranslatef( 1.0, 1.0, 0.0 );        // move axes origin to center
      glRotatef( xrot, 1.0f, 0.0f, 0.0f );  // rotate the image
      glRotatef( yrot, 0.0f, 1.0f, 0.0f );
      glRotatef( zrot, 0.0f, 0.0f, 1.0f );
      glTranslatef( -1.0, -1.0, 0.0f );     // move axes origin to center
      glTranslatef( xmov, ymov, 0.0f );     // translate location by mouse move

          .

          .

 

mouse() 함수:   왼쪽 Mouse 를 물체의 회전을 실행하는 것 대신에 물체의 이동에 대한 실행을 하고,  대신 중간 Mouse button 을 눌렀을 때 물체의 회전이 서로 toggling 하도록 다음과 같이 새로 작성한다.

 

 void mouse( int button, int state, int x, int y )
{
      if (state == GLUT_DOWN) {  // when the button is released
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        action = MOVE_OBJECT;
                        break;
               case GLUT_MIDDLE_BUTTON:
                        action = ROTATE_OBJECT;
                        rot_status = !rot_status;
                        if (rot_status) glutIdleFunc( idle );
                        else            glutIdleFunc( NULL );
                        glutPostRedisplay();
                        break;

               case GLUT_RIGHT_BUTTON:
                        action = ZOOM_OBJECT;
                        break;
            }

            /* Update the saved mouse position */
            xini = x;
            yini = y;
      } else {
            action = DO_NONE;
      }
}

 

motion() 함수:

 

void  motion( int x, int y )
{      
      // this will only be true when the left button is down
      if (action == MOVE_OBJECT) { // update dx, dy
            xmov += (GLfloat)(x - xini) * 0.025f;
            ymov += (GLfloat)(yini - y) * 0.025f;
      }

      /* Update the stored mouse position for later use */
      xini = x;
      yini = y;

 

      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;

// function prototypes
      .

      .

// void  pressKey( int, int, int );    // 2개의 함수 주석처리
// void  releaseKey( int, int, int );

void  motion( int, int );              // 새로운 함수 추가
void  mouse( int, int, int, int );
      .

      .

 

main() 함수:

 

                 .

          .


      // handling input events
      glutKeyboardFunc( keyboard  );
   // glutSpecialFunc( pressKey );  // 다음 3개의 함수를 주석처리
   // glutIgnoreKeyRepeat(1);       // ignore key repeat press
   // glutSpecialUpFunc( releaseKey );
      glutMotionFunc( motion );     // 2개의 함수 추가 

      glutMouseFunc( mouse );

 

      // enter GLUT event processing cycle
      glutMainLoop();

          .

          .

 

display() 함수아래 2개의 함수는 keyboard 를 통해서 들어오는 값은 처리하는 함수이므로 주석처리한다.

 

         .

    // if (dmov) computePos( dmov ); // 주석처리
    // if (drot) computeDir( drot );

         .

 

 pressKey()  와  releaseKey() 함수를 지운 후에, 다음의 motion() mouse() 함수를 만든다.

 

mouse() 함수:

 

void  mouse( int button, int state, int x, int y )
{
      // only start motion if the button is pressed
      if (state == GLUT_UP) { // when the button is released
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        angle += drot;
                        xini = 0;
                        break;
               case GLUT_RIGHT_BUTTON:
                        yini = 0;
                        break;
            }
      } else {
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        xini = x;
                        break;
               case GLUT_RIGHT_BUTTON:
                        yini = y;
                        break;
            }
      }
}

 

motion() 함수:

 

 void  motion( int x, int y )
{      
      // this will only be true when the mouse button is down
      if (xini > 0) {  // left mouse button is pressed
            drot = (GLfloat)(xini - x) * 0.002f; // update drot

            // update camera's direction
            lx =  sin(angle + drot);
            lz = -cos(angle + drot);
      }
      if (yini > 0) {  // right mouse button is pressed

            dmov = (GLfloat)(yini - y) * 0.05f;
            xx += dmov * lx * 0.1f;
            zz += dmov * lz * 0.1f;
      }
}

 

여기서 보면,   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
And
prev | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ··· | 11 | next