CURSO DE PROGRAMACIÓN GRÁFICA

Artículo 5: FUENTES DE LETRAS

Autor: (c) Miguel Cubas Serer.
Revista: Programación Actual (Prensa Técnica) nº 5, Agosto-1997


En anteriores entregas nos adentramos más en la programación gráfica con el cálculo del offset y el posicionamiento de los pixels en la VGA, con lo que ya podemos dibujar distintas formas gráficas en pantalla. En esta entrega nos encargamos de establecer comunicación entre el software y el usuario mediante las fuentes de letra.

Las fuentes de letras son la base de la información textual y muchas veces se hace imprescindible para el programador ofrecerle al usuario una serie de datos e informaciones, tales como pueda ser un menú de ayuda, cualquier texto de pantalla, información en los botones del entorno gráfico, etc. En los modos gráficos ya no disponemos de la fuente de letras de que disponíamos en el modo de texto, así que tenemos que ingeniárnoslas para, a partir de las primitvas gráficas de que disponemos, representar en pantalla el equivalente a los símbolos gráficos que representan las letras.

En anteriores artículos vimos la base de la programación gráfica con el desarrollo de la función PutPixel(), que representaba un punto en pantalla con el color especificado. En principio, el manejo de esta función va a ser la base de las fuentes de letra, pero ahora introduciendo en nuestros ejemplos más ensamblador proporcionando un mejor resultado en cuanto a velocidad de ejecución y eficiencia se refiere.


ORIENTACIÓN DEL CURSO

En principio veremos como siempre la manera más sencilla y estándar de hacer las cosas, y luego haremos una adaptación particular a MS-DOS usando ensamblador para acelerarlas. Puede decirse que este curso consta de 2 objetivos o partes: una es proporcionar pseudocódigo y conceptos para poder aplicar nuestros conocimientos a cualquier plataforma y sistema operativo, mientras que en la otra parte del curso nos encargamos de que el lector aprenda a utilizar los conceptos y programar de forma más optimizada, añadiendo código en ensamblador.

En este sentido de aplicación al MS-DOS, a medida que el curso avance, se irá eliminando código C y añadiendo nuevas instrucciones ASM que dotaran a nuestros programas de mejores resultados. Como siempre dispondremos del pseudocódigo de cada función, será sencillo portarlo a cualquier otro sistema simplemente cambiando la función más interna, la específica de cada sistema operativo. Esto quiere decir, en pocas palabras, que si queremos portar la rutina de dibujar sprites a Linux, por ejemplo, tan sólo habremos de sustituir la rutina PutPixel() en asm que habíamos creado para DOS por otra específica para Linux. De esta manera con un pequeño cambio podemos adaptar todas las rutinas y luego optimizarlas para cada sistema.


DEFINICION DE LETRA

En los modos de texto la unidad mínima era la celdilla (unidad de pantalla en que cabía un carácter ascii con su correspondiente color de plano y de fondo), y disponíamos de algunas funciones de la BIOS que nos permitía escribir carácteres en estas celdillas. En los modos gráficos no disponemos de estas celdillas. A cambio disponemos de una resolución mayor de pantalla en la que podemos representar las letras como conjuntos de pixels.

Como muchos ya habrán intuido, vamos a tratar cada letra como un bloque de pixels (como un bitmap o sprite), de manera que podremos guardarlas en arrays y dibujarlas en pantalla con uso de bucles anidados.

Lo anterior viene a decir que nosotros podemos crearnos nuestra propia definición de la letra 'A' (por poner un ejemplo) definiéndola como si fuera un sprite y dibujarla en pantalla de igual manera que hicimos en el número anterior:

    El caracter "A":

    ...XXXX...
    .XXX..XXX.
    XXX....XXX 
    XXXXXXXXXX
    XXXXXXXXXX
    XXX....XXX
    XXX....XXX 
    XXX....XXX 

