 ----------------------------------------------------------------------------
                        
                          TUTORIAL DE PROGRAMACION
                         DE  GRAFICOS  EN  PASCAL
                    
                                
                               
                             
                         
                           
                          
                                 
                                     
                               
                                
                                   
                                     
                      Nmero 11:     - Sombreado plano -
 ----------------------------------------------------------------------------

 ACERCA DE:

        Los tutoriales de programacin, as como los ejemplos que
        se presentan en ellos, son escritos por Alfonso Alba Cadena
        (FAC) y todos ellos pueden ser encontrados en el archivo
        Hornet en internet:

           http://www.hornet.org/code/tutors/graphics

        El Hornet Archive es el lugar ms seguro para encontrar los
        tutoriales, aunque seguirn estando el servidor de la Facultad
        de Ciencias:

           ftp://galia.fc.uaslp.mx/pub/tutorial
           http://galia.fc.uaslp.mx/~ganzo/prog/tutorial.html


        Tambin pueden encontrar otros documentos sobre programacin
        y algunos demos hechos por FAC y Delabu Alama (el primer grupo
        mexicano de demos).

        Para correcciones, dudas, comentarios y sugerencias, dirjanse
        con FAC va e-mail usando alguna de las siguientes direcciones:

             fac@slp1.telmex.net.mx      (preferida)

             shadowfac@hotmail.com       (hotmail (WWW))


        A partir de ahora, el mailing list ya no funcionar mas debido
        a la decadencia de Galia, nuestro servidor, por lo tanto, tendrn
        que conseguir los tutoriales por su propia cuenta.

                                    - o -

        Gracias a todos los que me han escrito por e-mail. Pienso
        seguir con los tutoriales por otro ao, por lo menos, y
        tal vez organizar un concurso de demos por internet. Los
        que estn interesados en participar, escrbanme.

        AVISO: A los que tengan acceso al IRC, les recomiendo ir al
        canal #coders en UnderNET o ircNET. Pueden aprender muchas
        cosas ahi. Tambin estamos tratando de llenar el canal
        #programacion en UnderNET as que anmense y entren ah.


INTRODUCCION:

     Continuando con la tercera dimensin, ahora veremos cmo realizar el
     sombreado plano y trabajar con una fuente de iluminacin.

     En realidad esto es algo muy sencillo y relativamente trivial, por lo
     que este tutorial no ser muy largo. Seguiremos usando bsicamente
     el cdigo de los tutoriales 8 y 9, pero con algunas diferencias.
     La ms grande de ellas es que ya no vamos a utilizar nmeros de
     punto fijo NUNCA MAS! (Bueno, en realidad los usaremos de vez en
     cuando en ensamblador).

     Esto es debido a que el Pentium se ha convertido en el estndar
     actual y su coprocesador matemtico es tan rpido como los nmeros
     de punto fijo, pero con la diferencia de que el cdigo se vuelve
     mucho ms fcil de entender. De hecho, el coprocesador de los nuevos
     procesadores (MMX, K6, Pentium II, etc...) es an ms rpido que las
     operaciones de punto fijo.

     Otra diferencia importante es que de ahora en adelante dejaremos
     de usar el tipo real. En Turbo Pascal, las operaciones que se hacen
     con el tipo real no se realizan con el coprocesador, por lo que son
     MUY lentas. En cambio, utilizaremos el tipo double, el cual es
     mucho ms rpido y preciso que el real y es compatible con C/C++.
     Si el compilador les muestra un error a la hora de utilizar este tipo,
     recuerden que deben activar las opciones del coprocesador numrico.
     Para hacerlo, vayan al men Options, submen Compiler y activen
     la casilla [X] 8087/80287.

     Los que tengan un procesador 486 o menor, deberan seguir usando
     el punto fijo, aunque no lo usemos en el tutorial. O deberan
     pensar en actualizar su mquina :P

     La tercera diferencia es que vamos a dividir el cdigo de los
     ejemplos en varias unidades para poder entenderlo mejor.
     Una unidad contendr los procedimientos relativos a los vrtices,
     otra los relativos a las caras y objetos 3D y finalmente, el programa
     principal. Las tablas trigonomtricas precalculadas se almacenarn en
     la unidad de los vrtices, la cual es usada por las dems unidades.


     Por ltimo, un anuncio: Hace algunos meses hice un pequeo demo
     llamado "Stupikeffyloopy" del cual se encuentra disponible el
     cdigo fuente completo para TMT Pascal. Pueden encontrar el demo
     y el cdigo en el Hornet Archive o en mi homepage. El demo usa
     algunos efectos sencillos y algo de 3D y mapeado de texturas.
     Tambin ya est disponible el primer demo de Delabu Alama llamado
     "Barbie meets Eazy-E". Lo pueden encontrar en el Hornet Archive
     buscando el archivo dlb-brez.zip. Y muy pronto (si no es que ya)
     estar tambin disponible el demo "Off The Roof" (dlb_otr.zip),
     el cual es un demo muy bueno con algunos efectos originales
     y mucho de 3D, incluyendo tneles 3D, objetos deformados y metaballs!

     Bueno, vamos a lo otro......


