[Tutorial] II.3 - glutTimerFunc()

Ver el tema anterior Ver el tema siguiente Ir abajo

[Tutorial] II.3 - glutTimerFunc()

Mensaje  HarZe el Mar Jul 21, 2009 10:08 pm

II.3 Funcion a través del tiempo: glutTimerFunc()
Novedades:
  • glutTimerFunc()
  • glutPostRedisplay()

Hasta ahora no hemos hecho más que dar instrucciones estáticas, es decir, no cambian con el paso del tiempo. Para que haya cambios según pasa el tiempo (que los objetos se muevan, por ejemplo) necesitamos un nuevo tipo del función GLUT: glutTimerFunc(). Que permite ejecutar una función cada cierta cantidad de tiempo. Un código de ejemplo:

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

float avx = 0.05f;
float avy = 0.05f;
float xpos = -1.0f;
float ypos = 2.0f;
int ms = 20;
int acelera = 1;

void IniciarGLUT() {
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(600,600);
  glutInitWindowPosition(100,100);
  glutCreateWindow("Practica II,3 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+0.25f, ypos-0.5f-0.25f, xpos+0.5f+0.25f, ypos+0.5f-0.25f);
   
   glColor3f(1.0f,1.0f,0.0f);
   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 Avanzar(int value) {
    xpos = xpos + avx;
    ypos = ypos + avy;
    if (xpos+0.5f>10.0f || xpos-0.5f<-10.0f) {
        avx = -avx;
        xpos = xpos + avx;
    }
    if (ypos+0.5f>10.0f || ypos-0.5f<-10.0f) {
        avy = -avy;
        ypos = ypos + avy;
    }
    if (acelera) ms++;
    else ms--;
    if (ms>60 || ms<2) acelera = !acelera;

    glutTimerFunc(ms,Avanzar,1);
    glutPostRedisplay();
}

int main(int argc, char **argv)
{
   glutInit(&argc,argv); //Solo necesario en Linux
  IniciarGLUT();
 
  glutReshapeFunc(ReProyectar);
  glutDisplayFunc(PintarEscena);
  glutTimerFunc(ms,Avanzar,1);
 
  glutMainLoop();
    return 0;
}

Al igual que antes, hemos ampliado el código anterior, mostrar el resultado es algo poco importante, pues lo importante es el movimiento:

Aparte de un sistema de rebote, la novedad del cógido es el uso. La bola va lenta, luego rápida, luego lenta, rápida, y así indefinidamente.
Para entender el código entero, primero hay que entender la función glutTimerFunc(), tiene 3 argumentos, y hay que explicarlos bien. Cuando llamas a esta función, ésta espera unos milisegundos (un int[/int] del primer argumento) para ejecutar una función (que es el segundo argumento), la función debe tener un argumento: [i]int value, al que podemos acceder porque también es el tercer argumento de glutTimerFunc().
Entendido esto, voy a explicar la función Avanzar():
Código:
void Avanzar(int value) {
    xpos = xpos + avx;
    ypos = ypos + avy;
    if (xpos+0.5f>10.0f || xpos-0.5f<-10.0f) {
        avx = -avx;
        xpos = xpos + avx;
    }
    if (ypos+0.5f>10.0f || ypos-0.5f<-10.0f) {
        avy = -avy;
        ypos = ypos + avy;
    }
    if (acelera) ms++;
    else ms--;
    if (ms>60 || ms<2) acelera = !acelera;

    glutTimerFunc(ms,Avanzar,1);
    glutPostRedisplay();
}
Tenemos cuatro variables, que almacenan la posición del cuadrado y cuanto deben avanzar cada vez. Primero hacemos esta operación. Luego comprobamos que si la posición indica que ha sobrepasado algún borde (-10 o 10) teniendo en cuenta que el cuadrado tiene 1 de lado (0,5 a añadir pues la posicion es la del centro del cuadrado, y el objeto rebota cuando un borde choca, no el centro). Si choca, la dirección X o Y se invierte.
Tras eso, la variable ms aumenta o disminuye, según acelere o no el cuadrado, es decir: como ms son los milisegundos que tardará la función en realizarse, cuantos más sean, más lenta irá la bola, cuantos menos segundos hay entre avance y avance, más rápido irá, alternando lento y rápido. Al final de la función, se pone de nuevo glutTimerFunc(ms,Avanzar,1);, ya que no se repite por sí sola. Y vale la pena mencionar glutPostRedisplay();, que fuerza a que se ejecute la función asignada a glutDisplayFunc(), si no usas esto, no se moverá la pieza hasta que cubras y descubras la ventana, o la cambies de tamaño, u otras cosas que obligen a redibujar.
Por cierto, en los glRectf() de arriba, hay dos, el primero es una "sombra" y lo otro es el supuesto cuadro, lo voy poniendo ya, para que el en próximo ejemplo, que tratará sobre usar las teclas pulsadas del teclado para mover a nuestro gusto el cuadro y "levantarlo" del suelo, cosa que es mentira, puesto que es 3D, pero lo parecerá. Esto nos hará que entendamos y que no olvidemos, que la pantalla es 2D y solo puede "simular" 3D. Una realidad en la que no siempre nos fijamos.

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.