---------------------------------------------------
        Tutorial de programacin grfica
                   Por: F A C
       ----------------------------------
            #3 .- Lneas y crculos
---------------------------------------------------


Mi monitor an no sirve y yo estoy aqu en el fabuloso saln de computacin
de la Facultad de Ciencias de la UASLP, escribiendo el tercer tutorial de
la serie FAC, exactamente a las 10:44 a.m. ya que no tuve clase de circuitos
lgicos.

Y a ustedes cmo les va?


Bueno... en esta semana vamos a ver algo muy importante: Lneas y Crculos.

Ya hemos visto cmo dibujar lneas horizontales y verticales, pero ya es
tiempo de dibujar lneas de cualquier pendiente, as que tendremos que
recordar un poco de geometra analitica. Tambin veremos cmo dibujar
crculos, algo que es MUY fcil, pero muy lento, as que antes que nada
vamos a ver cmo se pueden acelerar un poco las cosas...


Recuerden que pueden encontrar los tutoriales y algunos demos de grficas
en el FTP de Galia, o sea, en ftp://galia.fc.uaslp.mx/pub/tutorial

Les recomiendo que bajen los demos y los ejecuten de preferencia en una
mquina 486DX o Pentium y con unos 8 Mb de RAM. Tal vez les parezca que
es mucho pedir, pero cuando vean los demos vern porqu lo digo.

Recuerden: No han vivido realmente hasta que hayan visto un demo :)

Si tienen problemas para bajar los demos, escrbanme y se los mandar
por e-mail.



TABLAS PRECALCULADAS:

El Turbio Pascal tiene integradas varias funciones trigonomtricas, en las
que se incluyen el seno y el coseno. Desafortunadamente, esas funciones
hacen muchas comprobaciones de rangos y algunos clculos extra que hacen
de su uso algo MUY lento. Adems de que el parmetro que reciben debe ser
un ngulo en radianes. Por lo que si quisiramos usar grados, tendramos
que hacer antes una conversin, lo que significa ms clculos y ms tiempo.

Lo que tenemos que hacer entonces, es generar nuestra propia tabla de valores
de las funciones, almacenarla en un arreglo y simplemente usar el arreglo
en lugar de las funciones sin() y cos().

Para ejemplificar esto con un ejemplo, veamos el siguiente ejemplo ejemplar:


        type Tabla = array[0..360] of real;
             PTabla = ^Tabla;

        var Seno, Coseno : PTabla;

        procedure GeneraTablas;
        var ang : integer;
        begin
             Seno := new(PTabla);
             Coseno := new(PTabla);

             for ang := 0 to 360 do
             begin
                  Seno^[ang] := sin(ang * 3.14159265 / 180);
                  Coseno^[ang] := cos(ang * 3.14159265 / 180);
             end;
        end;


Ok, esto es lo que hicimos:

    Primero definimos un tipo de datos que almacena un arreglo de nmeros
    reales que corresponden a los senos y/o cosenos de ngulos enteros de
    0 a 360 grados. Tambin se declara un tipo de apuntador a la tabla. Esto
    se hace porque el Pascal solamente permite 64 Kilobytes para almacenar
    variables, por lo tanto, para no acabarnos el espacio de las variables,
    usamos apuntadoresy almacenamos las tablas de seno y coseno en el heap.

    Si no entienden muy bien cmo funcionan los apuntadores en Pascal,
    consigan un buen libro por ah o pregntenle a alguien que tenga
    algo de experiencia, o escrbanme un e-mail con las dudas que tengan.

    Luego definimos dos variables, las cuales son APUNTADORES a las tablas
    de seno y coseno.

    Despus, en el procedimiento GeneraTablas, reservamos el espacio
    necesario para nuestras tablas con la funcin new(). Si intentamos
    acceder a las tablas antes de reservar el espacio en memoria podramos
    hacer que se trabara la mquina.

    Despus calculamos los valores de las tablas. En este caso no importa
    usar las funciones sin y cos, puesto que solamente calculamos las
    tablas una vez en el programa (de preferencia al principio). Las
    funciones sin y cos usan un argumento en radianes, por lo tanto hay
    que convertir primero los grados a radianes.

    Una vez que hemos calculado las tablas, podemos usarlas en cualquier
    parte del programa, pero hay que recordar que las variables Seno y
    Coseno son APUNTADORES a las tablas, no las tablas en s, o sea que Seno^
    y Coseno^  son los que representan a las tablas. Otra cosa a recordar
    es que las tablas son arreglos, no funciones, por lo tanto tenemos que
    especificar el parmetro como si fuera un ndice, es decir, entre [].

    Por ejemplo:

                Seno^[45] devuelve el seno de 45 grados
                Coseno^[20] devuelve el coseno de 20 grados
                Seno^[30.5] devuelve un error de compilacin
                Coseno^[-20] devuelve un error de fuera de rango


    Antes de que termine un programa que usa tablas, debemos liberar la
    memoria que hemos reservado, para que el DOS la pueda utilizar.

    Esto lo hacemos con la instruccin dispose() del Turbo Pascal, de la
    siguiente manera:

              dispose(Seno);
              dispose(Coseno);
              dispose(MiTabla);

    Obviamente, despus de liberar la memoria de una tabla, ya no la
    podremos utilizar.


