Ahora vemermos un sencillo programa para dibujar un punto utilizando JOGL y, además, mostraremos en la línea de comandos la versión de nuestro Sistema Operativo y la marca de la tarjeta de video que tenemos instalada en nuestra computadora. Todo lo anterior lo haremos utilizando un JFrame centrado en la pantalla.



Para comenzar, tendremos que importar la librería:

import javax.media.opengl.*;

la cual contiene las clases e interfaces necesarias para llamar a los métodos de OpenGL en Java entre las que destacan:

  • Interfaz GL. Ésta interfaz nos proporcionará el acceso a las funciones de OpenGL.
  • Interfaz GLEventListener. Ésta interfaz declara eventos los cuales son utilizados por el código cliente para manipular el renderizado de OpenGL a través de GLAutoDrawable. Todo lo que sea manipulado por GLAutoDrawable será visualizado a través de un objeto instanciado de la clase GLCanvas.
  • Clase GLCanvas. Ésta clase nos proporcionará el soporte para el renderizado de los gráficos de OpenGL, el objeto instanciado de ésta clase deberá introducirse dentro de un JPanel para poder ser visualizado.
Nuestra clase principal, además de extender de la clase JFrame, deberá implementar la interfaz GLEventListener, descrita anteriormente, por lo que el código fuente quedará de la siguiente manera:

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.Dimension;

// Importamos la librería de OpenGL
import javax.media.opengl.*;

