sábado, 26 de mayo de 2007

PREVIO PRACTICA NO. 10

PREVIO NO. 10

Animación Esqueletal:
Un modelo 3d está compuesto por cientos o miles de polígonos de distintas formas y tamaños que unidos entre sí forman la figura deseada. El número de polígonos ha ido aumentando progresivamente de modo que ahora para formar el brazo de un determinado modelo se utilizan miles de polígonos... miles de polígonos que han de modificar su tamaño y forma con cada mínimo movimiento del modelo.
Calcular cada deformación de estos miles de polígonos y sus nuevas coordenadas en la escena, además de la aplicación sobre ellos de efectos luminosos, texturados, filtrados... El trabajo que supone para el sistema gráfico es tremendo. En eliminar esa inmensa carga se basa la tecnología del "esqueleto 3d". La "animación esqueletal" se basa en crear el modelo sobre una arquitectura o esqueleto y después recubrirlo de texturas (o piel). Con esta técnica, cada miembro del gorila del ejemplo se construiría recubriendo de polígonos un "hueso" (bone) del esqueleto. Las ventajas llegan cuando ese miembro se tiene que mover respecto al cuerpo. Cada hueso tendrá un movimiento limitado respecto al hueso con el que se une, exactamente del mismo modo que lo tiene el animal real. Cada parte móvil del modelo está formada a través de un hueso que tiene su propio recubrimiento de carne (polígonos) y su propia piel (texturas) y con la movilidad que el programador le quiera dar. De este modo, el gorila del ejemplo podría tener un hueso que le permita mover el brazo respecto al hombro, el antebrazo respecto al resto del brazo, la mano respecto al antebrazo, los dedos respecto a la mano... El movimiento es mucho más realista y, sobre todo, requiere muchos menos recursos del sistema al no tener que calcular la deformación de los polígonos que hasta ahora se utilizaban para representar las articulaciones.
El único problema que representa la creación de modelos 3d a partir del un esqueleto se encuentra en la unión de los distintos huesos. Entre un hueso y otro existe un espacio que, siguiendo el símil con el cuerpo de los vertebrados reales, llamaremos articulación. Esta articulación se contrae, se estira y de deforma de distintas formas dependiendo del movimiento que hagan los dos huesos que une por ejemplo:

La grieta que se crea entre ambos huesos es algo que no se puede mostrar en la imagen final. Para esconderla se utiliza la técnica "Skinning" que, como su nombre indica, se encarga de recubir de piel estas imperfecciones.

Mediante esta piel flexible, que une cada uno de los vértices de un hueso con el correspondiente en el otro, se da continuidad al objeto y se acerca mucho al movimiento totalmente natural que podemos observar en cualquier ser vivo. Un problema que genera esta "piel" radica en la textura que recubre esta piel.
El problema radica en cómo unir los distintos huesos de modo que la apariencia final sea realista. De eso se ocupa el Vertex Skinning. Esta técnica se basa en la aplicación lo más realista posible del cálculo de las funciones matemáticas que calculan la posición de cada vértice de un objeto en la escena. Explicado de una forma sencilla, se ocupa de rellenar de la forma más realista posible los espacios entre los distintos "huesos" de los que ya hemos hablado. La unión entre los citados huesos es más real cuanto más matrices se utilicen. Estas matrices son cálculos matemáticos destinados a unir entre sí cada vértice del objeto. Cuantas más veces se recalcule la unión (más matrices haya), más realista será el objeto final.

El brazo del modelo (en rojo) se une al torso (en azul). Cada color representa una de las matrices y, como vemos, la unión entre ambas es poco natural. Tarjetas como las ATi Radeon soportan hasta cuatro matrices por hardware, por lo que en ejemplos como este, añadiendo una tercera matriz se solucionaría el problema.

Entre las matrices roja y azul, se ha introducido una tercera matriz representada en verde. Esta matriz se introduce entre las otras dos actuando como una especie de colchón flexible que hace que la unión de las otras dos sea más natural. En caso de que el resultado no fuese el buscado, se podría introducir una cuarta matriz y perfeccionar aún más el resultado. Otra de las ventajas de contar con más matrices a la hora de representar un modelo, es que se puede definir el comportamiento de la textura (piel) que recubre cada matriz. Si se trata de representar la piel de un animal, la textura que recubre la matriz central se estirará mientras que la que recubre las otros dos matrices permanecerá igual. Del mismo modo, cada matriz puede verse afectada de forma diferente por la luz, ensombreciendo o aclarando la textura que la recubre.
La gran ventaja de las ATi Radeon es que calcula hasta cuatro de estas matrices por hardware. Calcular estas matrices por software sería imposible ya que el procesador principal quedaría completamente colapsado ante tal afluencia de operaciones de cálculo en tiempo real.
En el siguiente gráfico podemos ver un ejemplo real en un juego, el Dungeon Siege de Microsoft, en el que se pueden ver las cuatro matrices en distintos colores.

Cada color representa una matriz, sin embargo, la aplicación más efectiva de las distintas matrices, donde más efectiva se muestra es en las transiciones automáticas. Los conocidos "morphings".
Formatos:
.fbx
el formato FBX, desarrollado por Kaydara para el intercambio de información.
FBX es un formato binario que soporta toda clase de información 3D, 2D, video y audio, por lo que facilita enormemente la comunicación entre distintas aplicaciones (como Cinema4D, Lightwave, 3D Studio).
.fpx
Formato que admite múltiples resoluciones de una imagen. Con o sin compresión y de 8 a 24 bits de profundidad de color Desarrollado por Kodak en conjunto con Hewlett Packard
.x
Los ficheros .X estan compues de plantillas, que pueden ser definidas por el usuario. Una plantilla es una "definicion de como quiere el usuario que se almacene la informacion".
Para animar un fichero .X necesitas especificar una serie de animaciones con referencia a las matrices frame correspondientes. Abajo aparece un ejemplo de nuestro cuadrado texturizado y animado.
Un ejemplo de estos formatos "optimizados" para juegos son los utilizados por Id Software para su Quake. Es posible que escriba un tutorial sobre este formato mas adellante, pero por el momento vamos a empezar con uno mas sencillo: el formato .X que es el que usa por defecto DirectX.

Existe una herramienta que viene con el SDK de DirectX8 para transformar los ficheros del 3dStudio a formato .X en C:\mssdk\bin\DXUtils\XFiles\conv3ds.exe

Estos ficheros .X van a contener la informacion acerca de nuestros modelos 3D (personajes, naves, etc...) e incluso de nuestro mundo 3D (pistas, ciudades, mapas, etc...)

Los puntos claves cuando trabajamos con estos ficheros son:

- De que manera estan almacenados los objetos.

- De que forma se relacionan entre ellos.
MODELO:

sábado, 19 de mayo de 2007

Previo Practica 9

Previo Practica No.9

1.- Investigue acerca de los métodos usuales de la animación

