lunes, 17 de diciembre de 2012

Texturas BMP con SDL en objetos 3D OpenGL (The easy way)


Tetris

Es un juego originalmente programado por Alekséi Pázhitnov en la Union Sovietica, cuyo nombre viene de un prefijo numérico “tetra” (4) y el nombre del pasatiempo favorito de su creador, el tenis.
Este juego probablemente sea uno de los que mas versiones tiene, pues existe una para casi cada consola, aparato portátil, sistema operativo que existe, lo que le dio según la revista Electronic Gaming Monthly el titulo de el “mejor juego de todos los tiempos”

El programa a presentar esta vez, mas que un juego es una presentación de gráficos de OpenGL 3D con texturas cargadas a través de SDL, que de alguna forma, basa su estética en el juego original no siendo “fiel” en particular a ninguna versión conocida de tetris




Screenshot de los gráficos logrados


Para el desarrollo de la aplicación se ocuparon diferentes texturas cargadas como imágenes en formato BMP, lo que en fin, con un trabajo mas acabado se podría lograr un aspecto muy cercano al original del juego.



                   Screenshot de una de las versiones mas famosas del juego, la de NES


Descripción de la solución

Abordare esta parte del informe tomando primero en cuenta el enunciado propuesto por el profesor, para luego abordar los detalles técnicos la implementación del juego en su conjunto.

  • Sobre los objetos estáticos: Puesto que esta aplicación es mas que nada una presentación de gráficos no pretende ser jugable mas que por una mera demostración, por tanto solo existe un objeto estático que vendría siendo el escenario que es invocado mediante la función cargar_escenario(); que se apoya en una función creada anteriormente para cargar texturas desde imágenes en formato BMP.

  • Sobre los objetos animados: debido a especificaciones del enunciado la mayoría de los objetos son animados, aunque si se controla mediante el teclado uno puede desplazar o rotar de manera total el escenario junto a sus elementos.
Un alcance MUY importante es que todos los objetos se encueran animados por una única función que gracias a “glutTimerFunc(1,Avanzar,1);” se ejecuta cada 1 ms (milésima de segundo) asignando nuevos valores a variables globales que intervienen a través de todos los procesos del juego.

  • Por ultimo respecto al código:

El programa completo se encuentra segmentado en 3 partes un archivo de extensión “.c” y dos headers “.h” , esto debido que se separo lo que tiene que ver con funcionalidades de glut y linea general en un archivo “tetris.c”, el manejo de sprite y sus matrices en “sprites.h” y las acciones y mecánica del juego en “ttGL_SDL.h” (se describirá con mayor detalle en el siguiente tema).

