
-------------------------------------------------
        Tutorial de programacin grfica
                   por:  FAC 
       ----------------------------------
             Tutorial 1 - Lo bsico
-------------------------------------------------

Que tal? Bienvenidos al primer tutorial de la serie FAC, escrita, dirigida
y producida por FAC. Basada en los tutoriales de Denthor aka Grant Smith.

La idea es escribir un tutorial cada semana con teora, ejemplos y
ejercicios de programacin de grficos. Por ahora los tutoriales estarn
en el servidor Galia de la Facultad de Ciencias de la UASLP. Para bajarlos,
hagan un FTP a galia.fc.uaslp.mx y vayan al directorio pub/tutorial
en donde encontrarn los tutoriales en la forma TUT?.ZIP .

Esta primera parte trata de las funciones bsicas de la tarjeta VGA, modos
de video, dibujar pxels y otras cosas necesarias.

Antes que nada... RESPONSABILIDAD:

        No me hago responsable por cualquier falla, descompostura, prdida
        de informacin, explosin o cualquier problema causado a tu
        computadora (o a la que ests usando), persona, familia, mascota,
        pareja, alma, etc...

        El cdigo que se expone en estos tutoriales no es peligroso. No
        les voy a pedir que hagan algo como "format c:", as que si algo
        sale mal, NO ES MI CULPA.


Bueno, ahora que estamos de acuerdo, vamos a empezar el tutorial.


REQUERIMIENTOS MINIMOS:

        Estoy asumiendo que los lectores, o sea, ustedes, tienen ligeros
        conocimientos de programacin bsica, que conocen un poco del
        lenguaje Pascal, y lo ms importante, estoy asumiendo que quieren
        APRENDER.

        Tambin espero que el lector conozca y entienda trminos como:
        pxel, byte, RAM, memoria convencional, apuntador, etc, y de
        preferencia, que tenga conocimientos bsicos sobre el manejo de
        apuntadores en Pascal.

        Para aquellos que no saben Pascal, pero conocen el C / C++, no
        se preocupen, Pascal y C son muy similares y debe de ser MUY
        fcil traducir los ejemplos a C. Incluso, si recibo suficientes
        peticiones, podra escribir los tutoriales tanto para Pascal como
        para C... pero slo si hay varios interesados. Por ahora, todos
        los ejemplos estn escritos para usarse con Turbo Pascal.


COMO ENTRAR AL MODO GRAFICO DESDE PASCAL???

        Esto es bsico. Antes de dibujar cualquier cosa, necesitamos
        activar el modo grfico. Obviamente, NO vamos a usar las libreras
        BGI que vienen includas con Turbo Pascal, ya que son MUY lentas
        y no sirven para hacer efectos interesantes.

        Por ahora vamos a utilizar el modo grfico de 320 * 200 * 256.
        Esto significa que tendremos 320 pixels en cada lnea horizontal,
        200 pxels en cada lnea vertical y 256 colores.

        Este modo es mejor conocido como el modo MCGA o el modo 13.

        Si, bueno, pero cmo lo activamos? Muy fcil, slo necesitamos
        2 instrucciones de ensamblador. No se preocupen si no saben
        ensamblador. Yo tampoco s.

        procedure SetMode13; { procedimiento que activa el modo 13 }

        begin
             asm
                mov ax, 0013h 
                int 10h
             end;
        end; { fin del procedimiento }


        Bonito, no? Pero qu demonios hicimos?

        Bueno, lo que hicimos fu cargar el acumulador con el valor 0013h
        (la "h" significa que es hexadecimal). El acumulador es como una
        variable en ensamblador, as que:

        mov ax, 0013h

        mueve el valor 0013h al acumulador. Fcil, no?

        Despus llamamos a la interrupcin 10h de la siguiente forma:

        int 10h

        Una interrupcin es como un procedimiento que hace alguna funcin
        bsica del sistema operativo, como abrir un archivo, imprimir un
        caracter, etc... En este caso lo que hicimos fu cambiar el modo
        de video con la interrupcin 10h. Los parmetros que se le
        pasan a la interrupcin se encuentran en el acumulador.

        Si no entienden muy bien esto, no importa, simplemente usen el
        procedimiento anterior para cambiar al modo de video.


Y COMO REGRESAMOS AL MODO DE TEXTO?

        Igual de fcil. Slo que ahora cambiamos al modo 03h, que es el
        modo de texto de 80 * 25 caracteres.

        procedure SetTextMode;  { regresa al modo de texto }

        begin
             asm
                mov ax, 0003h;
                int 10h;
             end;
        end; { fin del procedimiento }


        Ahi lo tienen. Es incluso ms fcil que las rutinas del BGI.


