Você está na página 1de 35

Informática Gráfica

abril, 2007

Librerías de Recursos: Aux y Glut

Rubén de la Peña Ramos


Ana de la Viuda López
Pablo Sánchez Manzano

Departamento de Informática y Automática


Universidad de Salamanca
Tabla de Contenidos

1. Introducción __________________________________________________ 1
2. Registro de Funciones Callback___________________________________ 3
3. La librería AUX de OpenGL______________________________________ 5
3.1. Introducción ____________________________________________________ 5
3.2. Funciones de la librería AUX ______________________________________ 5
3.2.1 Inicialización_________________________________________________________5
3.2.2 Manejo de ventanas ___________________________________________________6
3.2.3 Proceso de eventos ____________________________________________________8
3.2.4 Uso del teclado y del ratón _____________________________________________10
3.2.5 Objetos predefinidos __________________________________________________13
4. La librería Glut de OpenGL _____________________________________ 15
4.1. Introducción ___________________________________________________ 15
4.2. Funciones de la librería Glut______________________________________ 16
4.2.1 Inicialización________________________________________________________16
4.2.2 Manejo de ventanas __________________________________________________18
4.2.3 Procesado de eventos _________________________________________________20
4.2.4 Manejo de menús ____________________________________________________23
4.2.5 Fuentes de texto _____________________________________________________24
4.2.6 Objetos predefinidos __________________________________________________26
5. Conclusión___________________________________________________ 27

Informática Gráfica i
ii Informática Gráfica
Lista de Figuras

Figura 01: Ejemplo de inicialización en Aux _______________________________________________6


Figura 02: Máquina de estados de la biblioteca GLUT ______________________________________16
Figura 03: Ejemplo de inicialización en GLUT ____________________________________________18
Figura 04: Ejemplo de múltiples ventanas y subventanas. ____________________________________19
Figura 05: Pseudocódigo de un programa basado en eventos _________________________________21
Figura 06: Ejemplo de registro de eventos en GLUT ________________________________________22
Figura 07: Ejemplo de creación de un menú en GLUT ______________________________________24
Figura 08: Ejemplo de manejo de textos en GLUT __________________________________________25
Figura 09: Rutina para escribir en texto en pantalla con GLUT _______________________________25

Informática Gráfica iii


iv Informática Gráfica
Lista de Tablas

Tabla 01: Librerías y Ficheros de OpenGL ________________________________________________1


Tabla 02: Valores para las características de ventana________________________________________6
Tabla 03: Constantes Teclado OpenGL __________________________________________________11
Tabla 04: Constantes de visualización ___________________________________________________17
Tabla 05: Comparación AUX – GLUT ___________________________________________________27

Informática Gráfica v
vi Informática Gráfica
1. Introducción
Este capítulo se centra en las bibliotecas que complementan a la API OpenGL. Las dos más
conocidas son Aux y Glut, ambas acompañan a OpenGL y se pueden obtener en las diversas
versiones de ésta. Aux es la más antigua de las dos y presenta algunas limitaciones que Glut
soluciona.
Las funciones del núcleo de OpenGL se limitan a facilitar las operaciones que podrían
denominar gráficas puras, no existiendo procedimientos para el uso de matrices, funciones
cuadráticas y similares o funciones de manejo de ventanas y eventos. Es por esta razón por la
que se utilizan bibliotecas complementarias que actuarán como una extensión de OpenGL para
facilitar dichas operaciones.
Las librerías que forman la API OpenGL son:

Nombre/Prefijo
Archivos Descripción
de las Funciones
Gl.h
gl Funciones del núcleo de OpenGL.
Opengl32.lib
Glu.h
glu Librería de utilidades más comunes. Totalmente portable.
Glu32.lib
Glaux.h
Librería de recursos. Contiene funciones que facilitan
aux Glaux.dll tareas como la creación de ventanas independientes de
plataforma.
Glaux.lib
Glut.h
OpenGL Utility Toolkit. Librería de recursos posterior a la
glut Glut32.dll
Aux. Añade nuevas prestaciones.
Glut32.lib

Tabla 01: Librerías y Ficheros de OpenGL

OpenGL puede operar sobre la superficie de una ventana o bien a pantalla completa, no
incorporando función alguna para la gestión de las ventanas. Esto significa que sería preciso
recurrir al API del sistema, algo que no entra dentro de la filosofía de OpenGL por el hecho de
ser una biblioteca multiplataforma, ya que en Windows habría que usar un conjunto de
funciones totalmente distinto que en Unix o Linux para crear y mostrar una ventana, lo cual
obligaría al programador a escribir bases de código distintas para cada sistema.
La alternativa para evitar esa duplicidad de código es utilizar las bibliotecas Aux o Glut,
con funciones que facilitan la gestión de las ventanas de manera independiente al sistema
operativo. Consisten en un archivo de cabecera, la biblioteca de importación y la que incorpora
el código de las funciones.
La librería Aux es un paquete auxiliar para construir aplicaciones de ventanas, además de
incluir algunas primitivas geométricas auxiliares. La gran ventaja de este paquete es, al igual
que en OpenGL su portabilidad y sencillez.

-1-
Librerías de Recursos: Aux y Glut

La librería Glut es un interfaz de programación para escribir programas OpenGL


independientes del sistema de ventanas. Este paquete ha sido implementado por Mark J. Kilgard
intentado mejorar la existente Aux y soluciona un hueco en la especificación de OpenGL. Las
utilidades que presenta Glut son: múltiples ventanas, uso sencillo de menús y mejora de algunos
aspectos ya existentes.

De los ejemplos que se han incluido en este tema, algunos incluyen una doble versión,
estando desarrollado con la biblioteca Aux y con la biblioteca Glut. Otros ejemplos sólo están
desarrollados con una librería. Es muy sencillo saber que librería estamos usando en cada
momento ya que OpenGL tiene una notación muy descriptiva, incluyendo el prefijo de la
biblioteca a la que pertenecen las funciones, así como el número y tipo de los parámetros de la
función. Así las funciones que comienzan por aux pertenecen a la librería Aux y glut a la
librería Glut.
Entre los ejemplos se encuentra un esqueleto de un programa, un ejemplo de creación de un
objeto en 3D y un ejemplo de rotación de una figura (los tres desarrollados tanto con Aux como
con Glut). También se incluyen otros ejemplos desarrollados con una de las dos bibliotecas
donde se pueden ver más funcionalidades de cada una de ellas.