Este carácter que nosotros hemos dibujado con distintos puntos (representados por las X) y por huecos donde no se dibuja (en este caso los puntos '.'), podemos transformarlo a códigos de colores comprensibles por el ordenador. Supongamos que queremos una letra azul (color 1) con fondo negro (color 0). Nuestro anterior caracter viene a ser representado ahora como:

   El caracter "A":

   0001111000
   0111001110
   1110000111 
   1111111111
   1111111111
   1110000111
   1110000111
   1110000111
Al transformalo en un array, quedaría almacenado así:


char Letra[10][8]= {0,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,1,1,1,0,etc ... }

Ya tenemos una letra guardada en el array. ¿Cómo la dibujamos en pantalla? Muy sencillo: supongamos inicializado cualquier modo gráfico (ya sea 320x200, 640x480 ó 1024x768) y disponiendo de una función PutPixel(x,y,color) que dibuje el punto (x,y) con el color especificado. Dibujar la letra en la posición (160,100) (por ejemplo) se reduce a dibujar todos los pixels que estén activados (con el color 1) y no dibujar nada en los que no deban ser modificados (el fondo de la letra, que es el color 0 en este caso):


#define ANCHO 10
#define ALTO   8

for( by=0; by<ALTO; by++)
  for( bx=0; bx<ANCHO; bx++)
    PutPixel(160+bx, 100+by, Letra[bx][by]);

Nótese que podemos crear las letras del tamaño que deseemos, de 8x16, de 16x16, etc. Así eliminamos el problema de los modos de texto que disponían de un tipo de letra con un tamaño fijo. Ahora podemos representar en pantalla las fuentes del tamaño y tipo que queramos. Podríamos haber dibujado la A inclinada en el array (con lo que representaría una letra cursiva), podíamos haberla dibujado más rellena (negrita), usar otros estilos de letra, etc. En modo gráfico disponemos de la libertad de creación con la resolución de pantalla como única limitación. Cualquier forma gráfica, siempre que quepa en la pantalla, está en nuestras manos.

Trazado de fuentes

En el ejemplo anterior hemos anidado dos bucles de manera que en su interior contenía la instrucción PutPixel() que dibujaba el pixel correspondiente del array bidimensional en pantalla. La letra ha sido guardada en un array bidimensional que contiene <anchoxalto> pixels. También es posible guardar una letra en un array unidimensional, cuya ventaja es la de disponer de los pixels que forman la letra de manera más intuitivamente lineal en memoria. Los arrays bidimensionales son más sencillos de leer (en cuanto a lectura y compresión del código se refiere), pero cuando nos encontremos trabajando con distintos modos gráficos es más conveniente disponer de memoria lineal y acceder a estos arrays con la formula (ya bastante conocida por los lectores) de:

 Color (x,y) del array = Array[Ancho*y+x]

Esto nos va a beneficiar en gran parte a la optimización del código que queramos desarrollar, y siguen siendo igual de legibles que los bidimensionales:

 Array unidimensional:

 char Letra[ancho*alto] = 
 {
  0,0,1,1,1,1,0,0,
  0,1,1,0,0,1,1,0,
  1,1,0,0,0,0,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,0,0,0,0,1,1,
  1,1,0,0,0,0,1,1,
  1,1,0,0,0,0,1,1
 };

De modo que a partir de ahora la mayoría de los ejemplos y listados estarán orientados mediante el uso de arrays unidimensionales, dada sencillez y linealidad en memoria.


LAS FUENTES DE LETRAS

Las fuentes de letra o de texto son un conjunto de letras guardadas en un array o fichero (con la posibilidad de utilización en nuestros programas) desde donde podemos acceder a ellas para dibujarlas en pantalla.

Cada una de estas letras están guardadas de la manera en que guardábamos la letra 'A' en el array de memoria, pero ahora en lugar de guardar una sóla letra, guardamos todas las que contiene la tabla de carácteres. De esta manera a la hora de desarrollar un programa seremos capaces de dibujar tanto carácteres individuales como frases completas, éstas últimas dibujando todos los carácteres que la componen consecutivamente en pantalla.