Debido a la falta de exactitud en cuanto al temporizador que provee glut, la velocidad debe ajustarse en el código manualmente si es que este llegara a verse demasiado rápido, (el numero a modifica se encuentra en el archivo “tetris.c” y se encuentra debidamente comentado.

Alcances:
  1. Existe forma de usar diferentes formatos para crear texturas para objetos creados con OpenGL, sin embargo no existe necesidad de reinventar la rueda para este cometido, por tanto se integra en este código de manera simple SDL y OpenGL (cosa que en realidad parece simple desde el punto de vista de codificación, pero se podrá observar que en los ejemplos propuestos en Internet el estilo de codificación cambia demasiado al integrar OpenGL con SDL, pues bien este no es el caso)
  2. Si bien SDL provee un completo conjunto de bibliotecas que hubiesen podido hacer posible la construcción de las demostración casi en su totalidad (excepto por el modelado 3D) no era materia del curso el trabajar con al API de SDL, por tanto solo se utilizo un mínimo de su capacidad para integrar la funcionalidad de las texturas al modelado con OpenGL.
  3. Las aplicaciones generadas con parte de esta API (SDL), por lo menos en versiones antiguas de windows XP, necesitan de la DLL “SDL.dll” pues en ellas se encuentran binarizadas las definiciones de las funciones que requiere SDL para su funcionamiento.
  4. Una observación importante es como cambia el mapeado de las texturas cuando se cambia entre “glOrtho” a “glPerspective”, pues uno respecto al otro invierte los mapeados hechos, por tanto para una plena compatibilidad entre estos modos es necesario tomar en cuenta en esto y programar debidamente, en esta demostración, eso no se hizo, ya que al existir este alcance se necesita comprobación.
  5. Por ultimo señalar que esta vez se trabaja con una melodía en formato WAV, cuya funcionalidad esta soportada por una biblioteca no portable, propia de los sistemas Microsoft.


Descripción de funciones y archivos usados:

tetris.c: En este archivo se encuentra la linea general de la demostración, ademas de las funcionalidades de glut que apoyan el proceso, tales como el apoyo al teclado, el re dimensionamiento de objetos etc.
  • void InicializarGL(); esta es una función de propósito general no especifica para el juego, libera de código extra en la función main(); ya que se encarga de tareas especificas de glut que no necesariamente son tarea de la linea principal de un programa.
  • void display(); esta función se encarga de exhibir todos lo objetos del juego y debe ser específicamente llamada por la función glutDisplayFunc(display); de lo contrario no hará nada.
  • void resize(int w, int h); esta función se encarga de ajustar los tamaños si es que la ventana se redimensiona, ademas crea la escala con la que se trabajara en el resto del juego, los argumentos “w”, “h” usan como argumento el tamaño actual de la pantalla.
Esta función debe ser llamada o enviada como argumento específicamente a la función glutReshapeFunc(resize); de lo contrario tampoco se hará nada.

  • void ControlTeclado(unsigned char key, int x, int y); fácil, esta función controla las teclas que no son especiales dentro del juego “ENTER” y “ESC” y debe ser argumentada para la función glutKeyboardFunc(ControlTeclado); y sus argumentos propios son un “key” correspondiente a una tecla y un “x” , “y” que aunque en mi caso particular no ocupo debe ser igualmente anexado.
  • void ControlFlechas(int key, int x, int y); igualmente fácil, esta función se encarga de los eventos que ocurren con la flechas del teclado, puesto a que estas son teclas especiales, no se consideran dentro de la función descrita anteriormente por tanto son argumentadas a glutSpecialFunc(ControlFlechas); y también cuentan entra sus argumentos un “key” que es la flecha oprimida, y un “x”, “y” que no utilizo.
  • void timer(int x); función que se auto ejecuta sobre intervalos dados que gracias a esto provee movimiento a la demostración.

tGL_SDL.h: En este archivo se concentran las acciones propias del juego y el soporte a texturas SDL no la funcionalidades de glut como por ejemplo la carga escenarios y piezas ademas de la variables globales que apoyan los cálculos y conjunto de flags que permiten las acciones

  • void void setmov(); esta función se encarga de establecer los valores iniciales (si es que se necesita) de la mayoría de la variables globales del juego.
  • SDL_Surface *LoadBMP(char *filename); función genérica VITAL para el trabajo con texturas y la integración de OpenGL y SDL, ademas genera archivos con los respectivos mensajes de error creados por SDL, da soporte al formato BMP que corresponda a la porfundidad de color requerida, en este caso imagenes de 24 bits (ni mas ni menos).
  • void LoadGLTextures(); función muy simple que se encarga de la transformación de archivos BMP a texturas que OpenGL puede utilizar
  • void cargar_piezas(int pieza); pone las piezas en juego y soporta la rotación de estas que se hace mediante el teclado se guia gracias a las matrices que hay en el archivo sprites.h.
  • void cargar_titulo(); Pone en pantalla el titulo de la demostración y soporta el cambio de color de sus miembros individuales.
  • void cargar_escenario(); crea el marco de trabajo con las texturas indicadas;
  • void cubo(int color, int x, int y, int z); crea la unidad de trabajo ademas de texturizarlo según el color pedido
space_sprites.h: aquí se encuentra la parte artística de todo este asunto, este archivo contiene el conjunto de sprites en matrices, que guisan a los procesos en como hacer las piezas y generar el titulo para esta demostración.


Librerias necesarias:Librerias 
Enlace descarga: tetris.rar

NOTA:

Esto es una demostración de gráficos basados en tetris se deben instalar los dos devpak
guardados en la carpeta "librerias"

1- la siguiente linea puede necesitarse como parámetro en el compilador (DEV-C++)
-DGLUT_STATIC

2- la sieguiente linea debe agregarse como parametro al linker (DEV-C++)
  -lmingw32 -lglut32 -lglu32 -lopengl32 -lwinmm -lgdi32 -lSDLmain -lSDL -lSDL_image

jueves, 11 de octubre de 2012

Space Invaders OpenGL (GLUT)


Space Invaders

Space invaders es un juego diseñado originalmente por Toshihiro Nishikado de Taito Corporation en el año 1978, que tuvo un gran éxito en el mercado, considerándoselo un clásico hasta el día de hoy, del cual se crearon versiones para distintas consolas y sistemas, pues curiosamente este no contaba con protección de copyright.

El juego se trata de eliminar oleadas de marcianos con un cañón el cual el jugador controla, antes de que estos lleguen a la “tierra”.
En el juego aleatoriamente y con una cantidad de puntaje indefinida aparece una nave extraterrestre de color rojo que proporciona al jugador, si este logra destruirla una cantidad aleatoria de puntaje, ademas en la pantalla de juego hay lo que parecen ser 4 bunkers que “ayudan” a defender la tierra.

En la versión creada en esta ocasión, hay algunas diferencias que por razones de tiempo no termine de programar, aunque en su esencia, se puede aprecia del juego su lógica y estética.

No ha sido fácil “emular” la estética del juego, puesto que encontrar los sprites originales en la web, a sido un trabajo muy duro, puesto que la cantidad de imitaciones del juego es basta, asi en el proceso de desarrollo, se obtuvieron resultados hasta llegar a tener una lo mas parecido al “original”, o mas bien al que todos conocen.

Screen durante el desarrollo del juego

Para el desarrollo de la aplicación se ocuparos los sprites de la siguiente imagen como modelos, alcanzando una estética bastante similar.


Screen original del juego

Screen actual del desarrollo
Los elementos faltantes dentro del diseño aun se encentran en fase de implementación, por falta de tiempo, aunque en teoría estos no son de una gran complejidad, puesto que la parte lógica “gruesa” del diseño ya se encuentra programada y entendida en el código.

Para finalizar con la presentación de la aplicación una ultima imagen correspondiente a la pantalla de inicio del juego, espero que lo disfruten.

Screen vista actual
Descripción de funciones y archivos usados:

space_slpha.c: En este archivo se encuentra la linea general del juego, ademas de las funcionalidades de glut que apoyan el proceso, tales como el apoyo al teclado, el re dimensionamiento de objetos..
  • void IniciarGLUT(); esta es una función de propósito general no especifica para el juego, libera de código extra en la función main(); ya que se encarga de tareas especificas de glut que no necesariamente son tarea de la linea principal de un programa.
  • void PintarEscena(); esta función se encarga de exhibir todos lo objetos del juego y debe ser específicamente llamada por la función glutDisplayFunc(“PintarEscena”); de lo contrario no hará nada.
  • void ReProyectar(int w, int h); esta función se encarga de ajustar los tamaños si es que la ventana se redimensiona, ademas crea la escala con la que se trabajara en el resto del juego, los argumentos “w”, “h” usan como argumento el tamaño actual de la pantalla. Esta función debe ser llamada o enviada como argumento específicamente a la función glutReshapeFunc(ReProyectar); de lo contrario tampoco se hará nada.
  • void ControlTeclado(unsigned char key, int x, int y); fácil, esta función controla las teclas que no son especiales dentro del juego “ENTER” y “ESC” y debe ser argumentada para la función glutKeyboardFunc(ControlTeclado); y sus argumentos propios son un “key” correspondiente a una tecla y un “x” , “y” que aunque en mi caso particular no ocupo debe ser igualmente anexado.
  • void ControlFlechas(int key, int x, int y); igualmente fácil, esta función se encarga de los eventos que ocurren con la flechas del teclado, puesto a que estas son teclas especiales, no se consideran dentro de la funcion descrita anteriormente por tanto son argumentadas a glutSpecialFunc(ControlFlechas); y también cuentan entra sus argumentos un “key” que es la flecha oprimida, y un “x”, “y” que no utilizo.


space_alpha.h: En este archivo se concentran las acciones propias del juego y no la funcionalidades de glut como por ejemplo la pantalla de juego, la pantalla principal y la acción de disparar, ademas de la variables globales que apoyan los cálculos y conjunto de flags que permiten las acciones

  • void cargar_variables(); esta función se encarga de establecer los valores iniciales (si es que se necesita) de la mayoría de la variables globales del juego.
  • void disparo(); se encarga de la acción de disparo cuando el usuario ataca.
  • void pantalla_de_juego(); pantalla de juego, básicamente el alma del juego, posiciona enemigos y jugador en la pantalla aparte de hacer los cálculos de rectángulos mínimos que se necesitan para detectar las colisiones, (el calculo del choque directo entre jugador y extraterrestre no se encuentra hecho aunque si se detecta si un disparo destruye a un enemigo(es efectivamente destruido)).
  • void presentación(); simple y estética, es la pantalla de “bienvenida al juego”, cabe señalar que si se esta un tiempo mirando la pantalla la nave roja o “UFO” escapara de la vista del usuario (efecto de una animación programada no una torpeza).
  • void Avanzar(int x); función recursiva que se encarga del manejo de contadores y posiciones necesarias para la correcta ejecución del juego aparte de dar continuidad en caso de que el usuario no intervenga “jugando”

space_sprites.h: aquí se encuentra la parte artística de todo este asunto, este archivo contiene el conjunto de sprites en matrices, y las respectivas funciones que manejan dichas matrices, básicamente todas la funciones hacen lo mismo pero al ser diferentes los tamaños de cada objeto no me propuse el crear una función genérica para todos los sprites, aunque si agrupe los de características similares.
  • void ubicar_sprite(int sprite, float six, float siy, float tam_pix); pone enemigos y jugador en pantalla “sprite”, es el subindice correspondiente al sprite deseado:
0 - “CALAMAR”
1 - “CANGREJO”
2 - “PULPO”
3 - “UFO”
4 - “NAVE”

Las variables “six”, “siy”, son posiciones eje coordenados para los objetos, y “tam_pix” define el tamaño del pixel usado para imprimir el objeto.

  • void simbolo(int sprite, float six, float siy); similar al anterior, pero imprime símbolos definidos en la matriz que maneja, no define tamaño de pixel:

0 - “?”
1 - “!”
2 - “=”

  • void say_space(float six, float siy); pone la palabra space en pantalla en la posición (six, siy);
  • void say_invaders(float six, float siy); pone la palabra invaders en pantalla en la posición (six, siy);
  • void say_pts(float six, float siy); pone la sigla pts. en pantalla en la posición (six, siy);
  • void numero(int num, float six, float siy); función similar al a ubicar sprite pero esta imprime números en pantalla donde, “num” es el numero a imprimir.
  • void bala(float six, float siy); pone el disparo en pantalla cuando se dispara;
  • void mostrar_text(char cadena[], float x, float y); imprime texto sin sprite donde “cadena[]” es el texto a imprimir, y (“x”, “y”) la posición.



    Enlace descarga código fuente: Space_invaders.rar








lunes, 8 de octubre de 2012

Ejemplo Simple OpenGL/glut

No acabo de encontrar un ejemplo de OpenGL que sea lo suficientemente simple y completo como para partir de una base cada vez que empiezo a escribir algún demo.
Me ahorre las explicaciones teóricas y entre otras cosas el siguiente código aplica, uso de teclado y sus funciones especiales, rotaciones controladas por teclado del plano general, rotaciones y traslaciones de los objetos en si (las cuales también pueden ser activadas o desactivadas por teclado) ademas del uso de objetos 3D.

Bueno, no es la gran cosa pero aquí esta, las teclas de función y sus respectivos usos están en los comentarios del código:

Enlace código: soltierraluna.c

Y aquí dejo un video demostracion:


domingo, 27 de mayo de 2012

Galería de fotografías automática (solo PHP y CSS)

Me gustan las cosas cómodas, aunque esto conlleve por lo general un esfuerzo adicional dado que no soy un experto en nada.
La cosa esta vez fue que desarrollando (de una forma menos que amateur) un sitio se me pido que manejara una galería de imágenes, rápidamente pensé... "Bueno existen muchos programas que generan galerías de manera automática en php o en flash de manera rápida solo dándole una lista de la imágenes que se desean poner en la web...." y  voilá, miles de gestores en la web... luego la pregunta matando mis ilusiones... "después puedo agregar mas fotos verdad?" El viento helado en mi espalda me recuerda que la mayoría de los gestores en la web no son automáticos, no es que uno les agregue una carpeta a su ruta y auto generen una galería, en la vida real esto no es así, y aunque hay algunos que si lo hacen, son un infierno de archivos... un infierno en el que no estoy dispuesto a entrar.

Pues bien el tema esa vez era crear una galería automática (que tome las fotos directamente del directorio donde se encuentran) de una manera absolutamente minimalista que genere vistas previas y que permita a su vez abrir individualmente cada foto haciendo un efecto tipo presentación, cabe señalar que no había mucho tiempo y mis conocimientos en javascript eran y son bastante limitados, por tanto me dispuse a programar con lo que mas o menos dominaba PHP y CSS

No voy a entrar en detalles respecto al código esta vez pues son varios archivos, en vez de eso dejare el un link con la galería a la vista y uno para su descarga completa y funcional (contiene álbumes con imágenes de muestra) con comentarios en el archivo principal "galeria.php".


Vista de Galería:



Vista de presentación:




Link de descarga: galeria_automatica.rar

Están advertidos que el código no esta completamente depurado y que quizá a partir de este alguien pueda crear algo que sea 1 chilion de veces mas eficiente, en fin.... a mi me resulto bien, pero como digo siempre... si alguien quiere lo mejora o encuentra errores siempre estaré agradecido de que me lo comenten.




jueves, 24 de mayo de 2012

Hola Mundo .NES... en C!!

Eso mismo pues, roms de NES generadas con simple y conocido lenguaje C, se trata de un compilador de C para sistemas basados en el procesador 6502 llamado cc65. El cc65 es capaz de compilar para sistemas Commodore, Atari y teóricamente Apple II (todos basados en el 6502), si bien yo me oriente principalmente en NES (por ser mi consola favorita) la información completa esta disponible en el sitio oficial del compilador para que prueben en el resto de los sistemas:

http://www.cc65.org/

A continuación el código del programa mas simple disponible prácticamente para cualquier lenguaje, esta vez compilable para roms de la vieja NES:

#include <conio.h>
int main (){
    gotoxy(6, 10);
    cprintf("Hola Mundo con cc65...\n");
    gotoxy(6, 12);  
    cprintf("Saludos Mirager...");
    while(1){}
    return 0;
}

Si bien para un programador, que conozca el lenguaje C esto es un código muchos menos que básico, a la hora de compilar habrá que tomar en cuenta las limitaciones de cada consola, este ejemplo debería ser compilable para todas ellas al no requerir de ninguna característica especial.
Otro dato a considerar es la forma en que se compilan los objetos, pues existe una forma paso a paso (lenta pero segura) y una forma rápida (con defectos), a continuación las dos opciones

A)


