[Tutorial] II.7 - glutIdleFunc(), glutKeyboardUpFunc() y glutSpecialUpFunc()

Ver el tema anterior Ver el tema siguiente Ir abajo

[Tutorial] II.7 - glutIdleFunc(), glutKeyboardUpFunc() y glutSpecialUpFunc()

Mensaje  HarZe el Mar Jul 28, 2009 3:37 pm

II.7 La perfecta relación teclado-movimento
Novedades:
  • glutIdleFunc()
  • glutKeyboardUpFunc()
  • glutSpecialUpFunc()


Lo que pretende enseñar este tutorial tiene más que ver con la programación de , y una correcta respuesta del estado del teclado que de OpenGL, pero lo considero necesario, muy necesario, para disfrutar a tope de OpenGL.

Código:
#include <GL/glut.h>

//Macros para tajar teclas
#define FLECHA_ARRIBA 0
#define FLECHA_ABAJO 1
#define FLECHA_IZDA 2
#define FLECHA_DCHA 3

#define CLICK_IZDA 0
#define CLICK_DCHA 1

float xpos, ypos;
float rojo, verde, azul, dis;
int flechas[4];
int raton_sombra[2];

void IniciarGLUT() {
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(600,600);
  glutInitWindowPosition(100,100);
  glutCreateWindow("Practica II,7 de OpenGL");
}
   
void PintarEscena() {
   glMatrixMode(GL_MODELVIEW);
   glClear(GL_COLOR_BUFFER_BIT);
   glLoadIdentity();
   
   glColor3f(0.0f,0.0f,0.4f);
   glRectf(-10.0f,-10.0f,10.0f,10.0f);
   
   glColor3f(0.0f,0.0f,0.0f);
   glRectf(xpos-0.5f+dis, ypos-0.5f-dis, xpos+0.5f+dis, ypos+0.5f-dis);
   
   glColor3f(rojo,verde,azul);
   glRectf(xpos-0.5f, ypos-0.5f, xpos+0.5f, ypos+0.5f);

   glutSwapBuffers();
}

void ReProyectar(int w, int h) {
   GLfloat formato;

   if(h == 0) h = 1;
      
    glViewport(0, 0, w, h);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   formato = (GLfloat)w / (GLfloat)h;
    if (w <= h) glOrtho (-10.0f, 10.0f, -10.0f / formato, 10.0f / formato, 1.0f, -1.0f);
    else glOrtho (-10.0f * formato, 10.0f * formato, -10.0f, 10.0f, 1.0f, -1.0f);
}

void ControlTeclado(unsigned char key, int x, int y) {
   switch (key)
   {
      case 114:
         if (rojo==1.0f) rojo = 0.0f;
         else rojo = 1.0f;
      break;
      case 103:
         if (verde==1.0f) verde = 0.0f;
         else verde = 1.0f;
      break;
      case 98:
         if (azul==1.0f) azul = 0.0f;
         else azul = 1.0f;
      break;
   }
}

void ControlFlechas(int key, int x, int y) {
   switch (key) {
      case GLUT_KEY_UP: flechas[FLECHA_ARRIBA] = 1; break;
      case GLUT_KEY_DOWN: flechas[FLECHA_ABAJO] = 1; break;
      case GLUT_KEY_LEFT: flechas[FLECHA_IZDA] = 1; break;
      case GLUT_KEY_RIGHT: flechas[FLECHA_DCHA] = 1; break;
   }
}

void ControlRaton(int button, int state, int x, int y) {
    if (button==GLUT_LEFT_BUTTON && state==GLUT_UP) raton_sombra[CLICK_IZDA] = 1;
    else if (button==GLUT_LEFT_BUTTON && state==GLUT_DOWN) raton_sombra[CLICK_IZDA] = 0;
    if (button==GLUT_RIGHT_BUTTON && state==GLUT_UP) raton_sombra[CLICK_DCHA] = 1;
    else if (button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) raton_sombra[CLICK_DCHA] = 0;
}

void ControlFlechasUp(int key, int x, int y) {
   switch (key) {
      case GLUT_KEY_UP: flechas[FLECHA_ARRIBA] = 0; break;
      case GLUT_KEY_DOWN: flechas[FLECHA_ABAJO] = 0; break;
      case GLUT_KEY_LEFT: flechas[FLECHA_IZDA] = 0; break;
      case GLUT_KEY_RIGHT: flechas[FLECHA_DCHA] = 0; break;
   }
}

void MoverCuadrado(int value) {
   if (flechas[FLECHA_DCHA]) {
        xpos = xpos + 0.08f;
        if (xpos > 10.0f-0.5f) xpos = 9.5f;
   }
   if (flechas[FLECHA_IZDA]) {
        xpos = xpos - 0.08f;
        if (xpos < -10.0f+0.5f) xpos = -9.5f;
   }
   if (flechas[FLECHA_ARRIBA]) {
        ypos = ypos + 0.08f;
        if (ypos > 10.0f-0.5f) ypos = 9.5f;
   }
   if (flechas[FLECHA_ABAJO]) {
        ypos = ypos - 0.08f;
        if (ypos < -10.0f+0.5f) ypos = -9.5f;
   }
   if (raton_sombra[CLICK_IZDA]) {
        dis = dis + 0.1f;
        if (dis > 5.0f) dis = 5.0f;
   }
   if (raton_sombra[CLICK_DCHA]) {
        dis = dis - 0.1f;
        if (dis < 0.0f) dis = 0.0f;
   }
   glutTimerFunc(20,MoverCuadrado,1);
   glutPostRedisplay;
}