2 Informática Gráfica
De la Peña, De la Viuda y Sánchez

2. Registro de Funciones Callback


Las librerías Aux y Glut están diseñadas con un motor dirigido por eventos. Existe un bucle
infinito que comienza después de la inicialización y procesa todos los eventos declarados al
inicio. Estos pueden ser un botón del ratón que se ha pulsado, una ventana que se cierra, se
redimensiona, un cursor que se mueve, unas teclas que se han pulsado, etc. Se deben registrar
cada uno de los eventos que se pueden dar en una de las variables de estado de la librería para
que el bucle de proceso de eventos compruebe periódicamente si dicho evento ha sido lanzado
por alguna acción del usuario.
Para registrar un evento utilizaremos rutinas de registro callback que se pasarán como
argumento a un conjunto de funciones.
Dichas funciones tienen la sintaxis aux/glut[algunEvento]Func, por ejemplo para
el click del ratón será auxMouseFunc() ó glutMouseFunc(). Un registro de una
función callback para un evento concreto le dice a la máquina de estados que función definida
por el usuario se debe llamar si el correspondiente evento es activado.
Si se escribe una rutina AccionRaton que especifica qué hacer cuando se pulsa el botón
izquierdo del ratón, o el botón derecho entonces será necesario registrar la función callback
después de la inicialización (funciones aux/glutInit) en el main() usando la sentencia
aux/glutMouseFunc(AccionRaton);.
Después de registrar todos los eventos importantes del programa se debe invocar la rutina
de procesado de eventos de la librería, aux/glutMainLoop(). Esta función nunca devuelve
el control, se queda esperando indefinidamente por eventos de manera que según sea necesario
invocará las funciones callback que hayan sido previamente registradas. Es por ello que la
función main() de cualquier aplicación OpenGL debe terminar con una sentencia
aux/glutMainLoop().

Informática Gráfica 3
Librerías de Recursos: Aux y Glut

4 Informática Gráfica
De la Peña, De la Viuda y Sánchez

3. La librería AUX de OpenGL

3.1. Introducción
La librería Aux es un paquete auxiliar para construir aplicaciones de ventanas, además de
incluir algunas primitivas geométricas auxiliares. La gran ventaja de este paquete es además de
simplificar mucho el código fuente del programa, que el mismo código nos servirá tanto en
Windows como en otras plataformas.
Fue creada para facilitar el aprendizaje y escritura de programas en OpenGL sin perderse
con las particularidades de un entorno concreto.
Aux también implementa funciones para permitir operaciones específicas del sistema,
como el intercambio de buffers, la apertura de imágenes y contiene funciones para el dibujo de
algunos objetos 3D relativamente simples como esferas, cubos, toros, etc.

3.2. Funciones de la librería AUX


Aux posee funciones para la inicialización, manejo de ventanas, procesado de eventos, gestión
de la actividad de teclado y ratón y soporte para algunos objetos predefinidos.
Todas estas características son compartidas con Glut, siendo ésta última considerablemente
más completa.

3.2.1 Inicialización
A diferencia de Glut, la librería Aux no necesita una función específica de inicialización para
empezar a funcionar. Sí tiene una serie de rutinas que comienzan con el prefijo auxInit que
definen las características de la ventana en la que se va a trabajar:

void APIENTRY auxInitDisplayMode(GLenum);


Inicializa el modo de visualización de la ventana (tipo de buffer y modo de color). Las
opciones de visualización que permite establecer esta función son las siguientes:
Valor Significado
AUX_SINGLE Especifica una ventana con buffer simple
AUX_DOUBLE Especifica una ventana con buffer doble
AUX_RGBA Especifica una ventana en modo RGBA
AUX_INDEX Especifica una ventana en modo color indexado
AUX_DEPTH Especifica un buffer de 32 bits de profundidad
AUX_DEPTH16 Especifica un buffer de 16 bits de profundidad
AUX_STENCIL Especifica un buffer
AUX_ACCUM Especifica un buffer de acumulación

Informática Gráfica 5
Librerías de Recursos: Aux y Glut

AUX_ALPHA Especifica un buffer alfa


AUX_FIXED_332_PAL Especifica una paleta fija 3-3-2 para la ventana

Tabla 02: Valores para las características de ventana

void APIENTRY auxInitPosition(int, int, int, int);


Define la posición y tamaño de la ventana.
GLenum APIENTRY auxInitWindow(LPCSTR);
Muestra la ventana generada.

A continuación un ejemplo que ilustre lo anterior: (incluye algunas funcionalidades que se


detallarán a continuación en este mismo apartado)

Figura 01: Ejemplo de inicialización en Aux

3.2.2 Manejo de ventanas


Creación

A la hora de dibujar una ventana en nuestra aplicación hay que tener en cuenta la posición, el
tamaño que va a ocupar en la pantalla y el título que le queremos dar. Para todo esto se usan las
funciones introducidas en el apartado anterior.
La función auxInitPosition(), permite seleccionar el tamaño y la posición de la
ventana que se cree a continuación. Recibe cuatro argumentos, los dos primeros (x e y) indican
las coordenadas donde se situará la esquina superior izquierda de la ventana, tomando como
referencia la esquina superior izquierda del monitor. Y los dos siguientes el ancho y el alto de la

6 Informática Gráfica
De la Peña, De la Viuda y Sánchez

ventana. Se debe tener en cuenta la resolución de configuración de la pantalla, ya que estos


parámetros son contados en píxeles.
La siguiente llamada debe realizarse a la función auxInitWindow(), que crea
físicamente la ventana sobre la pantalla. Se le pasa un único argumento que es el título de la
ventana.
Después de invocar a esta función, por si se deseara manejar la ventana de alguna forma
específica proporcionada por otra librería o dependiente del sistema operativo, se podrían
utilizar las siguientes funciones para obtener su manejador:
/* hwnd, hdc, and hglrc validos despues de auxInitWindow( )*/
HWND APIENTRY auxGetHWND(void);
HDC APIENTRY auxGetHDC(void);
HGLRC APIENTRY auxGetHGLRC(void);