Keyframes (Cuadros Llave):
Se refiere a imágenes o dibujos los cuales define una parte esencial de inicio y fin entre puntos de transición. Estos son llamados “frames” porque su duración en el tiempo forman parte de una filmación. Una secuencia de keyframes define el movimiento que el espectador puede ver, algunas veces la posición de los keyframes en un film, video o animación define el tiempo del movimiento. Por que la duración de solamente 2 o 3 keyframes en un segundo no produce una ilusión de movimiento, la permanencia de los frames son fijados con más dibujos o imágenes, llamadas “inbetweens”.

Forward Kinematics (Cinemática Directa):

Es un método de la computación grafica en 3D para la animación de modelos. El concepto esencial de este concepto es que la posición de partes particulares de un modelo en un especifico tiempo son calculados desde la posición de orientación d el objeto, junto con la información en la unión de alguna articulación del modelo.

Inverse Kinematics (Cinemática Inversa):

Es un proceso utilizado en la animación de computación grafica en 3D, para calcular lo que requiere la articulación de una serie de extremidades o conjunturas, tal como al final de las extremidades hacia arriba en una localización particular.

Motion Capture (Captura de Movimientos):

Es una técnica de grabación digital de movimientos para entretenimiento o espectáculo, deportes y aplicaciones médicas. Utiliza varios sistemas de captura desde los ópticos, mecánicos, sistemas magnéticos, ya sea mediante de el uso de censores u otros dispositivos. Solo graba los movimientos no la apariencia, este método surgió como investigación militar.

2.- Discuta acerca de las ventajas y desventajas de cada método y de ejemplos al menos dos de situaciones en las que cada uno este mejor aplicado.

Keyframes (Cuadros Llave):

Ventajas:
Fácil de manejar
Útil para hacer videos rápidos.
Solo se necesitan figuras básicas.

Desventajas:
Ineficiente para una buena animación.
Para un trabajo grande se necesitan varias figuras base.

Aplicaciones:
Videos
Films
Comerciales
Presentaciones

Forward Kinematics (Cinemática Directa):
Ventajas:
Determina comportamientos.
Determina Posiciones.
Se planea cada movimiento.

Desventajas:
No define leyes físicas como la gravedad y colisiones.

Aplicaciones:
Robotica
Juegos de Computadora
Animación.

Inverse Kinematics (Cinemática Inversa):
Ventajas:
Se encarga de los requerimientos en las articulaciones.

Desventajas:
Limites antropomórficos
Limites en las articulaciones

Aplicaciones:
Robotica
Animación por Computadora.

Motion Capture (Captura de Movimientos):
Ventajas:
Más rápido, algunas veces da mejores resultados en tiempo real.
La cantidad de trabajo no varia con la complejidad o tamaño de la calidad o el mismo grado cuando se usan las técnicas tradicionales.
El movimiento complejo y las interacciones realistas físicas tal como una animación secundaria, peso e intercambio de fuerzas puedes ser más fáciles de crear con un modo preciso de chequeo.
La tecnología concede a un actor jugar múltiples roles con un solo film.
Desventajas:
Necesita hardware específico y programas especiales requeridos para obtener y procesar datos.
El costo del software y equipo, personal requerido pueden no ser viables para pequeñas producciones.
El sistema de captura tendría que tener requerimientos específicos para ser operados en ellos.
Cuando ocurren problemas estos pueden ser fáciles es mejor reseguir la escena que intentar manipular los datos. Solamente pocos sistemas alojan vista en tiempo real del dato para decidir si se toman cartas en el asunto o se tiene que volver a rehacer.
Ampliado movimiento para cuadruplicar caracteres puede ser difícil.
La tecnología puede llegar a ser obsoleta en pocos años así como el software y técnicas para desarrollo.
Los resultados son limitados para que pueda existir una alta calidad en la captura dependiendo del volumen y la edición extra de los datos.
El movimiento no puede seguir las leyes de la física generalmente no se pueden representar.
Las técnicas de animación tradicionales tal como el énfasis o la anticipación y seguimiento, movimientos secundarios o manipulación, son estrechos en la animación y generalmente no se aplican.
Si el modelo de computadora tiene diferentes proporciones desde la captura del objeto, esto pueden ocurrir.
La calidad real de vida no puede trasladarse el modelo en la computadora como uno esperaba.

Aplicaciones:
En videojuegos donde se captura movimientos, por ejemplo: fútbol, básquetbol o combates de artes marciales, en general deportes de acción.
Para captura de efectos CG, en algunos casos remplaza la celda de animación, y por completamente la generación de criaturas por computadora como Golum, La Momia y King Kong
Realidad Virtual para interacción en tiempo real. Asi como visualización.
Generación de Personajes en tiempo real.

3.- Investigue que método de animación usan los modelos de Quake y de Unreal Tournament. Busque código que utilizando OpenGL permita visualizar un modelo de estos juegos y ejecútelo.


Los modelos Quake utilizan la predicción de movimiento por lo tanto utilizan el método de Forward Kinematics.

Los modelos de Unreal Tournament tienen bases de inteligencia Artificial

lunes, 14 de mayo de 2007

Pseudocodigo Iluminacion por Raster

int v1x,v1y,v2x,v2y,v3x,v3y,v4x,v4y; //vertices

