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:
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:
target: este valor debe ser GL_TEXTURE_2D.
level: este parámetro se usa sólo si se quieren especificar más de un nivel de detalle para la textura, si sóla mente se va a utilizar un nivel este valor debe ser 0.
components: indica la representación interna que queremos que tenga esta textura, indica si queremos usar el formato RGBA, el número de bits que se quieren, etc. Los valores permitidos son: GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12, yGL_RGBA16
width,height: indican las dimensiones (en pixeles) de la imagen que estamos pasando.
format: indica el formato de los pixeles que estamos pasando
type indica el tipo de datos que estamos pasando, lo valores que puede tomar son: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_BITMAP
pixels: es un apuntador a los datos de la imagen que queremos asignar a la textura.
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.
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.
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).
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.