ILUMINACION:

     Recuerdan el ejemplo del Tut #9? Nuestro cubo ya pareca mas slido,
     pero no haba forma de saber de donde provena la luz. Simplemente se
     le asignaba un color a cada cara y ese color no cambiaba, lo cual daba
     el efecto de que la luz incidente era la misma para todas las caras,
     en cualquier momento.

     Ahora supongan que todo nuestro espacio tridimensional est oscuro y
     colocamos un foco a la derecha del cubo. Esto hara que las caras
     que quedan a la derecha estuvieran mas iluminadas que las de la
     izquierda, y si el cubo est girando, entonces si una cara gira
     de la derecha hacia la izquierda, tambin debera irse oscureciendo.

     Adems, si un objeto est muy cerca del "foco", o de la fuente de luz,
     estar mas iluminado que si estuviera lejos de l.

     Por lo tanto, debemos encontrar una forma de lograr estos cambios en
     la iluminacin de nuestros objetos. Adems, podemos hacer que la
     fuente de luz no est fija, es decir que la podemos mover a donde
     queramos y obtener algunos efectos.

     Entonces, en resumen, esto es lo que vamos a ver:

               - Fuente de iluminacin
               - Sombreado plano
               - Sombreado por distancia


- Fuente de iluminacin:
------------------------

     NOTESE que dije "fuente", y no "fuentes". Eso significa que vamos a
     trabajar con una sola fuente de iluminacin, para que todo sea mas
     fcil. Adems voy a suponer que ya todos entienden lo que el trmino
     "fuente de iluminacin" mas o menos significa.

     Bueno, lo nico (por ahora) que necesitamos para tener una fuente de
     iluminacin, son sus coordenadas. A las cuales, desde ahora voy a llamar
     ix, iy, iz. Entonces la cosa es mas o menos as (en 2 dimensiones):

                                     |
                                     |      * (ix, iy, iz)
                                     |    /
                                     |  /
                                     |/
                   ------------------|--------------------
                                     |
                                     |
                                     |
                                     |

     Al vector que va desde el origen hasta el punto (ix, iy, iz) le
     llamaremos "Vector de Iluminacin", y obviamente es igual a (ix, iy, iz).

     El vector de iluminacin indica la direccin hacia la cual la luz est
     dirigida. Es decir que la luz siempre estar dirigida al origen, y lo
     nico que va a cambiar es el punto de donde proviene.

     As que vamos a tener algo como lo siguiente:

                   var Fuente : TVertice;

     Claro que la fuente de luz no es ningn vrtice, pero la declaramos
     de esa forma para poder rotarla y trasladarla como a cualquier vrtice.

     La variable anterior va a ser una variable global. Es decir que si
     tenemos 3 objetos tridimensionales en la pantalla, los 3 sern afectados
     por la misma fuente de luz. Tambin podramos hacer que cada objeto
     tuviera su propia fuente, pero esto no es muy comn.

     Y eso es TODO lo que hay que saber (por ahora) sobre una fuente de
     iluminacin. Solo tienen que tener en mente el concepto del vector de
     iluminacin y la siguiente parte ser igual de fcil.