public class puntoJOGL extends JFrame implements GLEventListener
{
JPanel panelDibujo;
Container contenedor;
Toolkit kit;
Dimension dimensionPantalla;
int altura;
int anchura;

// La interfaz GL nos proporcionará el acceso a las funciones de OpenGL
static GL gl;

/* La clase GLCanvas nos proporciona el soporte para el renderizado
* de los gráficos de OpenGL, por el momento solamente la utilizaremos
* para mostrar los cuatro métodos principales de GLEventListener */
static GLCanvas canvas;

// Constructor
public puntoJOGL()
{
super("Punto dibujado con JOGL");
kit = Toolkit.getDefaultToolkit();
dimensionPantalla = kit.getScreenSize();
altura = (int)dimensionPantalla.getHeight();
anchura = (int)dimensionPantalla.getWidth();

// Creamos el objeto de la clase GLCanvas
canvas = new GLCanvas();

/* Añadimos el oyente de eventos para el renderizado de OpenGL,
* esto automáticamente llamará a init() y renderizará los
* gráficos cuyo código haya sido escrito dentro del método display() */
canvas.addGLEventListener(this);

/* Inicializamos la interfaz de GL la cual utilizaremos
* para llamar a las funciones de OpenGL */
gl = canvas.getGL();

panelDibujo = new JPanel(new BorderLayout());

/* Agregamos el objeto GLCanvas en el centro del JPanel
* para que los gráficos renderizados dentro del
* objeto GLCanvas puedan ser visualizados. */
panelDibujo.add(canvas, BorderLayout.CENTER);

contenedor = getContentPane();
contenedor.add(panelDibujo, BorderLayout.CENTER);
this.setSize(anchura/2, altura/2);
this.setLocation(anchura/4, altura/4);
this.setResizable(true);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

// A continuación se muestran los métodos utilizados por GLEventListener

/* Como se explicó, este método es el que inicializará
* los gráficos de OpenGL que GLCanvas utilizará,
* para llamar a las funciones de OpenGL utilizaremos el objeto gl
* creado anteriormente. */
public void init(GLAutoDrawable drawable)
{
// Escribimos en pantalla la versión del S.O.
System.out.println (gl.glGetString(GL.GL_VERSION));
// Escribimos en pantalla la marca de nuestra tarjeta de video
System.out.println (gl.glGetString(GL.GL_VENDOR));
/* El fondo de los gráficos mostrados en el objeto
* GLCanvas será de color negro. Como se puede apreciar, estamos
* utilizando el método de OpenGL glClearColor(float, float, float, float)
* mediante la interfaz GL. */
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
/* Este método, como se explicó, se utiliza para que el
* usuario pueda modificar el "viewport" de los gráficos
* adecuadamente. En este caso declararemos que nuestro espacio
* de trabajo será del mismo tamaño que el JFrame. Esto se hace para que
* el punto que dibujemos aparezca exactamente en el centro del JFrame.*/
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();

/* Se define el punto de vista (viewport) de nuestro objeto GLCanvas
* el cual, como se dijo anteriormente, será del mismo tamaño que el
* JFrame. De esta manera, si existe un cambio en el tamaño del
* JFrame, el espacio de trabajo se ajustará al tamaño del mismo para
* que el punto siga mostrándose en el centro. */
gl.glOrtho(0, anchura, 0, altura, -1.0, 1.0);

/* Si el JFrame se dimensiona, se vuelven a dibujar los gráficos. */
canvas.repaint();
}

public void display(GLAutoDrawable drawable)
{
/* Este método es utilizado para crear todos los gráficos que
* se dibujarán dentro del objeto GLCanvas. Primero llamamos al
* método de OpenGL glClear(GLBitField mask) el cual limpiará
* todos los buffers para poder dibujar. */
gl.glClear(GL.GL_COLOR_BUFFER_BIT);

/* Ahora llamamos al método glColor3f(float, float, float)
* el cual definirá el color de los gráficos que se
* dibujarán. En este caso dibujaremos un punto de color Azul. */
gl.glColor3f(0.0f, 0.0f, 1.0f);

/* Definimos el tamaño del punto que dibujaremos utilizando
* el método glPointSize() de OpenGL, en este caso será de 10 pixeles. */
gl.glPointSize(10);

/* Esto es prácticamente igual a una declaración hecha
* en C ó C++ utilizando OpenGL. Indicamos que iniciaremos
* a dibujar con el método glBegin(GLEnum Mode) y que finalizaremos
* con el método glEnd(). Dentro de ambos métodos irán TODOS
* los gráficos que dibujaremos. */
gl.glBegin(GL.GL_POINTS);
/* Por el momento, solamente dibujaremos un vértice exactamente
* enmedio de nuestro objeto GLCanvas. Debido a que el objeto
* GLCanvas se encuentra en el centro del JPanel y éste se encuentra
* en el centro del JFrame, el
* punto aparecerá justo enmedio de éste último. */
gl.glVertex2i(anchura/2, altura/2);
gl.glEnd();

/* Indicamos que dibuje inmediatamente después utilizando el método
* glFlush(); */
gl.glFlush();
}

public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged, boolean deviceChanged)
{
/* Método para el manejo de eventos del cambio de visualizador,
* éste no lo utilizaremos ahora. */
}

// Finalizan los métodos utilizados por GLEventListener

// Método principal para iniciar la ejecución de nuestro programa
public static void main(String[] args)
{
/* Simplemente crearemos un objeto de la clase
* puntoJOGL, entonces el programa ejecutará
* el código del constructor. */
new puntoJOGL();
}
}

Al compilar y ejecutar el código anterior, nos mostrará un JFrame centrado con un punto dibujado en medio como el de la figura siguiente:


Mientras que en la línea de comandos nos aparecen unos datos como los siguientes:


Si desean descargar el código fuente pueden dar click en el enlace siguiente:

Descargar código fuente puntoJOGL.java

Métodos de OpenGL utilizados.

glClearColor(float, float, float)

En el método init(), nosotros podemos cambiar el fondo de los gráficos mediante el método de OpenGL, glClearColor(float, float, float, float), llamado mediante la interfaz GL implementada en el constructor. El método glClearColor(float, float, float, float) maneja los colores mediante el modelo RGBA con un intervalo de intensidad de colores comprendido entre 0 y 255. Debido a que maneja datos del tipo float, tendremos que utilizar la fórmula:

(r/255, g/255, b/255, alpha)