LLENAR (BORRAR) LA PANTALLA DE UN COLOR ESPECIFICO:

        Activar el modo grfico es algo excitante, pero el verdadero placer
        est en DIBUJAR algo en el modo grfico.

        Para empezar, vamos a "pintar" toda la pantalla de un solo color.

        Para hacer esto, necesitamos conocer una cosa MUY importante, la
        direccin en la memoria de la pantalla, la cual es A000h

        El nmero A000h (o $A000 como dira Pascal) es el SEGMENTO de
        la pantalla. Un segmento es un bloque de 64 kilobytes que se
        encuentra en la memoria convencional. Por lo tanto, la memoria
        convencional est dividida en 10 segmentos (64 Kb * 10 = 640 Kb).

(Nota: Un nmero en hexadecimal se expresa con una "h" al final del nmero
       o con un signo de pesos "$" al principio. Por lo tanto:
       A000h = $A000 = El segmento de memoria que ocupa la pantalla. )

       Bueno, lo que tenemos aqu es el SEGMENTO de la pantalla VGA.
       La pantalla est organizada de la siguiente forma:

       0  |1  |2  |3  |...  ...|317|318|319
       ---|---|---|---|--------|---|---|---
       320|321|322|323|...  ...|637|638|639
       ---|---|---|---|--------|---|---|---
       .   .   .    .             .  .   .
       .   .   .    .             .  .   .
       .   .   .    .             .  .   .


        en donde cada nmero representa un pxel. Por lo tanto, el pxel
        que est en la esquina superior izquierda tiene la posicin 0.
        El que le sigue a la derecha tiene la posicin 1, y recorremos
        los pxels hacia la derecha hasta que llegamos a la posicin 319.
        En la siguiente posicin (320) el pxel correspondiente se encuentra
        al principio (a la izquierda) pero de la lnea siquiente... y as
        nos vamos hasta que llegamos al pxel de la esquina inferior derecha
        el cual tiene la posicin 63999 (320 * 200 - 1).

        As que para acceder a un pxel especfico, lo nico que hay que
        hacer es calcular su posicin de memoria y utilizar el arreglo MEM
        para acceder a ese pxel, por ejemplo:

        mem[$A000:0] se refiere al pxel en la esquina superior izquierda.
              |   |
              |   |
              |   -----> esta es la posicin del pxel en la memoria.
              |
              |--------> este es el segmento de la pantalla.


        Slo hay que recordar que una direccin de memoria se especifica
        de la forma:

                SEGMENTO:OFFSET

        Donde en nuestro caso, el SEGMENTO es $A000 y el OFFSET es la
        posicin del pxel que nos interesa.

        No olviden escribir el signo de pesos ($) antes de A000, o
        Pascal pensar que A000 es una variable.

        Bueno, todo esto fu teora, ahora vamos a la prctica:

        Para llenar la pantalla de un slo color, usaremos la funcin
        FillChar del Pascal. Esta funcin trabaja de la siguiente forma:

                FillChar(Apuntador, N, Valor)

        y lo que hace es llenar N bytes con el Valor que queremos a partir
        de la direccin de memoria especificada por Apuntador)

        EJEMPLO:

                FillChar(Mem[$A000:0], 64000, 0);

        La instruccin anterior llena 64000 bytes (320 * 200) a partir
        de la primera posicin en la pantalla con el valor 0 (que usualmente
        es el color negro).

        En otras palabras, la instruccin anterior BORRA LA PANTALLA.

        Se puede utilizar

                FillChar(Mem[$A000:0], 64000, color);

        para llenar la pantalla de cualquier color que se desee. Despus
        veremos cmo cambiar los colores.


        Ahora vamos a escribir un pequeo programa para ejemplificar lo
        que hemos visto:

 --------------------------------------------------------------------------
        program Basico1;

        { Ejemplo de cmo activar el modo grfico, borrar la pantalla con
          un color determinado y regresar el modo de texto.

          Por: FAC SoFtWaRe
          greetz to Denthor
        }

        uses crt;

        procedure SetMode13;
        begin
             asm
                mov ax, 0013h;
                int 10h;
             end;
       end;

       procedure SetTextMode;
       begin
            asm
                mov ax, 0003h;
                int 10h;
            end;
       end;

       var i : byte;

       begin
            clrscr;
            writeln('Este programa activa el modo 13 y luego llena');
            writeln('la pantalla con un color diferente cada vez que');
            writeln('se oprime una tecla. Despus regresa al modo de texto.');
            writeln;
            writeln('Oprime cualquier tecla para empezar...');
            readkey;

            SetMode13;
            readkey;

            for i := 15 downto 8 do
            begin
                 FillChar(Mem[$A000:0], 64000, i);
                 readkey;
            end;

            SetTextMode;         
        end.      