- Sombreado Plano:
------------------

     Como ya les dije, el trmino "aplicar sombreado" significa hacer que
     un objeto 3D aparente estar iluminado por alguna fuente. Actualmente
     existen muchos mtodos de iluminacin y todos ellos se distinguen por
     su "aproximacin a la realidad" y su "complejidad y lentitud".

     El mtodo de sombreado plano es el mas sencillo y rpido de todos.
     Tambin el menos realista. La idea consiste en darle un color distinto
     a cada cara del objeto, segn su orientacin con respecto a la fuente
     de luz.

     Para entenderlo mejor, vamos a ver un ejemplo. Digamos que ustedes
     estn rotando un cubo, y supongamos que la fuente de iluminacin
     est sobre el eje Z, al igual que el observador.

     Ahora, si una cara queda de frente a ustedes, entonces quedara
     completamente iluminada, puesto que la luz le llega directamente.
     Pero si ustedes empiezan a rotar el cubo, esa cara se ir oscureciendo
     debido a que la luz ahora le llega de forma oblcua. Obviamente,
     esto tiene su explicacin fsica, pero es muy fcil entenderlo
     intuitivamente.

     Entonces, podramos decir que la "cantidad" de luz que le llega a
     una cara depende del ngulo que haga la cara con respecto al vector
     de iluminacin. Si la cara es perpendicular al vector de iluminacin,
     entonces estar completamente iluminada.

     Bueno, es muy fcil obtener el ngulo entre el vector de iluminacin
     y una cara del objeto, o mejor dicho, la normal de una cara. Para ello,
     utilizamos el producto punto entre dos vectores. Recuerden que el
     producto punto se puede obtener como la multiplicacin de las magnitudes
     de los vectores por el coseno del ngulo que forman entre ellos:

                     N  I  =  |N| * |I| * cos(angulo)

     N es el vector normal a una cara del objeto e I es el vector de
     iluminacin. Recuerden que el vector normal tiene una magnitud
     igual a uno, lo cual simplifica la frmula anterior. Si hacemos
     que el vector de iluminacin sea tambin unitario, entonces la
     frmula quedar muy simple:

                     N  I  =  cos(angulo)

     Y es por eso que debemos asegurarnos de que el vector I tenga
     magnitud igual a uno tambin. Recuerden que solamente hay que
     dividir al vector entre su magnitud para hacerlo unitario.
     Despus de eso, podremos rotarlo como cualquier otro vector.

     Por lo tanto, la frmula queda as:

         cos(angulo)  =  N  I  =  Nx * Ix + Ny * Iy + Nz * Iz

     El coseno nos dar un valor entre -1 y 1. Cuando ste sea 1,
     entonces la cara estar justo de frente a la fuente de iluminacin
     y estar completamente iluminada.

     Lo que debemos hacer ahora es obtener un color a partir del valor
     del coseno. Eso es muy fcil. Lo nico que debemos saber es el
     rango de colores que vamos a usar. Por ejemplo, si vamos a usar
     los colores del 0 al 64, entonces usaramos la siguiente formula:

                 color  :=  (cos(angulo) + 1) * 32;

     Le sumamos uno al coseno, lo cual nos da un rango entre 0 y 2,
     y al multiplicarlo por 32 el rango queda entre 0 y 64.

     Si quisiramos usar los colores del 128 al 254, usaramos lo
     siguiente:

                 color  :=  (cos(angulo) + 1) * 63 + 128;

     (cos(angulo) + 1) nos da un valor entre 0 y 2, al multiplicarlo por
     63 obtenemos un numero entre 0 y 126, le sumamos 128 y el rango
     queda entre 128 y 254.

     En general, podemos usar la siguiente frmula:

        color  :=  (cos(angulo) + 1) * (rango / 2) + colorinicial

     Y hacer que el rango y el colorinicial sean variables globales
     en nuestro programa para hacerlo mas flexible y poder utilizar
     la misma rutina de sombreado para diferentes rangos de colores.

     Despus de todo este rollo, lo nico que hay que hacer es calcular
     el color de cada cara y dibujarla con ese color.

     Bueno, es hora de checar el programa de ejemplo. El programa en s
     se llama BASE3D_3.PAS, el cual es la continuacin de los ejemplos
     anteriores, pero ahora se ha dividido en tres partes: la unidad
     VECTORES.PAS, la unidad OBJETO3D.PAS y el programa principal, adems
     se ha suprimido la unidad FMATH.PAS ya que ahora todos los clculos
     se hacen en el coprocesador usando el tipo double.

     Los programas precompilados vienen como CUBO.EXE y PIRAMIDE.EXE,
     los cuales son bsicamente BASE3D_3.PAS pero con figuras distintas.

     Dentro del programa se pueden usar las siguientes teclas:

            - ENTER:     para cambiar el color del objeto
            - ESPACIO:   para rotar la fuente de iluminacin
            - ESC:       para salir del programa

     La fuente de iluminacin en realidad es invisible, pero en el ejemplo
     se muestra como una pequea estrella, solamente para imaginarse de
     dnde proviene la luz y comprobar que el objeto se ilumine correctamente.

     La rotacin de la fuente de luz se realiza sobre el eje Y. En realidad,
     se puede rotar sobre cualquier eje, pero para los fines del ejemplo,
     el eje Y es suficiente.

     El procedimiento que dibuja un objeto con sombreado plano es
     el siguiente:


     procedure Objeto3DDibujaSombreadoPlano(obj : TObjeto3D; where : word);
     var i : integer;
         cosang : double;
     begin
          Objeto3DCalcula2D(obj);
          for i := 1 to obj.NCaras do
              if CaraVisible(obj.cara[i], obj) then
              begin
                   with obj.cara[i] do
                   begin
                        cosang := normal.x * FuenteLuz.x +
                                  normal.y * FuenteLuz.y +
                                  normal.z * FuenteLuz.z;
                        color := trunc((cosang+1) * rango/2) + colorinicial;
                   end;
                   CaraDibuja(obj, obj.cara[i], where);
              end;
     end;

     Como siempre, primero se calcula la proyeccin a dos dimensiones de
     todos los vrtices. Luego, para cada cara calculamos el coseno del
     ngulo que forma su normal con el vector de iluminacin, usando el
     producto punto. Finalmente obtenemos el color dentro del rango
     especificado por las variables globales rango y colorinicial.
     Entonces dibujamos el polgono. Eso es todo.


