
--------------------------------------------
      Tutorial de programacin grfica
                  Por: FAC
     -----------------------------------
               #5 - Scrolling
--------------------------------------------


Bienvenidos nuevamente a esta excitante experiencia de leer un tutorial
de programacin.

En este nmero, vamos a ver uno de los efectos ms comunes que todos
deben conocer: el scrolling.

El siguiente tutorial estar disponible hasta despus de vacaciones
(a principios de Agosto). Tambin es probable que durante las prximas
semanas no pueda leer el e-mail, as que si me escriben algo y no
reciben respuesta, busquen otra forma de ponerse en contacto.

Pueden comunicarse con:

                   Alfonso Alba Cadena
                   ganzo@galia.fc.uaslp.mx
                   tel: 13-34-71


Si se han perdido algn tutorial, los pueden encontrar en:

                  ftp://galia.fc.uaslp.mx/pub/tutorial


Para cualquier duda, comentario, sugerencia o correccin, comunquense
de la forma antes mencionada.


Para los siguientes tutoriales, empezaremos a hacer uso de herramientas
de dibujo que puedan trabajar con el formato PCX.

Existen muchos programas de dibujo pero son pocos los que nos permiten
manejar la paleta de colores a nuestro antojo. Yo, en lo personal,
utilizo los siguientes programas:

        Corel PhotoPaint 5 - (Dibujo de bitmaps para Windows)
        Paint Shop Pro 4.0 - (Dibujo de bitmaps para Windows 95)
        NeoPaint           - (Dibujo de bitmaps para DOS)
        FractInt           - (Generacin de fractales para DOS)
        Image Alchemy      - (Convertidor de imgenes para DOS)


Pueden usar cualquier programa que grabe en el formato PCX, incluyendo
el Paintbrush, pero esos programas no nos dan ninguna informacin sobre
la paleta de colores, ni nos permiten manejarla como queramos, por lo
tanto, les recomiendo usar alguno de los programas de dibujo mencionados.

Otra cosa: Como se habrn dado cuenta, a partir de este tutorial se incluye
una versin en C++ de los programas de ejemplo. La versin en C++ no tiene
comentarios ni explicaciones, pero las ideas son las mismas que para Pascal,
por lo que no debe haber ningn problema. Si necesitan comentarios, revisen
los ejemplos en Pascal.

Tambin existen las versiones en C++ de los ejemplos de los tutoriales
anteriores. Estos programas se encuentran en un archivo llamado TUTC1-4.ZIP
el cual pueden encontrar en el mismo lugar que los tutoriales.


 *** NOTA IMPORTANTE ***

 En el tutorial anterior, les present la funcin LoadPCX. Haba un
 pequeo error en el cdigo que no permita cargar imgenes de un
 tamao mayor que 255 * 255 pxels. El error ya ha sido corregido
 y para los que les interese, consista en lo siguiente:

 Las variables X y Y en la funcin LoadPCX eran contadores que iban
 desde cero hasta X = DimX  y  Y = DimY, es decir, el tamao de la imagen.

 Un travieso demonio de las oscuras profundidades de mi mente decidi
 declarar a X y Y como variables de tipo BYTE, por lo que solamente
 podan tomar valores entre 0 y 255.

 Me di cuenta del error cuando trat de cargar una imgen de 320 * 200
 y se produjo un error de fin de archivo. El problema era que cuando
 X vala 255, el siguiente incremento ( inc(x) ) haca a X := 0.

 As es, cuando trabajan con un BYTE, 255 + 1 = 0.

 La solucin es declarar UNICAMENTE a X y Y como WORD. El error ya ha sido
 corregido en la unidad Mode_13.PAS. Si alguien encuentra ms errores,
 por favor escrbanme un e-mail para hacer las correcciones necesarias.

 Recuerden que la unidad MODE_13 ir cambiando contnuamente. Pronto
 escribiremos algunas funciones como PutPixel, HLine, ClearScreen, etc...
 en ensamblador para ganar velocidad.

 Bueno... vamos al biz...


QUE ES EL SCROLLING?