El modo texto nos limita a utilizar el único estilo de letra que existe (aunque puede cambiarse como veremos al final de este texto), pero en los modos gráficos podemos crear nuestros propios estilos que harán diferenciar a nuestros programas de los demás.

Hasta ahora hemos generalizado con las fuentes como conjunto de letras almacenadas en un array o fichero, donde cada uno de los carácteres está compuesto de tantos colores como de ancho x alto tenga dicho caracter (es decir, un bloque o array de pixels). Pero las fuentes pueden ser guardadas de diversas maneras dependiendo del uso que se le vaya a dar. En este capítulo abordaremos las fuentes desde diferentes puntos de vista, planteando las diversas aplicaciones que pueden llegar a tener.

Las fuentes multicolor, las monocolor y las monotextura son algunos de los puntos que vamos a tratar en este capítulo, nombrando sus aplicaciones, así como sus ventajas y desventajas.


FUENTES MULTICOLOR

Aunque todas las fuentes de texto tengan la finalidad de dar información, no todas tienen los mismos métodos de almacenaje. Las fuentes multicolor tiene la ventaja de ser fáciles de leer y escribir. El método que utiliza esta fuente está basado en el tamaño que ocupa cada uno de los colores que forman las letras. Simplemente hemos de guardar en un array los colores que representan el sprite de la letra, de manera que si cada letra es de 16x16 (16 pixels de ancho por 16 de altura), para guardar una sóla letra necesitaremos un array de 16x16=256 elementos. Trabajando en el modo 13h, en que cada color es representado por un byte, necesitaremos un array de 256 bytes (ya que cada color está entre 0 y 255 y éste es el rango de un byte). En otros modos como SuperVGA, donde cada color está representado por 2 ó 3 bytes (hasta 16.7 millones de colores), utilizaremos arrays de ints o longs para esto. Como el modo en que aplicamos nuestros ejemplos es el 13h, tomaremos el byte (char) como el tamaño de cada elemento del array:


 char Letra[16*16];

Aquí tenemos una función que nos dibuja un caracter de 16x16 guardado en un array lineal (o unidimensional), imprimiendo todos los pixels que lo forman de manera consecutiva:


void PutLetter (int x,int y)
{
 int bx, by;

  for (by=0;by<16;by++)
    for (bx=0;bx<16;bx++ )
      PutPixel(x+bx, y+by, Letra[(by*16)+bx]);
}

Este ejemplo nos muestra la manera en que una letra almacenada en una array lineal es imprimida en pantalla medinate la función PutPixel(). Pero si recordamos, las fuentes son un conjunto de letras (como la del listado) guardadas en un array. Ahora hemos de guardar el "set" completo de carácteres. De nuevo recurrimos a arrays bidimensionales:


char Fuente[16*16][256];

En este array bidimensional guardamos espacio para 256 carácteres de 16x16 pixels. Como ya hemos comentado la preferencia de usar arrays unidimensionales, y sabiendo que cada letra ocupa 16*16=256 bytes( en nuestro ejemplo), si queremos almacenar n letras, necesitaremos (ancho*alto)*n bytes:


char Fuente[16*16*256];

De tal modo que si queremos acceder al caracter 71 (letra G) siendo que por delante están almacenados los demás carácteres, habrá que hacer un cálculo que nos dé la dirección del comienzo de la letra 'G'. Y una vez obtenido el resultado del cálculo, podremos a partir de dicha dirección empezar a leer los datos del caracter 71. Si tenemos una fuente de 16x16 con 256 carácteres y queremos obtener la dirección de comienzo de la letra 'G' (caracter 71) se tendrá que hacer el siguiente cálculo:

    offset = caracter * (ancho*alto);
El listado 1 nos muestra como con un cálculo y dos bucles anidados es posible visualizar un caracter contenido en una fuente de letras en VideoRAM, así como su versión ensamblador optimizada en el listado 2.

 LISTADO 1: Carácteres multicolor en C

