Este documento: www.elrincondelc.com/decas/ug/sp-vga.html
  Documento original: www.delorie.com/djgpp/doc/ug/graphics/vga.html

Guia: Modo grafico VGA 13h

Uno de los modos graficos mas ampliamente utilizados en la plataforma Pc es el modo VGA 13h. Su tamano es de 320x200, puede mostrar 256 colores simultanemante, y funcionara en cualquier tarjeta grafica compatible VGA ( este modo no esta soportado por las tarjetas EGA y CGA, pero muy pocas personas ejecutan DJGPP en un hardware tan obsoleto:-).

El primer paso es seleccionar este modo, lo cual se hace llamando a la interrupcion 0x10 de la BIOS, por ejemplo:

   #include <dpmi.h>

   void set_mode_13h()
   {
      __dpmi_regs r;

      r.x.ax = 0x13;
      __dpmi_int(0x10, &r);
   }

Lo importante aqui es el numero 0x13, el cual se pone dentro del registro AX antes de llamar a la funcion de la BIOS. Este valor especifica el modo que queremos de video (320x200).

! No hay premio por adivinar de donde viene el nombre "modo 13h" !.

Antes de salir del programa, deberias volver al modo texto del DOS, lo cual puede hacerse exactamente de la misma manera que antes pero utilizando el numero 3 como modo de video, por ejemplo:

   void return_to_text_mode()
   {
      __dpmi_regs r;

      r.x.ax = 3;
      __dpmi_int(0x10, &r);
   }

Despues de cambiar al nuevo modo de video, el siguiente paso es dibujar algo en la pantalla. La memoria VGA se localiza en la direccion fisica 0xA0000, por tanto necesitaras utilzar el fichero de cabezera <sys/farptr.h> o la funcion dosmemput() para acceder a esta zona de la memoria: Mirar el capitulo DPMI para mas detalles sobre el tema. A un nivel basico, un pixel puede dibujarse en la pantalla con el codigo:

   #include <go32.h>
   #include <sys/farptr.h>

   void putpixel_13h(int x, int y, int color)
   {
      _farpokeb(_dos_ds, 0xA0000+y*320+x, color);
   }

Dibujar graficos como una sequencia de pixels tiende ha ser muy lento, pero el mismo principio puede ser aplicado a formas mas complejas y utiles como lineas, rectangulos y circulos. Una optimizacion muy util es llamar a al funcion _farsetsel(_dos_ds) una vez al comienzo de la rutina, y despues utilizar las funciones _farns*() mucho mas rapidas para seguir dibujando en la pantalla. Utilizando este metodo, el relleno de un rectangulo podria ser implementado asi:

   void rectangle_13h(int x, int y, int w, int h, int color)
   {
      int i, j;

      _farsetsel(_dos_ds);

      for (j=y; j<y+h; j++)
	 for (i=x; i<x+w; i++)
	    _farnspokeb(0xA0000+j*320+i, color);
   }

Otra buena tecnica es dibujardos o cuatro pixel al mismo tiempo con las funciones _farnspokew o _farnspokel():Esto puede acelerar por cuatro la velocidad de dibujo, frente a las operaciones sobre un simple byte.

Una aproximacion diferente es construir el dibujo completo en un buffer de memoria antes de copiarlo a la pantalla. Esto se consigue facilemte con la funcion dosmemput(), por ejemplo:

   #include <sys/movedata.h>

   char framebuffer[320*200];
   int i;

   /* limpia el buffer */
   memset(framebuffer, 0, sizeof(framebuffer));

   /* dibuja algunas lineas diagonales */
   for (i=0; i<200; i++) {
      framebuffer[i*320+i] = i;
      framebuffer[i*320+i/2] = i;
      framebuffer[i*320+i/3] = i;
   }

   /* copia el buffer a la pantalla */
   dosmemput(framebuffer, 320*200, 0xA0000);

Hasta ahora estas funciones han pintado colores en la pantalla como numeros con un valor entre 0 y 255, peropara un programa "real", obviamente necesitaremos alguna manera de conocer los colores que representan cada uno de estos numeros. Esto se controla por un componente de hardware llamado " la paleta", que es una tabla con los valores actuales de cada uno de los colores que podemos visualizar.Cuando seleccionamos por primera vez un modo de video, los primeros 16 valores de la paleta (colores 0 a 15), tendran los valores estandar para los colores en modo texto del DOS (negro, azul, verde, cian, rojo, magenta,marron,gris claro, gris oscuro, azul palido, verde palido, cian palido, rojo palido, magenta palido, amarillo, y blanco), pero los otros 240 colores, pueden tener colores diferentes, dependiendo esto de la maquina..Para utilizar algunos mas que estos 16 colores por defecto, deberemos poner en la paleta los valores que queramos nosotros mismos. Esto se consigue colocando un valor en el puerto 0x3C8 , y a continuacion se envian tres valores en el puerto 0x3C9. Por ejemplo:

 

   #include <pc.h>

   void set_color(int color, int red, int green, int blue)
   {
      outportb(0x3C8, color);
      outportb(0x3C9, red);
      outportb(0x3C9, green);
      outportb(0x3C9, blue);
   }