DIBUJO DE CIRCULOS:

       Para ver cmo usar las tablas de senos y cosenos, vamos a implementar
       un algoritmo para dibujar crculos:

                                   Y
                                   ^
                                   |
                                 . . .
                               .   |  /o (x, y)
                             .     |/    .
                         ----.-----|-----.----> X
                             .     |     .
                               .   |   .
                                 . . .
                                   |
                                   |


     Digamos que el punto (x, y) es un punto del crculo (circunferencia,
     para los matemticos), entonces tenemos que:

                            x = Radio * coseno(theta)
                            y = Radio * seno(theta)

     Donde Radio es el radio del crculo (aahhh), y theta es el ngulo
     que forma el radio con la parte positiva del eje X.

     Para dibujar un crculo de un radio determinado, solamente tenemos
     que hacer un ciclo desde 0 hasta 360, pero con incrementos pequeos,
     calcular cada punto con las ecuaciones anteriores y dibujarlo.

     Pero no debemos hacer el ciclo de 0 a 360 contando de uno en uno, ya que
     para un crculo de radio muy grande, podran aparecer huecos entre un
     punto y el siguiente, por lo tanto tenemos que usar un incremento
     fraccionario. El valor 0.25 produce buenos resultados.

     El problema es que nuestras tablas de senos y cosenos son arreglos, y
     Pascal no permite que los arreglos tengan ndices fraccionarios, por
     lo que tenemos que hacer el arreglo un poco ms grande:

            type Tabla = array[0..1440] of real;

     Notar que: 1440 = 360 / 0.25 = 360 * 4

     Esto significa que para calcular el seno o coseno de un ngulo
     especfico, tendremos que usar:

                 Seno^[angulo * 4]
                 Coseno^[angulo * 4]

     por ejemplo:

                 Seno^[80] = seno de 20 grados
                 Seno^[720] = seno de 180 grados
                 Coseno^[1] = coseno de 0.25 grados


     Pero lo que nosotros vamos a hacer es un ciclo desde 0 hasta 1440, por
     lo tanto no necesitamos hacer ningn clculo extra.

     Aqu est parte del programa circulos.pas, el cual muestra cmo
     aplicar el algoritmo de crculos y las tablas trigonomtricas:

---------------------------------------------------------------------------
     program Circulos;

     uses Mode_13, Crt;

     type Tabla = array[0..1440] of real;  { tablas trigonomtricas }
          PTabla = ^Tabla;       { apuntador a tabla }

     var Seno, Coseno : PTabla;

     procedure GeneraTablas;
     var i : integer;
     begin
          Seno := new(PTabla);
          Coseno := new(PTabla);
          for i := 0 to 1440 do
          begin
               Seno^[i] := sin(i * 3.14159265 / 180 / 4);
               Coseno^[i] := cos(i * 3.14159265 / 180 / 4);
          end;
     end;

     procedure Circulo(cx, cy : integer; radio : word; color : byte);
     var x, y, i : integer;
     begin
          for i := 0 to 1440 do
          begin
               x := cx + round(radio * Coseno^[i]);
               y := cy + round(radio * Seno^[i]);
               if (x >= 0) and (y >= 0) and (x < 320) and (y < 200)
                  then PutPixel(x, y, color);
          end;
     end;


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

Ntese que al calcular "x" y "y", estamos sumndoles las coordenadas cx y cy.
Esto se hace para trasladar el centro del crculo a cualquier punto que
queramos. De esta forma, para dibujar un crculo solamente tenemos que
especificar las coordenadas del centro, el radio y el color del crculo.


