Tutorial básico sobre gráficos en Pascal
Escrito por Nicolás Rozas Salgado
Objetivo:
El objetivo de este tutorial es ofrecer una introducción al mundo
de la programación bajo gráficos para los usuarios de Turbo y
Borland Pascal. Este tutorial no abarca todos los aspectos de la
programacion con gráficos, sino que muestra en forma básica una introducción
de este mundo a las personas que no poseen los conocimientos suficientes sobre este
tema.
Desarrollo:
A través de este tutorial se explicará la utilización del modo
gráfico para ser utilizado en aplicaciones DOS, y donde se tocarán
diversos temas relacionados con la tarjeta gráfica. Para poder
entender mejor esta introducción abarcaremos los puntos mas
sencillos.
Hoy en día existen muchas tarjetas de video, muchas de las cuales
pueden exhibir gráficos de hasta 16 millones de colores y a estas
tarjetas las denominamos SVGA (Super VGA), pero estas tarjetas son
descendientes de otras mas primarias: La VGA. VGA son siglas de
Video Graphics Adaptor (Adaptador de gráficos de video), estas tarjetas
tenían hasta 256 kb de memoria y hasta 256 colores, con el tiempo
salieron las SVGA que basadas en las VGA ampliaron mucho más las
posibilidades que existían en ese momento.
Las VGA en realidad hoy no son muy útiles comparados a las exigencias
actuales, pero poder comprender su funcionamiento nos llevará a una
mejor comprensión posterior cuando utilicemos una SVGA (Vuelvo
a mencionarlo, la SVGA está basada en el modelo VGA y guarda muchas
de sus características).
Cuando nació la tarjeta VGA se desarrolló tambien un
estándar para poder utilizarlas, es decir que cada fabricante de
tarjetas VGA debía seguir una norma específica. Entre esas normas
están los modos gráficos de 16 y 256 colores, pero en este tutorial
hablaremos de un modo gráfico en especial: El modo de 320x200 y
256 colores, ya que este es el más facil de comprender, es rápido
y será la mejor opción por si deseamos ampliar nuestros conocimientos
después para comprender el funcionamiento de las tarjetas con resoluciones
y cantidades de colores más grandes.
Este modo (Que se le dice 320x200x256 o tambien se le suele decir "El
modo 13h") se ha convertido en un modo gráfico muy utilizado por
los programadores de juegos ya que podía ser utilizado en cualquier
VGA, era el único existente con 256 colores, utilizarlo era muy sencillo
y era un modo gráfico muy bueno (Era mejor usar el de 256 colores
que el de 16 colores).
Ahora... ¿Cómo accedemos a este modo gráfico? O ¿Como lo activamos?
Utiliza la siguiente rutina:
Procedure IniciarGraficos; Assembler;
Asm
Mov Ax,13h {Especifica que utilizaremos el modo 320x200 pixeles, 256 colores}
Int 10h {Le enviamos esta orden a la tarjeta de video}
End;
Aqui se ve por que se le dice "Modo 13h". 13h es un número expresado
en forma hexadecimal.
NOTA: Siempre ten cuidado cuando utilizas interrupciones
(La instrucción INT) ya que si la usas mal puedes causar que por
ejemplo la tarjeta de video no funcione adecuadamente e incluso
podría pasarte que se dañe el monitor, siempre verifica y lee
cuidadosamente antes de probar y experimentar con interrupciones.
Si queremos volver al modo texto utilizamos esta rutina:
Procedure TerminarGraficos; Assembler;
Asm
Mov Ax,3 {Especifica que utilizaremos el modo 80x25 caracteres, 16 colores, solo texto}
Int 10h {Le enviamos esta orden a la tarjeta de video}
End;
Verás que es igual que el primero pero con la diferencia que en vez de
especificar 13h especificamos el 3. Con esto distinguimos que el valor
"3" es para iniciar el modo texto y el 13h para los gráficos.
Volvamos con el modo 13h. Una vez que lo tenemos activado
nos aparecerá una pantalla oscura. Pues bien... ¿Cómo la utilizamos?
Bueno, dejamos aclarado en primer lugar que cuando trabajamos con
gráficos tendremos que utilizar pixeles ¿Y qué es un pixel? Un pixel
es un pequeño punto en la pantalla, para formar una imagen
en la pantalla necesitaremos utilizar un grupo de pixeles, y esta
es la forma como se crean las imágenes. Cuando
trabajamos con gráficos especificamos los detalles del modo de acuerdo
al ancho y alto de pixeles que pueden ser escritos y vistos, por
ejemplo decir 320x200 significa 320 pixeles de ancho y 200 de alto,
640x480 significa 640 pixeles de ancho y 480 de alto, después
están 800x600, 1024x768 y así sucesivamente. Volviendo al modo
320x200 de 256 colores, una vez que está activado podemos escribir
los pixeles y eso formará una imagen en pantalla. Pues bien... ¿Como
escribir un pixel? Cuando iniciamos el modo gráficos la tarjeta
de video utiliza 64 Kb de memoria RAM en la cual los datos que sean
escritos en ella serán mostrados inmediatamente en pantalla. Esta
area de memoria que utiliza la tarjeta de video es siempre la región
"A000:0" ¿Y como accedemos a esa area de memoria? En Pascal tenemos
una instrucción para leer y escribir a memoria y se llama MEM.
Por ejemplo, si queremos escribir el valor 255 a la dirección A000:0
especificamos esta instrucción:
MEM[$A000:0]:= 255; {Asigna el valor 255 a la region A000:0}
Nota: Observa que puse $A000. Cuando utilizas el simbolo $ en un
programa en Pascal significa que el valor que estás utilizando
está en formato hexadecimal, de hecho el valor A000 es una anotación
hexadecimal (En realidad es mejor haber hablado de A000h en un principio,
pero cuando se mencionan areas de memoria siempre se utilizan
anotaciones hexadecimales (Por ejemplo si te dicen que escribas en el
área 1234:5678 deberás usar mem[$1234:$5678] porque se están refiriendo
a valores en hexadecimal y no en decimal). Fíjate también que
estamos refiriéndonos a valores hexadecimales poniendo un símbolo
$ o también escribiendo una "h" al final del valor, cuando trabajas
en lenguaje Assembler bajo Pascal puedes utilizar las dos
formas, pero cuando trabajas con instrucciones en formato Pascal
(Por ejemplo, MEM) solo puedes utilizar el símbolo $.
Volvamos a este punto:
MEM[$A000:0]:= 255;
$A000 es la region de memoria, y lo que sigue a ":" es la posición
desde esa región especificada, con esto pasado a lenguaje coloquial
significa: "A la posición 0 del area de memoria $A000 le asigno el
valor 255". Si esta instrucción se ejecuta cuando el modo gráfico está activado
te aparecerá un pequeño punto blanco en el extremo superior
izquierdo de la pantalla. Con esa instrucción escribes un pixel.
Bueno... ¿Y cómo hago para escribir un pixel en un punto específico
de la pantalla? Si bien en la pantalla podemos ver que se puede
trabajar en formato (X,Y) la memoria no funciona así, sino que
trabaja con valores absolutos de posición. ¿Que significa todo esto?
Cuando activas el modo gráfico, en la region de memoria A000
puedes utilizar 64000 posiciones, cada una de esas posiciones
equivale a un punto en la pantalla. La posición 0 es para la
coordenada 0x, 0y, la posición 1 es para 1x, 0y,
la posición 2 es para la coordenada 2x, 0y, la posición 3 es para 3x,
0y, y asi sucesivamente. La posición 320 es para 0x,1y,
la posición 321 es para 1x, 1y, la posición 322 es para la coordenada
2x, 1y, y asi podriamos llegar a la ultima posición que es la
63999 que corresponde a 319x y 199y. ¿Y como convertir direcciones
puestas en formato (X,Y) a direcciones absolutas? Utiliza esta fórmula:
(Y*320)+X
Con esto podemos definir un procedimiento que nos escriba un pixel
en pantalla de acuerdo a la coordenada que le especifiquemos:
Procedure PutPixel(X,Y: Word; Valor: Byte);
Begin
Mem[$A000:(Y*320)+X]:= Valor;
End;
Como verás este procedimiento escribe un valor en una posición (X,Y)
que nosotros le indiquemos, por ejemplo:
PutPixel(150,165,200);
Escribe en la posición 150, 165 (150x, 165y) el valor 200.
¿Y que es ese valor que nosotros tenemos que especificar?. Este
valor es el pixel. Si especificas el valor 255, el pixel será de color
blanco, si especificas el valor 0 será un pixel negro, si especificas
el valor 1 será azul, el 2 será verde y así sucesivamente.
A continuación hay un programa de ejemplo que muestra todo lo visto hasta ahora:
Inicia el modo gráfico, muestra un rectángulo azul, después uno verde,
después uno rojo, después uno con un espectro de colores, y finalmente
vuelve al modo texto y sale.
Uses Crt;
Procedure IniciarGraficos; Assembler;
Asm
Mov Ax,13h {Especifica que utilizaremos el modo 320x200 pixeles, 256 colores}
Int 10h {Le enviamos esta orden a la tarjeta de video}
End;
Procedure TerminarGraficos; Assembler;
Asm
Mov Ax,3 {Especifica que utilizaremos el modo 80x25 caracteres, 16 colores, solo texto}
Int 10h {Le enviamos esta orden a la tarjeta de video}
End;
Procedure PutPixel(X,Y: Word; Valor: Byte);
Begin
Mem[$A000:(Y*320)+X]:= Valor;
End;
Var X,Y: Word;
Begin
IniciarGraficos;
For Y:= 0 to 150 Do
For X:= 0 to 255 Do
PutPixel(X,Y,1);
ReadKey;
For Y:= 0 to 150 Do
For X:= 0 to 255 Do
PutPixel(X,Y,2);
ReadKey;
For Y:= 0 to 150 Do
For X:= 0 to 255 Do
PutPixel(X,Y,4);
ReadKey;
For Y:= 0 to 150 Do
For X:= 0 to 255 Do
PutPixel(X,Y,X);
ReadKey;
TerminarGraficos;
End.
También es posible modificar los colores que existen, por ejemplo, se puede hacer que el blanco
sea un poco más grisaceo, un azul o un rojo más oscuro, etc. Y esto se puede hacer a través
de la paleta de colores. Así como un pintor utiliza colores y los mezcla para formar
gran variedad de tonalidades, tambien es posible para una aplicación en Pascal
trabajar de la misma forma a través de la Paleta de Colores. Y así como un pintor
utiliza colores primarios para crear otros colores, las aplicaciones deben hacer lo mismo
para lograr una tonalidad de color específica.
La tarjeta de video trabaja con tres colores básicos: Rojo, verde y azul. Con solo estos
tres colores se hace posible crear cualquier combinacion de colores, en el caso de las tarjetas
de video estas permiten 64 tonalidades distintas de rojo, 64 para el verde y 64 para el azul,
con esto se puede llegar a la idea que a través de las paletas se pueden lograr hasta
262144 combinaciones distintas de colores (64 * 64 * 64).
¿Cómo especifico una paleta de colores?
Como dijimos, las tarjetas de video aceptan hasta 64 tonalidades distintas para cada color
básico. Estas tonalidades se aplican sobre un valor de pixel en particular. Por ejemplo, se puede
modificar los valores de rojo, verde y azul del pixel con valor 15. Cuando utilizamos el valor
15 aparece un pixel blanco, pero por ejemplo podemos modificar ese blanco para que resulte
un poco mas grisáceo.
Pues bien, hay varias formas de especificar los valores de rojo, verde y azul para un pixel
en particular, y de esas formas utilizaremos la que es más rapida para la tarjeta de video:
Comunicándonos directamente con ella.
Según las normas de VGA para establecer una paleta de colores en forma directa
debemos seguir estos pasos:
1- Escribir en el puerto $3C8 1 byte con el valor del color a modificar
2- Escribir en $3C9 1 byte con la cantidad de rojo
3- Escribir en $3C9 1 byte con la cantidad de verde
4- Escribir en $3C9 1 byte con la cantidad de azul
Pasado a Pascal este procedimiento quedaría así:
Procedure ModificarPaleta(Color,Rojo,Verde,Azul:Byte);
Begin
Port[$3c8]:= Color;
Port[$3c9]:= Rojo;
Port[$3c9]:= Verde;
Port[$3c9]:= Azul;
End;
Veamos ejemplos acerca de como utilizar este procedimiento:
Este ejemplo asigna al color 120 los tonos más grandes de rojo, verde y azul. Esto forma
el blanco.
ModificarPaleta(120,63,63,63);
Este ejemplo asigna al color 65 los valores 0,0 y 0 para rojo, verde y azul. Esto forma
el negro. (El negro es la ausencia de todos los colores).
ModificarPaleta(65,0,0,0);
Este ejemplo asigna al color 205 los valores 63 para rojo, y 0 para verde y azul. Esto forma
un rojo fuerte.
ModificarPaleta(205,63,0,0);
Observa que el valor más alto que puedes especificar para rojo, verde y azul es 63.