Aula Macedonia


Curso de Programación Multimedia Bajo DOS


Artículo realizado por
José Antonio Suárez.





Capítulo 5.
Programación de tarjetas de vídeo (III).

2.1.9.- Efectos de Paleta


Como antes referenciamos, la tarjeta de vídeo mantiene un registro con 256 celdillas que conforman el DAC de vídeo. En cada una de esas celdas se guarda el valor de un color determinado por la intensidad de sus tres componentes primarias: rojo, azul y verde.

Cada uno de esos valores RGB (Red-Green-Blue) se encuentra en un rango de 0 a 63. De esta forma, el color de un rojo brillante podrá ser obtenido estableciendo el valor R a 63, el valor G a 0 y el valor B a 0. Esto permite que dos colores puedan ser exactamente el mismo, pero almacenados en distintas posiciones.

Resumanos lo que sabemos hasta ahora sobre la paleta:

Ahora hay que saber cómo se pueden acceder a esas celdas y qué se puede hacer con la paleta para conseguir algún efecto que merezca la pena.

Para leer un valor de la paleta, el medio que nos ofrece la tarjeta de vídeo es el puerto.

Si escribimos en el puerto 3C7h el número (0-255) del color, al leer el valor del puerto 3C9h obtendremos el valor de la componente R, si volvemos a leer de ese mismo puerto obtendremos el valor de G, y por último, el de B. La tarjeta de vídeo se encarga del resto.

El procedimiento que lo implementa es:

void Leer1ColorPaleta(BYTE color,BYTE *rojo,BYTE *verde, BYTE *azul)
{
    BYTE char rrojo,vverde,aazul;
    asm{
            mov dx,0x3c7
            mov al,color
            out dx,al
            mov dx,0x3c9
            in al,dx
            mov rrojo,al
            in al,dx
            mov vverde,al
            in al,dx
            mov aazul,al
    }
    *rojo=rrojo; *verde=vverde; *azul=aazul;
}

Por el contrario, si lo que queremos es establecer los valores de un color de la paleta, escribimos en el puerto 3C8h el número del color, y en el puerto 3C9h vamos escribiendo sucesivamente los tres valores de R, G y B. De esto se encarga:

void Establecer1ColorPaleta(BYTE color,BYTE rojo,BYTE verde, BYTE azul)
{
    asm{
            mov al,color
            mov dx,0x3c8
            out dx,al
            mov al,rojo
            mov dx,0x3c9
            out dx,al
            mov al,verde
            mov dx,0x3c9
            out dx,al
            mov al,azul
            mov dx,0x3c9
            out dx,al
    }
}
 

Apagar la Paleta: Fade Out

Es un efecto bastante vistoso y elegante que se puede observar continuamente en cualquier medio audiovisual, ya sea ordenador o televisión. Consiste en hacer ver que "se va la luz" cuando tenemos algo en pantalla. Es decir, da la apariencia de que la luz se va apagando poco a poco hasta ver solamente una pantalla completamente negra.

Para este fin está el procedimiento:

void ApagarPaleta(PALETA paleta,BYTE retardo)
{
    asm{
            push ds
            xor cx,cx
            mov ah,retardo
    }
    SIGUE_APAGANDO:
    asm{
            mov dx,0x3C8
            xor al,al
            out dx,al
            mov dx,0x3DA
    }
    ESPERA_FIN_RETR:
    asm{
            in al,dx
            and al,0x8
            jnz ESPERA_FIN_RETR
    }
    ESPERA_INI_RETR:
    asm{
            in al,dx
            and al,0x8
            jz ESPERA_INI_RETR
            dec ah
            jnz ESPERA_FIN_RETR
            mov ah,retardo
            mov dx,0x3c9
            lds SI,paleta
    }
    OTRO_DAC:
    asm{
            mov al,[si]
            sub al,ch
            jge DEC_ROJO
            xor al,al
    }
    DEC_ROJO:
    asm{
            out dx,al
            mov al,[si+1]
            sub al,ch
            jge DEC_VERDE
            xor al,al
    }
    DEC_VERDE:
    asm{
            out dx,al
            mov al,[si+2]
            sub al,ch
            jge DEC_AZUL
            xor al,al
    }
    DEC_AZUL:
    asm{
            out dx,al
            add si,3
            inc cl
            jnz OTRO_DAC
            inc ch
            cmp ch,00111111b
            jl SIGUE_APAGANDO
            pop ds
    }
}

Este procedimiento necesita ser comentado por su especial concepción.

Como se puede ver, dentro del código aparece la rutina presentada anteriormente como EsperarBarrido. El motivo de que el código vuelva a estar aquí de nuevo en lugar de lo aconsejable, que es hacer una llamada a la función, es por motivos de velocidad.

Cuando el C llama a una función (y cualquier otro lenguaje), el compilador realiza un cambio de contexto, es decir, guarda todos los valores actuales y luego realiza la llamada al nuevo procedimiento. Cuando éste termina, se restauran los valores y se continúa con la ejecución. Pero esto tiene una desventaja crucial para el objetivo que nos marcamos, que es el tiempo perdido en ese cambio de contexto. Por lo que si se incluye aquí el código de nuevo, al no ser excesivamente largo, conviene hacerlo en lugar de la llamada aconsejable.

El tener que "sincronizar" este procedimiento con el refresco de la pantalla es para evitar la aparición de la "nieve" por los desajustes entre actualización de memoria y refresco de la pantalla anteriormente comentados.

ApagarPaleta necesita que se le suministren dos valores, una estructura que guarde los valores de la paleta y un valor que indique cómo de lento se va "apagar" esa paleta.

El valor mínimo es 1, con lo que sólo se "esperará" a un barrido de pantalla. El máximo viene dado por el tipo de la variable, (64 por ser de tipo char, pero extendido a 255 por incluir el especificador unsigned). Un valor aconsejable para transiciones rápidas es 1, y para las lentas, 3 ó 4. A partir de 5 comienza a perder fluidez el efecto.

El significado de "apagar la paleta" consiste en que vamos decrementando los valores RGB de cada celda del DAC mientras no valgan todos 0. Con esto, poco a poco (aunque rápidamente efectuado), se van oscureciendo los colores con lo que la apariencia de que se apaga la imagen se consigue.

Encender la Paleta: Fade In

El efecto contrario se consigue con este procedimiento:

void EncenderPaleta(PALETA ,BYTE);

Este procedimiento hace lo contrario que ApagarPaleta. En EncendarPaleta partimos de la paleta determinada con todos los componentes RGB, de todos los colores, a 0. Paulatinamente vamos incrementando los valores del DAC hasta hacerlos coincidir con los valores de la paleta que le hemos pasado como variable. También se sincroniza con el barrido de la pantalla y se dispone de una variable para determinar la velocidad con que ejecutar el procedimiento.

Aparte de estos efectos, se encuentran otros como convertir toda paleta (con lo que también se convierte la pantalla que se esté viendo en ese momento) a una tonalidad determinada, como por ejemplo tonos grises (parecerá que la imagen está en blanco y negro), o azules, rojos, verdes...




AULA MACEDONIA
a
MACEDONIA Magazine