Quieren ver qu tanto ayudan las tablas de senos y cosenos???

Bueno... prueben a hacer lo siguiente:

En el procedimiento Circulo del ejemplo, cambien las siguientes lneas:

               x := cx + round(radio * Coseno^[i]);
               y := cy + round(radio * Seno^[i]);

por las siguientes:

               x := cx + round(radio * cos(i / 4));
               y := cy + round(radio * sin(i / 4));


... es decir que en vez de usar las tablas precalculadas, usamos las funciones
    de seno y coseno que vienen con Turbo Pascal. Ejecuten el programa y en
    lo que se dibujan los crculos, pueden ir por una botana o algo.

    Pero de la misma forma en que podemos hacer ms lento el procedimiento,
    tambin podemos hacerlo ms rpido (aunque no es tan fcil).

    Por ejemplo, modifiquen el procedimiento de la siguiente forma:


     procedure Circulo(cx, cy : integer; radio : word; color : byte);
     var x, y, i : integer;
     begin
          for i := 0 to 720 do
          begin
               x := cx + round(radio * Coseno^[i*2]);
               y := cy + round(radio * Seno^[i*2]);
               if (x >= 0) and (y >= 0) and (x < 320) and (y < 200)
                  then PutPixel(x, y, color);
          end;
     end;


     Lo nico que se hizo fu que en lugar de tomar ngulos con incrementos
     de 0.25 grados, los tomamos con incrementos de 0.5 grados. Esto podra
     hacer nuestro procedimiento el doble de rpido, pero tiene la desventaja
     de que si el radio es muy grande, el procedimiento se "brincar" algunos
     puntos de la circunferencia, por lo tanto solamente sirve para crculos
     de radio pequeo. En el programa de ejemplo (circulos.pas) se pueden
     notar algunos puntos faltantes cuando se usa el procedimiento anterior.


     Otra forma de acelerar el procedimiento es eliminando la lnea que
     comprueba si un punto est dentro de los lmites de la pantalla,
     o sea, en vez de escribir:

            if (x >= 0) and (y >= 0) and (x < 320) and (y < 200)
               then PutPixel(x, y, color);

     escribimos simplemente:

            PutPixel(x, y, color);


     pero entonces tenemos que estar SEGUROS de que nuestro crculo no va
     a sobrepasar el borde de la pantalla, lo cual en la programacin de
     demos es fcil, ya que el programador tiene todo controlado. Pero en
     un programa de dibujo o un juego, tenemos que comprobar los lmites.

     En el programa de ejemplo, algunos crculos se salen del borde de la
     pantalla, por lo que si eliminamos la comprobacin de lmites, veremos
     pedazos de crculos en un lugar que no deberan estar. Intntenlo.

     Cuando hagan su propio programa que utilice crculos, usen el
     procedimiento ms rpido que puedan sin que se pierda calidad
     en la presentacin. La nica forma de hacer esto es intentar
     varios parmetros para el incremento del ngulo y ver si es
     necesaria una comprobacin de lmites.



RAZON DE ASPECTO Y RESOLUCIONES CUADRADAS:


     Algo que se puede observar, es que nuestros crculos no son exactamente
     circulares, es decir, estn un poco "alargados". Esto se debe a que
     no estamos utilizando una resolucin "cuadrada".

     Una resolucin cuadrada es aquella en la que la resolucin (o nmero
     de pxels) en X es 4/3 de la resolucin en Y, ya que esto corresponde
     con las medidas fsicas de la pantalla y ocasiona que los pxels sean
     cuadrados. Ejemplos de resoluciones "cuadradas" son 640 por 480, o
     320 por 240 y 800 por 600.

     Pero nuestra resolucin de 320 por 200 NO produce pxels cuadrados,
     sino rectngulos que son un poco alargados en el sentido del eje Y.

     Si queremos dibujar un crculo perfecto en el modo de 320 por 200,
     tendramos que dividir el radio en la coordenada Y por un factor
     de 1.2, ya que:

          320 / 200 = 1.6

          1.6 / (4 / 3) = 1.2
           |       |       |
           |       |       |----- Factor de aspecto que debemos utilizar
           |       |
           |       |------------- Factor de aspecto de resolucin cuadrada
           |
           |
           |--------------------- Factor de aspecto de 320 por 200


     Cuando veamos (si llegamos a ver) el modo de video conocido como
     modo X, veremos que se pueden obtener resoluciones de 320 por 240,
     la cual es una resolucin cuadrada. Tambin podemos obtener resoluciones
     de 640 por 200, 320 por 400, 320 por 480 e incluso algo como 512 por 256.


     Podemos modificar nuestro procedimiento de crculo para que dibuje
     crculos circulares ;) , solamente hay que cambiar la lnea que dice:


              y := yc + round(radio * Seno^[i]);

     por una que diga:

              y := yc + round(radio * Seno^[i] / 1.2);


     De esta forma podemos dibujar crculos ms "perfectos", aunque sea
     un poco ms lento, ya que se hace una divisin extra por cada punto,
     o sea, 1440 divisiones por cada crculo. Intenten modificar el ejemplo
     circulos.pas para ver la diferencia en tiempo y aspecto.