Los valores rojo, verde y azul pueden variar de 0 a 63, asi por ejemplo llamando a la funcion set_color(10,0,0,0) cambiara el color numero 10 a negro, ( ya que los valores de rojo, verde y azul son cero), mientras que set_color(10, 63, 63, 63), cambiara el color 10 a blanco ( ya que las componentes del color tienen todas el maximo valor 63), y set_color(10, 63, 40, 0), cambiara el color a una tonalidad naranja.

Una buena cosa sobre la paleta de colores, es que puede utilizarse para cambiar los colores despues de que hallamos pintado algo sobre la pantalla, lo cual puede ser una manera muy util de realizar fundidos y algunos tipos de animacion. Por ejemplo el color 1 es el azul en la paleta por defecto, por tanto si pintamos montones de pixels con el color 1 por toda la pantalla, veremos pixels de color azul , pero si despues hacemos set_color(1,0, 63, 0), !odos estos puntos se cambiaran instantaneamente a verde|. Ademas de ser un manera facil de hacer que tus graficos cambien a un color diferente, este truco puede utilizarse para hacer fundidos desde o hacia negro en toda la pantalla, cambiando gradualmente los 256 colores de la paleta para hacerlos gradualmente mas claros o mas oscuros , y ademas muchos efectos interesantes pueden conseguirse alterando sutilmente la paleta.

Antes de alterar cualquiera de los valores de la paleta, es una buena idea sincronizar nuestro programa con el retrazado vertical., Este es el momento en el que el haz de electrones que pinta la pantalla ha llegado a la parte inferior de la pantalla, y vuelve a la parte superior para pintar de nuevo otra vez sobre la pantalla, es en este brevisimo periodo de tiempo en el que la tarjeta de video puede descansar ya que no tiene necesidad de enviar nuevos valores de pixels al monitor. El retrazado vertical ocurre 70 veces por segundo, y la mayoria de las tarjetas antiguas solo nos permitiran alterar los valores de la paleta en estos periodos. Podemos cambiar los valores de la paleta cuando queramos en las tarjetas graficas modernas, y nuestros programas seguiran funcionando sin problemas, pero si lo hacemos fuera de estos periodos de retrazado vertical sobre hardware antiguo puede causar ruido o "nieve", en la pantalla, que resulta bastante feo, aunque es facil de evitar si tenemos cuidado de sincronizar siempre nuestro programa con el retrazado vertical. El retrazado vertical puede ser detectado chekeando el bit 3 del puerto 0x3DA, por ejemplo:

   void vsync()
   {
      /* Esperar hasta que cualquier retrazado anterior halla terminado */
      do {
      } while (inportb(0x3DA) & 8);

      /* Esperar hasta que un nuevo retrazado halla comenzado */
      do {
      } while (!(inportb(0x3DA) & 8));
   }

Siempre deberemos llamar a esta funcion antes de modificar cualquier color de la paleta. Aunque es posible cambiar muchos colores dentro de un retrazado vertical, por lo que solo necesitaremos llamar una sola vez a la funcion vsync() incluso aunque hagamos varias llamadas a set_color() inmediatament despues.

You should always call this function before you modify any palette colors, although it is possible to change many colors within a single retrace, so you will only need to call vsync() once even if you are making several calls to set_color() immediately after it.

!Esto es todo , amigos!, esto deberia ser suficiente para que podamos construir nuestros programas, y hacerlos trabajar en el modo VGA 320x200 ( modo 13h), y las mismas tecnicas pueden aplicarse a otros modos de video el modo de 16 colores y las resoluciones en modo X. Para programar con DJGPP en todos estos modos graficos se realizan de la misma forma que para el modo 13h, por lo cual puede combinar el material de este documento con la informacion disponible en Internet sobre hardware, y y eventualmente ser capaces de acceder a cualquier modo grafico que deseemos.

Traducido por: (11 Septiembre2000)
Revisado por:

Referencias:

x2ftp - ftp://x2ftp.oulu.fi/pub/msdos/programming/
La mas completa coleccion de programacion sobre graficos en la red.
 
PCGPE - ftp://x2ftp.oulu.fi/pub/msdos/programming/gpe/
Una buena y clara introduccion a tecnicas de programacion grafica, aunque todos los ejemplos esten en lenguaje Pascal.
 
Abrash in DDJ - ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/graphpro.lzh
Los "legendarios" articulos escritos por Michael Abrash y publicados en DDJ entre 1991 y 1993, cubriendo el modo-X, rasterizacion de poligonos, y otros muchos topicos sobre programacion grafica.

  Copyright © 1997   by DJ Delorie     Updated Jan 1997