Tutorial básico sobre utilización de gráficos con la unidad "Graph"
Escrito por Nicolás Rozas Salgado
Objetivo:
El objetivo de este tutorial es brindar los conocimientos a aquellos
con interés de desarrollar aplicaciones que utilicen gráficos.
Este tutorial se basa en la unidad "Graph" incluida en las versiones de Turbo y Borland
Pascal.
Desarrollo:
Borland Pascal tiene una linda unidad para tratamiento de gráficos.
Esta unidad es "GRAPH.TPU". Asumiremos para ello que tienes
Turbo / Borland Pascal 7.0 (Si tienes la versión 5, 5.5 o 6 tal vez
sea necesario modificarlo un poco). Hay que asumir también que tienes
una tarjeta de video compatible con VGA (Si tu PC es al menos una 486 o
superior, entonces es muy probable que la tarjeta sea compatible).
Tendrás que verificar que tengas el archivo EGAVGA.BGI. Todos los archivos
de fuentes pueden ser útiles si deseas hacer programas que necesiten
muchas fuentes (Los archivos de fuentes tienen la extensión *.CHR).
Si no los tienes es porque tu versión de Turbo / Borland Pascal
no está completa.
Lo que se va a ver en este tutorial es simplemente el tratamiento con
gráficos. Desafortunadamente la unidad Graph solo provee modos gráficos
de 16 colores, pero por ahora será suficiente (Igualmente, ya veremos
posteriormente a cómo utilizar los modos de 256 colores). La unidad
es sencilla de utilizar, así que no es necesario inmiscuirse mucho
en la forma con la que trabaja la unidad, lo cual en consecuencia
nos es útil para aprender lo básico antes de apuntar más "hacia arriba".
La única resolución que se adoptará en este tutorial es 640x480 (16 colores).
Esta es la resolución más grande que se puede utilizar con EGAVGA.BGI.
Iniciando y cerrando:
Lo primero que hay que hacer antes de iniciar los gráficos
es iniciar el controlador. Cuando el controlador se inicie, el modo
gráfico se habrá establecido también.
Cuando se termine de utilizar los gráficos, lo que hay que hacer es "cerrar"
el controlador, con ello se volverá al modo de texto inmediatamente.
El siguiente código hace ese trabajo:
Uses Crt, Graph;
Const BGIDir = '.\BGI';
Procedure Iniciar;
Var Gd, Gm: Integer;
Begin
Gd:=VGA; Gm:=VGAHi; {Especificamos aquí el adaptador y el modo}
InitGraph(Gd, Gm, BGIDir); {Inicia el modo gráfico}
Gd:= GraphResult; {Guardo el resultado de la operación en "Gd"}
If Gd <> GrOK Then {¿Hubo algún error?}
Begin {Sí}
Writeln('Hubo un error iniciando el modo gráfico.');
WriteLn('La descripción del error es el siguiente: ');
WriteLn(GraphErrorMsg(Gd));
ReadKey;
Halt;
End;
End;
Procedure Cerrar;
Begin
CloseGraph;
End;
Begin
Iniciar;
ReadKey;
Cerrar;
End.
La parte principal del procedimiento "Iniciar" es "InitGraph".
Este acepta tres parámetros: Los primeros dos son el adaptador
y el modo gráfico (El adaptador gráfico es VGA y el modo
es VGAHi (640x480x16)). El tercer parámetro es la carpeta
donde está el controlador EGAVGA.BGI, en nuestro caso
la carpeta está definida como una constante (BGIDir), pero
habrá que cambiarle el valor si EGAVGA.BGI no se encuentra
en esa carpeta.
Después de llamar a "InitGraph", necesitaremos detectar
si se ha podido establecer el modo gráfico o no. Este valor
se puede obtener a través de "GraphResult", el problema
es que el valor que devuelve "GraphResult" se elimina
después de llamarla (Como pasa con "IOResult"), así que
debemos guardar el valor en alguna variable entera.
En nuestro caso utilizamos "Gd" que no se utiliza más después
de "InitGraph". Si hay un error (Esto quiere decir, que "Gd"
no es "grOk") podemos pasarle el valor de "Gd"
al procedimiento "GraphErrorMsg" (Cuyo mensaje saldrá escrito en inglés).
Luego viene la parte que cierra, que incluye solo a "CloseGraph".
Después de llamar a "CloseGraph", el modo texto es reestablecido.
A partir de aquí utilizaremos las instrucciones gráficas después
de llamar a "Iniciar" y antes de llamar a "Cerrar". El programa
escrito arriba solo utiliza "ReadKey", así que lo que hace en definitiva el
programa es iniciar el modo gráfico, espera a que se presione una tecla,
vuelve al modo texto y finalmente sale.
Comandos básicos para gráficos y colores:
Supongamos que una vez que ya tenemos el modo gráfico activado deseamos
dibujar una linea. Entonces debemos agregar la siguiente instrucción
antes de "ReadKey":
Line(0, 0, 639, 479)
Con esto podrás ver una linea diagonal a través de la pantalla. Este procedimiento
dibuja una linea desde (0, 0) hasta (639, 479). En el modo gráfico que
estamos utilizando los valores permitidos para las coordenadas deben
estar entre 0 a 639 para X, y 0 a 479 para Y. Intentar dibujar fuera de
estos rangos no tiene efecto alguno.
Si antes de "Line" escribes "SetColor(12)" la linea quedará pintada de verde en vez de blanco.
"SetColor" establece el color que se va a utilizar. Los rangos válidos
están entre 0 y 15.
Otros comandos de la unidad:
Rectangle(X1,Y1,X2,Y2) Dibuja un rectángulo de coordenadas (X1 Y1) hasta (X2 Y2).
Circle(X,Y,Radio) Dibuja un círculo con centro en (X Y) y de radio
en el parámetro "Radio".
Ellipse(X,Y,AnguloInicial,AnguloFinal,RadioX,RadioY) Dibuja un arco desde "AnguloInicial"
hasta "AnguloFinal" y con radio establecido en "RadioX" y "RadioY". El centro de ese arco se define
con los parámetros "X" e "Y".
FillEllipse(X,Y,RadioX,RadioY) Dibuja una elipse rellena con
centro en (X,Y) y con radio establecido en "RadioX" y "RadioY".
Arc(X,Y,AnguloInicial,AnguloFinal,Radio) Dibuja un arco desde "AnguloInicial"
hasta "AnguloFinal" y con radio establecido en "Radio". El centro del arco se define
con los parámetros "X" e "Y".
Bar(X1,Y1,X2,Y2) Dibuja una barra (Como las de las tablas de barras)
desde (X1,Y1) hasta (X2,Y2).
Bar3D(X1,Y1,X2,Y2,Profundidas,Tope) Igual a "Bar" con la diferencia
de poder dibujarla en tres dimensiones. "Profundidad" se refiere a la longitud
de la barra en la tercera coordenada. "Tope" debe ser de tipo "Boolean", si es
"True" la barra tendrá un tope dibujado, de lo contrario especifica "False" a este
parámetro.
Nota: Para especificar el color que se debe utilizar en el momento
de dibujar alguna de las figuras mencionadas, es necesario utilizar
el procedimiento "SetColor" y pasar como parámetro el color a utilizar
(Cuyo rango debe estar entre 0 y 15). Ejemplo: "SetColor(1);"
Comandos para fuentes y textos:
Contrario a lo que sucede en modo texto, en modo gráficos no
debemos utilizar "Write" o "WriteLn" para escribir algo a la pantalla.
En su lugar utilizamos "OutText" y "OutTextXY".
La diferencia entre ellos es que "OutTextXY" emplea coordenadas
"X" e "Y" directamente y "OutText" depende de la posición del "cursor virtual"
(Definido a través del procedimiento "MoveTo"). Prueba cómo funciona agregando
las siguientes instrucciones:
OutText('Hola a todos!!!');
OutTextXY(100,150,'Hola de nuevo!!!');
También es posible cambiar la fuente que se está utilizando. Primero,
hay que asegurarse de que tienes los archivos de fuentes. Estos se encuentran
en el directorio BGI con la extensión CHR (Busca los archivos TRIP.CHR, LITT.CHR, SANS.CHR, y GOTH.CHR. Si están
en la misma carpeta que EGAVGA.BGI las fuentes podrán ser utilizadas).
Para cambiar la fuente utilizada por "OutText" y "OutTextXY"
tienes que utilizar previamente el procedimiento "SetTextStyle".
"SetTextStyle" acepta tres parámetros numéricos.
El primero es el tipo de fuente (Especifica para ello valores entre 0 y 9).
El segundo es la dirección (0 si es horizontal y 1 si es vertical).
El último es el tamaño de la fuente, cuyo rango oscila entre 1 y 10.
Otro procedimiento es "SetTextJustify", cuya tarea es modificar la
justificación del texto. Acepta dos parámetros:
El primero es la justificación horizontal y el otro
es la justificación vertical. Para ello puedes utilizar las siguientes
constantes ya definidas dentro de GRAPH.TPU:
Horizontal:
LeftText (A la izquierda) CenterText (Al medio) RightText (A la derecha)
Vertical:
TopText (Hacia arriba) CenterText (Al medio) BottomText (Hacia abajo)
Ejemplo: "SetTextJustify(CenterText,TopText);" mostrará el texto centrado y puesto "hacia arriba".
También es posible modificar el tamaño de la fuente de otra forma,
utilizando el procedimiento "SetUserCharSize". Este procedimiento
toma cuatro parámetros, que podríamos mencionarlos como A, B, C y D.
Con este procedimiento, el texto será agrandado (A Div B)
veces horizontalmente y (C Div D) veces verticalmente. Por ejemplo:
SetUserCharSize(2,1,1,1);
OutTextXY(100,100,'Tanto como gordo');
SetUserCharSize(1,1,2,1);
OutTextXY(100,140,'Tanto como flaco');
Limpiar y limitar la pantalla:
Contrario a lo que pasa en la unidad CRT, en modo gráfico no puedes utilizar
"ClrScr". En su lugar utiliza "ClearDevice".
Tampoco es posible utilizar "Window" para definir una región de pantalla
adonde podamos dibujar, pero en modo gráfico este procedimiento se reemplaza
con "SetViewPort". Por ejemplo, si queremos limitar la región de uso
a las coordenadas (100, 150) y (400, 300) entonces utilizamos
"SetViewPort(100,150,400,300);". Notar que a partir del momento en que
se llama a "SetViewPort" todas las instrucciones dibujarán solo en esa
región definida tomando como extremo el (0,0). Como ejemplo, si utilizo
"Line(0,0,10,15)" la linea no será dibujada tomando las coordenadas de
la pantalla, sino que tomará las definidas en "SetViewPort".
Si lo que deseas ahora es volver a utilizar toda la pantalla vuelve
a llamar a "SetViewPort" especificando esta vez toda la región de la
pantalla, es decir "SetViewPort(0,0,639,479);".
Pixeles y paletas:
Con la unidad Graph puedes dibujar si quieres un simple punto en
la pantalla. Ese punto en la pantalla se llama "pixel" y la pantalla
que utilizamos dispone de un total de 640 pixeles de ancho y 480
pixeles de alto, es decir ¡Unos 307.200 pixeles pueden ser vistos
en la pantalla al mismo tiempo!
Para escribir un pixel puedes utilizar el procedimiento "PutPixel"
que toma tres parámetros: Los dos primeros son las coordenadas (X,Y)
a dibujar (No lo olvides: X debe estar entre 0 y 639, e Y debe estar entre 0 y 479).
El tercero es el color (Aquí no se utiliza "SetColor").
Ejemplo: "PutPixel(0,0,14);" Dibuja un pixel amarillo en el extremo
izquierdo de la pantalla.
Como un complemento a "PutPixel" está "GetPixel". "GetPixel" es una función
que devuelve el valor de un pixel que está en una posición (X,Y) pasados como
parámetros.
También es posible cambiar los valores de paleta de un pixel en particular
a través de "SetRGBPalette". (Si no comprendes en este momento para qué se
utilizan las paletas recuerda que cada color se forma con la combinación
de tres colores primarios. En una PC esos colores son el rojo, el verde
y el azul. Cada valor de pixel tiene definido sus valores de rojo, de verde
y de azul; una vez definidos estos valores la tarjeta de video los asigna
al pixel en pantalla inmediatamente)."SetRGBPalette" toma cuatro parámetros:
El primero de ellos es el valor del pixel y los otros tres corresponden a las tonalidades de rojo, verde y azul
(Cada una de ellas deben ser especificadas en valores que oscilan entre 0 a 255).
Normalmente, como ocurre en los modos de 256 colores, cada número de pixel
tiene asignada una entrada en la tabla de paletas con un número
de índice igual al valor del píxel. Lamentablemente, por una razón
interna de la arquitectura de la tarjeta VGA, esto no es así en el modo
de 16 colores que estamos utilizando. El siguiente arreglo de constantes
definidas posee el número de la entrada que le corresponde en realidad
a cada píxel en particular:
Const Entradas_VGA: Array[0..15] Of Byte = (0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63);
Comprendo que esto puede ser confuso y explicar los motivos de esta arquitectura
puede resultar en aun más confusión, así que lo recomendable es crear un procedimiento
que se encargue de asignar el valor real de cada píxel sin preocuparnos más
por el detalle:
Procedure EstablecerPaleta(Pixel,Rojo,Verde,Azul: Byte);
Const
Entradas_VGA: Array[0..15] Of Byte = (0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63);
Begin
SetRGBPalette(Entradas_VGA[Pixel],Rojo,Verde,Azul);
End;
Cuando desees cambiar el valor de rojo, verde y azul a un pixel
en particular llama a "EstablecerPaleta" pasándole como parámetros
el valor del píxel (De 0 a 15) seguido de las correspondientes tonalidades de rojo, verde y azul
que le corresponderán a ese pixel.