La forma paso a paso resultara útil una vez avanzando un poco con este tema para el uso de joystick y características propias de cada sistema, para este simple código seria de la siguiente forma:

holamundo.c -> cc65 -> holamundo.s ->  ca65 -> holamundo.o -> ld65 -> holamundo.nes (en esta parte se deberá linkar la librería del sistema requerido, en este caso nes.lib)

a continuación una imagen descriptiva:



Si tienes un emulador de NES instalado y configurado para abrir las roms automáticamente, el resultado debería verse como este (de lo contrario deberás abrir la roms manualmente desde el emulador (demasiado obvio)):


B)


La forma rápida para este código pasa por programa que se encarga de generar los ficheros necesarios para la compilación de la rom:

holamundo.c -> ld65 ->holamundo.nes

probablemente por alguna mala utilización mía el resultado se ve similar pero no idéntico, seguramente habrán usuarios del cc65 que conozcan bien las limitaciones de este compilador, de todos modos aqui va una imagen descriptiva:




Y el resultado generado es mas o menos así:



Podrán darse cuenta que en el caso de las letras mayúsculas en vez de diferenciarlas en tamaño con respecto a las minúsculas les agrega un fondo y ennegrece, si alguien esta sobrado de tiempo y descubre si se debe a una mala utilización del programa, siempre estaré agradecido de que me lo diga o comente :D