siendo r, g, b la intensidad del color deseado y alpha la transparencia del mismo, la combinación de todos nos dará como resultado el color solicitado. Para que quede más claro, veamos algunos ejemplos:
  1. Color AMARILLO. Para crear este color se necesita la combinación (255, 255, 0, 0), por lo tanto, en OpenGL será (1.0f, 1.0f, 0.0f, 0.0f).
  2. Color CYAN. Para crear este color se necesita la combinación (0, 255, 255, 0), por lo tanto, en OpenGL será (0.0f, 1.0f, 1.0f, 0.0f).
  3. Color MAGENTA. Para crear este color se necesita la combinación (255, 0, 255), 0, por lo tanto, en OpenGL será (1.0f, 0.0f, 1.0f, 0.0f).
  4. Color NARANJA. Para crear este color se necesita la combinación (255, 128, 0, 0), por lo tanto, en OpenGL será (1.0f, 0.5f, 0.0f, 0.0f).
  5. Color MORADO. Para crear este color se necesita la combinación (128, 0, 255, 0), por lo tanto, en OpenGL será (0.5f, 0.0f, 1.0f, 0.0f).
  6. Color ROSA. Para crear este color se necesita la combinación (255, 0, 128, 0), por lo tanto, en OpenGL será (1.0f, 0.0f, 0.5f, 0.0f).
Podemos hacer la prueba modificando los valores en el método glClearColor(float, float, float, float) dentro del método init().

Para mayor información puede visitar la documentación del método glClearColor().

glColor3f(float, float, float)

Éste método es utilizado para definir el color de los gráficos que se dibujarán, los colores creados utilizan el modelo RGB. Asi que para modificar los colores se emplea un método parecido que con glClearColor(float, float, float, float), solo que en esta ocasión no utilizaremos la variable alpha. Existen otras variantes del método glColor*() que dependen del tipo de datos que manejan por ejemplo:
  1. void glColor3i(int, int, int)
  2. void glColor3f(float, float, float) - Visto en el programa de ejemplo.
  3. void glColor3d(double, double, double)
  4. void glColor3fv(float[], int alpha) - Éste método, al igual que glClearColor, utiliza transparencia del color definida por alpha.
Podemos hacer la prueba modificando los valores en el método glColor3f(float, float, float, float) dentro del método display().

Para mayor información puede visitar la documentación del método glColor*().

glBegin(GL.GL_POINTS) y glEnd()

Estos métodos especidican el inicio y el fin del objeto dibujado, en este caso se trata de un punto. La forma general de estos métodos es la siguiente:

glBegin(GLenum mode)
// Dibujar objeto
glEnd()

Donde mode comprende algunos parámetros como:
  • GL_POINTS - Utilizado en este programa.
  • GL_LINES - Utilizado para dibujar líneas, existen otras variantes.
  • GL_TRIANGLES - Utilizado para dibujar triángulos, existen otras variantes.
  • GL_QUADS - Utilizado para dibujar cuadrados, exitsten otras variantes.
  • GL_POLYGON - Utilizado para dibujar polígonos.
Más adelante veremos algunos ejemplos concretos, si desean más información visiten la documentación del método glBegin().

glPointSize(int pixeles)

Éste método es utilizado para definir el tamaño del punto que se va a dibujar, en este programa de ejemplo fue de 10 pixeles.

glMatrixMode(GLenum mode);
gl.glLoadIdentity();
gl.glOrtho(double left, double right, double bottom, double top, double near, double far)

Estos métodos son necesarios para definir la proyección ortográfica es decir, en téminos más sencillos, define nuestro espacio de trabajo. En el caso de nuestro programa definimos un espacio de trabajo de anchura x altura x 2, en este caso el 2 no se percibe ya que estamos trabajando en dos dimensiones solamente. Para que se tenga una idea más clara, consideremos al espacio de trabajo como una "cubo" donde:
  • La esquina inferior izquierda de enfrente está definida por las coordenadas (left, bottom, far)
  • La esquina superior derecha de atrás está definida por las coordenadas (right, top, near)




Para más información puede visitar la documentación de glOrtho().

glVertex2i(int x, int y)


