
--------------------------------------------
      Tutorial de programacin grfica
                  Por: FAC
     -----------------------------------
           #7 - Efectos especiales
--------------------------------------------


Hola.

Despus de un laaaargo tutorial sobre animacin y ensamblador, vamos a
ver tres efectos sencillos que se pueden generar haciendo uso nicamente
de tablas precalculadas, rotacin de paleta y algunas ecuaciones extraas.

Recuerden que junto con este tutorial se encuentra el archivo TETDEMO.ZIP
que contiene un demo y parte de su cdigo fuente. Descompriman el archivo
en un directorio aparte y ejecuten el demo. Y no olviden leer el archivo
LEEME.TXT. El demo necesita un Pentium, pero podra funcionar en un 486DX2
con la opcin No Sound (sin msica).


Si tienen dudas, preguntas o sugerencias referentes a los tutoriales,
escrbanme a:

           Alfonso Alba C.
   e-mail: ganzo@galia.fc.uaslp.mx
 telfono: 13-34-71



EFECTOS ESPECIALES:
-------------------

     Supongo que todos tenemos una idea de los que es un efecto especial,
     incluso, en los tutoriales anteriores hemos logrado algunos efectos,
     que aunque son comunes y corrientes, siguen siendo efectos.

     Algunos ejemplos son: los efectos Fade In / Fade Out, efectos mediante
     rotacin de paleta, scrolling e incluso la animacin.

     En este "episodio" vamos a ver otros tres efectos comunes y corrientes,
     aunque tal vez no muy conocidos por algunos de ustedes. Esos efectos
     son interferencia, plasma y fuego.

     En algunos de los siguientes tutoriales veremos ms efectos comunes
     y corrientes pero solo algunos. Este tipo de efectos ya estn pasando
     de moda y lo mejor sera que ustedes inventaran o experimentaran con
     nuevos efectos.


INTERFERENCIA:
--------------

     Este es un efecto muy sencillo. De qu se trata? Bueno, enciendan
     su televisin y sintoncenla en el canal 38 o cualquier otro canal
     por el cual no se transmita nada. Lo que ven en la pantalla es el
     efecto que queremos lograr. Interferencia.

     El efecto es an mejor si aparece repentinamente sobre cualquier
     otra cosa que aparezca en la pantalla, como si realmente se
     produjera una interferencia.

     Pero cmo generamos ese efecto en una computadora?

     Pues hay varias formas de hacerlo. Una de ellas (la ms fcil) consiste
     en generar una pantalla virtual y llenarla de pxels de colores al
     azar. El rango de colores no debe ser muy amplio, digamos, entre 1 y 16,
     y luego en la paleta de colores fijamos un degradado de grises en los
     colores 1 al 16. Para obtener un tono de gris, simplemente fijamos
     el mismo valor de intensidad para las componentes rojo, verde y azul
     de un color.

     Todo lo anterior se puede expresar en Pascal de esta forma:


             var VirScr : PTVirtual;
                 VirSeg : word;
                 pal : TPalette;

             procedure IniciaInterferencia;
             var x, y : word;
             begin
                  { Inicializamos la pantalla virtual }
                  SetupVirtual(VirScr, VirSeg);

                  { Llenamos la pantalla virtual con pxels al azar }
                  for y := 0 to 199 do
                      for x := 0 to 319 do
                          PutPixel(x, y, random(16) + 1, VirSeg);

                  { Establecemos un degradado de grises en la paleta }
                  for x := 1 to 16 do
                  begin
                       pal[x][0] := (x - 1) * 16;
                       pal[x][1] := pal[x][0];
                       pal[x][2] := pal[x][0];
                  end;
             end;


     Bien, ya tenemos nuestra pantalla de interferencia almacenada en
     VirScr. Ahora, cuando queramos hacer visible la interferencia,
     simplemente copiamos la pantalla virtual a la pantalla VGA y hacemos
     una rotacin de paleta sobre los colores 1 a 16:


             procedure HazInterferencia;
             begin
                  { Copiamos la pantalla virtual a VGA }
                  CopyScreen(VirSeg, VGA);

                  { Rotamos la paleta hasta que se presione una tecla }
                  while not keypressed do
                  begin
                       RotatePalette(pal, 1, 16);
                       VRetrace;
                       SetPalette(pal);
                  end;
                  readkey;
             end;


     Y eso es todo! Ya tenemos nuestra interferencia funcionando.

     Pero como les haba dicho, lo interesante es que la interferencia
     INTERFIERA con algn efecto que se est realizando en ese momento.
     Para ello, podemos tener nuestro efecto funcionando normalmente y
     aplicar la interferencia segn cierta probabilidad.

     Digamos, por ejemplo, que tenemos un fondo esttico almacenado en
     otra pantalla virtual (FondoScr) y tenemos un procedimiento llamado
     DibujaObjeto, el cual dibuja un objeto tridimensional sobre el fondo.

     Tambin tendremos nuestra pantalla de interferencia en la variable
     InterScr (InterSeg para el segmento), de forma que VirScr se usar
     como una pantalla virtual extra.

     Podramos hacer que la interferencia surgiera al azar mientras el
     objeto tridimensional se desplaza sobre el fondo esttico:


            procedure HazInterferencia;
            begin
                 while not keypressed do
                 begin
                      if random(10) = 0 then CopyScreen(InterSeg, VirSeg)
                                        else CopyScreen(FondoSeg, VirSeg);
                      DibujaObjeto(VirSeg);
                      MueveObjeto;
                      RotatePalette(pal, 1, 16);
                      VRetrace;
                      CopyScreen(VirSeg, VGA);
                      SetPalette(pal);
                 end;
                 readkey;
            end;


     En el procedimiento anterior, la interferencia aparece cada vez que
     random(10) devuelve un 0, es decir, con una probabilidad de 1 / 10.

     Otra cosa es que el objeto tridimensional aparece SOBRE la interferencia
     como si no le afectara, debido a que dibujamos el objeto DESPUES de
     haber copiado la pantalla de interferencia a la pantalla virtual.

     Si queremos que el objeto tambin sea eclipsado por la interferencia,
     entonces debemos eliminar la lnea DibujaObjeto(VirSeg) y cambiar la
     lnea if..then por una como sta:

              if random(10) = 0 then CopyScreen(InterSeg, VirSeg);
                                else begin
                                          CopyScreen(FondoSeg, VirSeg);
                                          DibujaObjeto(VirSeg);
                                     end;


     Los procedimientos anteriores utilizan tres pantallas virtuales:
     FondoScr, InterScr y VirScr. Eso es mucha memoria (192 Kb).

     Para ahorrar un poco de memoria podemos olvidarnos de VirScr y
     dibujar todo directamente a VGA, pero eso podra causar parpadeos
     o regiones invisibles en sprites.

     La mejor solucin al problema consiste en usar memoria de "otros lados",
     pero eso corresponder a otro tutorial. Por ahora, trataremos de
     ahorrar toda la memoria posible y no usar ms de 2 pantallas virtuales.


     Otra forma de lograr el efecto de interferencia, es construr varias
     pantallas de interferencia, cada una diferente de la otra:


               var InterScr : array[0..3] of PTVirtual;
                   InterSeg : array[0..3] of word;

               procedure GeneraPantallasDeInterferencia;
               var i, x, y : word;
               begin
                    for i := 0 to 3 do
                        for y := 0 to 199 do
                            for x := 0 to 319 do
                                PutPixel(x, y, random(16) + 1, InterSeg[i]);
               end;


     La regin de la paleta usada por la interferencia se llena de la misma
     manera con un degradado de grises:

            for i := 1 to 16 do
            begin
                 pal[i][0] := (x - 1) * 16;
                 pal[i][1] := pal[i][0];
                 pal[i][2] := pal[i][0];
            end;


     Y para realizar el efecto, simplemente conmutamos entre las diferentes
     pantallas de interferencia:


            procedure HazInterferencia;
            var n : byte;
            begin
                 n := 0;
                 while not keypressed do
                 begin
                      VRetrace;
                      CopyScreen(InterSeg[n], VGA);
                      inc(n);
                      if n > 3 then n := 0;
                 end;
                 readkey;
            end;


     Este mtodo necesita an ms pantallas virtuales que el anterior,
     por lo tanto es muy poco recomendable a menos de que se utilice
     memoria de otros lugares, como memoria XMS o EMS.

     Tambin se podran combinar los dos mtodos anteriores y hacer una
     rotacin de paleta al mismo tiempo que se conmutan las pantallas.

     El programa INTERFER.PAS utiliza el primer mtodo, pero dibujando
     todo directamente a VGA con lo cual se desecha la tercera pantalla
     virtual. Sin embargo, esto causa que la regin superior del sprite
     no se vea cuando est cerca de la parte superior de la pantalla.
     Esto es debido a que la actualizacin de la pantalla, el dibujo del
     sprite y la activacin de la paleta no alcanzan a ser realizadas
     todas en el intervalo de retrazado vertical. Se puede alterar el
     programa para inclur otra pantalla virtual y eliminar este problema,
     pero eso es hablar de OTRA p. virtual.