---------------------------------------------------------------------------

        Ya lo ejecutaron? Muy bien, ahora podemos poner la pantalla
        de cualquier color. Pero eso no es muy interesante, as que
        vamos a ver lo que sigue.



COMO DIBUJAR UN PIXEL EN LA PANTALLA:


        Una de las grandes ventajas del modo 13 es que cada pxel ocupa
        exactamente un byte en la memoria de video. En ese byte se almacena
        el color del pxel, por lo tanto, si queremos dibujar un pxel,
        lo nico que hay que hacer es cambiar el byte en la posicin
        de memoria correcta.

        Pero normalmente nosotros especificamos la posicin de un pxel
        con dos coordenadas (X, Y) y no como una direccin de memoria,
        por lo tanto hay que calcular la direccin de memoria del pxel
        que nos interesa a partir de sus coordenadas en la pantalla.

        Esto es MUCHO ms facil de lo que parece, la idea es la siguiente:

        Las coordenadas (x, y) en la pantalla estn de esta forma:

                0 <----- X -----> 319
                ^
                |
                Y
                |
                v
               199

        o sea que la coordenada X va de izquierda a derecha, de 0 a 319, 
        y la coordenada Y va de arriba hacia abajo, de 0 a 199.

        En la memoria, el pxel (0,0) est en la posicin 0, el pxel
        (1,0) est en la posicin 1, el pxel (0,1) est en la posicin
        320, etc...

        Para calcular la posicin de cualquier pxel, usamos lo siguiente:

                posicin del pxel := (Y * 320) + X

        o sea que el pxel (319,199) (esquina inferior derecha) tiene la
        posicin 63999, lo cual coincide con la estructura de la pantalla
        en la memoria (modelo lineal).


        Para cambiar el color del pxel que se encuentra en (X, Y) usamos
        la siguiente instruccin:

                mem[$A000:(Y * 320) + X] := color;

        As de fcil. Ahora vamos a poner todo esto en un procedimiento
        para poder llamarlo de una forma todava ms fcil.

                const VGA = $A000;

                procedure PutPixel(X, Y : word; color : byte);
                begin
                     mem[VGA:(Y*320)+X] := color;
                end;

        Eso es todo. Ahora podemos utilizar la funcin PutPixel cada vez
        que queramos.

        Esta funcin es MUCHO ms rpida que la funcin PutPixel del BGI.
        Se imaginan por que? Bueno, la razn principal es que el BGI
        utiliza una interrupcin para dibujar un pxel, y las interrupciones
        son muuuuuy lentas. Adems el BGI comprueba primero si los valores
        de X y Y estn dentro de los lmites de la pantalla.

        Existen formas ms rpidas de dibujar un pxel en la pantalla,
        todas ellas involucran ensamblador. En los siguientes tutoriales
        voy a poner uno o dos procedimientos PutPixel ms rpidos. Pero
        slo hasta que la velocidad sea un factor importante.

        Vamos a ver un ejemplo de cmo usar nuestro PutPixel:

----------------------------------------------------------------------------
        program Basico2;

        { Ejemplo para el uso de PutPixel
          Por: FAC sOfTwArE
          greetz to Denthor
        }

        uses crt;

        const VGA = $A000;      

        procedure SetMode13;
        begin
             asm
                mov ax, 0013h;
                int 10h;
             end;
        end;

        procedure SetTextMode;
        begin
             asm
                mov ax, 0003h;
                int 10h;
             end;
        end;

        procedure PutPixel(x, y : word; color : byte);
        begin
             mem[VGA:(y*320)+x] := color;
        end;

        var x, y : integer;

        begin
             randomize;   

             clrscr;
             writeln('Este programa llena la pantalla con pxels de');
             writeln('diferentes colores.');
             writeln;
             writeln('Presiona cualquier tecla...');
             readkey;

             SetMode13;

             for x := 0 to 319 do
                 for y := 0 to 199 do
                     PutPixel(x, y, random(256));

             readkey;
             SetTextMode;
        end.
             