Borrado de la ventana

Una vez se tiene creada la ventana en pantalla ya se dispone de un espacio físico para dibujar.
OpenGL ofrece una gran variedad de funciones de primitivas geométricas, de hecho, las rutinas
de este apartado no pertenecen a Aux pero son fundamentales para la gestión y manejo de
ventanas.

La función glClearColor() selecciona los valores de color y alfa para borrar los
buffers de color. Su uso combinado con glClear()permite establecer un color de fondo
para la ventana o borrar el contenido de la misma sobrescribiéndola de un solo color. El
primer parámetro es la componente roja de color de relleno, el segundo la verde, el tercero
la azul y el cuarto la componente alfa (nivel de transparencia u opacidad).
En OpenGL los colores se representan como una mezcla de rojo, verde y azul, el valor para
cada componente del color es un número decimal que oscila entre 0 y 1. Este valor se
corresponde internamente al más cercano de los existentes en el hardware de video y la paleta
del sistema operativo que se tenga instalada. La cantidad de tonos que permite OpenGL sólo
está limitada por el hardware. La componente alfa se usa para efectos especiales.
// Establece el buffer de color a amarillo
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
Con la función anterior únicamente se ha establecido el color con el queremos limpiar la
pantalla pero todavía no se aprecian resultados. Se ha mencionado que OpenGL trabaja con
buffers, y esta función limpia un buffer en particular o una combinación de ellos según se le
pase por argumentos.

Carga de imágenes

Esta librería propone como funciones de carga de imágenes en OpenGL las siguientes::
AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCSTR);
AUX_RGBImageRec * APIENTRY auxDIBImageLoad(LPCSTR);

Informática Gráfica 7
Librerías de Recursos: Aux y Glut

Donde AUX_RGBImageRec se define como:


/* RGB Image Structure*/
typedef struct _AUX_RGBImageRec {
GLint sizeX, sizeY;
unsigned char *data;
} AUX_RGBImageRec;

Ambas reciben como argumento una cadena con el nombre de la imagen. No son muy
utilizadas ya que hay otras librerías creadas, mucho más eficaces en la carga de imágenes en
OpenGL.

Cerrado y destrucción

Como funciones de cerrado explícito de la ventana y salida del programa la librería Aux cuenta
con las funciones:
void APIENTRY auxCloseWindow(void);
void APIENTRY auxQuit(void);

3.2.3 Proceso de eventos


El bucle principal de visualización

La tarea interactiva más simple que implementa la librería auxiliar de OpenGL es permitir
que se controle la ejecución de la aplicación gráfica mediante un bucle principal de
visualización, que mantiene la ventana en pantalla hasta que el usuario pulse la tecla <Escape>.
El bucle principal de visualización espera a que se produzcan eventos de usuario (mover o
cambiar el tamaño de una ventana, pulsar un botón del ratón o pulsar una tecla), y cada vez que
se produce un evento, lo atiende y ejecuta una rutina “display” encargada de redibujar los
objetos en la escena. El formato de la orden es:
void auxMainLoop(void (*displayFunc)(void));

void APIENTRY auxMainLoop(AUXMAINPROC);


auxMainLoop se puede considerar una de las funciones principales de cualquier
aplicación OpenGL que utilice la librería aux, ya que es la encargada de mantener el
programa en funcionamiento hasta que se cierra la ventana y finaliza. Se le pasa un solo
argumento que será la función que deba invocar la primera vez que se muestre la ventana y
cada vez que esta tenga que ser redibujada.

void APIENTRY auxIdleFunc(AUXIDLEPROC);


Otra de las funciones que proporciona Aux es auxIdleFunc() que permite especificar la
función de rellamada que se ejecutará cuando no haya otra actividad pendiente o el

8 Informática Gráfica
De la Peña, De la Viuda y Sánchez

programa permanezca ocioso. Su uso junto con la función anterior permite realizar
animaciones simples. Se le pasa una función Callback como argumento. Para deshabilitar la
ejecución del proceso ocioso se le pasa NULL como argumento.
La función glFlush(), de la librería GL, permite gestionar la cola de instrucciones del
programa. Su invocación consigue que se ejecuten las sentencias OpenGL que se
encuentran en la cola esperando. El funcionamiento interno de OpenGL utiliza un canal de
generación de imágenes con procesamiento secuencial. Las sentencias del programa
OpenGL se almacenan en una cola hasta que el servidor OpenGL puede procesarlas. En
dibujos muy complejos esto supone una gran mejora de prestaciones.

Eventos de ventana, teclado y ratón

El bucle principal de visualización implementado por la rutina auxMainLoop mantiene a


OpenGL en un ciclo de espera de eventos. Cuando se produce un evento para el que se ha
programado una rutina de servicio, OpenGL realiza la siguiente secuencia de acciones:
Ejecutar la rutina de servicio asociada al evento. Habitualmente, esta rutina realiza
operaciones que afectan al dibujo en pantalla.
Ejecutar la rutina display para redibujar la pantalla (según la versión de la librería).

Los posibles eventos que puede atender OpenGL se dividen en tres grupos:

Eventos de ventana. Se generan al crear la ventana de la aplicación, cambiar su tamaño o


su posición en la pantalla. Los eventos de ventana se atienden mediante la orden
auxReshapeFunc de la librería auxiliar de OpenGL.
Eventos de teclado. Se generan al pulsar alguna de las teclas siguientes: ‘A’ ... ‘Z’, ‘a’ ...
‘z’, ‘0’ .. ‘9’, ‘←’, ‘↑’, ‘→’, ‘↓’, <Escape>, <Space>, <Return>. Los eventos de teclado se
atienden mediante la orden auxKeyFunc de la librería auxiliar de OpenGL.
Eventos de ratón. Se generan al pulsar o liberar los botones del ratón, y se atienden
mediante la orden auxMouseFunc de la librería auxiliar de OpenGL.

Eventos de ventana

La orden auxReshapeFunc de la librería AUX especifica la rutina de servicio a ejecutar