Este método dibujar un vértice ubicado en las coordenadas (x, y), en el programa de ejemplo ubicamos el vértice exactamente a la mitad de nuestro JFrame utilizando las variables altura y anchura. Debido a que definimos con el método gl.glOrtho un área de trabajo de (anchura, altura, 2) entonces, al llamar al método glVertex2i(anchura/2, altura/2) estamos colocando nuestro vértice exactamente en medio de nuestro espacio de trabajo, el cual, al estar situado en medio del JFrame nos muestra el punto exactamente en medio de éste último. El método glVertex*() contiene muchas variantes entre las que se encuentran:
  • glVertex2i(int x, int y) - Utilizado en el programa ejemplo.
  • glVertex2f(float x, float y)
  • glVertex2i(int x, int y, int z) - Utilizado para dibujar gráficos en 3 dimensiones.
Para mayor información puede visitar la documentación de glVertex().

Para finalizar, pueden jugar con el código y hacerle modificaciones para ver los resultados. He aquí algunas variantes modificando el código:

glClearColor(1.0f, 1.0f, 1.0f, 0.0f)
glColor3f(1.0f, 0.0f, 0.0f)


glClearColor(0.5f, 0.0f, 1.0f, 0.0f)
glColor3f(0.0f, 0.0f, 0.0f)


glClearColor(1.0f, 0.0f, 0.0f, 0.0f)
glColor3f(1.0f, 1.0f, 0.0f)

NOTA FINAL:
Recordemos que para llamar a las funciones de OpenGL debemos hacerlo a traves de la interfaz GL de JOGL.


Leer más...

Ya explicamos anteriormente cómo es la estructura general de un programa escrito en Java utilizando JOGL, por el momento mostraremos cómo dibujar un JFrame centrado en la pantalla sea cual sea la resolución de ésta para que, posteriormente, podamos dibujar dentro del mismo algunos gráficos utilizando JOGL. De ésta manera comenzaremos a estudiar la estructura general de un programa escrito en Java para qué, más adelante, se estudien los métodos utilizados por GLEventListener.



He aquí el código:

/* Importamos las clases JFrame y JPanel
* contenidas dentro del paquete SWING */
import javax.swing.JFrame;
import javax.swing.JPanel;

/* Importamos las clases Container, BorderLayout,
* Toolkit y Dimension del paquete AWT. */
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.Dimension;

// Creamos nuestra clase principal que extiende de la clase JFrame
public class jFrameCentrado extends JFrame
{
/* Necesitaremos un JPanel para introducir
* los elementos que se mostrarán en el JFrame. */
JPanel panel;

/* Declaramos un contenedor para introducir
* nuestro panel principal, el contenedor
* será el JFrame en general. */
Container contenedor;

/* El toolkit es útil para obtener
* información básica de la computadora, cómo la resolución
* o dimensión de la pantalla,
* dónde se está ejecutando el programa */
Toolkit kit;

/* Esta variable la utilizaremos para almacenar
* la dimensión (ancho x alto), en pixeles, de
* la pantalla dónde se está ejecutando el programa. */
Dimension dimensionPantalla;

// Variable para almacenar la altura, en pixeles, de la pantalla
int altura;
// Variable para almacenar la anchura, en pixeles, de la pantalla
int anchura;

// Constructor
public jFrameCentrado()
{
/* Llamamos a la superclase de JFrame
* la cual colocará un título al mismo. */
super("Frame centrado");

/* Instanciamos un objeto de Toolkit para obtener
* los datos generales de nuestra computadora. */
kit = Toolkit.getDefaultToolkit();

/* Obtenemos la dimensión de la pantalla en pixeles */
dimensionPantalla = kit.getScreenSize();

/* Almacenamos la altura y anchura, en pixeles, de la pantalla.
* Debido a que los métodos "getHeight" y "getWidth" regresan una
* variable de tipo double, necesitaremos obligar
* al programa que convierta dicha variable a int, es decir, haremos un "cast". */
altura = (int)dimensionPantalla.getHeight();
anchura = (int)dimensionPantalla.getWidth();

/* Le decimos a Java que el contenedor será el mismo JFrame */
contenedor = getContentPane();

/* Instanciamos un objeto de la clase JPanel, en este
* caso, estará vacío. */
panel = new JPanel();

/* Agregamos el JPanel dentro del JFrame utilizando el
* contenedor creado previamente, situando al JPanel
* en el centro del JFrame utilizando BorderLayout */
contenedor.add(panel, BorderLayout.CENTER);

/* Ya que tenemos obtenida la altura y anchura, en pixeles
* de la pantalla, definimos el tamaño del JFrame.
* En este caso será del tamaño de la mitad de ancho
* de la pantalla por la mitad de altura de la pantalla. */
this.setSize(anchura/2, altura/2);

/* Ahora situamos al JFrame exactamente en el centro de la
* pantalla donde se está ejecutando el programa */
this.setLocation(anchura/4, altura/4);

/* Lo hacemos redimensionable y visible */
this.setResizable(true);
this.setVisible(true);

/* Finalmente, le indicamos a Java que queremos que nuestro
* JFrame se cierre cuando demos click en el botón cerrar (tache)
* que aparecerá en la parte superior derecha del mismo. */
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} // Fin del constructor

// Método principal para iniciar la ejecución de nuestro programa
public static void main(String[] args)
{
/* Simplemente crearemos un objeto de la clase
* jFrameCentrado, entonces el programa ejecutará
* el código del constructor. */
new jFrameCentrado();
}
} // Fin de la clase jFrameCentrado