---------------------------------------------------------------------------

        El programa anterior llena la pantalla con pxels de colores
        aleatorios. Pero normalmente queremos saber exactamente de
        qu color va a aparecer el pxel... bueno, aqui tienen una
        tabla de los principales colores:

        valor      color
     -------------------------------------------
        0       | negro
        1       | azul oscuro
        2       | verde oscuro
        3       | Cyan (Azul cielo) oscuro      
        4       | Rojo oscuro
        5       | Magenta oscuro
        6       | Caf / Naranja oscuro
        7       | Gris Claro
        8       | Gris Oscuro
        9       | Azul brillante
        10      | Verde brillante
        11      | Azul cielo
        12      | Rojo brillante
        13      | Magenta brillante
        14      | Amarillo
        15      | Blanco


        Estos son los colores de la paleta que se activa por default al
        iniciar el modo grfico. O sea, que si por ejemplo, escribimos:

                PutPixel(160, 100, 12);

        estaremos dibujando un pxel rojo en el centro de la pantalla.

        Normalmente no se utilizan estos colores, sino que se cambian
        de forma que el nmero 15 podra ser por ejemplo verde en vez
        del blanco. En el siguiente tutorial veremos cmo y por qu se
        hace esto.


EJERCICIOS:

        Si, ya lo s... yo tambin odio esta parte, pero...
        quieren aprender o no?

        - Hagan un procedimiento que dibuje una lnea horizontal
          que tenga la siguiente sintaxis:

                LineaH(x1, x2, y1, color);

        - Hagan lo mismo pero para dibujar una lnea vertical:

                LineaV(x1, y1, y2, color);

        - Hagan un procedimiento que dibuje un rectngulo:

                Rect(x1, y1, x2, y2, color);

          TIP.- Un rectngulo son 2 lneas horizontales y 2 verticales

        - Si ya tienen el procedimiento del rectngulo, hagan lo siguiente:

           a) Dibujen un cuadrado
           b) Borren el cuadrado (para borrarlo, dibujenlo de color negro)
           c) Dibujen el cuadrado en una posicin ligeramente diferente
           d) repitan desde el paso b varias veces

           La idea de este ejercicio es MOVER el cuadrado.


CONCLUSION:

        Hasta ahora parece que no hemos visto nada interesante, pero
        cranme. Esto es la base de CUALQUIER programa que utilice
        grficos. Faltan muchas cosas que aprender, pero todo a su
        tiempo. Por ahora lean el tutorial, vulvanlo a leer, analicen
        el cdigo, entindanlo, jueguen con l y traten de hacer los
        ejercicios. 

        Esta es slo la primera parte de lo bsico en la programacin
        grfica en Pascal. Voy a escribir otros dos tutoriales, uno
        sobre el manejo de la paleta y efectos con la paleta y el otro
        sobre el dibujo de lneas, crculos y relleno de tringulos y
        polgonos. Si obtengo suficientes respuestas, entonces seguir
        escribiendo estos tutoriales, pero si no hay inters, entonces...

        Tengo pensado escribir sobre:

                - Manejo y rotacin de paleta.
                - Dibujo de lneas, crculos, tringulos, polgonos, etc.
                - Uso de pantallas virtuales y principios de animacin.
                - Distintos efectos como: scroll, plasma, fuego, etc.
                - Dibujo de slidos en 3D (vectores).
                - Sombreado de slidos (Flat, Gouraud y Phong)
                - Mapeado de texturas
                - Modo X (un modo grfico MUY verstil)
                - Usar el modo real-flat que permite hasta 4 Gigabytes

        y algunas otras cosas que yo mismo vaya aprendiendo. Yo tambin soy
        principiante en esto de las grficas :-)

        As que ya saben... si les interesan estos tutoriales, por lo
        menos hganmelo saber. Escribanme a:  ganzo@galia.fc.uaslp.mx
                                                             
        Tambin pueden escribir por si tienen preguntas, dudas o
        sugerencias.

        Si hacen algn programa basado en estos tutoriales, me gustara
        verlo. Y si utilizan el cdigo de los ejemplos dennos crdito
        a Denthor y a m.

        Y por ltimo, en el directorio FTP de Galia, hay algunos demos
        MUY buenos con los que se pueden dar una idea de lo que se puede
        hacer con un poco de creatividad. (Un "demo" es simplemente una
        demostracin "artstica" de las capacidades grficas y de sonido
        de una computadora).

        Para bajar los demos, slo hagan un FTP a Galia y vayan al
        directorio pub/prog donde encontrarn los siguientes archivos:

        EVADE.ZIP       - Intro de 64K hecha por el grupo Kloon.
        SYMBOLOG.ZIP    - Intro de 64K hecha por... ???
        SKUMLE.ZIP      - Demo hecha por el grupo dans Purple.

        Si no tienen ni idea de qu estoy hablando, entonces mndenme un
        e-mail y yo les mandar los demos por e-mail. O bsquenme en la
        facultad de Ciencias y les mostrar un demo :)

        Bueno... eso es todo por ahora. Divirtanse.

                                                      FAC aka Alfonso Alba