Mirager  

lunes, 21 de mayo de 2012

Perdida de precisión punto flotante (float) en C

Experimentando con distintas formulas implementadas en C, recién después de muchos años de ocupar este lenguaje caí en cuenta de la perdida de datos que acarrea el uso en operaciones sucesivas del tipo de dato float, tanto así que ociosamente me di el trabajo de hacer un programa que demostrara dicha perdida.
La información en general en Internet respecto a este punto es bastante limitada siendo la fuente que mejor explica este tema una pagina relacionada con la queridisima empresa para mis compañeros linuxeros microsoft :D


fuente: http://msdn.microsoft.com/es-es/library/c151dt3s.aspx


Si alguno de mi compañeros anda por ahi sobrado de 5 minutos para hacer copy paste del código, y lo prueba en linux, agradecería que me comente sus resultados :D


#include <stdio.h>


int main(){
    float a;
    float numero;
    float ultimo;
    printf("Elija el numero para calcular la precision: ");
    scanf("%f", &numero);
    for(a=0;a<=numero;a+=0.1){
        //printf("\n%f", a);
        //printf("\n%.21f", a);
        printf("\n\tnumero mostrado: %f, numero real %.21f", a, a);
        ultimo=a;
    }
    printf("\n");
    printf("\nNumero ingresado %d", (int)numero);
    printf("\nNumero en punto flotante %f", numero);
    printf("\nNumero en punto flotante con precision %.21f", numero);
    printf("\nUltimo numero del ciclo: %f", ultimo);
    printf("\nUltimo numero del ciclo con precision: %.21f", ultimo);

    printf("\n\nEstos numeros se obtienen cuando se corta el ciclo (for):\n");
    printf("\nNumero final procesado en punto flotante %f", a);
    printf("\nNumero final procesado en punto flotante con precision %.21f", a);
    getch();
    return 0;
}