siempre que la ventana de la aplicación se cambie de tamaño, de posición, o sea expuesta
después de estar total o parcialmente oculta. El formato de la orden es el siguiente:
void auxReshapeFunc(void (*function)(GLsizei, GLsizei));
El argumento function es un puntero a la función que actúa como rutina de servicio.
Esta función espera dos parámetros, la nueva anchura y altura de la ventana. Típicamente, la
rutina de servicio establecerá la proyección a utilizar y el marco sobre la ventana para que se
ajusten a las nuevas dimensiones manteniendo la proporcionalidad. Los eventos de ventana se
utilizarán en la siguiente práctica asociados a la definición de una vista.

Eventos de teclado

Informática Gráfica 9
Librerías de Recursos: Aux y Glut

La orden auxKeyFunc de la librería AUX especifica la rutina de servicio a ejecutar cada vez
que se pulsa una de las teclas incluidas en el conjunto de teclas manejables descrito
anteriormente. El formato de la orden es el siguiente:
void auxKeyFunc(GLint key, void (*function)(void));
El argumento function es un puntero a la función que actúa como rutina de servicio,
definida sin parámetros. Esta función se ejecutará cuando se pulse la tecla especificada por el
argumento key. Para indicar la tecla utilizaremos las constantes predefinidas al efecto en
glaux.h que se verán mas adelante.
Los eventos de teclado se suelen utilizar para aplicar transformaciones a un objeto o
modificar los parámetros característicos de la vista definida.

Eventos de ratón

La orden auxMouseFunc de la librería AUX especifica la rutina de servicio a ejecutar cada


vez que se pulse o se libere uno de los botones del ratón. El formato de la orden es el siguiente:
void auxMouseFunc(GLint button, GLint mode,
void (*function)(AUX_EVENTREC *));
La rutina de servicio function se ejecutará cuando el botón especificado por el
argumento button entre en el modo especificado por el argumento mode. Por ejemplo, para
asociar la función rutina1 a la pulsación del botón izquierdo del ratón utilizaríamos la orden
OpenGL:
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, rutina1);

3.2.4 Uso del teclado y del ratón


En cualquier aplicación actual es imprescindible que exista algún tipo de interacción con el
usuario, puesto que en ocasiones se pretenderá que el usuario pueda comunicarse con la
aplicación y esta responda de acuerdo a las peticiones realizadas.
Las dos formas más comunes de comunicación van a ser el teclado y el ratón. En OpenGL
mediante el teclado podemos asociar la pulsación una tecla o un conjunto de teclas a una acción
concreta, como cambiar de color el dibujo. Con el ratón existen menos posibilidades, podemos
definir acciones para cada botón del ratón (izquierdo, derecho y centro) y para la pulsación o
cuando se libera.

Interacción con el teclado

void APIENTRY auxKeyFunc(int, AUXKEYPROC);

Recibe el código asociado a la tecla deseada y una función Callback que establecerá la
función a llevar a cabo cuando la tecla sea pulsada. OpenGL tiene definidas una serie de
constantes para las distintas teclas:

#define AUX_RETURN 0x0D #define AUX_L 'L' #define AUX_d 'd' #define AUX_v 'v'

10 Informática Gráfica
De la Peña, De la Viuda y Sánchez

#define AUX_ESCAPE 0x1B #defineAUX_M 'M' #define AUX_e 'e' #define AUX_w 'w'

#define AUX_SPACE 0x20 #define AUX_N 'N' #define AUX_f 'f' #define AUX_x 'x'

#define AUX_LEFT 0x25 #define AUX_O 'O' #define AUX_g 'g' #define AUX_y 'y'

#define AUX_UP 0x26 #define AUX_P 'P' #define AUX_h 'h' #define AUX_z 'z'

#define AUX_RIGHT 0x27 #define AUX_Q 'Q' #define AUX_i 'i' #define AUX_0 '0'

#define AUX_DOWN 0x28 #define AUX_R 'R' #define AUX_j 'j' #define AUX_1 '1'

#define AUX_A 'A' #define AUX_S 'S' #define AUX_k 'k' #define AUX_2 '2'

#define AUX_B 'B' #define AUX_T 'T' #define AUX_l 'l' #define AUX_3 '3'

#define AUX_C 'C' #define AUX_U 'U' #define AUX_m 'm' #define AUX_4 '4'

#define AUX_D 'D' #define AUX_V 'V' #define AUX_n 'n' #define AUX_5 '5'

#define AUX_E 'E' #define AUX_W 'W' #define AUX_o 'o' #define AUX_6 '6'

#define AUX_F 'F' #define AUX_X 'X' #define AUX_p 'p' #define AUX_7 '7'

#define AUX_G 'G' #define AUX_Y 'Y' #define AUX_q 'q' #define AUX_8 '8'

#define AUX_H 'H' #define AUX_Z 'Z' #define AUX_r 'r' #define AUX_9 '9'

#define AUX_I 'I' #define AUX_a 'a' #define AUX_s 's'

#define AUX_J 'J' #define AUX_b 'b' #define AUX_t 't'

#define AUX_K 'K' #define AUX_c 'c' #define AUX_u 'u'

Tabla 03: Constantes Teclado OpenGL

Ejemplo del código que se debe insertar en el main de la aplicación para usar las teclas de
desplazamiento:
// Asociar funciones de movimiento para las teclas W,S,A,D
auxKeyFunc(AUX_a, accionIzquierda);
auxKeyFunc(AUX_d, accionDerecha);
auxKeyFunc(AUX_w, accionArriba);
auxKeyFunc(AUX_s, accionAbajo);

Otro ejemplo, para asociar la función rutina1 a la pulsación de la tecla <Return>


auxKeyFunc(AUX_RETURN, rutina1);

Informática Gráfica 11
Librerías de Recursos: Aux y Glut

Interacción con el ratón

void APIENTRY auxMouseFunc(int, int, AUXMOUSEPROC);

Recibe tres argumentos:


1º) Botón con el que se desea asociar una función (para ratón de 3 botones)
#define AUX_LEFTBUTTON 1
#define AUX_RIGHTBUTTON 2
#define AUX_MIDDLEBUTTON 4

2º) Cuando se debe realizar la acción asociada (al pulsar o al liberar el botón)
#define AUX_MOUSEDOWN 16
#define AUX_MOUSEUP 32