DIBUJO DE LINEAS RECTAS:


     Supongo que han de estar pensando: porqu vemos primero cmo dibujar
     crculos si las lneas rectas son ms sencillas?

     ERROR!!!!!

     Las rectas son ms difciles de dibujar que los crculos. Y an ms
     difcil es dibujarlas RAPIDO.

     La razn principal es que para los crculos ya tenamos las funciones
     de seno y coseno precalculadas, y el resto es simplemente un ciclo.

     Para las rectas es diferente. Primero tenemos que calcular la pendiente
     de la recta, ver si es positiva o negativa, ver si es mayor o menor
     que 1, y hasta que tengamos toda esa informacin podremos dibujar una
     recta.

     Vamos a recordar un poco de geometra analtica:

     La pendiente (m) de una recta se define como:

                  m = dy / dx

     donde:

                  dy = y2 - y1

                  dx = x2 - x1

                  (x1, y1), (x2, y2) son los puntos que definen a la recta.


     Para pendientes menores a 1, podemos usar las siguientes ecuaciones:

                     dx = 1
                     dy = m

          por lo tanto, el siguiente ciclo dibujara una recta:

              for x := x1 to x2 do
              begin
                   y := m * (x - x1) + y1; { Ecuacin de la recta. Recuerdan? }
                   PutPixel(x, y, color);
              end;


     Pero para pendientes mayores que 1, tenemos que invertir las cosas:

                     dy = 1
                     dx = 1 / m

          y la recta se dibuja as:

               for y := y1 to y2 do
               begin
                    x := (y - y1) / m + x1;
                    PutPixel(x, y, color);
               end;


     Fcil, no? Pues NO. No tan fcil. Existe otro problema:

     Los ciclos for ... do en Pascal usan las palabras clave to y downto
     para saber si el ciclo cuenta hacia adelante o hacia atrs. Por lo
     tanto, debemos asegurarnos que x1 es menor que x2, y que y1 es menor
     que y2. Dicho de otra forma, debemos comprobar el signo de dx y dy.

     Si dx es mayor que cero, entonces x1 es mayor que x2, y por lo
     tanto, hacemos un ciclo desde x1 hasta x2.

     Si dx es menor que cero, entonces x1 ser menor que x2 y tendremos
     que hacer el ciclo desde x2 hasta x1.

     Para dy se hace algo similar.

     Por lo tanto, tenemos 4 casos diferentes, que son:

                   dx = 1   y   dy > 0
                   dx = 1   y   dy < 0
                   dy = 1   y   dx > 0
                   dy = 1   y   dx < 0


     Y eso es todo? Todava no. An existen otros dos casos especiales,
     que son cuando dx = 0, y cuando dy = 0, lo que significa que la
     recta es vertical u horizontal. Estos casos se tienen que trabajar
     de una forma especial, ya que no podemos hacer una divisin entre
     dx o dy. Pero ya sabemos cmo dibujar lneas horizontales y verticales,
     as que no debe haber ningn problema.

     El procedimiento completo queda as:

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

     procedure Linea(x1, y1, x2, y2 : word; color : byte);

     var dx, dy, x, y : integer;
         m : real;

     begin
          dx := x2 - x1;
          dy := y2 - y1;

          { Comprobar si es una lnea vertical }
          if dx = 0 then
          begin
               if dy < 0
               then
                   for y := y2 to y1 do PutPixel(x1, y, color)
               else
                   for y := y1 to y2 do PutPixel(x1, y, color);
               exit;
          end;

          { Comprobar si es una lnea horizontal }
          if dy = 0 then
          begin
               if dx < 0
               then
                   for x := x2 to x1 do PutPixel(x, y1, color)
               else
                   for x := x1 to x2 do PutPixel(x, y1, color);
               exit;
          end;

          { Calcular la pendiente y comprobar si es menor o igual que 1 }

          m := dy / dx;

          if abs(m) <= 1.0 then
          begin
               { Si la pendiente es menor o igual a 1, entonces...}
               if dx < 0 then
                   for x := x2 to x1 do
                   begin
                        y := round((x - x1) * m) + y1;
                        PutPixel(x, y, color);
                   end
               else
                   for x := x1 to x2 do
                   begin
                        y := round((x - x1) * m) + y1;
                        PutPixel(x, y, color);
                   end;
          end
          else
          begin
               { Si la pendiente es mayor que 1, entonces... }
               m := 1 / m; { Obtenemos el recproco de la pendiente }

               if dy < 0 then
                   for y := y2 to y1 do
                   begin
                        x := round((y - y1) * m) + x1;
                        PutPixel(x, y, color);
                   end
               else
                   for y := y1 to y2 do
                   begin
                        x := round((y - y1) * m) + x1;
                        PutPixel(x, y, color);
                   end;
          end;
     end;


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

     Este procedimiento se encuentra en el programa lineas1.pas, con el
     nombre de Linea1.

     En el algoritmo anterior se hace una multiplicacin por cada punto
     de la recta, excepto en los casos en que sea una recta horizontal
     o vertical. Por ejemplo, para pendientes menores que 1 tenemos que:

                 y := round((x - x1) * m) + y1

     Pero debido a que el valor de x va desde x1 hasta x2, tenemos que la
     diferencia (x - x1) aumenta en incrementos de 1. Por lo tanto, el
     producto de ((x - x1) * m) aumenta en cada paso con incrementos
     iguales a m.

     Por lo tanto, nos podemos ahorrar todas las multiplicaciones, haciendo
     que  "y" al inicio tenga el valor de y1, y luego solamente hay que
     ir incrementando de la siguiente forma:

                      y := y + m;

     Pero hay que tener en cuenta que m es un nmero real, por lo tanto,
     tenemos que declarar a las variables "x" y "y" tambin como nmeros
     reales y hacer el redondeo a la hora de dibujar el pxel.

     El procedimiento queda as:

     (Suponiendo que dx > 0   y   m < 1)

                 y := y1;
                 for xx := x1 to x2 do
                 begin
                      PutPixel(xx, round(y), color);
                      y := y + m;
                 end;


     Se ha utilizado la variable xx para hacer la misma funcin que la
     variable x, que ahora est declarada como real y no se puede utilizar
     en un ciclo.


     An con el hecho de que estamos usando ms nmeros reales, el algoritmo
     anterior un poco ms rpido que el primer algoritmo, ya que solamente
     se hace una suma por cada punto. (En el primer algoritmo se hacan
     una resta, una suma y una multiplicacin por cada punto).

     El procedimiento completo es el siguiente:

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

     procedure Linea(x1, y1, x2, y2 : word; color : byte);

     var dx, dy, xx, yy : integer;
         m, x, y : real;

     begin
          dx := x2 - x1;
          dy := y2 - y1;

          { Comprobar si es una lnea vertical }
          if dx = 0 then
          begin
               if dy < 0
               then
                   for yy := y2 to y1 do PutPixel(x1, yy, color)
               else
                   for yy := y1 to y2 do PutPixel(x1, yy, color);
               exit;
          end;

          { Comprobar si es una lnea horizontal }
          if dy = 0 then
          begin
               if dx < 0
               then
                   for xx := x2 to x1 do PutPixel(xx, y1, color)
               else
                   for xx := x1 to x2 do PutPixel(xx, y1, color);
               exit;
          end;

          { Calcular la pendiente y comprobar si es menor o igual que 1 }

          m := dy / dx;

          if abs(m) <= 1.0 then
          begin
               { Si la pendiente es menor o igual a 1, entonces...}
               if dx < 0 then
               begin
                    y := y2;
                    for xx := x2 to x1 do
                    begin
                         PutPixel(xx, round(y), color);
                         y := y + m;
                    end;
               end
               else
               begin
                    y := y1;
                    for xx := x1 to x2 do
                    begin
                         PutPixel(xx, round(y), color);
                         y := y + m;
                    end;
               end;
          end
          else
          begin
               { Si la pendiente es mayor que 1, entonces... }
               m := 1 / m; { Obtenemos el recproco de la pendiente }

               if dy < 0 then
               begin
                    x := x2;
                    for yy := y2 to y1 do
                    begin
                         PutPixel(round(x), yy, color);
                         x := x + m;
                    end;
               end
               else
               begin
                    x := x1;
                    for yy := y1 to y2 do
                    begin
                         PutPixel(round(x), yy, color);
                         x := x + m;
                    end;
               end;
          end;
     end;

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