Otros cambios en el programa:
-----------------------------

     En el tutorial #9 vimos cmo funcionaba el algoritmo para determinar
     si una cara es visible o no. Todo dependa de la componente Z de la
     normal de la cara.

     Hace ya algn tiempo, me di cuenta de que ese algoritmo no era muy
     preciso, debido a que algunas veces se dibujaban caras que no deban
     ser visibles o viceversa. As que, experimentando un poco, encontr
     otra forma de determinar si una cara es visible o no. Este nuevo
     algoritmo es un poco mas lento, pero mucho mas preciso. Casi perfecto.

     La idea es bsicamente la misma, pero en lugar de utilizar la normal
     del polgono en 3D, calculamos la normal del polgono proyectado a
     dos dimensiones. Como ahora el polgono est en dos dimensiones,
     es decir, en el plano de la pantalla, su normal quedar siempre sobre
     el eje Z. Y de la misma forma que antes: si ese valor es mayor que
     cero, entonces el polgono ser visible.

     Bueno, suponiendo que los polgonos tienen al menos tres vrtices,
     debemos obtener dos vectores que correspondan a dos lados consecutivos
     del polgono, para ello, usaremos los tres primeros vrtices:

                   ax := Vertice[1].x2d - Vertice[2].x2d;
                   ay := Vertice[1].y2d - Vertice[2].y2d;

                   bx := Vertice[3].x2d - Vertice[2].x2d;
                   by := Vertice[3].y2d - Vertice[2].y2d;

     Noten que estoy utilizando x2d, y2d en lugar de x, y. Recuerden que
     vamos a usar la proyeccin a 2D en lugar del polgono en 3D.

     Entonces, (ax, ay) es el vector que va del vrtice 2 al vrtice 1,
     y (bx, by) es el vector que va del vrtice 2 al vrtice 3. Con estos
     dos vectores podemos calcular la normal haciendo el producto cruz
     entre ellos. Obviamente, solamente obtendremos la componente en Z,
     pero eso es lo nico que nos interesa:

                 normal2D  :=  (bx, by)  X  (ax, ay)

     Recuerden que el orden del producto cruz importa mucho. Estamos
     utilizando este orden porque nuestros vrtices estn ordenados
     en sentido CONTRARIO a las manecillas del reloj. Bueno, todo esto
     es puro rollo del tutorial #9.

     OK, entonces realizando el producto punto, obtenemos lo siguiente:

                  normal2D  :=  bx * ay  -  by * ax;

     Si normal2D es mayor que cero, entonces el polgono es visible.
     Eso lo podemos expresar en Pascal de la siguiente forma:

                  CaraVisible := normal2D > 0;

     Y con algunas sustituciones:

                  CaraVisible := (bx * ay - by * ax) > 0;

     Y otra forma mejor es:

                  CaraVisible := (bx * ay) > (by * ax);


     El procedimiento completo se encuentra en la unidad OBJETO3D.PAS,
     ah pueden compararlo con el procedimiento anterior y comprobar
     cul de los dos produce mejores resultados.