3º) Función Callback que define la acción asociada al evento


Del tipo: void CALLBACK accionRaton(AUX_EVENTREC *evento);
Dicha función espera un argumento que es un puntero a una estructura de datos
AUX_EVENTREC. Definida en el fichero de cabecera glaux.h como:
typedef struct _AUX_EVENTREC {
GLint event;
GLint data[4];
} AUX_EVENTREC;

Que contiene la información de:


Tipo de evento:
/* ToolKit Event Types */
#define AUX_EXPOSE 1
#define AUX_CONFIG 2
#define AUX_DRAW 4
#define AUX_KEYEVENT 8 //Evento de teclado
#define AUX_MOUSEDOWN 16 //Botón abajo
#define AUX_MOUSEUP 32 //Botón arriba
#define AUX_MOUSELOC 64 //Arrastrar con botón pulsado

Indices de data[4] para conocer la posición y estado del ratón:


/* Toolkit Event Data Indices */
//Para eventos de ventana
#define AUX_WINDOWX 0

12 Informática Gráfica
De la Peña, De la Viuda y Sánchez

#define AUX_WINDOWY 1
// Para eventos de ratón
#define AUX_MOUSEX 0
#define AUX_MOUSEY 1
#define AUX_MOUSESTATUS 3
// Para eventos de teclado
#define AUX_KEY 0
#define AUX_KEYSTATUS 1

En esta estructura se almacenan los parámetros característicos del evento,


fundamentalmente las coordenadas de ventana dónde se encontraba el cursor en el momento de
pulsar o liberar el botón. Para utilizar estas coordenadas, se debería definir function de una
forma similar a la siguiente:
void function(AUX_EVENTREC *event)
{ GLint x, y ;
x = event->data[AUX_MOUSEX];
y = event->data[AUX_MOUSEY];
. . .
}

3.2.5 Objetos predefinidos


OpenGL es una librería de visualización de polígonos. Es posible, por tanto, construir los
modelos a visualizar especificando manualmente los distintos polígonos que los componen; sin
embargo, esta tarea resulta tediosa y es relativamente fácil cometer errores. Para facilitar la
construcción de modelos a partir de primitivas simples, la librería Aux incluye ordenes para el
dibujo de esferas, cilindros, conos, etc.
A continuación se listan las funciones que implementan el dibujo de primitivas en Aux:
void APIENTRY auxWireSphere(Gldouble radio);
void APIENTRY auxWireCube(Gldouble tamaño);
void APIENTRY auxWireBox(Gldouble ancho, Gldouble alto,
Gldouble profundo);
void APIENTRY auxWireTorus(Gldouble radioInterior,
Gldouble radioExterior);
void APIENTRY auxWireCylinder(Gldouble radio,
Gldouble altura);
void APIENTRY auxWireIcosahedron(Gldouble radio);
void APIENTRY auxWireOctahedron(Gldouble radio);
void APIENTRY auxWireTetrahedron(Gldouble radio);
void APIENTRY auxWireDodecahedron(GLdouble);

Informática Gráfica 13
Librerías de Recursos: Aux y Glut

void APIENTRY auxWireCone(Gldouble radio, Gldouble altura);


void APIENTRY auxWireTeapot(Gldouble tamaño);

Estas rutinas dibujan las distintas primitivas en modo alámbrico, igualmente existen otras
similares para el dibujo en modo sólido:
void APIENTRY auxSolidSphere(GLdouble);
void APIENTRY auxSolidCube(GLdouble);
void APIENTRY auxSolidBox(GLdouble, GLdouble, GLdouble);
void APIENTRY auxSolidTorus(GLdouble, GLdouble);
void APIENTRY auxSolidCylinder(GLdouble, GLdouble);
void APIENTRY auxSolidIcosahedron(GLdouble);
void APIENTRY auxSolidOctahedron(GLdouble);
void APIENTRY auxSolidTetrahedron(GLdouble);
void APIENTRY auxSolidDodecahedron(GLdouble);
void APIENTRY auxSolidCone(GLdouble, GLdouble);
void APIENTRY auxSolidTeapot(GLdouble);

Todas las primitivas se encuentran centradas en el origen, y cuando los parámetros de las
órdenes son todos 1.0, todas ellas encajan en una caja con todas sus coordenadas entre -1 y 1.
No obstante, pueden utilizarse distintos valores en los parámetros para escalar las primitivas.
Por ejemplo, para dibujar un cono de radio 25.0 y altura 40.0 bastaría:
auxWireCone(25.0, 40.0);

14 Informática Gráfica
De la Peña, De la Viuda y Sánchez

4. La librería Glut de OpenGL


4.1. Introducción
Para hacer OpenGL verdaderamente portable e independiente de la plataforma fue necesario
sacrificar los comandos que interactuaban con el sistema de ventanas (como abrir, cerrar,
escalar o dar forma a una ventana, leer la posición del cursor,…) y también con los dispositivos
de entrada (como la lectura del teclado, etc). Todas estas acciones son altamente dependientes
del sistema operativo.
Originalmente, la biblioteca GL tenía su propio conjunto de comandos para manejo de
ventanas y periféricos pero eran específicos de IRIX (el SO UNIX de SGI). Se dejaba al
desarrollador de OpenGL conocer su propia plataforma y tomar medidas para manejar ventanas
en la plataforma nativa.
Hasta que Mark J. Kilgard escribió la GLUT-library, un conjunto de herramientas y
utilidades de OpenGL que sustituyen a la biblioteca AUX.
GLUT, OpenGL Utility Toolkit (no confundir con GLU, OpenGL Utility Library),
desarrolla un interfaz de programación con bindings para ANSI C y FORTRAN, para escribir
programas OpenGL independientes del sistema de ventanas. Junto con AUX cubre el gran
agujero dejado por la especificación de OpenGL. Gracias a GLUT, los desarrolladores pueden
usar un interfaz común para el sistema de ventanas independientemente de la plataforma
empleada.
Las aplicaciones de OpenGL que usan GLUT se pueden portar fácilmente entre
plataformas sin tener que introducir muchos cambios en el código fuente. En resumen, GLUT
simplifica la producción de código OpenGL y complementa dicha biblioteca. Además, tiene
mayor funcionalidad para la manipulación interactiva de objetos 3D. Ofrece, entre otras cosas,
las siguientes prestaciones:
Ventanas múltiples para render
Procesamiento de eventos de entrada iniciados por el usuario (callbacks).
Variados dispositivos de entrada.
Menús desplegables.
Rutinas para generar objetos estándar.