/*-----------------------------------------------------
WriteChar(); Dibujo de caracteres multicolor en C.

 Pseudocódigo:
 OFFSET_CARACTER = caracter*(ancho*alto)
   BUCLE1 Desde 0 a ALTO
    BUCLE2 Desde 0 a ANCHO
      PutPixel(X+BUCLE2, Y+BUCLE1 , FUENTE[OFFSET])
    END BUCLE2
   END BUCLE1

--------------------------------------------------- */

void WriteChar ( int x, int y, char ncar,
        int ancho, int alto, char *fuente )
{
 int offset_car;
 char bx , by;

 offset_car = ncar*(ancho*alto);

 for (by = 0;by < alto;by ++)
   for (bx = 0;bx < ancho; bx++ ) 
     PutPixel ( x+bx, y+by,
                fuente[offset+(by*ancho)+bx] );
}

 LISTADO 2: Fuentes multicolor en ASM:

*------------------------------------------
WriteChar(); Dibujo de caracteres en ASM.

Pseudocódigo:
 DS:SI = OFFSET DEL CARACTER
 ES:DI = OFFSET DE LA MEMORIA DESTINO
 ES:DI = (y*320) + x
  BUCLE1 FOR 0 TO ALTO
   BUCLE2  FOR 0 TO ANCHO
     ES:[DI] = DS:[SI]
     DI++; SI++
   END BUCLE2
   DI += 320-ANCHO
  END BUCLE1

------------------------------------------ */

void WriteChar ( int x, int y, char ncar, char masc,
     int ancho, int alto, char far *fuente, int segmento)
{
int offset_car;

offset_car = ncar * (ancho*alto);
asm {
    lds si, [fuente]   /*DS:SI = fuente*/
    add si, [offset_car]

    mov ax, [segmento]
    mov es, ax
    mov ax, [y]
    mov bx, ax
    shl ax, 8
    shl bx, 6
    add ax, bx
    add ax, [x]
    mov di, ax

    mov bx, [alto]
}
bucleY:;
asm mov cx, [ancho]

bucleX:;
asm {
    mov al, ds:[si]
    cmp al, [masc]
    je NoPinta
    mov es:[di] , al
   }

NoPinta:
asm {
    inc di
    inc si
    dec cx
    jnz bucleX

    sub di, cx
    add di, 320
    dec bx
    jnz bucleY
   }
}

Este estilo de fuentes tiene la ventaja de poder contener variedad de color en un mismo caracter, pero por eso mismo tienen el inconveniente de ocupar mucho tamaño. Existen otros métodos que nos ayudan a ahorrar espacio, pero que tienen unas desventajas que ya se comentarán más adelante.


FUENTES MONOCOLOR

Las fuentes monocolor son un estilo de letras muy diferente al de las multicolor. Un letra multicolor estaba compuesta por bytes que representaban los colores, y era así como se guardaban en el array o fichero. Las fuentes monocolor tienen otro método de escritura y lectura que nos ayudan a ahorrar memoria.

En una letra monocolor de 8x16 (las más comunes) un carácter ocuparía 16 bytes debido a que cada color del carácter está guardado de forma simbólica en un bit, donde hay color si el bit está activado y no lo hay si el bit no lo está. Por lo tanto un byte puede guardar la información de los 8 colores que debe tener la letra con el estado de sus bits.

  Byte 1:  00111100b
  Byte 2:  01100110b
  Byte 3:  11000011b
  Byte 4:  11000011b
  Byte 5:  11111111b
  Byte 6:  11111111b
  Byte 7:  11000011b
   ...      ... 
  Byte 16: 11000011b
Y en el array quedaría:


 char Letra[16]={60,102,195,195,255,255,195,...,195};

Sabiendo esto, ahora sólo hay que comprobar el estado de cada uno de los bits que contiene un byte con el fin de dibujar un pixel por cada bit que se encuentre activo. Esto debe hacerse con el cálculo del AND lógico de los operandos (& en lenguaje C), que nos da el resultado de 1 cuando dos bits se encuentran activos. De tal forma debemos calcular el AND entre un byte de la letra y el byte que contenga a 1 el bit que queramos comprobar. Así nos dará como resultado un valor mayor de 0 si el bit especificado está activo y 0 si no lo está.

 11000011b AND 10000000b = 10000000b (activo)
 11000011b AND 01000000b = 01000000b (activo)
 11000011b AND 00100000b = 00000000b (no activo)
 ... (comprobar con todos los bits) ...