Y eso es todo lo que hay que hacer para dibujar una recta. :)


Una cosa ms: Los algoritmos presentados aqu deberan ser lo suficientemente
rpidos para sus demos y aplicaciones (por ahora), pero NO SON los MAS
rpidos que se pueden hacer. De hecho, son un poco lentos. El procedimiento
se puede acelerar MUCHO mas usando ensamblador y aritmtica de punto fijo,
la cul solamente hace operaciones con nmeros enteros, pero poco a poco
iremos descubriendo cmo hacerlo. Adems, la idea principal es aprender
cmo funcionan los algoritmos, y no simplemente utilizarlos.

Si necesitan un procedimiento ms rpido para dibujar rectas, consulten
un libro sobre grficas para computadora. Les recomiendo el algoritmo
de Bressenham, el cual slo utiliza nmeros enteros y es uno de los ms
rpidos y populares.

El procedimiento Linea (el segundo, por supuesto) ser includo en la unidad
MODE_13.PAS a partir del siguiente tutorial, al igual que el procedimiento
Circulo y un procedimiento de rotacin de paleta. Tal vez despus del cuarto
tutorial estemos listos para hacer nuestro primer micro-demo.


No se si se habrn dado cuenta, pero este tutorial fu escrito durante una
semana entera en intervalos de 10 - 30 minutos. Los programas de ejemplo
no son muy impresionantes, les faltan comentarios e incluso algunas rutinas
no fueron probadas. La razn principal es que estoy usando un bellsimo
monitor TTL com una tarjeta de 8 bits, en lugar de la tarjeta PCI que
tuve que quitar. Realmente es un trauma. Este tutorial se retras una semana
y tal vez el siguiente tambin. Despus del quinto tutorial vendrn las
vacaciones y no tendr forma de "subir" los tutoriales a la red.