GLUT es una librería relativamente pequeña y fácil de aprender. Está bien diseñada
siguiendo los pasos de su predecesora AUX. Su API es una máquina de estados, como OpenGL.
Esto significa que GLUT tiene una serie de variables de estado que duran toda la ejecución de la
aplicación. El estado inicial de la máquina de GLUT se ha elegido razonablemente para
ajustarse a la mayor parte de aplicaciones. El programa puede modificar los valores de las
variables de estado para ajustarlas a su gusto.
Cuando se llama a una función de GLUT, su acción se modifica de acuerdo a los valores de
las variables de estado. Las funciones de GLUT son simples, tienen pocos parámetros. Nunca
devuelven punteros, y los únicos punteros pasados a las funciones de GLUT son punteros a
cadenas de caracteres y manejadores de fuentes.

Informática Gráfica 15
Librerías de Recursos: Aux y Glut

Figura 02: Máquina de estados de la biblioteca GLUT

Las funciones de GLUT se pueden clasificar en varias subAPIs según su funcionalidad:


Inicialización
Inicio del procesado de eventos
Control de ventanas
Control de overlay
Control de menús
Registro de funciones Callback
Control del mapa de colores
Obtención del estado
Trazado de fuentes
Trazado de formas geométricas
En los siguientes apartados, se explican algunas de las funcionalidades de esta biblioteca.

4.2. Funciones de la librería Glut


4.2.1 Inicialización
Todo programa OpenGL que utilice la biblioteca GLUT debe empezar inicializando el estado de
la máquina de estados de GLUT. La manera de hacer esto es muy similar a la de la biblioteca
AUX, aunque a diferencia de ésta, hay una nueva función, glutInit(), que inicializa el
valor de la máquina de estados.
Dicha función recibe dos parámetros: argcp y argv.

16 Informática Gráfica
De la Peña, De la Viuda y Sánchez

Argcp es un puntero a la variable argc de la función main() (sin modificar). Al acabar


la función, el valor apuntado por argcp se actualiza, ya que glutInit() extrae todas las
opciones de la línea de comandos relevantes para la librería GLUT.
Argv es la variable argv de la función main() (sin modificar).
GlutInit() se encarga de modificar las variables de estado de GLUT y negociar una
sesión con el sistema de ventanas.
Pocas funciones pueden preceder a glutInit(), sólo el resto de funciones de
inicialización de GLUT, aquellas que tienen el prefijo glutInit, y que se pueden usar para
establecer los estados de inicialización por defecto.
glutInitWindowPosition(int x, int **y)
Establece la posición de la ventana en la pantalla. Recibe dos parámetros que son las
coordenadas en píxeles de la esquina superior izquierda de la ventana.
glutInitWindowSize(int ancho, int **alto)
Establece el tamaño de la ventana. Se le pasan dos argumentos que son el ancho y alto en
píxels de la ventana.
glutInitDisplayMode(unsigned int mode)
Inicializa el modo de visualización. Se le pasa un único argumento que el modo de
visualizacion o un OR de los posibles valores de visualización, que se muestran en la
siguiente tabla:

Opción Significado
Selecciona una ventana en modo RGBA. Es el valor por defecto
GLUT_RGBA
si no se indican ni GLUT_RGBA ni GLUT_INDEX
GLUT_RGB Lo mismo que GLUT_RGBA
Seleciona una ventana en modo de índice de colores. Se impone
GLUT_INDEX
sobre GLUT_RGBA
Selecciona una ventana en modo buffer simple. Es el valor por
GLUT_SINGLE
defecto
Selecciona una ventana en modo buffer doble. Se impone sobre
GLUT_DOUBLE
GLUT_SINGLE.
GLUT_ACCUM Selecciona una ventana con un buffer acumulativo
Selecciona una ventana con una componente alpha del buffer de
GLUT_ALPHA
color
GLUT_DEPTH Selecciona una ventana con un buffer de profundidad
GLUT_STENCIL Selecciona una ventana con un buffer de estarcido
GLUT_MULTISAMPLE Selecciona una ventana con soporte multimuestra
GLUT_STEREO Selecciona una ventana estéreo
GLUT_LUMINANCE Selecciona una ventana con un modelo de color de "luminancia".

Tabla 04: Constantes de visualización

Informática Gráfica 17
Librerías de Recursos: Aux y Glut

Se muestra a continuación un ejemplo de inicialización para un programa de animación. Se


puede observar que el display se inicializa en modo de doble buffer, ideal para animaciones ya
que elimina el parpadeo cuando cambia la imagen en la secuencia de animación.

Figura 03: Ejemplo de inicialización en GLUT

4.2.2 Manejo de ventanas


Como su nombre indica, éste subAPI se ocupa de tareas relacionadas con las ventanas usadas
por una aplicación OpenGL: crear, cerrar, minimizar una ventana; poner delante, detrás
esconder, mover; y poner títulos, posiciones, etc...
GLUT permite la creación de dos tipos básicos de ventanas: principal o top-level y
subventanas. Ésta es una de las principales novedades de la biblioteca. Ambos tipos soportan
operaciones en OpenGL y puede llevar asociadas rutinas Callback.
int glutCreateWindow(const char *title);
Permite crear una o varias ventanas principales. Se le pasa un argumento que es el nombre
de la barra de título. Devuelve un valor entero identificador de la ventana creada ya que en
este entorno pueden existir más de una. Los parámetros establecidos en las funciones
glutInitWindowPosition() y glutInitWindowSize() afectan únicamente a
aquellas ventanas que se definen como top-level.
int glutCreateSubWindow(int win, int x, int y, int width, int
height)
Permite crear una subventana. Los parámetro que se le pasan son, el identificador de la
ventana padre, la posición y el tamaño en píxeles de la nueva ventana. También devuelve un
valor entero identificador de la ventana. Esta función en vez de crear una nueva ventana en
pantalla, utiliza la ya existente para dibujar en ella el contenido de la nueva ventana. Cuando
la biblioteca GLUT abre una subventana le proporciona un contexto OpenGL completo e
independiente, de forma que cada ventana tiene su propio sistema de coordenadas. El uso de
subventanas supone una pérdida de rendimiento para el sistema ya que GLUT refresca el