Seguramente todos han visto algn videojuego en el que el fondo se
desliza suavemente mientras un personaje o una nave espacial o cualquier
otra cosa se mueve libremente encima de ese fondo.

Tambin habrn visto alguna vez un "scroller de texto", eso es un
letrero que se va desplazando por la pantalla sobre un fondo que puede
ser esttico o no. Cuando una pelcula termina, se utiliza muchas veces
este efecto para presentar los crditos.

En este tutorial vamos a ver cmo desplazar regiones grandes de la pantalla
en cualquier direccin, haciendo que aparezcan por un lado de la pantalla y
desaparezcan por el otro. Este tipo de efecto se llama "scrolling", y
se utiliza principalmente en juegos, en demos y en alguna que otra
aplicacin.

Tambin se pueden desplazar regiones pequeas en la pantalla, como por
ejemplo una nave espacial en un juego, o un "pacman", o un peleador
de Street Fighter. Estas regiones pequeas que se desplazan libramente
por la pantalla son llamadas "sprites" y normalmente incluyen algn
tipo de animacin. Dejaremos el tema de los "sprites" para otro tutorial,
ya que se trabajan de una manera completamente diferente que el scrolling.

El efecto del scrolling consiste en dos pasos:

   1) Mover la zona de la pantalla en la direccin deseada
   2) Dibujar la siguiente lnea que aparece en el OTRO extremo
      de la pantalla



SCROLLING DE PANTALLA COMPLETA


          El scrolling se puede hacer en una direccin vertical, horizontal
          o diagonal.


          SCROLLING VERTICAL DE PANTALLA COMPLETA:

          Digamos que queremos desplazar la pantalla de abajo hacia arriba.
          Lo que tenemos que hacer es lo siguiente:

          1) Desplazar la pantalla una lnea hacia arriba. Esto se hace
          moviendo el bloque de memoria de la pantalla 320 bytes hacia
          atrs empezando desde la segunda lnea. La lnea superior
          desaparecer. El nmero total de bytes que vamos a mover
          es 63680, es decir 64000 - 320, lo cual es toda la pantalla
          menos una lnea (la primera).

          2) Dibujamos la siguiente lnea en la lnea inferior de la
          pantalla. La informacin de la lnea la podemos obtener de
          una pantalla virtual o de una imgen PCX.

          3) Si lo anterior lo hicimos en una pantalla virtual, (as es
          como lo vamos a hacer), copiamos la pantalla virtual a la VGA,
          (durante el retrazado vertical, por supuesto).

          4) Repetimos desde el paso 1.


          En Pascal, lo anterior se dice as:

          { Scroll de pantalla completa hacia arriba }
          1: Move(mem[VirSeg:320], mem[VirSeg:0], 63680);
          2: { Aqu dibujamos la siguiente lnea en VirSeg }
          3: VRetrace; CopyScreen(VirSeg, VGA);
          4: goto 1;


          As que no es tan difcil como parece. Para desplazar la
          pantalla de arriba hacia abajo, simplemente movemos la memoria
          de la pantalla 320 bytes hacia adelante y dibujamos la primera
          lnea en vez de la ltima, es decir:

          { Scroll de pantalla completa hacia abajo }
          1: Move(mem[VirSeg:0], mem[VirSeg:320], 63680);
          2: { Aqu dibujamos la siguiente lnea (la primera) en VirSeg }
          3: VRetrace; CopyScreen(VirSeg, VGA);
          4: goto 1;


          Es muy facil, no? El programa SCROLLV.PAS muestra cmo se hace
          el scroll vertical de pantalla completa. El programa genera un
          fondo ajedrezado y hace scroll hacia arriba y hacia abajo.



          SCROLLING HORIZONTAL DE PANTALLA COMPLETA:

          Para hacer el scrolling en sentido horizontal hacemos exactamente
          lo mismo que en el scrolling vertical, pero en vez de desplazar
          la pantalla 320 bytes hacia atrs o hacia adelante, la desplazamos
          solamente 1 byte. Vamos a ver un ejemplo, desplazando la pantalla
          hacia de derecha a izquierda:

          1: Move(mem[VirSeg:1], mem[VirSeg:0], 63999);
          2: { Aqu dibujamos la nueva lnea (la de la derecha) }
          3: VRetrace; CopyScreen(VirSeg, VGA);
          4: goto 1;

          Qu es lo que hace el cdigo anterior?

          Pues lo que pasa es que hemos recorrido todas las lneas de la
          pantalla un byte, es decir, un pxel hacia la izquierda. El primer
          pxel de cada lnea pasar a ser el ltimo de la lnea anterior,
          pero eso no importa porque la ltima lnea vertical de la pantalla
          va a ser reemplazada por lo que nosotros queramos.

          Para hacer el scrolling de izquierda a derecha, simplemente
          desplazamos la pantalla hacia adelante, es decir:

          1: Move(mem[VirSeg:0], mem[VirSeg:1], 63999);
          2: { Dibujamos la primera lnea vertical (la de la izquierda) }
          3: { ya saben qu poner aqu }


          Vean el programa SCROLLH.PAS, el cual es un ejemplo de scrolling
          horizontal de pantalla completa.



          SCROLLING DIAGONAL DE PANTALLA COMPLETA:

          Demonios, el scrolling diagonal s que es difcil... NAAAAHHHH!!!

          Ya se lo imaginaron???

          Pues solamente combinen el scrolling vertical y el horizontal
          y que obtienen??? CORRECTO!!! Scrolling diagonal!

          Vean el programa SCROLL1.PAS como ejemplo.



