Capítulo 4: Texturas

Hasta ahora sólo dibujamos y coloreamos, pero ahora le vamos a poner texturas a nuestros programas, algo que es muy útil para crear escenas mas reales y fáciles. No sería muy buena idea dibujar un mundo de pequeños polígonos de diferentes colores, mejor uno grande y le ponemos nuestra textura. Este código es prácticamente una traducción del que existe en la pagina nehe.gamedev.net, capítulo 25, si quieres saber más, este es un sitio genial (en ingles).

Para empezar hay que definir lo que va a guardar a nuestra textura, esto lo hacemos mediante una estructura:

typedef struct {
  GLuyte *dibujo; // Un puntero a los datos de la imagen
  GLuint bpp;     // bpp significa bits per pixel (bits por punto) 
                  // es la calidad en palabras sencillas
  GLuint largo;   // Largo de la textura
  GLuint ancho;   // Ancho de la textura
  GLuint ID;      // ID de la textura, es como su nombre para opengl
} textura;
 
textura  texturas[1]; // Definimos nuestras texturas, por ahora solo 1

Listo, ahora hay que empezar a cargar el código en la memoria. El código que viene a continuación solo carga tga de 24 o 32 bits sin compresión. cabezeraTGA va a guardar 12 bytes que describen un archivo tga, compararTGA, va a ser donde guardamos los primeros 12 bytes leídos del archivo y los comparamos con los de cabezeraTGA. cabezera, guarda los 6 mas importantes bytes (largo, ancho y bpp).

int cargarTGA( char *nombre, textura *imagen) {
  GLubyte  cabezeraTGA[12]={0,0,2,0,0,0,0,0,0,0,0,0};
  // Cabecera de un tga sin compresión
  GLubyte  campararTGA[12];   // Acá vamos a comprar la cabecera
  GLubyte  cabezera[6];       // Los 6 bytes importantes
  GLuint   bytesporpunto;     // Cuantos bytes hay por punto
  GLuint   tamanoimagen;      // Acá guardaremos el tamaño de la imagen
  GLuint   temp,i;            // Variable temporal, y una para usar con el for
  GLuint   tipo=GL_RGBA;      // Nuestro tipo por defecto, lo veremos mas abajo

  FILE *archivo=fopen(nombre, "rb"); // Cargamos nuestro archivo en memoria
  if( archivo == NULL ||                // Existe nuestro archivo??
      fread(compararTGA,1,sizeof(compararTGA),FILE)!=sizeof(compararTGA) ||
      // Hay 12 bytes para leer??
      emcmp(cabezeraTGA,compararTGA,sizeof(compararTGA))!=0 ||
      // Son iguales??
      fread(cabezera,1,sizeof(cabezera),archivo)!=sizeof(cabezera)) {
    if(archivo==NULL)
      return 0;  // No se abrió el archivo
    else {
      fclose(archivo);
      return 0;
    }
  }
  /* Ahora hay que leer la cabecera del archivo, para saber cuanto es el 
     largo, ancho, y los bytes por puntos,
     para eso acá hay una ilustración de la cabecera :
     6 bytes -> xxxxxxx xxxxxxx xxxxxxx xxxxxxx xxxxxxx xxxxxxx	
                |--- Largo ---| |---Ancho-----| |-bpp-|
     El dato del largo se guarda en el cabezera[0] y cabezera[1], para 
     leerlo hay que multiplicar cabezera[1] por 256 y sumarselo a cabezera[0], 
     para leer ancho y bpp es el mismo procedimiento */
  imagen->largo=256*cabezera[1]+ cabezera[0];
  imagen->ancho=256*cabezera[3]+ cabezera[2];

  /* Ahora vemos si hay datos no válidos, como largo o ancho iguales 
     menores a 0 o iguales a 0 */
  if( imagen->largo <= 0 ||	// Largo mayor que 0?? 
      imagen->ancho <= 0 ||	// Ancho mayor que 0??
      (cabezera[4]!=24 && cabezera[4]!=32)) {
      // bpp es 24 o 32?? (solo se cargan 24 y 32 bpp)
    fclose(archivo);
    return 0;
  }
  imagen->bpp=cabezera[4];     // Acá se guardan los bits por punto
  bytesporpunto=cabezera[4]/8; // Acá los bytes por punto (1 byte = 8 bits)
  tamanoimage=imagen->largo * imagen-&gt;ancho * bytesporpunto;	
  // Esta es la memoria que necesitaremos para guardar los datos de la textura
  /* Ahora reservamos espacio en memoria para nuestra textura, luego leemos la 
     textura del archivo */
  imagen->dibujo = (GLubyte *)malloc(tamanoimagen);
  // Reservamos la memoria necesaria para nuestra textura
  if(imagen->dibujo== NULL ||  // Se logró reservar la memoria???
     fread(imagen->dibujo, 1, tamanoimagen, archivo) != tamanoimagen ) {	
        // Se lee, y se comprueba que lo leído es de la 
        // misma longitud que la asignada a a dibujo.
        if(imagen->dibujo != NULL)
           free(imagen->dibujo);
        fclose(archivo);
        return 0;
  }
  /* El formato tga guarda las imágenes en BGR, y opengl usa RGB, por lo 
     cambiamos de lugares */
  for(i=0; i < int(imageSize); i+=bytesporpunto)
  {
    temp=imagen->dibujo[i];                    // Guardamos el primer valor
    imagen->dibujo[i] = imagen->dibujo[i + 2]; // Asignamos el nuevo primer valor
    imagen->dibujo[i + 2] = temp;              // Asignamos el ultimo valor
  }
	
  fclose (archivo);	// Cerramos el archivo
	
  /* Listo, terminamos con el código de carga, volvemos a opengl, ahora hay 
     que asignarle a la textura un ID, luego decirle a opengl cuales son el 
     largo, el ancho y los bpp */

  glGenTexture(1,&imagen->ID);	// Crea un ID para la textura, buscando un id que este vacío
  glBindTexture(GL_TEXTURE_2D, imagen->ID);	// Seleccionamos nuestra textura
  if(imagen->bpp == 24) tipo= GL_RGB;	// Si nuestra textura es de 24 bits, entonces 
                                       // se crea una textura rgb, sino una rgba
  /* Ahora creamos nuestra textura, entrando el largo, ancho y tipo */
  glTexImage2D(GL_TEXTURE_2D, 0, tipo, imagen-&gt;ancho, imagen->largo, 0, 
     tipo, GL_UNSIGNED_BYTE, imagen->dibujo);
  /* Ahora le decimos a opengl como queremos que se vea nuestra textura, MAG_FILTER 
     es cuando la textura es mas grande que el lugar donde la asignamos, y MIG_FILTER, 
     es cuando la textura es mas pequeña que el lugar donde la asignamos, GL_LINEAR es 
     para que se vea bien tanto cerca como lejos, pero ocupa bastante procesador. 
     Otra opción el GL_NEARES, que ocupa menos procesador */
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  // La m
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  return 1;	// Todo salió bien
}