void ilumina(){

float *Ax,*Ay;

float *A'x,*A'y;

float *Bx,*By;

float *B'x,*B'y;

float *Cx,*Cy;

float *C'x,*C'y;
int ret;

if(ordena1==1){ //la funcion ordena devulve el vertice de mayor ordenada

B'x=bresenham1(*Ax,*Ay,*By,*Bx) //se utiliza el algoritmo de Bresenham
B'y=bresenham2(*Ax,*Ay,*By,*Bx)
color(r,g,b,B'x);
color(r,g,b,B'y);
C'x=bresenham1(*Ax,*Ay,*Cy,*Cx)
C'y=bresenham2(*Ax,*Ay,*Cy,*Cx)
color(r,g,b,C'x);
color(r,g,b,C'y);


}



if(ordena2==1){
B'x=bresenham1(*Ax,*Ay,*By,*Bx)
B'y=bresenham2(*Ax,*Ay,*By,*Bx)
color(r,g,b,B'x);
color(r,g,b,B'y);
C'x=bresenham1(*Ax,*Ay,*Cy,*Cx)
C'y=bresenham2(*Ax,*Ay,*Cy,*Cx)
color(r,g,b,C'x);
color(r,g,b,C'y);
}
if(ordena3==1){
B'x=bresenham1(*Ax,*Ay,*By,*Bx)
B'y=bresenham2(*Ax,*Ay,*By,*Bx)
color(r,g,b,B'x);
color(r,g,b,B'y);
C'x=bresenham1(*Ax,*Ay,*Cy,*Cx)
C'y=bresenham2(*Ax,*Ay,*Cy,*Cx)
color(r,g,b,C'x);
color(r,g,b,C'y);
}
if(ordena4==1){
B'x=bresenham1(*Ax,*Ay,*By,*Bx)
B'y=bresenham2(*Ax,*Ay,*By,*Bx)
color(r,g,b,B'x);
color(r,g,b,B'y);
C'x=bresenham1(*Ax,*Ay,*Cy,*Cx)
C'y=bresenham2(*Ax,*Ay,*Cy,*Cx)
color(r,g,b,C'x);
color(r,g,b,C'y);
}
while(By!=Cy){

if( B'y<=c'y&& c'y==cy){
A'y=cy
A'x=cx}


if( c'y<=B'y&& B'y==By){
Ay=By
Ax=Bx}


if(c'y=cy){
cy=V3Y
cx=v3X
}

if( B'y==By){
By=V3Y
Bx=v3X
}

}
B'x=bresenham1(*Ax,*Ay,*By,*Bx)
B'y=bresenham2(*Ax,*Ay,*By,*Bx)
color(r,g,b,B'x);
color(r,g,b,B'y);
C'x=bresenham1(*Ax,*Ay,*Cy,*Cx)
C'y=bresenham2(*Ax,*Ay,*Cy,*Cx)
color(r,g,b,C'x);
color(r,g,b,C'y);


}
}


int ordena1(){
if(v2y<=v1y>=v3y && v1y>=v4y){
Ay=A'y=v1y;
Ax=A'x=v1x;
if(v3y<=v2y>=v4y({
By=B'y=v2y;
Bx=B'x=v2x;

if(v3y<=v4y{
cy=c'y=v4y;
cx=c'x=v4x;
}else{

cy=c'y=v3y;
cx=c'x=v3x;
}
}
if(v2y<=v3y>=v4y){
By=B'y=v3y;
Bx=B'x=v3x;
if(v2y<=v4y{
cy=c'y=v4y;
cx=c'x=v4x;
}else{

cy=c'y=v2y;
cx=c'x=v2x;
}
}

}

if(v3y<=v4y>=v2y){
By=B'y=v4y;
Bx=B'x=v4x;
if(v3y<=v2y{
cy=c'y=v2y;
cx=c'x=v2x;
}else{

cy=c'y=v3y;
cx=c'x=v3x;
}
}
verif=1;
}

else
verif=0;
}


}

martes, 8 de mayo de 2007

Previo 8

1.- Investigue como crear y definir una fuente de luz en opengl creación de la luz:
CREACION DE FUENTES DE LUZ
Las propiedades de una fuente de luz son el color, posición y dirección. El comando usado para especificar todas las propiedades de una luz es glLight*(), tiene tres argumentos para identificar la luz que se está utilizando, la propiedad y el valor deseado para esapropiedad.
Después de definir las características de las luces, hay que encenderlas con el comando glEnable(). También hay que llamar a este comando con el parámetro GL_LIGHTING , de esta forma se preparar OpenGL para desarrollar los cálculos de Iluminación.

¿Cuantas luces se pueden definir?:
Podemos tener al menos ocho fuentes de luz en la escena (puede haber más, depende de la implementación de OpenGL. OpenGL necesita realizar cálculos para determinar cuanta luz recibe cada vértice de cada fuente de luz. El incremento del número de luces influye en una ejecución más lenta.

Parametrización de la fuente de luz

void glLight{if}[v] (GLenum light, GLenum pname, TYPE param )
Crea la luz especificada por light, la cual puede ser GL_LIGHT0, GL_LIGHT1,
…GL_LIGHT7. Las características de la luz quedan definidas por pname. El argumento
param indica los valores que establece la característica pname; si se utiliza la versión de
vector(v) pname es un puntero a un grupo de valores, o el propio valor si la versión sin vector es la que estamos usando(i,f).
Valores por defecto para el parámetro pname de glLLight*().
Tipos de luces
En OpenGL existen tres tipos fundamentales de luces:
Luces direccionales
Luces locales
Focos
Todos los tipos de luces permiten definir una componente ambiente, una difusa y una especular con componentes RGBA.
Definir las fuentes de luz (propiedades de cada una de las luces).
GLvoid glLightfv(GLenum light, GLenum pname, const GLfloat *params);
Light: la luz a la que se esté haciendo referencia (GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, etc.).
*params, es un array de valores RGBA, cada valor define el porcentaje de intensidad de cada color que tiene la luz.
Luces direccionales
Una luz direccional esta situada en el infinito
Definir el vector direccional
float difusa[3]={1.0,0.0,0.0};
float direccion[4]={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0, GL_POSITION, direccion};
glLightfv(GL_LIGHT0, GL_DIFFUSE,difusa);
Luces locales
Las luces locales se definen de la misma forma que las direccionales solo que el cuarto elemento del vector vale uno.
float difusa[3]={1.0,0.0,0.0};
float posicion[4]={1.0,1.0,1.0,1.0};
glLightfv(GL_LIGHT0, GL_POSITION, posición};
glLightfv(GL_LIGHT0, GL_DIFFUSE, difusa);
Focos de luz
El foco viene definido como: una luz local, una dirección o una apertura del foco.
float difusa[3]={1.0,0.0,0.0};
float posicion[4]={1.0,1.0,1.0,1.0};
float direccion[3]={1.0,1.0,1.0};
glLightfv(GL_LIGHT0, GL_POSITION, posicion};
glLightfv(GL_LIGHT0, GL_DIFFUSE, difusa);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direccion); //Dirección del foco
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 20); // ángulo de corte entre 0 y 180

Color de la luz
OpenGL permite asociar a cualquier luz tres parámetros relacionados con el color:
GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR. El parámetro GL_AMBIENT se refiere a la intensidad RGBA de la luz ambiente que una fuente de luz añade a la escena. El valor por defecto es que no hay luz ambiente. El parámetro GL_DIFFUSE es el que está más relacionado con el concepto que tenemos normalmente de “color de una luz”; se refiere a la intensidad RGBA de la luz difusa que una fuente de luz añade a la escena. El valor por defecto es (1.0, 1.0, 1.0, 1.0) para GL_LIGHT0 que produce una luz blanca brillante. El valor por defecto para GL_LIGHT1… GL_LIGHT7 es (0.0, 0.0, 0.0, 0.0). El parámetro GL_SPECULAR afecta a el color del brillo especular en un objeto. Un objeto como un vaso tiene una luz especular que es el color de la luz que está brillando en él, normalmente blanca. Si queremos crear un efecto realista, el parámetro GL_SPECULAR y GL_DIFFUSE se deben establecer al mismo valor.

Habilitación y desabilitación de luces
Para que las luces tengan efecto se debe activar el cálculo del modelo de iluminación utilizando las luces usando la llamada: glEnable(GL_LIGHTING) y para deshabilitarlo glDisable(GL_LIGHTING);
y activar cada una de las luces individuales que se quieran utilizar con
glEnable(GL_LIGHTn) y deshabilitarlas glDisable(GL_LIGHTn);

Luz por defaul y características por defaul
Es una luz ambiente básica la cual especificará como se realiza la iluminación de la escena en cuanto a si las luces afectan a las dos partes de un objeto el modelo de cálculo de la relación entre el observador y los objetos en el caso de componente especular.
Propiedades para definir del modelo básico de iluminación:
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambiente); //Valores de lacomponente ambiente base.
GlLightModelf(GL_LIGHT_MODEL_TWO_SIDE,TRUE); //las luces afectana ambas caras de un material.
GlLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, TRUE); //Coloca el modo de cálculo especular con el observador local, si no todos los cálculos se hace como si el observador estuviese situado sobre el eje Z.


2.- Investige la diferencia entre luz he iluminación(ligth/ligthing)

Habilitación y desabilitación de la iluminación (¿Cómo?)
Para la habilitación/deshabilitación de toda la iluminación dentro de una escena se utiliza:
glEnable(GL_LIGHTING);
glDisable(GL_LIGHTING);

Para que hay que habilitar o desabilitar la iluminación
Con OpenGL necesitas habilitar o deshabilitar explícitamente la iluminación. Si no
Está habilitada el color actual es mapeado al vértice pero los cálculos de normales, fuentes de luz, modelo de iluminación y propiedades de material no se producen.

3.- Investigue la definición de propiedades de material a una superficie
Ø El modelo de iluminación de OpenGL realiza una aproximación del color de un material en función de la luz que incide sobre él y la luz que es capaz de reflejar
Ø Por ejemplo una pelota perfectamente roja es aquel objeto cuyo material es capaz de absorber todas longitudes de onda excepto el rojo y es capaz de reflejar únicamente este color
Ø Los materiales tienen dos propiedades sobre sus colores, que indican cómo influye cada una de las propiedades de un rayo de luz sobre él
Ø Ambient
Ø Diffuse
Ø También tiene tres propiedades sobre la capacidad de emisión y reflexión de luz
Ø Specular
Ø Shininess
Ø Emission
Ø Ambient
Ø se casa con la propiedad Ambient de un rayo de luz e indica cómo se va a comportar el material en función de la componente Ambient del rayo de luz incidente
Ø se refiere al color por defecto del material
Ø Diffuse
Ø se casa con la propiedad Diffuse de un rayo de luz e indica cómo se va a comportar el material en función de la componente Diffuse del rayo de luz incidente
Ø se refiere a la luz que reflejará de forma difusa
Ø Estas dos propiedades determinan el color del material y suelen tener valores aproximados sino iguales
Ø Specular
Ø se casa con la propiedad Specular de un rayo de luz e indica cómo se va a comportar el material en función de la componente Specular del rayo de luz incidente
Ø La propiedad especular se suele definir blanca o gris, de forma que los reflejos del material se degradan desde el color base de la luz incidente hasta el color definido en esta propiedad
Ø Shininess
Ø Determina la concentración de los puntos que van a reflejar la luz
Ø Puede ser un único punto o toda la superficie del objeto

Ø Emission
l Esta propiedad define la capacidad de un objeto de simular la emisión de luz
l NO es una fuente de luz
l Se definen los colores de la luz que emite
l Sirve para simular estrellas, lámparas u otros objetos similares

Características de las superficies (difusa, especular, brillantez, emisividad, etc.)
Luz ambiente
La luz ambiental es aquella que no proviene de una dirección concreta, incide sobre todas las partes del objeto por igual.
Iambiente = ka Ia
ka coeficiente de reflexión ambiental [0,1] dependiente de cada objeto.
Ia intensidad ambiental en todo punto del espacio.

Luz difusa
• La fuente tiene una localización y una dirección particular
• Una vez toca la superficie del objeto, se refleja en todas direcciones
La luz difusa es la que proviene de una dirección particular y es reflejada en todas direcciones.
Afecta a aquellas partes del objeto en las que la luz incide.
La luz difusa es reflejada por la superficie de un objeto de manera adireccional.
I L : Intensidad de la fuente
q : Angulo de incidencia [0º..90º]
Kd: Coeficiente de reflexión difusa para cada objeto [0..1]
N: Normal a la superficie (unitario)
L: Vector de iluminación (unitario)
Luz especular
• También es direccional, pero el reflejo se produce en una dirección concreta
• Produce un punto brillante en la superficie que ilumina --> reflejo especular
La luz especular procede de una dirección concreta y se refleja en una única dirección.
Produce brillos intensos.
Las reflexiones especulares son normalmente del mismo color que la fuente de luz.
La intensidad de la luz especular reflejada depende de:
La longitud de onda de la luz incidente
El ángulo de la luz incidente
Las características del material
En un espejo perfecto la dirección desde la que se observa el reflejo es la dirección de reflexión perfecta R.
La reflexión especular depende de la posición del observador.
Dependiendo de la superficie (grado de pulido) el brillo es más o menos concentrado alrededor del punto donde R y V coinciden.
BRILLOS
Se basan en la componente especular de los materiales
Produce un blanqueamiento del material
Depende del punto de vista
Produce reflejos especulares
Para realizar brillos en un material, la luz debe contener una componente especular distinta de cero:
Espec[]= {1.0f, 1.0f, 1.0f, 1.0f};
glLigth(GL_LIGHT0, GL_SPECULAR, Espec);
El material sobre el que incida también deberá tener una componente especular distinta de cero:
Glfloat especular[] = {1.0f, 1.0f, 1.0f, 1.0f}; glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMaterialfv(GL_FRONT, GL_SPECULAR, especular);

La propiedad de brillo del material determina el tamaño de la superficie que va a reflejar el brillo
glMaterialf(GL_FRONT, GL_SPECULAR, mat_option);
glMateriali(GL_FRONT, GL_SHININESS, 128);

El valor de esta componente varía entre:
0 La superficie es un punto
128 Toda la superficie del objeto refleja
SOMBRAS
Ausencia de luz producida generalmente por la superposición de un cuerpo opaco entre una fuente de luz y otro cuerpo
En OpenGL las proyecciones sólo se realizan sobre objetos volumétricos
Tipos de Sombras:
Sombras Proyectadas
Sombras Volumétricas
Sombras proyectadas
Es la técnica más sencilla, y consiste en calcular una matriz de proyección sobre el plano sobre el que se quiere dibujar la sombra
Una vez calculada esta matriz, si se multiplica por la matriz del modelo, y se dibujan el resto de las figuras, éstas se estarán proyectando sobre ese plano

Sombras volumétricas
La técnica anterior es muy sencilla, pero solo sirve para dibujar esas sobras proyectadas sobre planos
Si se tiene una composición de figuras en las que unas proyectan sombras sobre otras, con la técnica anterior no se podrán representar
Para evitar esto se utiliza una matriz especial que calculará la influencia de la posición de un objeto sobre los restantes

NIEBLA
Efecto especial utilizado para difuminar una escena dando la impresión de que se halla realmente cubierta por una masa de niebla
En general consiste en difuminar el color de la escena, oscureciendo los objetos más lejanos llegando incluso a desaparecer, mientras que los objetos más cercanos aparecen más claros
El efecto niebla se puede aplicar de dos formas principalmente:
Basado en vértices
Basado en tablas

¿Como se define sobre que cara(s) de un polígono se aplican los materiales?
Se tiene la función
void glMaterial{if}{v} (GLenum face, GLenum pname, TYPE *param);
Donde:
Parámetros de glMaterial{fv}
Face: Indica la cara sobre la que se va a aplicar el material
GL_FRONT à Se aplica sobre las caras delanteras del objeto
GL_BACK à Se aplica sobre las caras internas del objeto
GL_FRONT_AND_BACK à Se aplica sobre todas las caras del objeto
Param: Indica la propiedad que se va a establecer de las ya explicadas 4.- Invetige acerca del mapeo de texturas en opengl

Carga-definición de bytmap

La carga se hace abriendo el archivo de el bitmap directamente y asignándolo a un apuntador para después pintarlo:
bool CTextura::CargarBMP(char *szNombreFichero)
{
FILE *hFichero;
AUX_RGBImageRec *Imagen;
bool bResultado=false;


if (szNombreFichero) // Comprobamos que el nombre de fichero sea correcto
{
hFichero=fopen(szNombreFichero,"r"); // Comprobamos si el fichero existe (Si podemos abrirlo)

if (hFichero) // ¿Existe el fichero?
{
fclose(hFichero); // Cerramos el handle
Crear(szNombreFichero);

Imagen=auxDIBImageLoad(szNombreFichero); // Cargamos el BMP
m_nAncho=Imagen->sizeX;
m_nAlto=Imagen->sizeY;

glTexImage2D(GL_TEXTURE_2D, 0, 3, m_nAncho, m_nAlto, 0, GL_RGB, GL_UNSIGNED_BYTE, Imagen->data);

bResultado=true;
}
}
delete Imagen->data;
delete Imagen;
return bResultado;
}

Transformación de la textura y Modos de aplicación de una textura (repeat,wrap,etc)

Se indica con la función:
El tamaño de una textura generalmente no es el mismo que el del polígono proyectado sobre el que se pega, existirán casos en que el tamaño de la textura será mayor que el del polígono proyectado y otros en que será menor.

Necesitamos especificar cómo se calculará el color final de los píxeles sobre el polígono proyectado, a partir de la imagen de textura. Por otro lado, quizás estemos interesados en que la textura se repita cada cierto intervalo de tiempo. Todo este comportamiento se fija a través de la función:

void glTexParameter{if}{v}(GLenum tipoTex, GLenum param, TYPE valor);

donde tipoTex puede ser GL_TEXTURE_1D o GL_TEXTURE_2D y param y valor pueden tomar los valores de las siguiente tabla:

Parámetro Valor
GL_TEXTURE_WRAP_S GL_CLAMP, GL_REPEAT
GL_TEXTURE_WRAP_T GL_CLAMP, GL_REPEAT
GL_TEXTURE_MAG_FILTER GL_NEAREST, GL_LINEAR
GL_TEXTURE_MIN_FILTER GL_NEAREST, GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_LINEAR
GL_TEXTURE_BORDER_COLOR cuatro valores en el intervalo [0...1]

Un ejemplo de su uso es el siguiente:
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

Mapeo de la textura en una superficie

Se inicializa la textura antes de indicar el tipo de la superficie por ejemplo:
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
La primera permite que las texturas se repitan en horizontal, y la segunda,
en vertical.
Con este cambio, podríamos mapear las texturas con coordenadas mayores
a 1, de manera que las texturas se repetirían, de esta manera:
glBindTexture(GL_TEXTURE_2D,texture_floor);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(0.0,6.0);
glVertex3f(-6.0,0.0,6.0);
glTexCoord2d(6.0,6.0);
glVertex3f(6.0,0.0,6.0);
glTexCoord2d(6.0,0.0);
glVertex3f(6.0,0.0,-6.0);
glEnd();

5.- Programa

Previo 8

Programa que crea 2 cubos, dos luces, utiliza textura y materiales

#include GL/glut.h
#include stdlib.h
#include stdio.h
#include math.h
#include "bitmap.h"
int Width;
int Height;
int bd,bi;
BITMAPINFO *BitmapInfo;
GLubyte *BitmapBits;
char *nomimage;
float xRot=0;
float yRot=0;

void init(void)
{
bd=0;
bi=0;
//glClearColor (0.0, 0.0, 1.0, 0.0);
glClear( GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
//glEnable(GL_DEPTH_TEST);
glShadeModel (GL_SMOOTH);


}
void carcatex(){
BitmapBits = LoadDIBitmap(nomimage, &BitmapInfo);
glTexImage2D(GL_TEXTURE_2D,0,3,BitmapInfo->bmiHeader.biWidth,BitmapInfo->bmiHeader.biHeight,0,GL_RGB,GL_UNSIGNED_BYTE,BitmapBits);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_BLEND);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 128,128,0,GL_RGB,GL_UNSIGNED_BYTE,BitmapBits);
}
void cmaterial (x,y){
float colorf[4]={0.0,0.4,0,1};
float colora[4]={0.2,.4,1,1};
float colord[4]={0.3,0,1,1};
float colori[4]={0.5,.0,0,1};
float colors[4]={0.5,.6,0,1};
float colorin[4]={0.0,.6,0,1};
glShadeModel(GL_SMOOTH);
glPushMatrix();
glRotatef(45,0,1,1);
glTranslatef(x,y,0);
/* Caras transversales */
nomimage="mountain.bmp"; //Nombre de la imagen
carcatex();
glMaterialfv(GL_FRONT, GL_DIFFUSE, colord );
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
/* Vertical hacia atras */
glTexCoord2f(0.0, 0.0);
glVertex3f( 1, 0, 0 );
glTexCoord2f(1.0, 0.0);
glVertex3f( 0, 0, 0 );
glTexCoord2f(1.0, 1.0);
glVertex3f( 0, 1, 0 );
glTexCoord2f(0.0, 1.0);
glVertex3f( 1, 1, 0 );
glEnd();
glMaterialfv(GL_FRONT,GL_SPECULAR, colori );
nomimage="mountain1.bmp";
carcatex();
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
/* Superior, horizontal */
glTexCoord2f(0.0, 0.0);
glVertex3f( 1, 1, 1 );
glTexCoord2f(1.0, 0.0);
glVertex3f( 0, 1, 1 );
glTexCoord2f(1.0, 1.0);
glVertex3f( 0, 1, 0 );
glTexCoord2f(0.0, 1.0);
glVertex3f( 1, 1, 0 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colorf );
nomimage="mountain2.bmp";
carcatex();
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
/*Vertical delantera*/
glTexCoord2f(0.0, 0.0);
glVertex3f( 1, 0, 1 );
glTexCoord2f(1.0, 0.0);
glVertex3f( 1, 0, 0 );
glTexCoord2f(1.0, 1.0);
glVertex3f( 1, 1, 0 );
glTexCoord2f(0.0, 1.0);
glVertex3f( 1, 1, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_EMISSION, colorin );
nomimage="mountain3.bmp";
carcatex();
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
/*Inferior */
glTexCoord2f(0.0, 0.0);
glVertex3f( 0, 0, 1 );
glTexCoord2f(1.0, 0.0);
glVertex3f( 0, 0, 0 );
glTexCoord2f(1.0, 1.0);
glVertex3f( 0, 1, 0 );
glTexCoord2f(0.0, 1.0);
glVertex3f( 0, 1, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colora );
/* Costados */
nomimage="mountain4.bmp";
carcatex();
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
glTexCoord2f(0.0, 0.0);
glVertex3f( 1, 0, 1 );
glTexCoord2f(1.0, 0.0);
glVertex3f( 1, 0, 0 );
glTexCoord2f(1.0, 1.0);
glVertex3f( 0, 0, 0 );
glTexCoord2f(0.0, 1.0);
glVertex3f( 0, 0, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT, colors );
nomimage="aide.bmp"; //fotografia
carcatex();
glEnable(GL_TEXTURE_2D);
glBegin( GL_QUADS );
glTexCoord2f(0.0f, 1.0f);
glVertex3f( 1, 0, 1 );
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 1, 1, 1 );
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 0, 1, 1 );
glTexCoord2f(0.0f, 0.0f);
glVertex3f( 0, 0, 1 );
glEnd();
glPopMatrix();
}
void cmaterial1 (x,y){
float colorf[4]={0.0,0.4,0,1};
float colora[4]={0.2,.4,1,1};
float colord[4]={0.3,0,1,1};
float colori[4]={0.5,.0,0,1};
float colors[4]={0.5,.6,0,1};
float colorin[4]={0.0,.6,0,1};
glShadeModel(GL_SMOOTH);
glPushMatrix();
glRotatef(45,0,1,1);
glTranslatef(x,y,0);
/* Caras transversales */
glBegin( GL_QUADS );
/* Vertical hacia atras */
glVertex3f( 1, 0, 0 );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 1, 0 );
glVertex3f( 1, 1, 0 );
glEnd();

glMaterialfv(GL_FRONT,GL_SPECULAR, colori );
glBegin( GL_QUADS );
/* Superior, horizontal */
glVertex3f( 1, 1, 1 );
glVertex3f( 0, 1, 1 );
glVertex3f( 0, 1, 0 );
glVertex3f( 1, 1, 0 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colorf );
glBegin( GL_QUADS );
/*Vertical delantera*/
glVertex3f( 1, 0, 1 );
glVertex3f( 1, 0, 0 );
glVertex3f( 1, 1, 0 );
glVertex3f( 1, 1, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_EMISSION, colorin );
glBegin( GL_QUADS );
/*Inferior */
glVertex3f( 0, 0, 1 );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 1, 0 );
glVertex3f( 0, 1, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colora );
/* Costados */
glBegin( GL_QUADS );
glVertex3f( 1, 0, 1 );
glVertex3f( 1, 0, 0 );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 0, 1 );
glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT, colors );
glBegin( GL_QUADS );
glVertex3f( 1, 0, 1 );
glVertex3f( 1, 1, 1 );
glVertex3f( 0, 1, 1 );
glVertex3f( 0, 0, 1 );
glEnd();
glPopMatrix();
}
void display(void)
{
GLfloat light_ambient[]={0.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_position[]={xRot, yRot, 1.0, 1.0};
GLfloat light1_ambient[]={0.0, 0.0, 0.0, 1.0};
GLfloat light1_diffuse[]={.5, .5, .5, .5};
GLfloat light1_specular[]={.1, .1, .1, .1};
GLfloat light1_position[]={1.0, 1.0, 10, 10.0};
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glLoadIdentity (); /* clear the matrix */
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable( GL_LIGHTING );
if(bi==1){
glDisable( GL_LIGHT0 );
glEnable( GL_LIGHT1 );}
if(bi==2){
glEnable( GL_LIGHT0 );
glDisable( GL_LIGHT1 );}
cmaterial(-1,1);
cmaterial1(-1,-1);
glFlush ();
}
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode (GL_MODELVIEW);
}
void onMouse(int button, int state, int x, int y)
{
int aux;
if ( (button == GLUT_LEFT_BUTTON) & (state == GLUT_DOWN) ) {
bi=1;
}
if ( (button == GLUT_RIGHT_BUTTON) & (state == GLUT_DOWN) ) {
bi=2;
}
display();
}
void keyboard(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
xRot-= 0.2f;
if(key == GLUT_KEY_DOWN)
xRot += 0.2f;
if(key == GLUT_KEY_LEFT)
yRot -= 0.2f;
if(key == GLUT_KEY_RIGHT)
yRot += 0.2f;
if(key > 1.0f)
xRot = 0.0f;
if(key < 0.0f)
xRot = 1.0f;
if(key > 1.0f)
yRot = 0.0f;
if(key < 0.0f)
yRot = 1.0f;
// Refresh the Window
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (300,230);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutMouseFunc(onMouse);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

LIBRERIA AUXILIAR PARA CARGAR LA TEXTURA BITMAP.C

#include "bitmap.h"
#include stdio.h
#include stdlib.h
#include errno.h

#ifdef WIN32
GLubyte * /* O - Bitmap data */
LoadDIBitmap(const char *filename, /* I - File to load */
BITMAPINFO **info) /* O - Bitmap information */
{
FILE *fp; /* Open file pointer */
GLubyte *bits; /* Bitmap pixel bits */
int bitsize; /* Size of bitmap */
int infosize; /* Size of header information */
BITMAPFILEHEADER header; /* File header */

/* Try opening the file; use "rb" mode to read this *binary* file. */
if ((fp = fopen(filename, "rb")) == NULL)
return (NULL);
/* Read the file header and any following bitmap information... */
if (fread(&header, sizeof(BITMAPFILEHEADER), 1, fp) < 1)
{
/* Couldn't read the file header - return NULL... */
fclose(fp);
return (NULL);
}
if (header.bfType != 'MB') /* Check for BM reversed... */
{
/* Not a bitmap file - return NULL... */
fclose(fp);
return (NULL);
}
infosize = header.bfOffBits - sizeof(BITMAPFILEHEADER);
if ((*info = (BITMAPINFO *)malloc(infosize)) == NULL)
{
/* Couldn't allocate memory for bitmap info - return NULL... */
fclose(fp);
return (NULL);
}
if (fread(*info, 1, infosize, fp) < infosize)
{
/* Couldn't read the bitmap header - return NULL... */
free(*info);
fclose(fp);
return (NULL);
}
/* Now that we have all the header info read in, allocate memory for *
* the bitmap and read *it* in... */
if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0)
bitsize = ((*info)->bmiHeader.biWidth *
(*info)->bmiHeader.biBitCount + 7) / 8 *
abs((*info)->bmiHeader.biHeight);
if ((bits = malloc(bitsize)) == NULL)
{
/* Couldn't allocate memory - return NULL! */
free(*info);
fclose(fp);
return (NULL);
}
if (fread(bits, 1, bitsize, fp) < bitsize)
{
/* Couldn't read bitmap - free memory and return NULL! */
free(*info);
free(bits);
fclose(fp);
return (NULL);
}
/* OK, everything went fine - return the allocated bitmap... */
fclose(fp);
return (bits);
}

/*
* 'SaveDIBitmap()' - Save a DIB/BMP file to disk.
*
* Returns 0 on success or -1 on failure...
*/
int /* O - 0 = success, -1 = failure */
SaveDIBitmap(const char *filename, /* I - File to load */
BITMAPINFO *info, /* I - Bitmap information */
GLubyte *bits) /* I - Bitmap data */
{
FILE *fp; /* Open file pointer */
int size, /* Size of file */
infosize, /* Size of bitmap info */
bitsize; /* Size of bitmap pixels */
BITMAPFILEHEADER header; /* File header */

/* Try opening the file; use "wb" mode to write this *binary* file. */
if ((fp = fopen(filename, "wb")) == NULL)
return (-1);
/* Figure out the bitmap size */
if (info->bmiHeader.biSizeImage == 0)
bitsize = (info->bmiHeader.biWidth *
info->bmiHeader.biBitCount + 7) / 8 *
abs(info->bmiHeader.biHeight);
else
bitsize = info->bmiHeader.biSizeImage;
/* Figure out the header size */
infosize = sizeof(BITMAPINFOHEADER);
switch (info->bmiHeader.biCompression)
{
case BI_BITFIELDS :
infosize += 12; /* Add 3 RGB doubleword masks */
if (info->bmiHeader.biClrUsed == 0)
break;
case BI_RGB :
if (info->bmiHeader.biBitCount > 8 &&
info->bmiHeader.biClrUsed == 0)
break;
case BI_RLE8 :
case BI_RLE4 :
if (info->bmiHeader.biClrUsed == 0)
infosize += (1 <<>bmiHeader.biBitCount) * 4;
else
infosize += info->bmiHeader.biClrUsed * 4;
break;
}
size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;
/* Write the file header, bitmap information, and bitmap pixel data... */
header.bfType = 'MB'; /* Non-portable... sigh */
header.bfSize = size;
header.bfReserved1 = 0;
header.bfReserved2 = 0;
header.bfOffBits = sizeof(BITMAPFILEHEADER) + infosize;
if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
{
/* Couldn't write the file header - return... */
fclose(fp);
return (-1);
}
if (fwrite(info, 1, infosize, fp) < infosize)
{
/* Couldn't write the bitmap header - return... */
fclose(fp);
return (-1);
}
if (fwrite(bits, 1, bitsize, fp) < bitsize)
{
/* Couldn't write the bitmap - return... */
fclose(fp);
return (-1);
}
/* OK, everything went fine - return... */
fclose(fp);
return (0);
}

#else /* !WIN32 */
/*
* Functions for reading and writing 16- and 32-bit little-endian integers.
*/
static unsigned short read_word(FILE *fp);
static unsigned int read_dword(FILE *fp);
static int read_long(FILE *fp);
static int write_word(FILE *fp, unsigned short w);
static int write_dword(FILE *fp, unsigned int dw);
static int write_long(FILE *fp, int l);

/*
* 'LoadDIBitmap()' - Load a DIB/BMP file from disk.
*
* Returns a pointer to the bitmap if successful, NULL otherwise...
*/
GLubyte * /* O - Bitmap data */
LoadDIBitmap(const char *filename, /* I - File to load */
BITMAPINFO **info) /* O - Bitmap information */
{
FILE *fp; /* Open file pointer */
GLubyte *bits; /* Bitmap pixel bits */
GLubyte *ptr; /* Pointer into bitmap */
GLubyte temp; /* Temporary variable to swap red and blue */
int x, y; /* X and Y position in image */
int length; /* Line length */
int bitsize; /* Size of bitmap */
int infosize; /* Size of header information */
BITMAPFILEHEADER header; /* File header */

/* Try opening the file; use "rb" mode to read this *binary* file. */
if ((fp = fopen(filename, "rb")) == NULL)
return (NULL);
/* Read the file header and any following bitmap information... */
header.bfType = read_word(fp);
header.bfSize = read_dword(fp);
header.bfReserved1 = read_word(fp);
header.bfReserved2 = read_word(fp);
header.bfOffBits = read_dword(fp);
if (header.bfType != BF_TYPE) /* Check for BM reversed... */
{
/* Not a bitmap file - return NULL... */
fclose(fp);
return (NULL);
}
infosize = header.bfOffBits - 18;
if ((*info = (BITMAPINFO *)malloc(sizeof(BITMAPINFO))) == NULL)
{
/* Couldn't allocate memory for bitmap info - return NULL... */
fclose(fp);
return (NULL);
}
(*info)->bmiHeader.biSize = read_dword(fp);
(*info)->bmiHeader.biWidth = read_long(fp);
(*info)->bmiHeader.biHeight = read_long(fp);
(*info)->bmiHeader.biPlanes = read_word(fp);
(*info)->bmiHeader.biBitCount = read_word(fp);
(*info)->bmiHeader.biCompression = read_dword(fp);
(*info)->bmiHeader.biSizeImage = read_dword(fp);
(*info)->bmiHeader.biXPelsPerMeter = read_long(fp);
(*info)->bmiHeader.biYPelsPerMeter = read_long(fp);
(*info)->bmiHeader.biClrUsed = read_dword(fp);
(*info)->bmiHeader.biClrImportant = read_dword(fp);
if (infosize > 40)
if (fread((*info)->bmiColors, infosize - 40, 1, fp) < 1)
{
/* Couldn't read the bitmap header - return NULL... */
free(*info);
fclose(fp);
return (NULL);
}
/* Now that we have all the header info read in, allocate memory for *
* the bitmap and read *it* in... */
if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0)
bitsize = ((*info)->bmiHeader.biWidth *
(*info)->bmiHeader.biBitCount + 7) / 8 *
abs((*info)->bmiHeader.biHeight);
if ((bits = malloc(bitsize)) == NULL)
{
/* Couldn't allocate memory - return NULL! */
free(*info);
fclose(fp);
return (NULL);
}
if (fread(bits, 1, bitsize, fp) < bitsize)
{
/* Couldn't read bitmap - free memory and return NULL! */
free(*info);
free(bits);
fclose(fp);
return (NULL);
}
/* Swap red and blue */
length = ((*info)->bmiHeader.biWidth * 3 + 3) & ~3;
for (y = 0; y < (*info)->bmiHeader.biHeight; y ++)
for (ptr = bits + y * length, x = (*info)->bmiHeader.biWidth;
x > 0;
x --, ptr += 3)
{
temp = ptr[0];
ptr[0] = ptr[2];
ptr[2] = temp;
}
/* OK, everything went fine - return the allocated bitmap... */
fclose(fp);
return (bits);
}

/*
* 'SaveDIBitmap()' - Save a DIB/BMP file to disk.
*
* Returns 0 on success or -1 on failure...
*/
int /* O - 0 = success, -1 = failure */
SaveDIBitmap(const char *filename, /* I - File to load */
BITMAPINFO *info, /* I - Bitmap information */
GLubyte *bits) /* I - Bitmap data */
{
FILE *fp; /* Open file pointer */
int size, /* Size of file */
infosize, /* Size of bitmap info */
bitsize; /* Size of bitmap pixels */

/* Try opening the file; use "wb" mode to write this *binary* file. */
if ((fp = fopen(filename, "wb")) == NULL)
return (-1);
/* Figure out the bitmap size */
if (info->bmiHeader.biSizeImage == 0)
bitsize = (info->bmiHeader.biWidth *
info->bmiHeader.biBitCount + 7) / 8 *
abs(info->bmiHeader.biHeight);
else
bitsize = info->bmiHeader.biSizeImage;
/* Figure out the header size */
infosize = sizeof(BITMAPINFOHEADER);
switch (info->bmiHeader.biCompression)
{
case BI_BITFIELDS :
infosize += 12; /* Add 3 RGB doubleword masks */
if (info->bmiHeader.biClrUsed == 0)
break;
case BI_RGB :
if (info->bmiHeader.biBitCount > 8 &&
info->bmiHeader.biClrUsed == 0)
break;
case BI_RLE8 :
case BI_RLE4 :
if (info->bmiHeader.biClrUsed == 0)
infosize += (1 <<>bmiHeader.biBitCount) * 4;
else
infosize += info->bmiHeader.biClrUsed * 4;
break;
}
size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;
/* Write the file header, bitmap information, and bitmap pixel data... */
write_word(fp, BF_TYPE); /* bfType */
write_dword(fp, size); /* bfSize */
write_word(fp, 0); /* bfReserved1 */
write_word(fp, 0); /* bfReserved2 */
write_dword(fp, 18 + infosize); /* bfOffBits */
write_dword(fp, info->bmiHeader.biSize);
write_long(fp, info->bmiHeader.biWidth);
write_long(fp, info->bmiHeader.biHeight);
write_word(fp, info->bmiHeader.biPlanes);
write_word(fp, info->bmiHeader.biBitCount);
write_dword(fp, info->bmiHeader.biCompression);
write_dword(fp, info->bmiHeader.biSizeImage);
write_long(fp, info->bmiHeader.biXPelsPerMeter);
write_long(fp, info->bmiHeader.biYPelsPerMeter);
write_dword(fp, info->bmiHeader.biClrUsed);
write_dword(fp, info->bmiHeader.biClrImportant);
if (infosize > 40)
if (fwrite(info->bmiColors, infosize - 40, 1, fp) < 1)
{
/* Couldn't write the bitmap header - return... */
fclose(fp);
return (-1);
}
if (fwrite(bits, 1, bitsize, fp) < bitsize)
{
/* Couldn't write the bitmap - return... */
fclose(fp);
return (-1);
}
/* OK, everything went fine - return... */
fclose(fp);
return (0);
}

/*
* 'read_word()' - Read a 16-bit unsigned integer.
*/
static unsigned short /* O - 16-bit unsigned integer */
read_word(FILE *fp) /* I - File to read from */
{
unsigned char b0, b1; /* Bytes from file */
b0 = getc(fp);
b1 = getc(fp);
return ((b1 << 8) b0);
}

/*
* 'read_dword()' - Read a 32-bit unsigned integer.
*/
static unsigned int /* O - 32-bit unsigned integer */
read_dword(FILE *fp) /* I - File to read from */
{
unsigned char b0, b1, b2, b3; /* Bytes from file */
b0 = getc(fp);
b1 = getc(fp);
b2 = getc(fp);
b3 = getc(fp);
return ((((((b3 << 8) b2) << 8) b1) << 8) b0);
}

/*
* 'read_long()' - Read a 32-bit signed integer.
*/
static int /* O - 32-bit signed integer */
read_long(FILE *fp) /* I - File to read from */
{
unsigned char b0, b1, b2, b3; /* Bytes from file */
b0 = getc(fp);
b1 = getc(fp);
b2 = getc(fp);
b3 = getc(fp);
return ((int)(((((b3 << 8) b2) << 8) b1) << 8) b0);
}

/*
* 'write_word()' - Write a 16-bit unsigned integer.
*/
static int /* O - 0 on success, -1 on error */
write_word(FILE *fp, /* I - File to write to */
unsigned short w) /* I - Integer to write */
{
putc(w, fp);
return (putc(w >> 8, fp));
}

/*
* 'write_dword()' - Write a 32-bit unsigned integer.
*/
static int /* O - 0 on success, -1 on error */
write_dword(FILE *fp, /* I - File to write to */
unsigned int dw) /* I - Integer to write */
{
putc(dw, fp);
putc(dw >> 8, fp);
putc(dw >> 16, fp);
return (putc(dw >> 24, fp));
}

/*
* 'write_long()' - Write a 32-bit signed integer.
*/
static int /* O - 0 on success, -1 on error */
write_long(FILE *fp, /* I - File to write to */
int l) /* I - Integer to write */
{
putc(l, fp);
putc(l >> 8, fp);
putc(l >> 16, fp);
return (putc(l >> 24, fp));
}
#endif /* WIN32 */

LIBRERIA AUXILIAR BITMAP.H
#ifndef _BITMAP_H_
# define _BITMAP_H_
/*
* Include necessary headers.
*/
# include
# ifdef WIN32
# include
# include
# endif /* WIN32 */
/*
* Make this header file work with C and C++ source code...
*/
# ifdef __cplusplus
extern "C" {
# endif /* __cplusplus */

/*
* Bitmap file data structures (these are defined in under
* Windows...)
*
* Note that most Windows compilers will pack the following structures, so
* when reading them under MacOS or UNIX we need to read individual fields
* to avoid differences in alignment...
*/
# ifndef WIN32
typedef struct /**** BMP file header structure ****/
{
unsigned short bfType; /* Magic number for file */
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
# define BF_TYPE 0x4D42 /* "MB" */
typedef struct /**** BMP file info structure ****/
{
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER;
/*
* Constants for the biCompression field...
*/
# define BI_RGB 0 /* No compression - straight BGR data */
# define BI_RLE8 1 /* 8-bit run-length compression */
# define BI_RLE4 2 /* 4-bit run-length compression */
# define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */
typedef struct /**** Colormap entry structure ****/
{
unsigned char rgbBlue; /* Blue value */
unsigned char rgbGreen; /* Green value */
unsigned char rgbRed; /* Red value */
unsigned char rgbReserved; /* Reserved */
} RGBQUAD;
typedef struct /**** Bitmap information structure ****/
{
BITMAPINFOHEADER bmiHeader; /* Image header */
RGBQUAD bmiColors[256]; /* Image colormap */
} BITMAPINFO;
# endif /* !WIN32 */
/*
* Prototypes...
*/
extern GLubyte *LoadDIBitmap(const char *filename, BITMAPINFO **info);
extern int SaveDIBitmap(const char *filename, BITMAPINFO *info,
GLubyte *bits);
# ifdef __cplusplus
}
# endif /* __cplusplus */
#endif /* !_BITMAP_H_ */

Nota: Para observar el texturizado es necesario tener las imagenes