18 Informática Gráfica
De la Peña, De la Viuda y Sánchez

área de memoria de ventana en pasadas separadas. A continuación se muestra un ejemplo de


lo anterior:

id_padre=glutCreateWindow("Ventana principal");

glutDisplayFunc(EscenaPrincipal);

...

id_hijo = glutCreateSubWindow(id_padre,0,0,600,600);

glutSetWindow(id_hijo);

glutDisplayFunc(OtraEscena);

Figura 04: Ejemplo de múltiples ventanas y subventanas.

void glutSetWindow(int win)


En el caso de trabajar con más de una ventana, el identificador puede ser utilizado como
parámetro de esta rutina, que especifica la ventana en la que se va a trabajar y la establece
como ventana actual.
void glutPostRedisplay(void)
Fuerza un evento de exhibición de la ventana, debe ser llamada siempre que un cambio no
sea exhibido en pantalla.

Las siguientes rutinas completan la lista de funciones soportadas por la gestión de ventanas
en GLUT:

Informática Gráfica 19
Librerías de Recursos: Aux y Glut

void glutDestroyWindow(int win)


Cierra la ventana cuyo identificador se pasa como parámetro.
int glutGetWindow(void)
Devuelve el identificador de la ventana actual.
void glutSetWindowTitle(const char *title)
Establece el texto que se le pasa como parámetro como título de la ventana.
void glutSetIconTitle(const char *title)
Establece el texto mostrado de la ventana cuando se encuentre minimizada en la barra de
tareas.
void glutPositionWindow(int x, int y)
Modifica la posición de la ventana dentro de la pantalla.
void glutIconifyWindow(void)
Minimiza la ventana actual.
void glutShowWindow(void)
Muestra la ventana actual.
void glutHideWindow(void)
Oculta la ventana actual.
void glutFullScreen(void)
Maximiza la ventana actual.

4.2.3 Procesado de eventos


Las aplicaciones desarrolladas con la librería GLUT se basan en una interfaz de ventanas. Este
tipo de interfaces son muy cómodas de usar, pero la programación se complica bastante porque
no se puede predecir lo que el usuario va a hacer y en que momento.
Como ya se ha dicho antes, GLUT es una máquina de estados. Ahora se verá que también
está diseñada como un motor dirigido por eventos. Esto significa que hay un "timer" o bucle
continuo que comienza después de la inicialización correspondiente y que procesa uno por uno
todos los eventos declarados a GLUT durante la inicialización.
Los eventos pueden ser un botón del ratón que se ha pulsado, una ventana que se cierra,
una ventana que se redimensiona, un cursor que se mueve, unas teclas del teclado que se han
pulsado, un curioso evento "idle" ( esto es, no pasa nada), etc.
Cada uno de los posibles eventos se debe registrar en una de las variables de estado de
GLUT para que el "timer" o bucle de proceso de eventos de GLUT mire periódicamente si este
evento ha sido activado por el usuario. La ejecución de un programa basado en eventos se
resume con en el siguiente pseudocódigo:

20 Informática Gráfica
De la Peña, De la Viuda y Sánchez

Figura 05: Pseudocódigo de un programa basado en eventos

Por ejemplo, se puede registrar "pulsar botón del ratón" como un evento para GLUT. Los
eventos se registran mediante rutinas de registro callback. Todas tienen la sintaxis
glut[algunEvento]Func, en el caso del click del ratón será glutMouseFunc.
Un registro de callback le dice a la máquina de GLUT que función definida por el usuario
se debe llamar si el correspondiente evento es activado.
Así pues, si se escribe una rutina MyMouse que especifica qué hacer cuando se pulsa el
botón izquierdo del ratón, o el botón derecho, entonces se registrará esa función callback
después de glutInit() en main() usando la sentencia: glutMouseFunc(MyMouse).
Después de registrar todos los eventos importantes de una aplicación, se debe invocar la
rutina de procesado de eventos de GLUT, glutMainLoop(). Esta función nunca vuelve, el
programa básicamente comienza un bucle infinito. Irá llamando, cuando sea necesario, a las
funciones callback que hayan sido previamente registradas. Toda función main() de una
aplicación OpenGL debe terminar en una sentencia glutMainLoop().
Por defecto, la GLUT tiene definidas funciones callbacks para cada evento posible, pero se
puede personalizar este comportamiento según las necesidades. Para hacer esto, algunas de las
funciones de las que se dispone son:
void glutDisplayFunc( void (*func) (void))
La función func(), que se le pasa como argumento será llamada cada vez que haya que
redibujar la ventana.
void glutIdleFunc( void (*func) (void))
La función que se le pasa como argumento es llamada cuando no hay entradas del usuario.
Cada vez que el procesador de eventos de GLUT da una vuelta al bucle infinito y no
encuentra ningún nuevo evento activado.
void glutReshapeFunc(void (*func) (int width, int height))
La función func(width, height) se llamará cada vez que la ventana cambie de
tamaño, y recibirá como argumentos la nueva anchura y altura.
void glutMouseFunc( void (*func) (int button, int state,
int x, int y))

Informática Gráfica 21
Librerías de Recursos: Aux y Glut

La función func(button, state, x, y) se llamará cuando se apriete o cuando se


suelte el botón definido por el parámetro button en la posición (x,y).
Valores de state:
GLUT_DOWN Pulsar con un botón del ratón.
GLUT_UP Soltar un botón del ratón.
Valores de button:
GLUT_LEFT_BUTTON Botón izquierdo.
GLUT_MIDDLE_BUTTON Botón del medio.
GLUT_RIGHT_BUTTON Botón derecho.
void glutMotionFunc(void (*func) (int x, int y))
La función func(x, y) se llamará cuando el ratón se mueva mientras está pulsado uno
de sus botones. Esta funcionalidad no estaba implementada en la librería Aux.
void glutKeyboardFunc(void (*) unsigned char key, int x,
int y)
Permite al usuario asociar una acción a la pulsación de una tecla o a un conjunto a de teclas.

