Una vez visto lo que queremos hacer, pasaremos directamente a comentar cómo se puede implementar un algoritmo que haga ésto. Nuestro algoritmo sólo necesita una imagen del mismo tamaño de la pantalla y la posición (Xl,Yl) de la "fuente" de luz en la pantalla (como en el efecto de bumping). La rutina dibujará líneas desde este punto de la pantalla hasta los bordes, cubriéndola totalmente, y mientras dibuja realizará el proceso comentado en la parte superior. Así, nos podemos olvidar de planos, cámaras, etc. Tan sólo hace falta coger una rutina de dibujar líneas (cualquiera servirá, mientras cumpla unas condiciones que comentaremos más adelante) y modificar la parte en la que se escribe el color en la pantalla, que quedará de forma parecida a esto:
if (dibujo[pos]!=0)
{
acumulado=acumulado+luz_detras*factor;
pantalla[pos]=luz_detrás+acumulado;
}
else pantalla[pos]=acumulado;
Se trata de un pseudo-código. Expresa lo que tiene que hacer la rutina a grandes trazos, sin entrar en pequeños detalles. En el programa de ejemplo está totalmente desarrollado.
En este caso, sólo se cuenta que la abertura deja pasar luz (diferente de 0 en ese punto) u obstruye totalmente el paso de luz (igual a 0). En cuanto al algoritmo de dibujar líneas, como ya hemos dicho, deberá cumplir ciertas condiciones:
- Debe tener en cuenta el sentido. Las líneas se tienen que dibujar desde la posición de la luz hasta los bordes de la pantalla, no en sentido contrario.
- Si se quiere que la fuente de luz salga fuera de la pantalla, la rutina de dibujar líneas deberá ser capaz de "cortar" la parte que queda fuera. A esto se le llama hacer "clipping".
- Cuanto más rápida sea la rutina de dibujar líneas, mejor. Pero tampoco se puede perder precisión, ya que entonces podrían quedar "huecos" entre las líneas que afean el resultado final.
Así tendremos una rutina de dibujar líneas:
void linea(int Xi,int Yi,int Xf,int Yf,unsigned char *pantalla)
{
acumulado=0;
// inicializa las demas variables
for (pos=inicial; pos< final; incrementa_pos)
if (dibujo[pos]!=0)
{
acumulado=acumulado+luz_detras*factor;
pantalla[pos]=luz_detrás+acumulado;
}
else pantalla[pos]=acumulado;
}
donde (Xi,Yi) es el punto de inicio de la línea y (Xf,Yf) el final. Y, además, necesitaremos una rutina que se encarga de trazar líneas desde un punto de la pantalla (Xluz,Yluz) hasta los bordes:
void Efecto (unsigned char *dibujo,int Xluz,int Yluz)
{
for (xp=0;xp<320;xp++)
{
linea (Xluz,Yluz,xp,0,dibujo);
linea (Xluz,Yluz,xp,199,dibujo);
}
for (yp=0;yp<200;xp++)
{
linea (Xluz,Yluz,0,yp,dibujo);
linea (Xluz,Yluz,319,yp,dibujo);
}
}
A PARTIR DE LA BASE QUE
EXPLICAMOS AQUÍ ES POSIBLE CREAR GRAN VARIEDAD DE EFECTOS
DERIVADOS. ¡LA IMAGINACIÓN AL PODER!
|
 | El programa de ejemplo |
En el programa de ejemplo de este efecto, éste está implementado en 24 Bits, es decir, que se considera cada canal de color (R,G,B) independientemente. La rutina de dibujar líneas está basada en el algoritmo de Bresenham, que se caracteriza por ser rápido y preciso. Este algoritmo es bastante conocido (uno de los más comentados en libros dedicados a los gráficos por ordenador) y fue analizado hace ya bastante tiempo en esta sección.
Otro punto interesante del programa de ejemplo es el cargador de ficheros TGA que se ha incluido. Se ha utilizado el formato gráfico TGA (sin comprimir), ya que es lo más simple para guardar imágenes de 24 Bits, como se puede ver en la Figura 6. Después de una pequeña cabecera de 18 bytes con información sobre el tamaño de la imagen, se encuentra la imagen sin comprimir, en el mismo formato que se utiliza para escribir en la pantalla. El único inconveniente es que las imágenes se encuentran invertidas, pero esto ya se encarga de arreglarlo la rutina que utilizamos.
La única pega que tiene este formato es que, al no estar la imagen comprimida como en el formato PCX, los ficheros pueden llegar a ocupar bastante.
EN EL PROGRAMA DE EJEMPLO
SE HA UTILIZADO EL ALGORITMO DE BRESENHAM PARA DIBUJAR LAS LÍNEAS,
POR SER RÁPIDO Y PRECISO
|