Icono del sitio Shakaran

Menús y cambio de formas geométricas con OpenGL


OpenGL es un librería de gráficos bastante versátil. En este artículo vamos a ver un pequeño ejemplo de su potencial.

El ejemplo consiste en dibujar un triángulo blanco en una ventana y que al pulsar la tecla ‘c’ nuestro triángulo se coloree de rojo, verde y blanco en cada vértice. Por otro lado si pulsamos la tecla escape ‘Esc’ la aplicación terminará. Además añadiremos un pequeño menú que se accionara al pulsar el botón derecho del ratón, donde tendremos la opción de cambiar de modo y salir.

Una pequeña imagen que detalla el proceso:

Ejemplo sencillo con OpenGL

A continuación pongo el código y más adelante lo detallo paso a paso:

#include < stdio.h >;
#include < stdlib.h >;
#include < GL/glut.h >;

enum {
  MENU_CHANGE = 1,
  MENU_EXIT
};

static int mode = 0;

void SelectFromMenu(int idCommand)
{  
    switch (idCommand)
    {
        case MENU_CHANGE:
            mode = (mode == 0) ? 1: 0;
            glutPostRedisplay();
            break;

        case MENU_EXIT:
            exit(0);
            break;
    }
    glutPostRedisplay();
}

void Keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27: // ESCAPE key
            exit(0);
            break;

        case 'c':
            SelectFromMenu(MENU_CHANGE);
            break;
    }
}

int buildPopupMenu(void)
{
    int menu = glutCreateMenu(SelectFromMenu);
    glutAddMenuEntry("Cambiar modo\tc", MENU_CHANGE);
    glutAddMenuEntry("Salir\tEsc", MENU_EXIT);

    return menu;
}

void display ()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -4.0); 

    if(mode == 0)
    {
        glBegin(GL_TRIANGLES);

            glColor3f (1.f, 1.f, 1.f);    // White colour
            glVertex3f(0.0, 1.0, 0.0);
            glVertex3f(-1.0, -1.0, 0.0);
            glVertex3f(1.0, -1.0, 0.0);

        glEnd();
    }
    else
    {
        glBegin(GL_TRIANGLES);

            glColor3f (0.f, 1.f, 0.f);    // Green colour
            glVertex3f(0.0, 1.0, 0.0);

            glColor3f (1.f, 1.f, 1.f);    // White colour
            glVertex3f(-1.0, -1.0, 0.0);

            glColor3f (1.f, 0.f, 0.f);    // Red colour
            glVertex3f(1.0, -1.0, 0.0);

        glEnd();
    }

    glutSwapBuffers();
}

void resize (int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50., w/(double)h, 1., 10.);
    glMatrixMode(GL_MODELVIEW);
}

void init (void)
{
    glEnable(GL_DEPTH_TEST);
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(200, 200);
    glutCreateWindow("Ejercicio");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(resize);
    glutKeyboardFunc(Keyboard);

    buildPopupMenu();
    glutAttachMenu(GLUT_RIGHT_BUTTON);

    glutMainLoop();

    return 0;
}

El funcionamiento principal, es tener una función display(), que según en el modo que estemos, dibujara una u otra figura (coloreada de una manera u otra). Para ello utilizaremos una variable global estática con la que guardaremos el modo en el que estamos, cuando se requiera redibujar, miraremos el modo y lo cambiaremos y dibujaremos la nueva figura. Las funcion de keyboard() llamará al menu según la tecla (salir o cambiar modo) y el menú se encargara de llamar a display y cambiar el modo.

De forma más detalla en la funcion main() primero pasamos los argumentos de entrada con glutInit() y inicializamos glutInitDisplaymode con un doble buffer y RGB, ya que necesitaremos un buffer doble para que nuestras figuras se rendericen en un frame y mientras en otro se procesen.

Le damos un tamaño a la ventana de 400×400 con glutInitWindowSize() y en la posición 200×200 con un título de ventana “Ejercicio”. y llamamos a la función init para que active la prueba de profundidad.

Luego asignamos una funcion de retrollamada (callback) para mostrar nuestra ventana con lgutDiplayFunc(), la función de retrollamada sera display(), que la veremos más adelante.

Otra función de retrollamada para cuando redimensionemos la ventana y despues llamaremos a buildPopupMenu() que sera una función para construir nuestro menú.

Y adjuntaremos el menú cuando se presione el botón derecho del ratón con glutAttachmenu(). Despues llamamos al bucle principal de glut.

Nota: algo importante a resaltar, si utilizas una tarjeta gráfica ATI, es posible que tengas algun fallo si pones la línea, ya que el buffer no quedara totalmente limpio al dibujar en pantalla:

 glClear(GL_COLOR_BUFFER_BIT);

Por eso es mejor ponerlo así y evitamos este tipo de fallos (desconozco si en otras tarjetas se da dicho fallo):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Para compilar:

gcc -lGL -lGLU -lglut ejercicio.c -o ejercicio

Y ejecutarlo:

./ejercicio

¿Te ha gustado o resultado útil? Pues deja un comentario con tu opinión 😉


Salir de la versión móvil