COMO DIBUJAR LA "SIGUIENTE" LINEA:

     Despus de haber desplazado la pantalla entera, es necesario dibujar
     la lnea siguiente, ya sea horizontal o vertical, de un lado o de otro.

     Para eso, debemos tener la informacin de la siguiente lnea en un
     arreglo o en una pantalla virtual. Supongamos que estamos haciendo
     un scrolling hacia arriba, entonces tendramos que dibujar contnuamente
     la lnea inferior. Esto lo podemos hacer as:

     for i := 0 to 319 do PutPixel(i, 199, c, VirSeg);

     en donde la variable c puede ser un valor obtenido de un arreglo o
     una pantalla virtual. Por ejemplo:

     for i := 0 to 319 do PutPixel(i, 199, buffer[i], VirSeg);

     Lo anterior obtiene los datos de la siguiente lnea a partir de
     un arreglo llamado buffer[].

     No es estrictamente necesario mover una lnea en cada ciclo, de hecho,
     para acelerar el efecto, se pueden hacer varias cosas:

          1) Mover ms de una lnea en cada ciclo.
          2) No desplazar la pantalla entera, sino solamente una regin.
          3) Utilizar rutinas en ensamblador.
          4) Utilizar el modo X en lugar del modo 13.

     Por ahora, solamente vamos a ver los primeros dos incisos. El
     ensamblador lo dejaremos para cuando realmente necesitemos velocidad,
     es decir, cuando hagamos el primer demo. El modo X nos permite hacer
     un scrolling utilizando solamente el hardware de la tarjeta de video,
     dejndole mucho tiempo libre al procesador.

     En el ejemplo scroll1.pas se hace el scrolling en diagonal,
     pero desplazando la pantalla 4 lneas en cada ciclo,
     (2 verticales y 2 horizontales), por lo que la velocidad
     aumenta considerablemente.

     El ejemplo es una combinacin de los dos primeros ejemplos pero con
     algunas modificaciones.


     Ahem! Antes de continuar... pido disculpas. En este momento estoy
     retomando la actividad de escribir este tutorial, aproximadamente
     un mes despus de haberlo comenzado. No fu posible terminarlo antes
     de vacaciones pero la ventaja es que los siguientes dos o tres
     tutoriales ya estarn escritos para cuando lean esto, por lo tanto
     no habr mas retrasos (excepto por los retraZos verticales).

     Perdn otra vez... lo de los retrazos fu un mal chiste. Mejor
     continuemos con el tutorial...