Teniendo una fuente de 8x16, el código que visualiza un caracter contiene un sólo bucle que se repite 16 veces de alto que tiene el caracter (16 bytes), en cuyo interior desarrolla los cálculos que comprueban los bits del byte actual.


 char Letra[16];
 void PutChar (int x,int y,char color)
 {
  char valor;
  for (bucle=0;bucle<16;bucle++) 
  {
   valor = Letra[bucle];
   if ((valor & 128) != 0) PutPixel (x,y+bucle,color);
   if ((valor &  64) != 0) PutPixel (x,y+bucle,color);
   if ((valor &  32) != 0) PutPixel (x,y+bucle,color);
   if ((valor &  16) != 0) PutPixel (x,y+bucle,color);
   if ((valor &   8) != 0) PutPixel (x,y+bucle,color);
   if ((valor &   4) != 0) PutPixel (x,y+bucle,color);
   if ((valor &   2) != 0) PutPixel (x,y+bucle,color);
   if ((valor &   1) != 0) PutPixel (x,y+bucle,color);
  }
}

Este ejemplo visualiza en pantalla un sólo caracter guardado en memoria. Pero al tener un fuente con todos los carácteres, habrá que hacer el cálculo que realizábamos con las fuentes multicolor para desplazarnos al comienzo del caracter deseado (listado 3).

 LISTADO 3: Trazado de un carácter monocolor.

/*----------------------------------------------
     PutChar8x16( ); Dibujo de letras monocolor.
----------------------------------------------- */
void PutChar8x16 (int x, int y, unsigned char color,
              unsigned char caracter,char *fuente)
{
int offset_inicio, by;
unsigned char getbyte;

 offset_inicio = caracter * 16;

 for (by=0; by<16; by++ , offset_inicio++) 
  {
   getbyte = fuente[offset_inicio];
   if((getbyte & 128)!= 0) PutPixel( x , y + by, color);
   if((getbyte &  64)!= 0) PutPixel( x+1 , y + by, color);
   if((getbyte &  32)!= 0) PutPixel( x+2 , y + by, color);
   if((getbyte &  16)!= 0) PutPixel( x+3 , y + by, color);
   if((getbyte &   8)!= 0) PutPixel( x+4 , y + by, color);
   if((getbyte &   4)!= 0) PutPixel( x+5 , y + by, color);
   if((getbyte &   2)!= 0) PutPixel( x+6 , y + by, color);
   if((getbyte &   1)!= 0) PutPixel( x+7 , y + by, color);
    }
}


FUENTES MONOTEXTURA

A pesar de tener las fuentes monocolor la ventaja de ocupar poco espacio, tienen la desventaja de dibujarse en pantalla con el único color especificado por la función PutChar(x,y,color). Las fuentes monotextura van a tener también la ventaja de ocupar un mínimo espacio y la posibilidad de tener variedad de colores, cosa que las monocolor no permitían.

Si recordamos, las letras multicolor guardaban el color en la misma fuente donde el color de un pixel lo contenia uno y cada uno de los bytes con los que eran formados los carácteres. Ahora las fuentes monotextura podrán tener aplicada una variedad de colores como las multicolor guardando un bloque de bytes (textura) en un array que contenga tantos bytes como de alto por ancho sean los carácteres de la fuente monocolor. Así se podrá asignar cada uno de los colores de la textura a los pixels que forman un caracter. Aquí se muestra la manera en que una letra monocolor es dibujada en pantalla aplicándosele una textura de color.


 char Letra[16];
 char Textura[8*16];
 