Al compilar y ejecutar el código anterior, nos mostrará un JFrame centrado como el de la figura siguiente:


Este JFrame nos será de gran utilidad en nuestros programas posteriores, ya que podremos introducir dentro de éste, con la ayuda del JPanel creado, los gráficos creados con JOGL. Si desean descargar el código fuente pueden dar click en el enclas siguiente:

Descargar código fuente jFrameCentrado.java


Leer más...

Antes que todo, explicaremos cómo está conformada la estructura de un programa escrito en Java utilizando librerías de JOGL. Como la mayoría de ustedes saben, un programa escrito solamente en Java está conformado por un mínimo de cinco partes:

  1. La clase principal de nuestro programa.
  2. Las variables utilizadas por la clase.
  3. El constructor de la clase.
  4. Los métodos que utilizará la clase.
  5. El método principal (main) que comenzará la ejecución de nuestro programa.

Entonces, un programa sencillo en Java estaría escrito más o menos de la siguiente manera:

// Debemos importar los paquetes que vayamos a necesitar
import java.awt.*; // Por ejemplo

// Clase principal
public class MiClase
{
// Variable 1
// Variable 2

// . . .

// Variable n

// Constructor
public MiClase()
{
/* Aquí inicializamos las variables 1, 2, . . ., n
* declaradas anteriormente */
}

// Métodos que utilizará la clase "MiClase"

public void metodo_1()
{ }

public int metodo_2()
{ }

// . . .

public double metodo_n()
{ }

// Método principal
public static void main(String[] args)
{
/* Instanciación de los objetos de la clase "MiClase"
* Comenzará la ejecución del código */
}
} // Fin de la clase "MiClase"

Ahora bien, como trabajaremos con gráficos de OpenGL será necesario implementar la interfaz conocida con el nombre de GLEventListener además de que, debido a que debemos montar los gráficos en alguna parte, tenemos que extender de la clase JFrame o JPanel.

La interfaz GLEventListener declara eventos los cuales son utilizados por el código cliente para manipular el renderizado de OpenGL a travez de GLAutodrawable.

Para que tengan una idea más clara, algo parecido ocurre cuando implementan la interfaz ActionListener para escuchar los eventos de los botones los cuales son manipulados por el código cliente a través de ActionEvent.

La interfaz GLEventListener utiliza cuatro métodos principales los cuales será necesario declarar dentro de la estructura de nuestro programa para que éste funcione.

1 -public void init(GLAutodrawable drawable)

Este método es llamado por drawable inmediatamente después de que el contexto de OpenGL (procedimiento que realizará un objeto GLCanvas) es inicializado. Puede ser utilizado para la inicialización de los gráficos de OpenGL que GLCanvas utilizará tales como el color de fondo, color de los objetos que se dibujarán, luces que se manejarán, etc.

2 - public void reshape(GLAutodrawable drawable, int x, int y, int width, int height)