SCROLLING EN UNA REGION DE LA PANTALLA:


     Bueno, ya vimos cmo desplazar la pantalla entera. Ahora vamos
     a ver cmo desplazar solamente una regin de la pantalla.

     La forma en que vamos a hacerlo no es la nica ni la mejor, pero
     seguramente es la ms sencilla.

     Lo que vamos a hacer es primeramente definir la regin que queremos
     desplazar, y para hacerlo un poco ms general, digamos que la regin
     a desplazar es el rectngulo definido por los siguientes puntos:

                 ----------------------------------------
                 |                                      |
                 |                                      |
                 |                                      |
                 |         (Xmin, Ymin)                 |
                 |              .-------------------    |
                 |              |                  |    |
                 |              |                  |    |
                 |              |                  |    |
                 |              |                  |    |
                 |              |                  |    |
                 |              -------------------.    |
                 |                          (Xmax, Ymax)|
                 ----------------------------------------

     ( Tienen derecho a no decir nada sobre mis dibujos en ASCII )


     Ahora lo nico que tenemos que hacer es desplazar TODOS los puntos
     en la direccin deseada y dibujar la siguiente lnea.

     Por ejemplo, si quisiramos desplazar la regin anterior hacia arriba,
     tendramos que hacer lo siguiente:

             for Y := Ymin to (Ymax - 1) do
                 for X := Xmin to Xmax do
                     PutPixel(x, y, GetPixel(x, y+1, VirSeg), VirSeg);

             { Aqu dibujan la siguiente lnea horizontal (en Ymax) }


     Entendieron? Eso espero, porque realmente es muy fcil.

     Supongamos que ahora queremos desplazar la misma regin hacia la
     izquierda. Entonces el procedimiento se ve as:

             for X := Xmin to (Xmax - 1) do
                 for Y := Ymin to Ymax do
                     PutPixel(x, y, GetPixel(x+1, y, VirSeg), VirSeg);

             { Aqu dibujan la siguiente lnea vertical (en Xmax) }


     Y eso es todo. Como ya les haba dicho, la "siguiente lnea" la pueden
     dibujar a partir de un arreglo o buffer que ya tengan en la memoria
     o a partir de otra pantalla virtual. Ese es su problema :)

     Incluso se pueden tener varias regiones de la pantalla, cada una
     desplazndose en una direccin y con una velocidad diferentes.
     Solamente hay que controlar cada deslizamiento por separado.
     (ver programa de ejemplo SCROLL2.PAS )

     La desventaja de este mtodo es su lentitud. Conviene usar
     lo ms que se pueda la funcin Move del pascal para desplazar
     varios pxels a la vez, o an mejor, utilizar ensamblador para
     realizar todo el efecto. No debe de ser muy difcil.

     Es muy poco comn que se realize un scrolling hacia la derecha en
     una regin de la pantalla en un demo, pero se utiliza a veces en
     los juegos de "scrolling omnidireccional" y en muchas aplicaciones
     grficas, pero no en la siguiente seccin:


LETREROS:

     Los letreros, o mejor conocidos en mi rancho como "text scrollers",
     simplemente son una serie de palabras que se van desplazando de un
     lado a otro de la pantalla. Lo ms comn es que se desplacen de
     derecha a izquierda o de abajo hacia arriba... por que? Pues porque
     as son ms fciles de leer.

     La forma de realizar un letrero es bsicamente la misma que la del
     scrolling en una regin de la pantalla. La diferencia est en que
     muchas veces, el letrero aparece "flotando" sobre el fondo, es decir,
     el fondo permanece esttico y las letras se mueven.

     Digamos que tenemos una fotografa en el fondo y queremos desplazar
     un letrero sobre ese bello paisaje, que puede ser cualquier cosa,
     desde Marte hasta tu bao. Para verlo mejor, voy a hacer un "dibujo":

           --------------------------------
           |                              |
           |            /\                |
           |          /    \       -------------------------------------
           |        /        \     | Este es el letrero en movimiento  |
           |      / |  ----  | \   -------------------------------------
           |        |  |  |  |            |
           |        |  |  |  |            |
           |        ----------            |
           --------------------------------

     El letrero "entra" por la parte derecha de la pantalla y sale
     por la parte izquierda. Incluso podra ser un letrero "infinito"
     o repetitivo. El problema es que si desplazamos el letrero de la
     forma que hemos visto (mediante scrolling horizontal), la pantalla
     quedara as despus de algn tiempo:

           --------------------------------
           |                              |
           |            /\                |
           |      /    \       -------------------------------------
           |    /        \     | Este es el letrero en movimiento  |
           |  / |  ----  | \   -------------------------------------
           |        |  |  |  |            |
           |        |  |  |  |            |
           |        ----------            |
           --------------------------------

     Lo que sucede es que cuando desplazamos la zona en la que se mueve
     el letrero, tambin desplazamos el fondo, por lo tanto tenemos
     que buscar la manera de desplazar UNICAMENTE los puntos que forman
     el letrero y reemplazar el fondo en cada paso. De forma que
     quede algo como esto:

           --------------------------------
           |                              |
           |            /\                |
           |          /    -------------------------------------
           |        /      | Este es el letrero en movimiento  |
           |      / |  -----------------------------------------
           |        |  |  |  |            |
           |        |  |  |  |            |
           |        ----------            |
           --------------------------------

     Adems, si se fijan, el propio fondo del letrero sobreescribe al fondo
     de la pantalla por lo que se ve un gran rectngulo rodeando a las
     letras. Es MUCHO mejor cuando no se ve ese rectngulo, ya que el
     letrero parece estar "flotando" sobre el fondo. En ASCII se ve as:

           --------------------------------
           |                              |
           |            /\                |
           |          /    \              |
           |        /    Este es el letrero en movimiento
           |      / |  ----  |            |
           |        |  |  |  |            |
           |        |  |  |  |            |
           |        ----------            |
           --------------------------------

     Espero que se imaginen la idea, pero si no, ejecuten rpidamente el
     programa SCROLL2.PAS para ver de qu estoy hablando.

     (Recuerden usar la unidad MODE_13 de ESTE tutorial)


     La forma de lograr el efecto es la siguiente:

        1.- Asegurarse de que la imagen de letrero tenga un color de
            fondo uniforme, preferiblemente el color 0. Es decir, que
            solamente las letras tienen colores diferentes de cero.

            Por ejemplo, esta podra ser la letra "A":

                         ------------
                         |0000110000|
                         |0001111000|
                         |0011001100|
                         |0111111110|
                         |0110000110|
                         |0110000110|
                         ------------

        2.- Formar un arreglo cuyas dimensiones sean las de la zona de
            la pantalla por la que el letrero se desplazar y llenar
            el arreglo con ceros.

               var Letrero : array[0..319, 0..19] of byte;
               { Esto nos da una regin de 320 * 20 pxels }


        3.- Para desplazar el letrero, NO desplazamos la pantalla, sino
            que desplazamos en el arreglo mencionado anteriormente, de
            forma parecida a lo que hacamos para rotar la paleta.

               for x := 0 to 318 do
                   for y := 0 to 19 do
                       Letrero[x, y] := Letrero[x+1, y];

            Y luego dibujamos la siguiente lnea del letrero, obteniendo
            los datos de un arreglo o un juego de caracteres:

               for y := 0 to 19 do
                   Letrero[319, y] := Caracter['A', cx, y];
               inc(cx);
               if cx = 10 then cx := 0;

            { El cdigo anterior supone que tenemos un juego de caracteres
              almacenado en el arreglo Caracter, y que la anchura de cada
              caracter es 10 y la altura es 20. }


        4.- Dibujan el letrero en la pantalla, pero ANTES restauran la
            imgen del fondo:

                   CopyScreen(FondoSeg, VirSeg);
                   { Esto copia la pantalla con la imgen de fondo a
                     una pantalla virtual }

            Cuando dibujen el letrero, solamente dibujan los pxels que
            tienen un color DIFERENTE de cero (o diferente del que usaron
            como fondo en la imagen del letrero).

                 for y := 0 to 19 do
                     for x := 0 to 319 do
                         if Letrero[x, y] <> 0 then
                            PutPixel(x, y, Letrero[x, y], VirSeg);

            Recuerden que YO estoy usando el color 0 como color de fondo
            pero en realidad puede ser cualquier color.


        Y creo que eso es todo (PFFFIUFF!).

        Les repito que estos mtodos no son los mejores, pero son fciles
        de implementar. La gran desventaja es que consumen MUCHA memoria,
        ya que se necesita un gran arreglo de 320*N pxels para el letrero
        en movimiento y adems se necesita otro gran arreglo para guardar
        la imformacin de los caracteres o de las "siguientes lneas" y
        para las DOS pantallas virtuales. Eso es alrededor de 200 Kb!!!