void PrintLetter ( int x , int y )
{
 char offset_letra, offs_text, valor;

 offset_letra = offs_text = 0;

 for(bucle=0;bucle < 16;bucle++,offset_letra++)
 {
   valor = Letra[offset_letra];
   if ((valor & 128) !=0) 
    PutPixel(x,y+bucle,Textura[offs_text]);
    offs_text++;

   (...resto de condiciones...)

   if ((valor & 1) !=0)
    PutPixel(x+7,y+bucle,Textura[offs_text]);
    offs_text++;
 }
}

Esta función nos da ejemplo de cómo se puede aplicar una textura guardada en un array a un caracter de una fuente monocolor. Pero si disponemos de un estilo de fuente monocolor y un array que contenga una textura, podremos ser capaces mediante una función (listado 4) de dibujar en pantalla cualquier caracter de la fuente. Este método puede ser muy útil y sencillo de manejar para simples programas que no requieran mucho espacio y sin embargo tengan una buena presentación en cuanto a carácteres.

   LISTADO 4: Letras texturadas.

/*-------------------------------------------------
PutChar_MonoTextura8x16( ); Dibujo de letras
                          monocolor con textura
--------------------------------------------------- */
void PutChar_MonoTextura8x16 (int x, int y, 
       unsigned char caracter,char *fuente, char *textura )
{
 int offset_inicio, by;
 unsigned char getbyte;
 char offset_textura;

 offset_inicio = caracter * 16;
 offset_textura = 0;

 for (by=0; by<16; by++, offset_inicio++) 
 {
  getbyte = fuente[offset_inicio];
  if((getbyte & 128)!=0)
      PutPixel( x, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 64)!=0)
      PutPixel( x+1, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 32)!=0)
      PutPixel( x+2, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 16)!=0)
      PutPixel( x+3, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 8)!=0)
      PutPixel( x+4, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 4)!=0)
      PutPixel( x+5, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 2)!=0)
      PutPixel( x+6, y+by, textura[offset_textura]);
  offset_textura++;
  if((getbyte & 1)!=0)
      PutPixel( x+7, y+by, textura[offset_textura]);
  offset_textura++;
 }
}


FUENTES VECTORIALES

Las fuentes vectoriales son un tipo más complejo de fuentes cuya definición se realiza mediante vectores que representan la imagen de la letra. Gracias a esto, es posible rotarlas, escalarlas, etc. de una manera puramente matemática, rotando, escalando y trasladando los vectores que las definen. Este es el caso de las fuentes de Windows, por ejemplo, y que vamos a dejar por ahora debido a su complejidad.


EFECTOS CON LAS FUENTES

Además de la simple impresión de las letras podemos aplicar algunos efectos a las fuentes, tales como visualizar los textos centrados en pantalla o en un punto, dar sombra a estos con tal de resaltar su imagen, invertirlos, etc.

El centrado de texto se consigue con una simple operación que calcula la coordenada X a partir de la cual el texto debe ser visualizado para estar centrado en un punto. Supongamos que quiero calcular la coordenada X de un texto que tiene n pixels de largo contando los espacios entre carácteres, y queriéndolo centrar en el punto (100,50). El cálculo sería de la siguiente forma:

  X_INICIAL = 100 - (n/2)

Otro nuevo efecto sería dotar a un texto de sombra, produciendo un efecto de relieve que da una imagen diferente de la habitual. Dar sombra a un texto no es nada complicado ya que se logra dibujando dos veces la cadena en diferentes posiciones. Teniendo como coordenadas los valores X e Y, la cadena que representa la sombra se dibujará en X+1 e Y+1, y la misma cadena se dibuja a continuación en las coordenadas X e Y. De tal forma el texto queda escrito sobre la sombra que se encuentra en una posición más hacia la derecha y hacia abajo (aunque también podemos dibujar más alejada o hacia arriba, pero el efecto más visual se consigue con (+1,+1)).

 LISTADO 5: Trazado de fuentes con sombra:

/*----------------------------------------------------------
    Print8x16( ); Imprime una cadena de texto con sombra 
----------------------------------------------------------- */

