Práctica 3. Textura en OpenGL.

 En OpenGL existe la posibilidad de asignar texturas a una primitiva que es dibujada. Esto puede verse como colocar un papel tapiz sobre una superficie. El uso de texturas es de gran ayuda al momento de definir objetos muy complicados, por ejemplo, si queremos dibujar una rueda de un carro sin utilizar texturas tendriamos primero que dibujar la llanta, después el rín, y por último las tuercas usando un número muy grande de polígonos, en cambio, si usamos texturas podríamos tomar una foto a una llanta y esa foto aplicarla sobre sólo un poligono regular.

 Para poder usar texturas en OpenGL hay que hacer 4 pasos:

1. Crear una textura y especificar la imagen que queremos utilizar

 Para crear una textura primero tenemos que pedir a OpenGL que nos dé un identificador para la nueva textura que vamos a utilizar. Este paso no es necesario, sin embargo es muy útil si vamos a usar más de una textura pues permite tener un mejor control de las mismas. Para pedir un nuevo identificador hay que usar el comando

glGenTextures(n: GLsizei; textures: PGLuint)

 En este comando, n indica el número de identificadores que queremos solicitar y textures indica el lugar donde queremos guardar esos identificadores. Este comando se encuentra a partir de la especificación 1.1 de OpenGL. Si la libreria que estamos usando es anterior, en Delphi podemos indicarle al compilador que esta función la queremos cargar a partir de las librerias de OpenGL que tenga el sistema, esto lo hacemos con la siguiente línea de código:

procedure glGenTextures(n: GLsizei; textures: PGLuint); stdcall; external opengl32;

 Una vez que tengamos un identificador, hay que indicarle a OpenGL que la textura que vamos a utilizar es la que corresponde al identificador que obtuvimos. Esto lo hacemos con el comando

glBindTexture(target: GLenum; texture: GLuint)

 Aquí target indica el tipo de textura con el que estamos trabajando y texture debe ser uno de los identificadores que solicitamos. Los valores que puede tomar target son GL_TEXTURE_1D or GL_TEXTURE_2D  los cuales indican si se trata de una textura en 1 o 2 dimensiones.

 Una vez que creamos el identificador y le indicamos a OpenGL con cual textura vamos a trabajar, el siguiente paso es indicarle que imagen queremos utilizar como textura. OpenGL no incluye ningún comando para manejar archivos de imágenes, lo que tenemos que hacer es generar o leer la imagen de alguna forma y después esos datos pasarlos a la textura utilizando el siguiente comando:

glTexImage2D (target: GLenum; level, components: GLint;
              width, height: GLsizei; border: GLint;
              
format, type: GLenum; pixels: Pointer);

 Los parametros de esta función son:

Una nota muy importante es que las dimensiones de la textura deben ser una potencia de 2 (o bien una potencia de 2 más 2 si se usan bordes). Si la imagen que vamos a usar como textura no cumple con esta restricción, podemos usar el comando

function  gluScaleImage(format: GLenum;widthin, heightin:GLint;
                       typein: GLenum; datain: Pointer;
                       widthout, heightout: GLint; 
                       typeout: GLenum; dataout: Pointer): Integer;

format corresponde al formato que tiene la imagen, widthin y heightin a las dimensiones originales, typein al tipo de datos en el que está la entrada, datain un apuntador a los datos de la imagen; widthout y heightout corresponden a las dimensiones de la imagen de salida, typeout al tipo de datos que queremos de salida y por último dataout es un apuntador a donde queremos que se guarde la imagen modificada.

2. Indicar como se va a aplicar la textura a cada pixel

 Para indicar como queremos aplicar una textura hay que usar el siguiente comando:

glTexEnvi (target, pname: GLenum; param: GLint);

 target debe ser GL_TEXTURE_ENV, pname debe ser GL_TEXTURE_ENV_MODE y param puede ser cualquiera de los siguientes valores: GL_MODULATE, GL_DECAL, GL_BLEND, o GL_REPLACE. Dependiendo del valor de param y de el número de componentes que tiene la textura se aplicará una de las siguientes funciones para combinar los colores de la textura con el color del pixel:

Los subindices t corresponden a valores de la textura, f a valores del la primitiva y v a los valores que se colocaran en la pantalla. Las letras C, L y A corresponden a Color, intensidad y Alfa respectivamente.

3. Activar el uso de texturas

 Para activar el uso de texturas lo único que hay que hacer es llamar el comando glEnable con el parámetro GL_TEXTURE_2D o GL_TEXTURE_1D dependiendo de que tipo de textura queremos usar (si se activan ambos se utiliza 2D).

4. Dibujar el objeto indicando tanto coordenadas geométricas como coordenadas de textura

 Para hacer esto, una vez que hayamos empezado una primitiva y antes de especificar cada vértice que la va a formar hay que indicar en que lugar de la textura caera ese vértice utilizando el comando

glTexCoord*(datos:tipo)

los parámetros que recibe dependen de que función se está usando, por ejemplo, si usamos glTextCoord2d los parámetros serán 2 GLdouble que corresponden a las coordenadas S y T de la textura. La esquina inferior izquierda de la textura corresponde a la coordenada (0,0) y la superior derecha a la (1,1). Podemos asignar valores fuera de estos rangos, OpenGL tiene dos formas de tratar estos valores: GL_CLAMP y GL_REPEAT. Con el primero si el valor de la coordenada es menor que 0 simplemente se convierte a 0 y si es mayor a 1 se convierte a 1. Con la segunda opción la textura se maneja como si esta estuviera repetida una infinidad de veces. Para indicar como queremos tratar las coordenadas fuera del rango [0,1] utilizamos el siguiente comando:

glTexParameteri (target, pname: GLenum; param: GLint)

con target iagual a GL_TEXTURE_2D, pname con GL_TEXTURE_WRAP_S si queremos indicar como manejar la primer coordenada y GL_TEXTURE_WRAP_T si queremos indicar como manejar la segunda. Por último, param puede tomar los valores GL_CLAMP y GL_REPEAT.

Al igual que los vértices, todos los puntos que demos con glTexCoord son transformados utilizando una Matriz de tamaño 4x4. Esta transformación es muy útil si quieremos dar movimiento a nuestra textura sin modificar en realidad lo que hay dentro de la misma. Para modificar esta matriz tenemos que cambiar la matriz de trabajo utilizando el comando glMatrixMode con el parámetro GL_TEXTURE.