Ampliación 2: Gráficos sin BGI (2).
Curso: Curso de Pascal, por Nacho Cabanes
Curso de Pascal. Ampliación 2: Gráficos sin BGI (2).
A través de la memoria de pantalla.
Aquí nos encontramos un primer "pequeño" problema: la memoria de pantalla puede empezar en distintas posiciones de la memoria física total del ordenador, según la tarjeta gráfica (o el modo gráfico) que estemos usando. Por ello me centraré en la VGA.El segundo "pequeño" problema es que incluso para la VGA, el acceso a la memoria no siempre es igual: tenemos modos como el 13h (320x200, 256 colores) en lo que cada byte corresponde a un pixel. Otros modos en los que un byte corresponde a 8 pixels (640x480 mono: 11h). En otros, tenemos 4 planos: un byte en cada uno afectará al color de ocho pixels...
Hay montones de libros que os pueden ayudar a programar en esos modos "complicados", en los que hay que fijar sólo algunos de los bits de cada byte para dibujar un pixel, o hacer cambios de plano.
Mi intención no es esa, sino daros la base para que cada uno
pueda experimentar por donde quiera, así que me voy a centrar en
el modo más fácil de programar, y que además es el
más vistoso de la VGA estándar: el modo 13h: 320x200,
256 colores.
En ese modo tenemos que cada punto de la pantalla corresponde a un byte y viceversa. Así, si el primer byte de la memoria de pantalla es un 3, quiere decir que en las coordenadas (0,0) (esquina superior izquierda) hay un punto de color 3.
Esta memoria de pantalla, en un PC con tarjeta gráfica VGA funcionado con sistema operativo MsDOS, está en el segmento A000h, luego la dirección de dicho primer punto será A000:0000. La cantidad de memoria que ocuparemos será 320x200 = 64.000 bytes.
Entonces, cambiaremos al modo gráfico como antes:
procedure Modo320x200x256; { Cambia a modo gráfico } begin regs.ah := 0; { Función 0 } regs.al := $13; { El modo es el 13h = 19 } intr($10,regs); { Interrupción de video } end;
y para dibujar un punto podemos acceder directamente a la posición de memoria que nos interesa:
procedure PonPixel(x,y: word; color: byte); { Dibuja Pixel } begin Mem[$A000 : y * 320 + x] := color; end;
Con lo que la adaptación del ejemplo anterior es inmediata.
También podemos leer fácilmente el color de un cierto punto de la pantalla:
function LeePixel(x, y : Word) : Byte; { Color de un pixel } begin LeePixel := Mem[$A000 : y * 320 + x]; end;
Otra forma muy sencilla de dibujar puntos en pantalla y leerlos es
creando un array en la posición concreta de la memoria
que ya conocemos:
var pantalla: array [ 0..319, 0..199 ] of byte absolute $A000:0000;
Dibujaríamos un punto con
pantalla [x,y] := color;
y lo leeríamos con
color := pantalla [x,y];
Así, si usamos Turbo Pascal 7, el ejemplo anterior podría quedar simplemente
{--------------------------} { Ejemplo en Pascal: } { } { Gráficos accediendo a } { memoria de pantalla: } { 320x200, 256 colores } { Versión para TP7 } { GRB2.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Turbo Pascal 7.0 } {--------------------------} program GrB2; 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 } pantalla: array [0..319,0..199] of byte absolute $A000:0; { Pues la pantalla ;-) } procedure ModoPantalla( modo: byte ); { Cambia a un modo dado } begin regs.ah := 0; { Función 0 } regs.al := modo; { El modo indicado } intr($10,regs); { Interrupción de video } end; begin ModoPantalla($13); for bucle := 1 to NumPuntos do Pantalla[ random(319), random(199)] := random(255) ; readln; ModoPantalla(3); end.
Si compilamos con TMT, debemos indicarle la dirección
de memoria de la pantalla de una forma ligeramente distinta:
{--------------------------} { Ejemplo en Pascal: } { } { Gráficos accediendo a } { memoria de pantalla: } { 320x200, 256 colores } { Versión para TMT } { GRB2T.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Tmt Pascal Lt 1.00 } {--------------------------} program GrB2T; 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 } pantalla: array [0..319,0..199] of byte absolute $A0000; { Pues la pantalla ;-) } procedure ModoPantalla( modo: byte ); { Cambia a un modo dado } begin regs.ah := 0; { Función 0 } regs.al := modo; { El modo indicado } intr($10,regs); { Interrupción de video } end; begin ModoPantalla($13); for bucle := 1 to NumPuntos do Pantalla[ random(319), random(199)] := random(255) ; readln; ModoPantalla(3); end.
Si empleamos Free Pascal, en general no podremos usar este método, porque existe para distintos tipos de ordenadores, con distintos sistemas operativos y diferentes subsistemas gráficos, y nada nos garantiza que la memoria de video se encuentre en esa posición de memoria.
Actualizado el: 28-06-2009 19:28