void Print8x16 (int x ,int y ,unsigned char color,
       unsigned char colsombra ,char *frase,char *fuente )
{
int loop = 0;

 while (frase[loop] != 0)
 { 
  PutChar8x16 ( x+1 , y+1 , colsombra , frase[loop] , fuente );
  PutChar8x16 ( x , y , color , frase[loop] , fuente );

  x = x + 8 + 1;         /* separación entre carácteres */
  loop++;
 }
}

Para invertir un carácter tan sólo hemos de dibujar los pixels que lo componen en sentido inverso. En el caso de las fuentes monocolor es preciso comprobar los bits de todos los bytes, pero si antes lo hacíamos analizando del último bit al primero, ahora podemos hacerlos de forma invertida. Por tanto el resultado de dibujar la letra 'F' invertida quedaría así:

   XXXXXXXX
   XXXXXXXX
   .....XXX
   ..XXXXXX
   ..XXXXXX
   .....XXX
   .....XXX
   .....XXX

Estos son algunos de los efectos que pueden hacerse con las fuentes de texto, pero todavía quedan muchos que deben salir de la propia imaginación del programador, como letras en cursiva al incrementar la x de dibujo en cada pixel, aplicación de la función seno durante el dibujo, escalación, etc.


LAS FUENTES DEL DOS

Las fuentes del MS-DOS son un ejemplo de como el Sistema Operativo utiliza fuentes monocolor, que con un tamaño de 8x16 (4096 bytes) están guardadas en memoria (en la ROM) y es de donde la BIO accede para representar en pantalla (en esas celdillas que la forman) los distintos carácteres. Estas letras pueden ser cambiadas mediante una subfunción de la INT 10h, destinada a controlar los modos de funcionamiento de pantalla y escritura de carácteres gráficos.

Mediante la subfunción 1100h de la INT 10h es posible cambiar la dirección del nuevo buffer de carácteres de 8x16. De esta forma el MS-DOS puede adquirir una nueva imagen distinta de la habitual (como realiza el programa FDOS incluido en el directorio UTILS).


IMPRESIÓN DE UNA FRASE COMPLETA

Escribir una frase consiste simplemente en escribir todos los carácteres que la componen. El mecanismo es muy simple, basta con imprimir todos los carácteres del array o frase a imprimir desde el número 0 hasta que se encuentre el indicador de fin de cadena que es el caracter 0 (o '\0'). Un ejemplo de esto podemos verlo en los ejemplos y librerías de código del CD que acompaña a la revista.


ORDEN DE ALMACENAJE DE LAS FUENTES

Hasta ahora hemos estado guardando las fuentes en el orden lógico en el que las visualizamos en pantalla (es decir, por scanlines horizontales). Por esto mismo, si es necesario en alguna aplicación dibujar las letras por líneas verticales en lugar de horizontales, será más cómodo guardarlas en el orden en el que vayamos a sacarlas.

La figura 2 ilustra como es guardado el mismo caracter de una forma y de otra. De modo que si, por ejemplo, deseamos realizar un scroll de texto en modo gráfico, donde los carácteres tienen que salir por el borde de la pantalla visualizando líneas verticales, será más cómodo y rápido el guardar las fuentes en el orden en el que salen.

Almacenaje de fuentes

Para demostrar las posibilidades de las fuentes de texto y como ejemplo de almacenaje de las fuentes en sentido vertical disponemos de 2 ejemplos en el CD que acompaña a la revista que realizan un scroll horizontal por software, tan utilizado en el mundo de las demos.


HASTA LA PRÓXIMA ENTREGA

En la próxima entrega veremos el tratamiento de sprites y utilización de pantallas virtuales para conseguir un mayor rendimiento en nuestros programas y aplicaciones. Mientras tanto, los ejemplos que acompañan al artículo y algunas utilidades propias y otras freeware nos ayudarán a dominar el dibujo de fuentes en modos gráficos.

Pulse aquí para bajarse los ejemplos y listados del artículo (66 Kb).

Figura 1: "Definición de carácteres individuales."
Figura 2: "Métodos de almacenaje de las fuentes."

Santiago Romero


Volver a la tabla de contenidos.