int main(int argc, char **argv)
{
   glutInit(&argc,argv); //Solo necesario en Linux
  IniciarGLUT();
 
  glutReshapeFunc(ReProyectar);
  glutDisplayFunc(PintarEscena);
  glutSpecialFunc(ControlFlechas);
  glutKeyboardFunc(ControlTeclado);
  glutMouseFunc(ControlRaton);
  glutSpecialUpFunc(ControlFlechasUp);
  glutTimerFunc(20,MoverCuadrado,1);
  glutIdleFunc(PintarEscena);
 
  glutMainLoop();
    return 0;
}

Primero explicaré el funcionamiento que tendrá desde ahora nuestros programas, y éste también. A partir de ahora, guardaremos en variables (arrays en este caso) el estado de las teclas. Usaremos 0 para suelto y 1 para pulsado. En este programa son:
Código:
#define FLECHA_ARRIBA 0
#define FLECHA_ABAJO 1
#define FLECHA_IZDA 2
#define FLECHA_DCHA 3

#define CLICK_IZDA 0
#define CLICK_DCHA 1

······

int flechas[4];
int raton_sombra[2];

Usamos unos macros para no perdernos. Guardaremos con esas variables el estado de cada tecla, por ejemplo flechas[FLECHAS_IZDA], que es como poner flechas[2], guardará el estado de pulsación de la tecla flecha izquierda.
El otro array guardará el estado de los clicks de raton.

Hasta ahora conocías glutKeyboard/SpecialFunc(), que indica que variable has sido pulsada. Pero glutKeyboard/SpecialUpFunc(), indica que variable ha sido SOLTADA. Pues aquí, con glutSpecialUpFunc(ControlFlechasUp); aludimos a esta función:
Código:
void ControlFlechasUp(int key, int x, int y) {
   switch (key) {
      case GLUT_KEY_UP: flechas[FLECHA_ARRIBA] = 0; break;
      case GLUT_KEY_DOWN: flechas[FLECHA_ABAJO] = 0; break;
      case GLUT_KEY_LEFT: flechas[FLECHA_IZDA] = 0; break;
      case GLUT_KEY_RIGHT: flechas[FLECHA_DCHA] = 0; break;
   }
}
Básicamente dice que cuando se suelte la tecla, valdrá 0. La función ControlFlechas() (sin el Up), es idéntica, pero dando valor 1.
Es decir, ahora las función de control del teclado, son solo informativas. Ahora quien administra el movimiento es una función que se repite cada 20 milisegundos glutTimerFunc(20,MoverCuadrado,1);, aquí está la función:
Código:
void MoverCuadrado(int value) {
   if (flechas[FLECHA_DCHA]) {
        xpos = xpos + 0.08f;
        if (xpos > 10.0f-0.5f) xpos = 9.5f;
   }
   if (flechas[FLECHA_IZDA]) {
        xpos = xpos - 0.08f;
        if (xpos < -10.0f+0.5f) xpos = -9.5f;
   }
   if (flechas[FLECHA_ARRIBA]) {
        ypos = ypos + 0.08f;
        if (ypos > 10.0f-0.5f) ypos = 9.5f;
   }
   if (flechas[FLECHA_ABAJO]) {
        ypos = ypos - 0.08f;
        if (ypos < -10.0f+0.5f) ypos = -9.5f;
   }
   if (raton_sombra[CLICK_IZDA]) {
        dis = dis + 0.1f;
        if (dis > 5.0f) dis = 5.0f;
   }
   if (raton_sombra[CLICK_DCHA]) {
        dis = dis - 0.1f;
        if (dis < 0.0f) dis = 0.0f;
   }
   glutTimerFunc(20,MoverCuadrado,1);
   glutPostRedisplay;
}

Las distintas funciones de los anteriores tutoriales, se juntan aquí. Si su correspondiente tecla es 1, se produce el cambio correspondiente. Ahora podrás mover el cuadrado libremente, en diagonal y de forma continua, a la vez que también mueves la sombra. Ésta es la verdadera forma de controlar un programa con el teclado y ratón.

Una cosa más que añadir: glutIdleFunc(PintarEscena);. Esta función glutIdleFunc(); es la que se usará cuando no ocurra nada, cuando nada sea pulsado, en esta caso es redibujar las escena. Esto provoca que no dependamos tanto de glutPostRedisplay();, solo usarlo si queremos o necesitamos. Esta función es útil para un juego por ejemplo, imagina que no hay motivo para que se redibuje la pantalla cuando no pasa nada, porque has puesto que se redibuje al tocar una tecla, entonces un juego como el Pang, en el que la bola se meuve sola, solo verías los cambios al tocar teclas, y esto quedaría fatal.

De momento, tenemos suficiente conocimiento de GLUT para meternos el OpenGL de lleno.

HarZe
WebMaster & Desarrollador

Cantidad de envíos : 58
Fecha de inscripción : 21/06/2009
Edad : 24

Ver perfil de usuario http://opengl-esp.superforo.net

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba

- Temas similares

 
Permisos de este foro:
No puedes responder a temas en este foro.