Habíamos comentado cómo crear gráficos mediante los drivers BGI que distribuye Borland. Estos tienen como principal ventaja la gran cantidad de funciones y procedimientos que ponen a nuestra disposición.
Pero también tienen inconvenientes, principalmente dos:
Podemos saltarnos estos dos inconvenientes, accediendo nosotros
mismos a la pantalla gráfica. Lo haremos de dos formas:
a través de la BIOS o manejando directamente la memoria de video
(a cambio, todo este apartado será exclusivo de Turbo Pascal 7 para MsDOS).
Una guía de referencia muy buena para todos aquellos que
quieren programar el PC a un nivel algo más bajo del habitual (más
cercano a la máquina) es la lista de interrupciones recopilada por
Ralf Brown. En ella encontramos lo siguiente:
Interrupt List Release 41
Last change 6/5/94
This compilation is Copyright (c) 1989,1990,1991,1992,1993,1994
Ralf Brown
[...]
INT 10 - VIDEO - SET VIDEO MODE
AH = 00h
AL = mode (see #0009)
y la lista de modos (muy resumida, dejando sólo las más habituales de las más de 600 líneas que aparecen en esta recopilación):
Values for video mode:
text/ text pixel
pixel colors disply scrn system
grph resol box
resolution pages addr
00h = T 40x25 8x8 320x200
16gray 8 B800 CGA
= T 40x25
8x14 320x350 16gray 8 B800 EGA
= T 40x25
8x16 320x400 16 8
B800 MCGA
= T 40x25
9x16 360x400 16 8
B800 VGA
01h = T 40x25 8x8 320x200
16 8 B800 CGA
= T 40x25
8x14 320x350 16 8
B800 EGA
= T 40x25
8x16 320x400 16 8
B800 MCGA
= T 40x25
9x16 360x400 16 8
B800 VGA
02h = T 80x25 8x8 640x200
16gray 4 B800 CGA
= T 80x25
8x14 640x350 16gray 8 B800 EGA
= T 80x25
8x16 640x400 16 8
B800 MCGA
= T 80x25
9x16 720x400 16 8
B800 VGA
03h = T 80x25 8x8 640x200
16 4 B800 CGAy
= T 80x25
8x14 640x350 16/64 8 B800
EGA
= T 80x25
8x16 640x400 16 8
B800 MCGA
= T 80x25
9x16 720x400 16 8
B800 VGA
04h = G 40x25 8x8 320x200
4 . B800 CGA,EGA,MCGA,VGA
05h = G 40x25 8x8 320x200
4gray . B800 CGA,EGA
= G 40x25
8x8 320x200 4 .
B800 MCGA,VGA
06h = G 80x25 8x8 640x200
2 . B800 CGA,EGA,MCGA,VGA
07h = T 80x25 9x14 720x350
mono var B000 MDA,Hercules,EGA
= T 80x25
9x16 720x400 mono . B000 VGA
0Dh = G 40x25 8x8 320x200
16 8 A000 EGA,VGA
0Eh = G 80x25 8x8 640x200
16 4 A000 EGA,VGA
0Fh = G 80x25 8x14 640x350
mono 2 A000 EGA,VGA
10h = G 80x25 8x14 640x350
4 2 A000 64k EGA
= G .
. 640x350 16 .
A000 256k EGA,VGA
11h = G 80x30 8x16 640x480
mono . A000 VGA,MCGA
12h = G 80x30 8x16 640x480
16/256K. A000 VGA
13h = G 40x25 8x8 320x200
256/256K. A000 VGA,MCGA
Es decir: para cambiar al modo 640x480 con 16 colores, tendremos que hacer:
AH = 00 (Función de elegir el modo de pantalla)
AL = 12h (Modo 640x480x16, VGA)
INT 10h (Interrupción de video)
Antes de ver meternos con el Pascal, vamos a ver cómo dibujar un punto:
INT 10 - VIDEO - WRITE GRAPHICS PIXEL
AH = 0Ch
BH = page number
AL = pixel color (if bit 7 set, value is xor'ed
onto screen)
CX = column
DX = row
Desc: set a single pixel on the display in graphics modes
Notes: valid only in graphics modes
BH is ignored if the current video mode supports
only one page
y también podemos leer el color de un pixel con
INT 10 - VIDEO - READ GRAPHICS PIXEL
AH = 0Dh
BH = page number
CX = column
DX = row
Return: AL = pixel color
Desc: determine the current color of the specified pixel
in grahics modes
Notes: valid only in graphics modes
BH is ignored if the current video mode supports
only one page
Bueno, ya vale de parrafadas en inglés y vamos a empezar a aplicarlo.
Hagamos un programa que dibuje puntos en la pantalla en modo 640x480x16:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Gráficos mediante los }
{ servicios de la BIOS: }
{ 640x480, 16 colores }
{ GRB1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.00 }
{--------------------------}
program GrB1; { Gráficos a través de la BIOS - 1 }
uses dos; { Usaremos interrupciones }
const NumPuntos = 10000; { Número de puntos que dibujaremos }
var
regs: registers; { Para acceder a los registros, claro }
bucle: word; { Para bucles, claro }
procedure Modo640x480x16; { Cambia a modo gráfico }
begin
regs.ah := 0; { Función 0 }
regs.al := $12; { El modo es el 12h = 18 }
intr($10,regs); { Interrupción de video }
end;
procedure ModoTexto; { A modo texto, similar }
begin
regs.ah := 0;
regs.al := 3;
intr($10,regs);
end;
procedure PonPixel(x,y: word; color: byte); { Dibuja Pixel }
begin
regs.ah := $0c; { Función 0Ch }
regs.bh := 0; { Página 0 }
regs.al := color; { Color }
regs.cx := x; { Columna }
regs.dx := y; { Fila }
intr($10,regs);
end;
begin
Modo640x480x16;
for bucle := 1 to NumPuntos do
PonPixel( random(639), random(479), random(15) ); { Puntos
aleatorios}
readln;
ModoTexto;
end.
Hemos conseguido un programa que dibuja puntos sin necesidad de los BGI. El EXE resultante ocupa escasamente 2.5K (compilado con TP7).
Si lo compilamos con TMT Pascal Lite, el tamaño sube hasta los 18K, pero es porque este compilador incluye mayor información adicional, para que el fichero .EXE trabaje en modo protegido del 386 (aprovechando toda la memoria de nuestro ordenador, etc). Por cierto, la línea del "uses", si se compila con TMT, deberá ser:
uses dos, use32;
Pero esto que hemos hecho también es mejorable: llamar a esa
interrupción cada vez que queramos dibujar un punto resulta lento,
especialmente cuando queramos dibujar líneas o rellenar zonas.
La forma más rápida, al menos en ciertos modos gráficos,
o si se programa con cuidado, es acceder directamente a la memoria de video.