Sombreado por distancia:
------------------------

     Otra forma de aparentar sombreado es hacer que un objeto que est
     lejos de la fuente de luz se vea ms oscuro que uno que est cerca.

     Esto es muy fcil de implementar. Solamente necesitamos conocer
     la distancia desde el centro de la cara hasta la fuente de luz.
     Una vez que hemos calculado esa distancia, la multiplicamos por
     algn factor para obtener un valor dentro del rango permitido
     de colores y le restamos el resultado al color de la cara. Solamente
     hay que cuidar que el color resultante no quede debajo del rango
     permitido, es decir, que no sea menor que colorinicial.

     Por lo tanto, supongamos que la distancia mxima permitida entre la
     fuente de luz y el objeto 3D es 1000. Necesitamos conocer esta
     distancia mxima, sin embargo, podemos empezar utilizando algn
     valor arbitrario y modificarlo hasta que nos guste el resultado.

     Supongamos tambin que ya hemos calculado el color de una cara
     aplicando el algoritmo que vimos anteriormente. Entonces, aadimos
     las siguientes lneas para aplicar sombreado por distancia:

         color := color - round(rango * distancia / DistanciaMaxima);
         if color < colorinicial then color := colorinicial;

     en donde:

        color: es el color de la cara, previamente calculado
        rango: es el mismo rango de colores usado para el sombreado
        distancia: es la distancia entre la cara y la fuente de luz
        DistanciaMaxima: determina el valor mximo permitido para distancia

     NOTA: Si la variable color es de tipo byte, la resta nunca producir
     un valor negativo y el valor de color no tendr ningn sentido, por
     eso conviene usar el tipo integer para hacer el clculo anterior.

     La nica cosa difcil de calcular ahora sera la distancia, debido
     a que hasta ahora hemos trabajado con una fuente de luz que solamente
     tiene direccin, y por lo tanto, est descrita por un vector unitario.

     El problema del vector unitario es que no podemos utilizarlo para
     obtener ninguna distancia. Por lo tanto, lo que hay que hacer es
     lo siguiente: manejar la fuente de iluminacin como un vector cualquiera
     y NO normalizarlo. Porque si lo normalizamos, perder todo el sentido
     de "distancia". Desgraciadamente, esto tiene otras implicaciones:
     Si no normalizamos el vector de iluminacin, entonces tendremos que
     calcular su magnitud y dividir entre ella a la hora de obtener el
     coseno del ngulo que usamos para el sombreado. Esto no es realmente
     ningn problema, pero hay que hacerlo.

     Bueno, entonces vamos a calcular la distancia entre dos vectores:
     el vector de iluminacin y otro vector que corresponde al centro
     de la cara a la cual le vamos a aplicar el sombreado. Para obtener
     el centro de la cara, simplemente obtenemos el promedio de todos
     sus vrtices, mas o menos de la siguiente forma:

         var centro : TVertice;
             factor : double;

         centro.x := 0;
         centro.y := 0;
         centro.z := 0;
         for i := 1 to cara.NVertices do
         begin
              centro.x := centro.x + Vertice[i].x
              centro.y := centro.y + Vertice[i].y
              centro.z := centro.z + Vertice[i].z
         end;
         centro.x := centro.x / NVertices;
         centro.y := centro.y / NVertices;
         centro.z := centro.z / NVertices;

     Una vez que tenemos eso, hay que obtener la distancia entre el centro
     de la cara y el vector de iluminacin:

        distancia := sqrt((centro.x-FuenteLuz.x)*(centro.x-FuenteLuz.x) +
                          (centro.y-FuenteLuz.y)*(centro.y-FuenteLuz.y) +
                          (centro.z-FuenteLuz.z)*(centro.z-FuenteLuz.z));

     Ahora s podemos aplicar el sombreado con la frmula que vimos. Pero
     recuerden que tambin deben modificar la parte que realiza el sombreado
     normal debido a que el vector de iluminacin no est normalizado.


     El programa BASE3D_4.PAS muestra cmo se aplica el sombreado por
     distancia. Se incluye una nueva funcin para dibujar el objeto:
     Objeto3DDibujaSombreado(), pero esta funcin no se incluye en la
     unidad OBJETO3D.PAS, sino en el programa de ejemplo. Si ustedes
     quieren, la pueden inclur directamente en OBJETO3D.PAS, pero
     tengan en cuenta que aplicar este tipo de sombreado es mas lento
     y se notar la diferencia cuando utilcemos objetos ms complejos
     (en el prximo tutorial).

     En este nuevo ejemplo, pueden usar tres teclas adicionales:

        Q:   Acerca la fuente de luz hacia el centro
        A:   Aleja la fuente de luz del centro
        R:   Restaura la posicin original de la fuente (0, 0, 500)

     Jueguen un poco con el programa, pero no acerquen ni alejen demasiado
     la fuente de iluminacin, ya que eso se hace por medio del escalado,
     es decir que el vector de iluminacin se multiplica por un escalar
     para acercarlo o alejarlo del centro y puede llegar a haber un error
     si se hace muy grande. Adems de que no se hace ninguna comprobacin
     de lmites (clipping) al dibujar la fuente de luz.