CONCLUSIONES:

     - Ummmm.... el scroll es un efecto muy bonito.

     - Hmmmm.... muy lento cuando se hace en el modo 13h

     - Uhhhh.... necesita un ****** de memoria

     - Cuando veamos el modo X, terminarn nuestros problemas.


EJERCICIOS:

     - Traten de disear un sencillo juego de caracteres, por ejemplo,
       nicamente de la 'A' a la 'Z' y almacenen la informacin en un
       arreglo y luego utilcenlo para realizar un scroller de texto
       en el que puedan escribir cualquier frase.

     - Hagan un scroller de texto que se desplace de abajo hacia arriba
       como se ve al final de una pelcula (la parte de los crditos).

     - Y para los que se crean realmente muy scalepunta:

       Hagan un scroller de texto como el que aparece al principio de la
       pelcula de STAR WARS. (Si no han visto la pelcula, primero vayan
       a ver a un psiquiatra).

       Y si eso se les hace fcil, aadan algunas un campo de estrellas
       en el fondo, pero EN MOVIMIENTO.

       Un campo de estrellas, solamente son muchos pxels movindose en
       la misma direccin.



FIN DEL TUTORIAL #5


     Despus de una larga ausencia, los tetoriales han regresado. En el
     siguiente "nmero", vamos a ver un poco de animacin sencilla. Tambin
     empezar a acelerar un poco las cosas con ensamblador. No se preocupen,
     solamente sern algunos procedimientos como PutPixel, ClearScreen,
     CopyScreen, etc...

     Este NO es un tutorial de ensamblador, por lo tanto, los procedimientos
     escritos en asm (ensamblador) no sern explicados y no tendrn muchos
     comentarios, PERO si a alguien le interesa saber cmo funciona alguno
     de los proc's, solamente escrbanme un e-mail.

     Hasta ahora el plan es el siguiente:

           - TUT 6 : Animacin. (Algo sencillo, nada del otro mundo).
           - TUT 7 : Efectos especiales. (Interferencia, plasma y llamas).

     Y creo que despus empezaremos a ver la tercera dimensin desconocida.

     Ahh, y por cierto, me preguntaba si quisieran que este tutorial
     fuera presentado en forma de revista electrnica, es decir, hacer
     un programa ejecutable que mostrara un men con todos los temas
     para un rpido acceso (adems del archivo de texto completo, como
     hasta ahora). Si recibo suficientes "si", entonces lo har tambin
     de esa forma. Tal vez uno de los siguientes tutoriales lo use como
     prueba para esta idea.


     Hmmm... por ltimo, gracias a todos los que han escrito, y tambin
     al Chivo por el trmino "Tetorial" (te acuerdas de ese demo de la
     cascada en la atari? Solo era una rotacin de paleta. Ha!).


     Y ahora doy paso a la seccin que a todos les vale m*dre:


RIMAS DE LA SEMANA:


      "We gotta make rules,
       never ever ever with the fake crews"

       - Por: Q-Tip


      "It ain't a crime if you don't get caught
       it ain't a sale if it don't get bought
       it ain't a show if I don't get paid
       she ain't a ho if you don't get laid"

       - Por: Everlast


      "One, two,
       Freddy comes for you"

       - Por: Wes Craven (?)


      "Let it flow,
       let yourself go,
       slow and low
       that is the tempo"

       - Por: Beastie Boys


      HEY! Manden sus propias rimas y sern publicadas aqu!!!
      Hasta podramos hacer un concurso :)


-------------------------E - E - Eso es todo, amigos ----------------------