Este método es llamado por drawable durante el primer redibujado (repaint) y después de que el componente se redimensiona (resize). El cliente puede actualizar el punto de vista (viewport) de los gráficos apropiadamente.

3 - public void display(GLAutodrawable drawable)

Este método es llamado por drawable para iniciar el renderizado de OpenGL a petición del cliente. Dentro de este método se incluirán los gráficos que GLCanvas dibujará y será llamado cada vez que se le solicite, o bien, cuando todos los GLEventListeners hayan sido notificados de que ocurrió algún evento.

4 - public void displayChanged(GLAutodrawable, boolean modeChanged, boolean deviceChanged)

Este método es llamado por drawable cuando ocurre algún cambio en el visualizador (pantalla) asociado con GLAutoDrawable. Los dos parámetros de tipo boolean indican el tipo de cambio que ha ocurrido.

Para que se tenga una idea más clara sobre los cambios que pueden ocurrir en el visualizador (pantalla) se presentan dos ejemplos:
  1. Cambio de modo de pantalla (display mode changed). Esto ocurre cuando, por ejemplo, la calidad del color cambia (digamos de 32-bits a 16-bits) en un monitor donde el GLAutoDrawable está siendo dibujado.
  2. Cambio de visualizador (display device changed). Esto ocurre cuando, por ejemplo, el usuario arrastra una ventana que contiene un GLAutoDrawable de un monitor a otro en una configuración de múltiples monitores con diferentes resoluciones.
Por lo tanto, un programa escrito en Java utilizando librerías JOGL estaría escrito más o menos de la siguiente manera:

// Debemos importar los paquetes de Java que vayamos a necesitar
import java.awt.*; // Por ejemplo
// Debemos importar las librerías de JOGL que vayamos a necesitar
import javax.media.opengl.*; // Por ejemplo

// Clase principal que extenderá de JFrame e implementará
// la interfaz GLEventListener
public class MiClase extends JFrame implements GLEventListener
{
// Variable 1
// Variable 2

// . . .

// Variable n


// La interfaz GL nos permitirá el acceso a todos
// los métodos utilizados por OpenGL

static GL gl;

/* La clase GLCanvas nos proporciona el soporte para
* el renderizado
de los gráficos de OpenGL, es decir,
* dentro de este objeto se dibujarán
los gráficos
* creados. */

static GLCanvas canvas;

// Constructor
public MiClase()
{
/* Aquí inicializamos las variables 1, 2, . . ., n
* declaradas anteriormente, así como
* todas las variables de las librerías JOGL */

}

// Métodos que utilizará la clase "MiClase"

public void metodo_1()
{ }

public int metodo_2()
{ }

// . . .

public double metodo_n()
{ }

/* Aquí agregamos los métodos que utilizará la
* interfaz GLEventListener */

public void init(GLAutoDrawable drawable)
{
/* Este método es el que inicializará
* los gráficos de OpenGL que GLCanvas utilizará,
* para llamar a las funciones de OpenGL
* utilizaremos el objeto gl
* instanciado anteriormente. */
}

public void reshape(GLAutoDrawable drawable,
int x, int y, int anchura, int altura)
{
/* Este método, como se explicó, se utiliza para que
* el usuario pueda modificar el "viewport" de los
* gráficos adecuadamente */
}

public void display(GLAutoDrawable drawable)
{
/* Este método es utilizado para crear todos
* los gráficos que se dibujarán dentro del
* objeto GLCanvas */
}

public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged,
boolean deviceChanged)
{
/* Método para el manejo de eventos del cambio de
* visualizador. */
}

// Método principal
public static void main(String[] args)
{
/* Instanciación de los objetos de la clase "MiClase"
* Comenzará la ejecución del código */
}
} // Fin de la clase "MiClase"

Hasta el momento no hemos creado algún código que produzca algún resultado, lo anterior simplemente fue un ejemplo de la apariencia que debe tener un programa escrito en Java utilizando librerías con OpenGL. En la siguiente entrada de este blog mostraremos el ejemplo, ahora sí, de un programa que mostrará algo en pantalla.


Leer más...