En vacaciones escribir unos 4 o 5 tutoriales ms y entrando a clases los
subir a Galia. Pero los que quieran los tutoriales durante las vacaciones,
escrbanme un e-mail con su telfono o algo as para que yo pueda ponerme
en contacto. Y ahora....


EJERCICIOS (hehehe):


           - Hagan un procedimiento que dibuje elipses, basndose en el
             procedimiento Circulo, que tenga la siguiente sintaxis:

             Elipse(cx, cy, rx, ry, color);

             Donde (cx, cy) son las coordenadas del centro de la elipse,
             rx es el semieje horizontal y ry el semieje vertical.

             TIP: Recuerdan cmo modificamos el procedimiento Circulo para
                  cambiar la razn de aspecto??? Bueno, pues las elipses
                  son algo parecido. Su radio en X es diferente de su
                  radio en Y.


           - Recuerdan el tnel en el ejemplo de rotacin de paleta en
             el segundo tutorial??? Intenten hacer un tnel circular o
             elptico que ocupe TODA la pantalla. Obviamente, tendrn que
             "activar" la comprobacin de lmites, pero una vez que hayan
             dibujado el tnel, la rotacin de paleta har todo el trabajo.


CONCLUSIONES Y CONTUSIONES:

     Bueno, sobre las tablas precalculadas, si hicieron el experimento de
     usar las funciones sin() y cos() para dibujar el crculo, entonces
     ya saben las grandes ventajas que tienen.

     Las tablas precalculadas no solo se usan para funciones trigonomtricas.
     Se pueden tener matrices de transformacin precalculadas para objetos
     en 3D. Se pueden tener matrices precalculadas para hacer efectos como
     plasmas, llamas y lentes, los cuales veremos despus.

     Les recomiendo que siempre que puedan precalcular algo, lo hagan,
     siempre y cuando no se acaben la memoria de la mquina. Entre menos
     clculos tenga que hacer el CPU, ms rpido se ejecutar su programa.

     Las rectas y crculos pueden parecer algo trivial, pero son la base
     de objetos ms complicados.

     Con rectas se pueden formar polgonos y con polgonos se pueden
     formar slidos. Pronto veremos cmo dibujar en 3 dimensiones.

     Los crculos no son tan usados como las rectas, pero modificando el
     algoritmo original, se pueden obtener algunas lneas curvas muy
     interesantes. Prueben utilizando diferentes radios y ngulos para
     X y Y, prueben aadiendo un poco de "ruido" a las tablas de senos
     y cosenos. Esto se puede hacer as:

          for i := 0 to 360 do
              Seno^[i] := sin(i * 3.14159 / 180) + random(100) / 1000 - 0.05;

     o cualquier otra cosa... Jueguen con los algoritmos.