PLASMA:
-------

     Cuntos de ustedes han visto un "plasma"? Probablemente no muchos,
     ya que los demos no son algo muy comn en Mexico.

     Creo que la nica forma de saber qu es un plasma es viendo uno,
     as que les aconsejo ejecutar alguno de los ejemplos de plasmas
     (PLASMA1.PAS o PLASMA2.PAS) para que se den una idea de lo que es.

     Ya lo vieron? Bien... ahora, cmo se hace?

     Para empezar, hay que distinguir entre dos tipos de plasma:
     el plasma esttico y el plasma generado en tiempo real.

     No se si existan otros tipos de plasmas pero estos son los ms comunes.


PLASMA ESTATICO:
----------------

     Este es de lo ms fcil de implementar. Consiste simplemente en
     un imagen fractal (llamada plasma :) y una rotacin de paleta.

     El nico problema que se nos presenta aqu es cmo generar la imagen
     fractal. Bueno, existe un programa llamado FractInt que genera
     todo tipo de fractales, incluyendo plasmas. En el programa de ejemplo
     SPLASMA1.PAS yo us una imagen producida por FractInt. Esta es
     la forma ms fcil de conseguir un plasma.

     Despus de que tenemos la imagen, digamos en el archivo 'plasma.pcx',
     lo nico que hay que hacer es rotar la paleta.

     En Pascal, la idea anterior se escribe as:


                var pal : TPalette;
                begin
                     SetMode13;   { iniciamos el modo grfico }
                     FadeOut(0);  { ponemos todos los colores en negro }
                     LoadPCX('plasma.pcx', VGA, 320, 200, 0, 0, pal);

                     while not keypressed do
                     begin
                          RotatePalette(pal, 0, 255);  { rotamos la paleta }
                          VRetrace;      { Esperamos al retrazado vertical }
                          SetPalette(pal);   { y activamos la nueva paleta }
                     end;
                end;


     Y ya tenemos un plasma!  Fcil.

     Sera mejor an si no tuviramos que depender de FractInt y poder
     generar el fractal por nosotros mismos ya que de esa forma podramos
     modificar fcilmente la apariencia de nuestro plasma.


     Bueno, yo no conozco la teora detrs de la generacin de plasmas
     fractales, pero un viejo programa llamado ACPLASMA.PAS, escrito por
     Alex Chalfin, utiliza un algoritmo relativamente sencillo para
     generar el fractal. La idea bsica es esta:

     Tenemos una funcin GeneraPlasma(), la cual toma cuatro parmetros
     que son las coordenadas de la regin rectangular en donde se genera
     el plasma. Nosotros llamaremos a la funcin de la siguiente forma:

                GeneraPlasma(0, 0, 320, 200);

     para que dibuje el plasma en toda la pantalla.

     El procedimiento GeneraPlasma, primero comprueba que la distancia
     entre los dos puntos que toma como parmetros sea mayor que 1.
     Si la distancia es menor que 1, entonces ah termina el procedimiento.

     Despus se hace una llamada al procedimiento NuevoColor, el cual
     calcula el color de los 4 puntos medios de la regin rectangular:

            x1, y1                                        x2, y1
             ----------------------*------------------------
             |                     ^                       |
             |                     |                       |
             |                     |                       |
             |                     |                       |
             |               fijamos estos                 |
             *  <------------   puntos    -------------->  *
             |                                             |
             |                     |                       |
             |                     |                       |
             |                     |                       |
             |                     v                       |
             ----------------------*------------------------
            x1, y2                                        x2, y2


     El color que se le da a cada uno de estos puntos es igual al
     promedio de los colores de las dos esquinas adyacentes al punto
     mas un valor al azar que es proporcional a la distancia entre
     los dos puntos adyacentes. Nada complicado ;)

     Por ejemplo, el color que le correspondera al punto medio del
     lado superior del rectngulo sera el siguiente:


          dist := abs(x1 - x2)
          color := ((GetPixel(x1, y1) + GetPixel(x2, y1) div 2) +
                   random(dist) - dist div 2;


     El -dist div 2  se utiliza para que el valor que aadimos al azar
     pueda ser tanto positivo como negativo.

     En el programa de ejemplo (SPLASMA2.PAS) se aade adems una constante
     de "rugosidad", la cual indica qu tanto cambian los colores en el
     fractal. Esta constante nicamente multiplica el valor que se le
     suma al azar al color final.


     Bueno, despus de que hemos fijado los cuatro puntos medios, debemos
     calcular el color del punto central.

     El color del punto central es simplemente el promedio de los colores
     de los puntos de las cuatro esquinas, es decir:

        color := (GetPixel(x1, y1) + GetPixel(x2, y1) +
                  GetPixel(x1, y2) + GetPixel(x2, y2)) div 4;

     Despus de hacer eso, en teora tenemos cinco puntos dibujados en
     las posiciones que se muestran con un asterisco:

            x1, y1                                        x2, y1
             ----------------------*------------------------
             |                                             |
             |                                             |
             |                                             |
             |                                             |
             |                                             |
             *                     *                       *
             |                                             |
             |                                             |
             |                                             |
             |                                             |
             |                                             |
             ----------------------*------------------------
            x1, y2                                        x2, y2


     Si trazamos una lnea vertical imaginaria que pase por el punto central
     y otra lnea horizontal, entonces tendremos nuestro rectngulo
     dividido en 4 rectngulos menores.

     Entonces, utilizando RECURSION, llamamos al procedimiento GeneraPlasma,
     pero ahora para cada uno de los cuatro rectngulos obtenidos y
     repetimos el procedimiento hasta que la distancia entre las esquinas
     sea igual a 1. De esta forma, llenamos la pantalla de plasma.

     Creo que todo ser un poco ms entendible si ven el programa
     SPLASMA2.PAS.  Probablemente toda la explicacin anterior fu
     muy mala, pero eso es todo lo que puedo deducir del algoritmo.
     No tengo idea de porqu debe ser as ni en qu est basado, pero
     supongo que cambiando algunos parmetros y usando los valores
     de otros puntos (no necesariamente las esquinas) se pueden obtener
     plasmas ms interesantes.

     Antes de generar el plasma, se pueden colocar algunos puntos
     al azar en cualquier parte de la pantalla, para modificar la
     forma del fractal puesto que la generacin del plasma se basa
     en los puntos que ya han sido colocados. Estos puntos "extras"
     se conocen como "semillas", y debido a que no han sido originados
     por el algoritmo del fractal, pueden causar algunas regiones
     contrastantes que pueden no verse muy bien.


LA PALETA DE COLORES:
---------------------

     Una vez que hemos generado nuestro plasma, el siguiente aspecto
     a tomar en cuenta es cmo vamos a establecer nuestra paleta de
     colores para lograr un efecto agradable.

     La idea principal es hacer dos o mas transciciones entre dos
     o mas colores. Por ejemplo, podramos hacer que la paleta cambiara
     de rojo a verde, luego de verde a azul, luego de azul a amarillo
     y finalmente de amarillo a rojo.

     Esto lo podemos lograr en Pascal con el siguiente cdigo:


          var pal : TPalette;

          procedure GeneraPaleta;
          var i : byte;
          begin
               for i := 0 to 63 do
               begin
                    pal[i][0] := 63 - i; { disminuye el rojo }
                    pal[i][1] := i;      { y aumenta el verde }
                    pal[i][2] := 0;      { nada de azul }
               end;
               for i := 0 to 63 do
               begin
                    pal[i + 64][0] := 0;        { nada de rojo }
                    pal[i + 64][1] := 63 - i;   { disminuye el verde }
                    pal[i + 64][2] := i;        { y aumenta el azul }
               end;
               for i := 0 to 63 do
               begin
                    pal[i + 128][0] := i;       { aumentamos el rojo }
                    pal[i + 128][1] := i;       { y tambin el verde }
                    pal[i + 128][2] := 63 - i;  { y disminuye el azul }
               end;
               for i := 0 to 63 do
               begin
                    pal[i + 192][0] := 63;      { El rojo al mximo }
                    pal[i + 192][1] := 63 - i;  { disminuye el verde }
                    pal[i + 192][2] := 0;       { y nada de azul }
               end;
          end;


     Lo importante siempre es que la transicin entre colores sea
     suave. La nica forma de saber con qu combinacin de colores
     un plasma determinado se ve bien es haciendo varias pruebas.



PLASMAS EN TIEMPO REAL:
-----------------------

     Los plasmas estticos ofrecen muy pocas variantes. Fuera de cambiar
     los colores de la paleta y aadir algunas "semillas", los fractales
     de plasma son muy similares y carecen de movimiento real.

     Existe otro tipo de plasmas en los cuales cada cuadro se calcula
     en tiempo real, lo cual significa estar regenerando el plasma
     constantemente. La ventaja de esto es que como no tenemos todo el
     tiempo del mundo para generar los cuadros, debemos usar un mtodo
     MUCHO ms sencillo para generar el plasma que el algoritmo fractal.

     La forma en que se genera el plasma es diferente. Ahora, en lugar
     de subdividir la pantalla recursivamente, simplemente la recorreremos
     punto por punto. Y para cada punto, calcularemos su color mediante
     la suma de varias funciones, las cuales estarn previamente calculadas
     y almacenadas en arreglos.

     Matemticamente, un plasma de este tipo es simplemente una
     representacin de la suma de varias funciones.

     Por lo tanto, para cada punto de la pantalla, calculamos un color
     de la siguiente forma:

        color := Tabla1[p1] + Tabla2[p2] + Tabla3[p3] + ...

     donde Tabla1, Tabla2, etc... son tablas de funciones precalculadas,
     y p1, p2, etc... son los ndices que le corresponden a cada punto.

     Estos ndices deben ir cambiando conforme nos movemos en el plasma
     y tambin en cada cuadro. Eso es lo que da el efecto de movimiento.


     Los problemas que se nos presentan aqu son:

         1.- Necesitamos varias tablas precalculadas (mucha memoria)
         2.- Necesitamos mantener el control de varios ndices


     El primer problema es fcil de resolver. Simplemente usaremos una
     o dos tablas de la siguiente manera:

           color := Tabla1[p1] + Tabla1[p2] + Tabla2[p3] + Tabla2[p4] + ...

     Es decir que las funciones que se intersectan NO tienen que ser
     diferentes, solamente estn "desfasadas". Con una o dos tablas
     se pueden producir plasmas muy llamativos.


     El segundo problema tambin es fcil de resolver. Dos de los ndices
     pueden ser las coordenadas del punto para el que estamos calculando.
     Otros ndices cambiarn segn nos movemos en el eje X y otros cambiarn
     segn nos movemos en el eje Y.

     Por lo tanto, si nuestro plasma consistiera en la suma de 6 funciones,
     utilizando dos tablas, el procedimiento de dibujo podra ser algo as:


                { Cuatro de los ndices son pos1, pos2, pos3 y pos4 }

                procedure DibujaPlasma;
                var x, y : word;
                    color, p1, p2, p3, p4 : byte;
                begin
                     p3 := pos3;
                     p4 := pos4;
                     for y := 0 to 199 do
                     begin
                          p1 := pos1;
                          p2 := pos2;
                          for x := 0 to 199 do
                          begin
                               color := Tabla1[p1] + Tabla1[p2] +
                                        Tabla1[p3] + Tabla1[p4] +
                                        Tabla2[x] + Tabla2[y];
                               PutPixel(x, y, color, VirSeg);
                               inc(p1);
                               inc(p2);
                          end;
                          inc(p3);
                          inc(p4);
                     end;
                end;


     Como pueden ver, utilizamos dos tablas precalculadas. Dos de los
     ndices son las coordenadas del punto (x, y). Otros dos de los
     ndices cambian sobre el eje X  y los otros dos sobre el eje Y.

     La primera cosa importante que hay que notar es que los ndices
     originales (que estn en las variables pos1, pos2, pos3 y pos4)
     se conservan. Estos ndices solamente deben cambiar en cada cuadro,
     pero no durante el proceso de dibujo, ya que se perdera la
     continuidad.

     La segunda cosa importante es la forma en que estn declaradas las
     variables color, p1, p2, p3 y p4. Estan declaradas como BYTES.

     Esto es MUY importante, ya que de esta forma aseguramos que su
     valor est SIEMPRE en el rango de 0 a 255. Si la variable vale
     255 y le sumamos 1, su siguiente valor ser 0, lo cual es perfecto
     si usamos funciones cclicas como seno o coseno.

     Lo anterior nos lleva a un aspecto muy importante:


COMO GENERAR LAS TABLAS PRECALCULADAS:

     Debido a que buscamos una transicin suave entre los colores, TODAS
     las funciones usadas para generar las tablas deben de ser CONTINUAS.

     As es, fanticos matemticos. El lmite de las funcin evaluada
     en 'x' cuando 'x' tiende a 'y' debe ser igual a la funcin evaluada
     en 'y' para todo valor de 'x' dentro del dominio de la funcin.

     Para los ndices que NO son las coordenadas del punto, es decir,
     para p1, p2, p3, etc... lo ms conveniente es usar funciones cclicas,
     siendo las ms comunes el seno y el coseno. Ya que los ndices van
     de 0 a 255, nos conviene definir la tabla de forma que abarque un
     periodo entero de la funcin. Recuerden que el seno y el coseno
     nos dan valores entre -1 y 1, por lo tanto, tendremos que hacer
     algunas operaciones extra para obtener un valor dentro de un rango
     de colores en la paleta, por ejemplo, entre 0 y 63.


             for i := 0 to 255 do
                 Tabla1[i] := round(sin(2 * Pi * i / 255) * 31) + 32;

     Bueno, vamos a analizar un poco esto:

     Para obtener un periodo completo de la funcin seno, debemos evaluarla
     entre 0 y 2*Pi.

     Pero nuestra variable i va de 0 a 255, por lo tanto, si dividimos
     i entre 255, el resultado estar entre 0 y 1.

     Tomamos ese resultado (i / 255) y lo multiplicamos por 2*Pi para
     obtener valores entre 0 y 2*Pi. Ya tenemos un periodo de la funcin.

     La expresin sin(2 * Pi * i / 255) nos da valores entre -1 y 1.
     Por lo tanto, una multiplicacin por 31 nos devuelve valores entre
     -31 y 31. Finalmente sumamos 32 para obtener un rango entre 1 y 63.

     Pero los colores en la paleta van de 0 a 255. Porqu limitamos
     el rango hasta 63??? Bueno, la razn es muy simple. Recuerden que
     vamos a SUMAR varias funciones. Si cada una de estas funciones nos
     devuelve un nmero entre 0 y 255, los cambios en el plasma seran
     demasiado grandes. Algo as como una alta "rugosidad" en el plasma
     fractal que generamos anteriormente.

     Por eso es que limitamos el rango de cada funcin a un valor razonable,
     como 32 o 64, con lo cual la suma de varias funciones no ocasiona
     demasiados "overflows".


     La funcin a la que se aplican como ndices las coordenadas de los
     puntos no tiene por que ser cclica. De hecho, se producen mejores
     resultados cuando esa funcin no es cclica.

     Ya que la coordenada X va de 0 a 319, conviene tener la tabla con
     una dimensin de 0 a 319.

                   var Tabla2 : array[0..319] of byte;

     O algo as. La funcin que se le asigna a esta tabla puede ser
     prcticamente cualquiera que nos podamos imaginar, aunque algunas
     darn mejores resultados que otra. Podemos tener algo como:

           for i := 0 to 319 do Tabla2[i] := i;

           for i := 0 to 319 do Tabla2[i] := i mod 8;

           for i := 0 to 319 do Tabla2[i] := round(sqrt(i) * 20);

           for i := 0 to 319 do
               Tabla2[i] := round(exp(i / 48) * 10 + sqr(320 - i) / 40);


     Como siempre, la nica forma de saber qu funcin produce un buen
     plasma es probar con todas las que se nos ocurran.


COMO "MOVER" EL PLASMA:
-----------------------

     Como les haba dicho, se supone que los valores de los ndices
     pos1, pos2, pos3, etc... son copiados a la hora de generar el
     plasma, pero NO SON ALTERADOS en ese momento.

     Despus de generar cada cuadro del plasma, debemos incrementar
     o decrementar los ndices originales o de lo contrario, nuestro
     plasma permanecer inmvil.

     Adems, podemos introducir un poco de azar al plasma sumando o
     restando un valor aleatorio a cada ndice.

     Esto se puede hacer en un procedimiento aparte, como ste:


          { Suponiendo que tenemos cuatro ndices: pos1, pos2, pos3, pos4 }

          procedure MuevePlasma;
          begin
               pos1 := pos1 - 4 + random(3);
               pos2 := pos2 + 1 - random(3);
               pos3 := pos3 + 4 + random(3);
               pos4 := pos4 - random(3);
          end;


     Obviamente, la magnitud del incremento en cada ndice es un valor
     arbitrario que queda a disposicin de ustedes para escoger.

     Generalmente, un incremento (o decremento) mayor ocasiona que el
     plasma se mueva con mayor rapidez.

     Tambin se puede aadir una rotacin de paleta adems del movimiento
     del plasma. De esta forma, el efecto se vuelve menos montono, aunque
     a veces se ve mejor sin la rotacin de colores. El ejemplo PLASMA1.PAS
     no utiliza rotacin de paleta y el ejemplo PLASMA2.PAS s la utiliza.

     La paleta de colores para un plasma de tiempo real se elabora de
     la misma manera que la de un plasma esttico. Haciendo transiciones
     suaves de un color a otro.

     Y eso es todo lo que les puedo decir sobre los plasmas. El siguiente
     paso es revisar los programas de ejemplo y modificarlos. Prueben a
     cambiar las funciones que los generan, los incrementos de los ndices,
     la combinacin de colores, aadir ms funciones, etc...


PROBLEMAS DE VELOCIDAD:
-----------------------

     Los programas de ejemplo utilizan toda la resolucin del modo 13h,
     es decir que se calcula el color de cada uno de los 64000 pxels.

     Hace algunos aos, esto no era posible (y mucho menos con cdigo
     100% en Pascal), pero ahora los procesadores son mucho ms rpidos
     y nos permiten hacer este tipo de cosas.

     Mi mquina no es la ms rpida (AMD K5 75) y sin embargo, los ejemplos
     corren suavemente y sin problemas. Supongo que as debe de ser incluso
     en una 486DX2. Pero con un procesador ms lento, puede haber problemas
     con la velocidad.

     Si eso ocurre, existen algunas soluciones:

        1.- No dibujen el plasma a pantalla completa. Por ejemplo, si
            dibujan el plasma solamente en el rectngulo limitado por
            los puntos (80, 50) y (240, 150), la regin resultante es
            la cuarta parte de la pantalla, por lo tanto, solamente
            tendrn que dibujar 16000 pxels, no 64000.


        2.- Usen una resolucin menor. Es decir, que en vez de calcular
            el color de cada pxel, calculen el color de un bloque de
            2 * 2 pxels y dibujen esos 4 pxels del mismo color. Eso
            disminuye un poco la calidad, pero aumenta MUCHO la velocidad.
            Un ejemplo en Pascal podra ser el siguiente:

                  offset := 0;
                  for y := 0 to 99 do
                  begin
                       for x := 0 to 159 do
                       begin
                            color := { aqu calculan el color del bloque }
                            col2bytes := word(color) shl 8 + color;
                            memw[VirSeg:offset] := col2bytes;
                            memw[VirSeg:offset+320] := col2bytes;
                            inc(offset, 2);
                       end;
                       inc(offset, 320);
                  end;

            Aqu utilizamos el arreglo memw[] en lugar de mem[]. La diferencia
            est en que con memw[] accedemos a "palabras" y no a bytes, por
            lo tanto, podemos dibujar dos pxels a la vez.

            Col2Bytes es una variable de tipo word en la que tanto el
            byte superior como el inferior son igual a color.

            Adems, probablemente hay que hacer algunos ajustes con los
            incrementos en los ndices y en las tablas que usan coordenadas
            como ndices.

            El ejemplo PLASMA3.PAS es exactamente el mismo plasma que el
            de PLASMA2.PAS, pero usando una resolucin menor de 160 * 100.
            Como pueden ver, no hay mucha diferencia en la calidad de la
            imagen, pero s en la velocidad de ejecucin.


        3.- El ltimo recurso para aumentar la velocidad es el ms temido
            por todos: e n s a m b l a d o r.

            No voy a hacer en este tutorial lo mismo que en el anterior,
            pero si quieren ver un ejemplo de plasma en ensamblador,
            revisen el cdigo fuente del demo que viene includo con
            este tutorial.


FUEGO Y LLAMAS:
---------------

     El concepto de "fuego" es seguramente ms entendible que el de
     "plasma". An as, sera buena idea que ejecutaran alguno de los
     ejemplos (LLAMAS1.PAS o LLAMAS2.PAS) para que vieran cmo se ve
     un efecto de llamas en la computadora.

     Aunque algunas personas acostumbraban decir que el efecto de
     llamas es una variacin de un plasma, la forma de obtener llamas
     es muy diferente al algoritmo del plasma, y aunque ambos tienen
     algunas cosas en comn, las llamas NO son un plasma.

     El efecto de llamas tambin es un efecto en tiempo real, lo que
     significa que debemos calcular el color de cada punto en la pantalla
     (o en la regin en donde se realiza el efecto). Sin embargo,
     a diferencia del plasma, el fuego no necesita complicadas funciones
     precalculadas. El color de cada pxel se determina mediante un
     simple promedio de los colores alrededor de ese pxel.

     Esto parece tener cierto sentido, si lo vemos desde un punto de
     vista fsico. Ya que este es un efecto que simula fuego, vamos a
     hablar de TEMPERATURA.

     La temperatura de cada punto est determinada por la temperatura
     de sus alrededores. Para calcular la temperatura de un punto,
     simplemente obtenemos el promedio de las temperaturas de varios
     puntos alrededor del que nos interesa. Digamos que queremos calcular
     la temperatura del punto central del siguiente esquema:


                          -------------------
                          |  2  |  1  |  1  |
                          |     |     |     |
                          |-----|-----|-----|
                          |  6  |  ?  |  5  |
                          |     |     |     |
                          |-----|-----|-----|
                          |  7  | 10  |  8  |
                          |     |     |     |
                          -------------------


     La temperatura de los puntos alrededor del central est indicada
     con un valor numrico. Por lo tanto, si tomamos el promedio de los
     ocho puntos, obtenemos la temperatura del punto central:

          temp == (2 + 1 + 1 + 6 + 5 + 7 + 10 + 8) / 8  == 5

     La temperatura del punto central es 5.


     Bueno, pero cmo VEMOS nosotros la temperatura? En una llama, la parte
     blanca es la ms caliente, despus, el blanco se vuelve amarillo
     conforme disminuye la temperatura hasta llegar al rojo. El rojo
     representa una temperatura media, y poco a poco se va apagando hasta
     llegar al negro, lo cual indica fro.

     Limitando los valores de temperatura entre 0 y 255, siendo 0 el
     ms fro y 255 el ms caliente, podemos obtener un color de la
     paleta a partir del valor de temperatura. As que desde ahora,
     el calor se transforma en color.

     El siguiente problema es cmo generar la paleta de colores. En un
     plasma podamos hacer cualquier combinacin de colores, pero
     obviamente nosotros no queremos obtener llamas verdes con centro
     morado y nubes de humo rosas. Necesitamos organizar la paleta de
     forma que el color 0 (el ms fro) sea negro, y el color 255 sea
     blanco, pasando por amarillo, naranja y rojo. Incluso podemos
     obtener una simulacin de "humo" si ponemos un poco de azul o gris
     en los primeros colores de la paleta. De cualquier forma, recuerden
     que los cambios en la paleta deben de ser suaves. En los ejemplos
     pueden ver cmo generar este tipo de paletas (proc. GeneraPaleta).


COMO REALIZAR EL EFECTO:
------------------------

     Vamos a necesitar dos arreglos grandes y del mismo tamao, algo
     as como 320 * 200, para abarcar toda la pantalla.

     Para hacer ms simple la explicacin, voy a utilizar como arreglos
     dos pantallas virtuales: OrigScr y DestScr, aunque esto no es necesario,
     ni conveniente.

     Lo primero que hay que hacer es inicializar los arreglos llenndolos
     de ceros. En el caso de nuestras pantallas virtuales, simplemente
     usamos el procedimiento ClearScreen.

     La siguiente parte es inicializar uno de los arreglos, al que
     llamaremos ORIGEN de la siguiente forma: Debido a que el fuego
     comienza desde la parte inferior (siendo esta parte la ms caliente),
     vamos a generar algunos "puntos calientes" al azar en las lneas
     inferiores de nuestro arreglo origen. Esto lo hacemos recorriendo
     las ltimas dos o tres lneas del arreglo y decidiendo si cada
     punto debe valer 0 o 255:


           for x := 0 to 319 do
           begin
                PutPixel(x, 198 random(2) * 255, Origen);
                PutPixel(x, 199 random(2) * 255, Origen);
           end;

           { Ntese que random(2) * 255 devuelve 0  255 }

     Con el ciclo anterior, llenamos las dos lneas inferiores con puntos
     que tienen un valor mximo o mnimo.


     Despus de la inicializacin, la parte siguiente es la rutina que
     genera las llamas. Aqu es donde vamos a usar los dos arreglos.

     Vamos a calcular el arreglo DESTINO de la forma en que habamos visto,
     es decir, promediando los colores de los puntos que se encuentran
     alrededor de cada punto en el arreglo.

     La razn por la que usamos dos arreglos es porque si calculamos
     los colores a partir del arreglo origen y los almacenamos ah mismo,
     entonces a la hora de modificar el arreglo origen se producirn
     resultados inesperados, por lo tanto, debemos calcular los colores
     promediando los del arreglo origen y guardando los resultados en
     el arreglo destino. O algo as...

     Creo que todo se entender mejor si lo digo en Pascal:


       for y := 1 to 198 do
           for x := 1 to 318 do
           begin
                { Aqu promediamos los ocho puntos alrededor de (x, y) }
                color := GetPixel(x-1, y-1, Origen) +
                         GetPixel(x, y-1, Origen) +
                         GetPixel(x+1, y-1, Origen) +
                         GetPixel(x-1, y, Origen) +
                         GetPixel(x+1, y, Origen) +
                         GetPixel(x-1, y+1, Origen) +
                         GetPixel(x, y+1, Origen) +
                         GetPixel(x+1, y+1, Origen);

                color := color div 8;

                PutPixel(x, y, color, Destino);
           end;


     Si se fijan, los ciclos empiezan desde 1 y no desde 0. Esto es as
     porque a la hora de llamar a algo como GetPixel(x-1, y-1, Origen),
     si empezramos desde 0 se produciran coordenadas negativas. Por esa
     misma razn calculamos solamente hasta el punto (318, 198) y no
     hasta (319, 199).

     El cdigo anterior calcula un nuevo cuadro y lo almacena en Destimo.
     El paso siguiente es copiar Destino a la pantalla y hacer que destino
     sea ahora el arreglo origen. Esto lo hacemos con dos instrucciones:

               CopyScreen(Destino, Origen);
               CopyScreen(Destino, VGA);


     Se puede insertar un VRetrace antes de copiar a VGA en caso de que
     se produzcan parpadeos, aunque eso hace un poco ms lento el efecto.

     Pero eso no es todo. Debemos asegurarnos de que la parte inferior
     siga caliente, ya que cada vez que generamos una pantalla nueva,
     cada punto adquiere un valor menor que el anterior debido al
     promedio de los que estn a su alrededor.

     Para mantener la parte inferior "caliente", simplemente generamos
     una serie nueva de puntos calientes y fros como lo hicimos al
     inicializar el arreglo origen:

           for x := 0 to 319 do
           begin
                PutPixel(x, 198, random(2) * 255, Origen);
                PutPixel(x, 199, random(2) * 255, Origen);
           end;


     Si no hacemos lo anterior, lo nico que conseguiremos ser algo
     parecido a un "flamazo".


     Si en este momento elaboraran un programa con lo que se ha visto,
     no obtendran los resultados esperados. Esto es por varias razones:

     Para empezar, las llamas no "suben". La solucin a esto es que a
     la hora de calcular el color de cada punto, el resultado lo almacenamos
     en el punto que se encuentra directamente arriba del que estamos
     calculando.

     Dicho de otra forma, debemos promediar los puntos que estn alrededor
     del punto que se encuentra DEBAJO del que nos interesa:

         color := GetPixel(x-1, y, Origen) + GetPixel(x, y, Origen) +
                  GetPixel(x+1, y, Origen) + GetPixel(x-1, y+1, Origen) +
                  GetPixel(x+1, y+1, Origen) + GetPixel(x-1, y+2, Origen) +
                  GetPixel(x, y+2, Origen) + GetPixel(x+1, y+2, Origen);
         color := color div 8;
         PutPixel(x, y, color, Destino);


     El cdigo anterior le da al punto (x, y) el color que le correspondera
     al punto (x, y+1). Eso hace que el fuego se mueva hacia arriba.


     El segundo problema es la velocidad. Estamos haciendo SIETE sumas
     y una divisin POR CADA PIXEL en la pantalla (bueno, casi).

     No es necesario que promediemos TODOS los ocho puntos de la periferia.
     Podemos utilizar solamente dos o cuatro de esos puntos. En los ejemplos
     se utilizan cuatro puntos: los de arriba, abajo, izquierda y derecha.
     Esto reduce los clculos de la siguiente forma:

          color := GetPixel(x, y, Origen) + GetPixel(x, y+2, Origen);
                   GetPixel(x-1, y+1, Origen) + GetPixel(x+1, y+1, Origen);
          color := color div 4;


     Si el nmero de colores a promediar es una potencia de 2, por ejemplo
     2, 4 u 8. Entonces podemos cambiar la divisin por un desplazamiento
     de bits. El desplazar un nmero binario hacia la derecha equivale a
     dividirlo entre 2 por cada posicin que sea desplazado. Y eso es lo
     que hace el operador SHR (shift right), por lo tanto:

              color := color div 4;

     equivale a:

              color := color shr 2; { Desplazamos 2 posiciones }


     y  color := color div 8;  equivale a  color := color shr 3;

     Tambin existe un operador que hace desplazamientos hacia la izquierda
     (SHL) y como podrn adivinar, cada desplazamiento equivale a
     MULTIPLICAR un nmero por 2:

        color := color shl 4;   equivale a   color := color * 16;


     Y por cierto, un desplazamiento binario es MUCHO ms rpido que una
     divisin, as que cuando tengan que dividir o multiplicar algo por
     una potencia de 2, cambien la operacin por un desplazamiento.

     *** NOTA.-  Los desplazamientos solamente funcionan con nmeros de
                 tipo entero. Y NO utilicen el desplazamiento a la derecha
                 para dividir nmeros negativos. Eso no funciona.


     El ltimo problema que se nos puede presentar es que las llamas tardan
     demasiado en decaer y dan la apariencia de una gran pared anaranjada.

     La solucin a este problema es muy simple, solamente disminuyan el
     valor del color despus de calcularlo. Esto presenta otro problema:
     Si el color vale cero, entonces al disminurlo dar negativo, por lo
     tanto, debemos hacer una comprobacin extra para evitar esos casos.

     La rutina final queda parecida a esto:


        procedure MueveLlamas;
        var x, y, color : integer;
        begin
             for y := 0 to 197 do
                 for x := 1 to 318 do
                 begin
                      color := GetPixel(x, y, Origen) +
                               GetPixel(x, y+2, Origen) +
                               GetPixel(x-1, y+1, Origen) +
                               GetPixel(x+1, y+1, Origen);

                      color := color shr 2 - 1;
                      if color < 0 then color := 0;

                      PutPixel(x, y, color, Destino);
                 end;

             CopyScreen(Destino, Origen);
             CopyScreen(Destino, VGA);

             for x := 0 to 319 do
             begin
                  PutPixel(x, 198, random(2) * 255, Origen);
                  PutPixel(x, 199, random(2) * 255, Origen);
             end;
        end;


     Una rutina parecida a esta es la que se usa en el ejemplo LLAMAS1.PAS,
     solamente que en vez de usar GetPixel y PutPixel, accedemos directamente
     a la memoria modificando nicamente el offset en incrementos de 1 y 2,
     con lo que evitamos varias de las operaciones que hace la funcin
     GetPixel. Como ya les haba dicho, el simple hecho de llamar a una
     funcin consume tiempo, por lo que lo ms rpido es acceder directamente
     a la memoria. Nada de PutPixels ni GetPixels.


MAS RAPIDO, MAS RAPIDO, MAS RAPIDO:
-----------------------------------

    Est bien, ya elimin los Put- y Get- Pixels. Hago el promedio de
    cuatro puntos y no ocho. Utilizo SHR para dividir, pero mi programa
    sigue siendo muy lento.... QUE HAGO???

    Bueno, los tips para la velocidad de las llamas son exactamente los
    mismos que para la velocidad de los plasmas:


         1.- Realizen el efecto en una zona menor de la pantalla.

         2.- Utilicen resoluciones menores y dibujen un bloque de
             2 * 2 pxels para cada color. Esto reduce el tamao de
             los arreglos a 160 * 100 y por lo tanto ya no podemos
             usar pantallas virtuales (que son de 320 * 200), pero
             eso no representa ningn problema, excepto que tenemos
             que cambiar algo como CopyScreen(VSeg1, VGA) por una
             rutina que dibuje 4 pxels por cada punto de Destino.

             Esto acelera mucho el efecto y adems ahorra mucha memoria.
             El ejemplo LLAMAS2.PAS utiliza esta tcnica para acelerar
             las llamas. Desafortunadamente, como siempre, hay una
             disminucin de la calidad de la imagen.

         3.- Invoquen al Gran y Poderoso Seor Ensamblador.



DANDOLE FORMA AL FUEGO:
-----------------------

     La forma de las llamas depende completamente de dnde situamos
     los "puntos calientes". Algo as como las "semillas" del plasma
     fractal.

     Si situamos puntos calientes (puntos cuyo color es 255) a lo largo
     de una figura, entonces la figura quedar envuelta en llamas.

     Recuerdan lo que les dije de un "flamazo"?

     Un flamazo se origina cuando tenemos una regin que mantenemos
     "caliente", (como la parte inferior de la pantalla), y simplemente
     dejamos de hacerlo. Cuando eso sucede, en esa regin, el "calor"
     disminuye rpidamente y las llamas desaparecen.

     En el ejemplo LLAMAS3.PAS se muestra la forma en que se hace este
     efecto.

     El ejemplo es exactamente igual que LLAMAS1.PAS, pero al presionar
     la barra espaciadora, aparecen en el centro de la pantalla las letras
     FAC en llamas y desaparecen despus de un momento, convirtindose
     en humo.


TIPS SOBRE LA PALETA DE COLORES:
--------------------------------

     El efecto de interferencia no necesita de muchos colores, con 8 o 16
     es suficiente, pero los plasmas y las llamas necesitan usar un
     gran rango de la paleta para obtener una buena calidad.

     Por lo general, estos efectos aparecen junto con otros. Es decir que
     se pueden tener tostadores volando sobre la ciudad en LLAMAS, o
     figuras tridimensionales rotando sobre un plasma, o figuras cuyas
     caras son plasmas, etc...

     Pero entonces, no podemos hacer que nuestros efectos usen los 256
     colores, ya que no nos quedarn colores libres para el OTRO efecto
     que aparece al mismo tiempo.

     En el caso de que el OTRO efecto sea uno o ms sprites que no
     utilicen muchos colores, podemos restringir los colores del plasma
     y llamas a 200 o 220, lo cual no produce diferencias notables, pero
     si el OTRO efecto consume muchos colores, como por ejemplo: una
     figura tridimensional sombreada, otro plasma o una imagen esttica,
     tal vez tengamos que reducir el rango de colores del plasma o llamas
     hasta 128 colores. Eso produce una pequea prdida de calidad, pero
     tendremos DOS efectos presentndose al mismo tiempo, lo cual es
     ms notable que la calidad del plasma o fuego.

     Con memos de 128 colores (mas o menos), la transicin entre un color
     y otro deja de ser suave y lo que veremos en la pantalla sern varias
     franjas en lugar de un degradado consistente.

     Esto tiene que ver con el rango de intensidad de los colores.
     Recuerden que cada componente de un color (rojo, verde y azul)
     puede tener una intensidad de 0 a 63, por lo tanto, si quisiramos
     hacer una transicin de rojo a verde, haramos algo como esto:

           for i := 0 to 63 do
           begin
                pal[i][0] := 63 - i;   { disminuye el rojo }
                pal[i][1] := i;        { aumenta el verde  }
                pal[i][2] := 0;        { nada de azul      }
           end;


     Ese degradado de rojo a verde ha consumido 64 colores de la paleta.
     Ya que en un plasma debemos tener tambin una transicin del ltimo
     color al primero, debemos utilizar otros 64 colores en una transicin
     de verde a rojo:

           for i := 0 to 63 do
           begin
                pal[i + 64][0] := i;         { aumentamos el rojo }
                pal[i + 64][1] := 63 - i;    { disminuye el verde }
                pal[i + 64][2] := 0;         { nada de azul       }
           end;


     En un plasma, la transicin de los colores debe de ser cclica,
     es decir, que el primer color debe de ser igual al ltimo.

     Por ejemplo, las siguientes transiciones funcionan para un plasma:

         - De rojo a verde a azul a rojo
         - De negro a rojo a amarillo a rojo a negro
         - De prpura a azul a blanco a prpura


     Eso significa que una transicin cclica entre solamente 2 colores
     (abarcando todo su rango de intensidades) utiliza 128 colores de
     la paleta.

     En el caso de las llamas no necesitamos que la transicin sea
     cclica, pero necesitamos hacer transiciones entre varios colores:

          - De negro a rojo a amarillo a blanco
          - De negro a azul oscuro a negro a rojo a amarillo a blanco


     Tal vez otras combinaciones de colores produzcan resultados interesantes
     en las llamas. Como fuego verde con humo rosa.


EL COLOR 0:
-----------

     El primer color en la paleta, conocido como el color cero, es un
     color muy especial. Aparentemente no tiene ninguna diferencia con
     respecto a los otros 255 colores en la paleta, pero no es as.

     Para empezar, el borde de la pantalla se dibuja con el color 0.
     Prueben algo como lo siguiente:

             var i : byte;
             begin
                  SetMode13;
                  ClearScreen(1, VGA);
                  while not keypressed do
                  begin
                       SetPal(0, i, i, i);
                       inc(i);
                  end;
                  SetTextMode;
             end.

     Solamente hagan un nuevo programa, incluyan las unidades Mode13
     y Crt, copien el cdigo anterior y ejecuten el programa.

     Aparecer la pantalla azul, ya que la hemos "borrado" con el color
     1, el cual por default es azul. Pero tambin aparece el borde de
     la pantalla cambiando de color debido a que estamos modificando
     el color cero.

     Por esa razn no es buena idea usar el color 0 dentro de un plasma,
     ya que al hacer la rotacin de paleta, el color 0 estar cambiando
     y eso se refleja en el borde de la pantalla.

     En el caso de las llamas no hay ningn problema, ya que las llamas
     no necesitan rotacin de paleta, con lo que el color 0 no se altera.

     Otra razn para preservar el color 0, es su uso en los sprites
     y en los letreros como color "transparente", debido a que es
     muy fcil comprobar si un valor es igual a cero.

     En ensamblador es incluso ms fcil comprobar un cero, sobre todo
     si ese valor proviene de una operacin anterior, ya que si una
     operacin da cero, podemos ahorrarnos la comparacin y utilizar
     inmediatamente las instrucciones JZ o JNZ.


CONCLUSIONES:
-------------

     Espero que se hayan dado cuenta de que generar efectos que parecen
     complicados en realidad no es tan complicado. Probablemente, el
     mayor problema que estos efectos presentan es la velocidad de
     ejecucin, especialmente los efectos en tiempo real (plasma y llamas).

     En realidad, la nica forma (hasta ahora) de lograr una velocidad
     y calidad aceptables es el ensamblador. Tal vez estos efectos se
     ejecuten tolerablemente en una mquina rpida, pero a partir del
     siguiente tutorial empezaremos a ver objetos tridimensionales y
     tal vez lleguemos a necesitar del ensamblador cuando queramos
     realizar sombreado y mapeado de texturas.

     Por ahora, seguiremos adelante con el Pascal. Veremos algunas cosas
     diferentes, como el uso de XMS para ahorrar un poco de memoria,
     los nmeros de punto fijo para acelerar las operaciones, etc...

     Este tutorial estuvo plagado de ejemplos. Nueve en total y
     desafortunadamente para los usuarios de C / C++, no tengo
     tiempo de traducir (ni de comentar) todos los ejemplos. A partir
     del siguiente tutorial habr menos ejemplos, pero ms complejos.


EJERCICIOS:
-----------

     Espero que ya hayan visto el demo TETORIAL que se incluye con
     este documento. Excepto por el objeto tridimensional que aparece
     en el demo, la msica y el manejo de XMS, ya tienen los conocimientos
     suficientes para realizar un pequeo demo.

     Es muy fcil. Solamente desarrollen algunos efectos, mzclenlos con
     otros efectos, pnganlos en una secuencia, incluyan una pantalla
     con los crditos (quin program el demo, quin dibuj las grficas,
     etc...) y ya tienen un demo. El programa ni siquiera necesita
     interactuar con el usuario.

     Esa es la tarea. Hagan un demo.

     Tal vez despus incluso podamos organizar un concurso de demos.



RIMAS DE LA SEMANA:
-------------------


     "I came to bring the pain / hardcore from the brain "

                                          - Tupac Shakur (RIP)


     "Knowledge is the key / learn is the advice,
      knowledge isn't free / learning is the price"

                                          - Francis Foley


     "Yesterday night and the night before,
      Tommyknockers, tommyknockers, knocking at the door"

                                          - Stephen King ?


      "I looked out my window, it's a bright day
       and I might display
       my skills in the hills.
       Or in a different neighborhood
       cause my flavor could
       be the best, so let's test this,
       yes bitch"

                                          - Del the Funky Homosapien



FIN:
----

     Preprense para el siguiente tutorial. Repasen sus apuntes de
     geometra analtica y lgebra vectorial porque empezaremos
     a ver los principios de la tercera dimensin.

     Sean felices. Empujen un bit en la pila.


                                                                FAC
                                                                ---
----------------------------------------------------------------------------