A continuación un ejemplo, ampliando la plantilla vista para una animación en el apartado


4.2.2:

Figura 06: Ejemplo de registro de eventos en GLUT

22 Informática Gráfica
De la Peña, De la Viuda y Sánchez

4.2.4 Manejo de menús


Una de las novedades de esta librería es la creación de menús popup, que no contemplaba la
Aux. La GLUT posee un conjunto de rutinas que permiten de una manera sencilla definir y usar
menús en cualquier aplicación.
int glutCreateMenu(void (*func) (int value)
Esta función crea un menú (todavía sin opciones), y le asigna la función func(value).
Esta función se llamará cada vez que una de las opciones del menú sea seleccionada por el
usuario, y recibirá en value el código identificativo de la opción seleccionada. De esta
manera, podremos definir que hace cada opción de menú. Devuelve un identificador de
menú, que nos servirá cuando tengamos que referirnos a él.
void glutSetMenu(int menu)
Esta función hace que el menú identificado como menu sea el menú actual. Por defecto, el
menú actual es el último que se ha creado.
void glutAddMenuEntry(char *name, int value)
Añade una opción de menú al menú actual. Esta opción se llamará name y se identificará
por el número value.
Void glutAddSubMenu(char *name, int menu)
Añade una opción de menú que abrirá un submenú (en lugar de ejecutar directamente un
comando, como en el caso anterior). La opción se llamará name y el menú que aparecerá
será el identificado como menu (ver función glutCreateMenu())
Void glutChangeToMenuEntry (int entry, char *name, int value)
Esta función sirve para modificar una opción del menú actual. El parámetro entry nos indica
la opción a modificar (por ejemplo, para modificar la primera, entry = 1), name será el
nuevo nombre de la opción y value el nuevo identificador que se le pasará a la función
controladora de menú.
void glutAttachMenu(int button)
Esta función hace que el menú actual aparezca cada vez que se pulse el botón del ratón
indicado por button (GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON,
GLUT_RIGHT_BUTTON).

A continuación se muestra el código necesario para la creación de un sencillo menú:

Informática Gráfica 23
Librerías de Recursos: Aux y Glut

Figura 07: Ejemplo de creación de un menú en GLUT

4.2.5 Fuentes de texto


El manejo de fuentes de texto es una de las partes débiles de OpenGL. Su implementación es
complicada ya que la biblioteca GL sólo proporciona funciones muy primitivas para trazado de
bitmaps que obligan a disponer de una librería propia de bitmaps para los caracteres. GLUT va
un poco más allá y dispone de unas pocas funciones que permiten renderizar texto en pantalla.

glutBitmapCharacter(void * font, int character)


Permite escribir texto carácter a carácter pasándole sólo la fuente del texto y el carácter a
imprimir.
Tipos de fuentes en Glut:
o GLUT_BITMAP_9_BY_15
o GLUT_BITMAP_8_BY_13

24 Informática Gráfica
De la Peña, De la Viuda y Sánchez

o GLUT_BITMAP_TIMES_ROMAN_10
o GLUT_BITMAP_TIMES_ROMAN_24
o GLUT_BITMAP_HELVETICA_10
o GLUT_BITMAP_HELVETICA_12
o GLUT_BITMAP_HELVETICA_18

Figura 08: Ejemplo de manejo de textos en GLUT

En el ejemplo de ventanas y subventanas se han usado también estas funciones para


generar texto en pantalla. Esta es la rutina definida para escribir en pantalla el texto que obtiene
como parámetro:

Figura 09: Rutina para escribir en texto en pantalla con GLUT

Informática Gráfica 25
Librerías de Recursos: Aux y Glut

4.2.6 Objetos predefinidos


No existen novedades en las rutinas de dibujo implementadas por glut, al igual que aux ofrece
dos tipos de dibujos, sólidos o alámbricos:
Se dispone de las siguientes funciones:
Esferas:
glutWireSphere(radius, slices, stacks),
glutSolidSphere(radius, slices, stacks)
Cubos:
glutWireCube(size),
glutSolidCube(size)
Conos:
glutWireCone(base, height, slices, stacks),
glutSolidCone(base, height, slices, stacks)
Dodecaedros:
glutWireDodecahedron(void),
glutSolidDodecahedron(void)
Octaedros:
glutWireOctahedron(void),
glutSolidOctahedron(void)
Tetraedros:
glutWireTetrahedron(void)
glutSolidTetrahedron(void)
Icosaedros:
glutWireIcosahedron(void)
glutSolidIcosahedron(void)
Teteras:
glutWireTeapot(void)
glutSolidTeapot(void)
Toroides:
glutWireTorus(void)
glutSolidTorus(void)

26 Informática Gráfica
De la Peña, De la Viuda y Sánchez

5. Conclusión

A lo largo de todo el tema se ha pretendido dar una visión general de las dos librerías mas
importantes de OpenGL para el uso de ventanas que son independientes de plataforma, Aux y
Glut.
La librería Aux otorga un control total sobre los eventos y para la creación de ventanas.
Aux se caracteriza por su sencillez, lo cual no quiere decir que no sea completa. Unos años
después de la creación de esta librería se creó Glut, basada completamente en su predecora,
cumpliendo por lo tanto sus funciones y añadiéndole algunas más, como la creación de menús, o
llamada a subventanas.
Características:
Característica AUX GLUT
Funciones de Inicialización X X
Manejo de Ventanas X X
Manejo de Subventanas X
Procesado de Eventos X X
Objetos Predefinidos X X
Manejo de Menús X

Tabla 05: Comparación AUX – GLUT

Para concluir resaltar que las dos librerías son igual de válidas, su estructura es similar, por
lo que a la hora de diseñar cualquier programa tan solo deberemos basarnos en si vamos a
necesitar cualquiera de las opciones que añade Glut.
Si no se requieren las funcionalidades extra aportadas por Glut, se puede escoger
cualquiera de las dos, aunque lo mas recomendable es usar Glut, ya que la estructura es similar,
y se puede continuar utilizando si un día se desea ampliar las funciones de la aplicación.

Informática Gráfica 27

Você também pode gostar