PARA LOS SIGUIENTES TUTORIALES...

     Los siguientes tutoriales estn planeados para antes de salir de
     vacaciones (eso es, dentro de 3 semanas).


     Tutorial 4: Pantallas virtuales y formato PCX.

              Con las pantallas virtuales podemos hacer muchas cosas, como
              eliminar completamente el parpadeo, hacer animaciones, scroll,
              interferencia y muchos otros efectos. Adems veremos cmo
              cargar una imagen PCX en la pantalla VGA o en una pantalla
              virtual.


     Tutorial 5: Scrolling y principios de animacin.

              - Cmo deslizar la pantalla completa en cualquier direccin.
              - Cmo deslizar un letrero por la pantalla.
              - Un clsico: La invasin de los tostadores voladores.


     Tutorial 6: El primer micro-demo.

              Un ejemplo de cmo usar todo lo que hemos visto en los
              tutoriales anteriores y juntar todo para hacer un demo.


     Y para despus de (o durante) vacaciones:


     Tutorial 7: Las bases de la tercera dimensin.

              Cmo dibujar objetos en 3D. Cmo hacer rotaciones y
              traslaciones en 3D.


     Tutorial 8: Slidos en 3D y sombreado plano.

              Cmo dibujar polgonos rellenos para que los objetos
              tridimensionales parezcan slidos. Cmo dar un sombreado
              artificial a los polgonos. Cmo suprimir las caras ocultas.

     Tutorial 9: ???? Tal vez sombreado Gouraud y Phong? o tal vez
                      algunos efectos especiales???


Bueno, todo lo anterior es lo que tengo planeado por ahora, pero necesito
RESPUESTA!!!! Slo algunas personas se han dignado a escribirme y yo no s
qu opinen los dems de los tutoriales. Aqu est mi direccin, USENLA!

    E-Mail:    ganzo@galia.fc.uaslp.mx
    Telfono:  (48) 13-34-71


Gracias a todos los que se han interesado hasta ahora. Apenas vamos empezando.

Ah, por cierto, un mensaje para el Loco y todos los usuarios de C/C++ :

    Muy estimados lectores:

        Con mucho gusto me dignara yo a traducir los ejemplos en Pascal
        al queridsimo lenguaje C++. Pero desgraciadamente, la situacin
        que se me presenta en esta poca no me permite tomarme el tiempo
        para dicha actividad. No obstante, en el subsecuente perodo de
        vacaciones veraniegas, pondr todo mi empeo en tan solicitada
        hazaa. Gracias por su comprensin.

    (Que mam*n, pero as es)

    PS.- C++ es un asco. Aprendan Pascal y vern por qu.


LAS RIMAS DE LA SEMANA:

    La ventaja de escribir mi propio tutorial es que puedo escribir lo que
    yo quiera :)

    Adems el nico precio de este tutorial es que lo lean...

    PHAT RHIMEZ:

    "More words and phrases / my style amazes"
                                       Por: Del the Funky Homosapien

    "No one needs to know
     I'll proceed and go
     into
     and then tell you what I've been through"
                                       Por: Del the Funky Homosapien

     "Shorty let me tell you about my only vice
      it has to do with lots of lovin and it ain't nothin nice"
                                       Por: Q-Tip

      "Now it's on / she's on me / and her fangs are long"
                                       Por: shadow


Eso es todo... hasta el siguiente.

                                                     FAC
                                                     ganzo@galia.fc.uaslp.mx