OpenGL – C++ Bài 10: Xử lý sự kiện bấm chuột và move chuột

 

Hi chào mừng các bạn đến với chủ đề Học Lập Trình OpenGL Tại blog : Phát Triển Phần Mềm 123AZ

Bài hôm nay chúng ta sẽ cùng đi tìm hiểu về kỹ thuật nhận sự kiện khi click chuột trong opengl

Đây là một trong số những kỹ thuật rất cơ bản và phổ biến trong lập trình đồ họa.

I. Lý thuyết cơ bản.
1. Bắt sự kiện bấm chuột trái, chuột phải và chuột giữa.

 Step1: Viết một hàm MouseButton như sau:

void MouseButton(int type_button, int state, int x, int y)
{
 if (type_button == GLUT_LEFT_BUTTON)
 {
  if (state == GLUT_UP)
  {
   //Todo
  }
  else
  {
   //Todo
  }
 }
 else if(type_button == GLUT_RIGHT_BUTTON)
 {
  if (state == GLUT_UP)
  {
   //Todo
  }
  else
  {
   //Todo
  }
 }
}

+ type_button : Là kiểu phím bấm chuột, đó thể hiện là chuột trái hay chuột phải

+ state: là trạng thái bấm xuông hay nhả ra.

+ x,y là tọa độ hiện tại của chuột trên màn hình windows.

Chúng ta có 3 loại cho type_button được định nghĩa trong glut.h như sau

#define GLUT_LEFT_BUTTON 0
#define GLUT_MIDDLE_BUTTON 1
#define GLUT_RIGHT_BUTTON 2

Từ đó chúng ta hoàn toàn có thể dễ dàng bắt được button nào của chuột được sử dụng.

+ Step 2: Gọi hàm MouseButton trong hàm main thông qua hàm xử lý chuột như sau:

glutMouseFunc(MouseButton);

2. Bắt sự kiện khi thực hiện move chuột.

Step 1: Viết một hàm MouseMove như sau:

void mouseMove(int x, int y)
{

//Todo

}

+ x,y là tọa độ của chuột liên tục cập nhật khi chuột đang được move.

Step2: Trong hàm Main gọi hàm MouseMove như sau:

glutMotionFunc(mouseMove);

Note: Hàm MouseMove là hàm chạy gần như liên tục khi chúng ta di chuột liên tục.

Ok. Các bạn có thể thử và đặt debug vào để kiểm tra.

II. Thực hành.

Có thể nhiều bạn sẽ thắc mắc rằng, Vậy với mouse chúng ta sử dụng mouse để làm gì trong lập trình đồ họa.

Mouse sử dụng rất phổ biến và không thể thiếu.

Với Game: Mouse sử dụng để định dạng phương hướng nhìn của model chủ vào các model khác, hoặc nhận nhiệm vụ là bắn đạn, tấn công của các nhân vật game….

Với phần mềm đồ họa: Mouse sử dụng để select đối tượng, kéo đối tượng, hoặc xoay cameral để nhìn đối tượng theo nhiều hướng.

Và nó sử dụng theo bất cứ mục đích nào bạn mong muốn.

Ok, Và bây giờ chúng ta sẽ thực hành việc sử dụng kỹ thuật bắt sự kiện mouse để thực hay quay cameral vòng quanh vật.

+ Yêu cầu:

– Chỉ khi bấm chuột trái (phải) thì cameral mới có thể quay quanh vât.

– Nếu nhả chuột thì ko thể quay cameral quanh vật.

– Khi kéo chuột move từ vị trí A sang vị trí B theo tọa độ màn hình windows, thì cameral trong opengl sẽ quay đi một góc anpha theo trục Y.

Hãy cùng xem hình mình họa

Chúng ta cần tính được z’ và x’ mỗi khi kéo chuột từ A đến B

Full Code:

 

#include <gl\glut.h>
#include <math.h>

float g_x = 0.0;
float g_z = 0.0;
float lz = -10.0;
float lx = 0.0;
float angle = 0.0;

float deltaAngle = 0.0f;
int xOrigin = -1;
bool g_is_rotate = false;

void Init()
{
  g_x = 10 * sin(angle);
  g_z = 10 * cos(angle);

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  GLfloat light_pos[] = { 0.0, 0.0, 1.0, 0.0 };
  glLightfv(GL_LIGHT0, GL_POSITION, light_pos);

  GLfloat ambient[] = { 1.0, 1.0, 1.0, 1.0 };
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);

  GLfloat diff_use[] = { 0.7, 0.7, 0.7, 1.0 };
  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff_use);

  GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);

  GLfloat shininess = 50.0f;
  glMateriali(GL_FRONT, GL_SHININESS, shininess);

}

void ReShape(int width, int height)
{
  glViewport(0, 0, width, height);
  float ratio = (float)width / (float)height;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, ratio, 1, 100.0);
  glMatrixMode(GL_MODELVIEW);
}

void OnKeyDown(int key, int xx, int yy) {
  switch (key)
  {
  case GLUT_KEY_LEFT:
    g_x -= 0.1;
    break;
  case GLUT_KEY_RIGHT:
    g_x += 0.1;
    break;
  case GLUT_KEY_UP:
    g_z -= 0.1;
    break;
  case GLUT_KEY_DOWN:
    g_z += 0.1;
    break;
  }
}

void mouseButton(int button, int state, int x, int y)
{
  // only start motion if the left button is pressed
  if (button == GLUT_RIGHT_BUTTON)
  {
    // when the button is released
    if (state == GLUT_UP)
    {
      angle += deltaAngle;
      xOrigin = -1;
      g_is_rotate = false;
    }
    else
    {
      g_is_rotate = true;
      deltaAngle = 0.0;
      xOrigin = x;
    }
  }
}

void mouseMove(int x, int y)
{
  if (g_is_rotate)
  {
    // this will only be true when the left button is down
    deltaAngle += (x - xOrigin) * 0.0005f;
    // update camera's direction
    g_x = 10 * sin(angle + deltaAngle);
    g_z = 10 * cos(angle + deltaAngle);
  }

}


void DrawCoordinate()
{
  glDisable(GL_LIGHTING);
  glBegin(GL_LINES);
  glColor3f(1.0, 0.0, 0.0);
  glVertex3f(-100.0, 0.0, 0.0);
  glVertex3f(100.0, 0.0, 0.0);
  glEnd();
  glBegin(GL_LINES);
  glColor3f(0.0, 1.0, 0.0);
  glVertex3f(0.0, -100.0, 0.0);
  glVertex3f(0.0, 100.0, 0.0);
  glEnd();
  glBegin(GL_LINES);
  glColor3f(0.0, 0.0, 1.0);
  glVertex3f(0.0, 0.0, -100.0);
  glVertex3f(0.0, 0.0, 100.0);
  glEnd();
  glEnable(GL_LIGHTING);
}

void RenderScene()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  gluLookAt(g_x, 1.0, g_z, 0, 1.0, 0, 0, 1, 0);
  DrawCoordinate();

  glPushMatrix();
  glutSolidTeapot(1.0);
  glPopMatrix();
  glutSwapBuffers();
  glFlush();
}

void main()
{
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(640, 480);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("Opengl Study");
  Init();
  glutReshapeFunc(ReShape);
  glutDisplayFunc(RenderScene);
  glutIdleFunc(RenderScene);
  glutSpecialFunc(OnKeyDown);
  glutMouseFunc(mouseButton);
  glutMotionFunc(mouseMove);
  glutMainLoop();

  return;
}

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.