FINAL:
------

     Bueno, esto termina con el tutorial #11. An nos falta mucho que
     ver sobre 3D: ordenacin de polgonos, sombreado gouraud y phong,
     mapeado de texturas y entornos y algunos efectos especiales que se
     pueden lograr con las 3D.

     Por ahora, el tutorial #12 ser sobre ordenacin de polgonos y
     posiblemente el #13 sea sobre sombreado gouraud. Tambin quiero
     hacer ms tutoriales sobre efectos diversos: agua, tneles, ondas,
     deformaciones, blurring, blobs, etc, as que hay mucho material
     como para otros 5 o 6 ediciones, al menos. Espero que tambin haya
     tiempo ;)


More words and phrases / my style amazes:
-----------------------------------------

     He aqu nuevamente la seccin de rimas que no viene al caso con el
     tutorial....... pero como nadie se ha quejado.........  :P


     "Yo soy un disco quebrado /
      yo tengo chicle en el cerebro"

                      Beck - Hotwax

      "So yo, who be dat?
      Dat wanna do me like this to get booby trapped
      jack,
      cos my crew be strapped fat
      like dat"

                      Das EFX - Back 'N Affect

      "Bonita Applebum
       You got to put me on"

                      Q-Tip - Bonita Applebum


Y por supuesto, la seccin amarilla:
------------------------------------

  -------------------------------------------------------------------------
  |                                                           |
  |                                                          |
  |                         |
  |                  |
  |                          |
  |                      |
  |                  |
  |                   |
  |                    |
  |                                                                       |
  |        presenta (no muy) orgullosamente sus nuevas producciones       |
  |                                                                       |
  |   STUPIFEKKYPLOOPY        BARBIE MEETS EAZY-E         OFF THE ROOF    |
  |    (f_loopy.zip)            (dlb-brez.zip)           (dlb_otr.zip)    |
  |                                                                       |
  |                                                                       |
  |   Disponibles en formato ZIP en los siguientes lugares:               |
  |                                                                       |
  |          - http://www.hornet.org/demos                                |
  |          - http://galia.fc.uaslp.mx/~ganzo/prog/demos.html            |
  |                                                                       |
  |   fac:   fac@slp1.telmex.net.mx   |  mr. e:   mre@galia.fc.uaslp.mx   |
  |          shadowfac@hotmail.com    |                                   |
  -------------------------------------------------------------------------
          ----------------------------------------------------------
          |                                                        |
          |    Tienes algo que decir o anunciar al resto de la     |
          |               comunidad programadora?                  |
          |                                                        |
          |             Para eso est este espacio!                |
          |                                                        |
          |     Enva tus anuncios a  fac@slp1.telmex.net.mx       |
          |   con el ttulo "Tutorial - Anuncio" y ser puesto     |
          |                 en el prximo tutorial                 |
          |                                                        |
          |    * Limitado a dos o tres anuncios por tutorial *     |
          |                                                        |
          ----------------------------------------------------------
  -------------------------------------------------------------------------
  |                                                                       |
  |       Quieres aprender los ltimos trucos sobre programacin?         |
  |                                                                       |
  |  - Grficos - Windows - Linux - C++ - VESA 2.0 - Direct X - Sonido -  |
  |                                                                       |
  |           El nico lugar es en los canales #coders en IRC             |
  |                                                                       |
  |                     UnderNET:  us.undernet.org                        |
  |                       ircNET:  irc.stealth.net                        |
  |                                                                       |
  |         #coders en UnderNET son mas orientados a los juegos           |
  |         #coders en  ircNET  son mas orientados a la "scene"           |
  |                                                                       |
  |          Tambin en UnderNET: el nuevo canal #programacin            |
  |                                                                       |
  |       Consigue tu programa de IRC y date una vuelta en #coders        |
  |                                                                       |
  -------------------------------------------------------------------------