Tenemos lista la función para cargar las texturas a memoria, ahora hay que decirle a opengl que vamos a usar texturas y debemos cargarlas.

void inicializar() {
  .
  .
  .
  glEnable(GL_TEXTURE_2D);
  if(!cargarTGA("textura.tga", texturas[0])) exit(); 
    // Cargamos la textura y chequeamos por errores
}

Listo, textura en memoria, ahora hay que usarla en algo.

void dibujar () {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // Se borra el buffer de la pantalla
  glRotatef(angulo, 0.0, 1.0, 1.0);	// Rotamos nuestro objeto
  glBingTexture(texturas[0]->ID);
  // Vamos a usar un cubo
  glBegin(GL_QUADS);
  /* La textura es una imagen cuadrada, ahora hay que asignarle los lugares donde va, 
     para eso esta glTexCoord2f(float x, float y) donde x e y son las coordenadas de la 
     textura que van a coincidir con el punto que vamos a definir */	
  glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,  1.0);
  glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0,  1.0);
  glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0);
  glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0);

  glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0);
  glTexCoord2f(1.0, 1.0); glVertex3f(-1.0,  1.0, -1.0);
  glTexCoord2f(0.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
  glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0);

  glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0, -1.0);
  glTexCoord2f(0.0, 0.0); glVertex3f(-1.0,  1.0,  1.0);
  glTexCoord2f(1.0, 0.0); glVertex3f( 1.0,  1.0,  1.0);
  glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);

  glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0);
  glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0);
  glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0,  1.0);
  glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0,  1.0);

  glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0);
  glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
  glTexCoord2f(0.0, 1.0); glVertex3f( 1.0,  1.0,  1.0);
  glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0,  1.0);

  glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0);
  glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0,  1.0);
  glTexCoord2f(1.0, 1.0); glVertex3f(-1.0,  1.0,  1.0);
  glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0, -1.0);
  glEnd();
  angulo++;
  glutSwapBuffers();
}

Listo!!! tenemos texturas!! ahora casi podemos hacer un Quake IV!!! bueno... intenta.

Programas en C


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplos y texturas glut.zip 2001-05-01 55169 bytes 1195



suministrado por FreeFind
Valid HTML 4.0! Valid CSS!