Tag Archives: Opengl

Diario de desarrollo (SeventhEngine): OpenGL

opengl

Hace bastante tiempo que no escribo por estos lares. Pero eso no significa que no le haya dado caña, ni mucho menos, al desarrollo del motor. En estas semanas he tenido bastantes problemas de tiempo, pero aun así he sacado lo suficiente para seguir avanzando sustancialmente. Por otro lado, he encontrado problemas grandes, sobre todo con el tema del renderizado, y me he decidido finalmente a hacer una refactorización final, con los errores aprendidos y asumidos, del rendering pipeline. De este modo CTexture y CTextureManager desaparecer. Además, a partir de ahora SDL, en lo que a gráficos respecta, sólo será un intermedio entre el motor y OpenGL.

OpenGL >>>>> SDL_Surface

Uno de los objetivos del proyecto es conseguir que el motor sea multiplataforma, es decir, compile tanto en Windows, como en Linux y Mac OSX. Este último SO lo dejo para el final, pero Linux y Windows, especialmente Windows, requieren de muchas optimizaciones, no sólo en código, sino a la hora de compilar. Siendo un desarrollo inicial en Linux, el motor funciona bastante bien en esta plataforma. Sin embargo, al compilar en Windows, además de tener que hacer modificaciones en el código (el compilador de C++ de Windows es menos permisivo que gcc), hay que elegir muy bien el tipo de compilación que queremos y sus parámetros. En Visual Studio 2010 mayormente se trabaja en modo Debug, pero este entorno no tiene apenas optimizaciones de compilación, linkeo, etc. y trabajar así es muy lento. No obstante, compilar bajo Release, con todas las optimizaciones activas, etc. da unos resultados aceptables.

La decisión crítica en este proceso fué dejar de usar SDL_Surface, la unidad básica de gráficos de SDL. Puesto que SDL es mucho más lento que OpenGL, decidí dejar de usar los SDL_Surfaces como elemento básico de renderizado en el motor. Sin embargo, usaré los SDL_Surface como el paso intermedio para cargar gráficos en la memoria. Puesto que la interfaz de uso de SDL es más sencilla que OpenGL, la usaré para hacer una carga inicial de los recursos (además, los recursos serán imágenes de formatos normales, jpg, png, etc. es decir, no habrá formato propio por el momento); una vez hecha la carga del recurso, transferirla a OpenGL para que éste gestione su renderizado. De este modo uso lo mejor de ambos sistemas. La penalización es la sobrecarga a la hora de cargar recursos, penalización aceptable si tenemos en cuenta que el sistema optimiza (a través de varios flags) la carga dinámica de los recursos:

  • Mantener en memoria lo que ha cargado hasta que haya una señal específica de limpieza, por ejemplo al final de un State o de un World.
  • Hacer la carga en memoria sólo de aquellos elementos que se está visualizando en memoria: muy óptimo en cuanto a memoria, pero bastante lento si tenemos muchos elementos cambiantes en el juego.
  • Mi solución preferida, un híbrido entre ambos: eliminar aquellos elementos que no se están visualizando, pero no tocar aquellos a los que previamente hemos asignado una flag indicando que vamos a usarlo a menudo en el juego. Por ejemplo, en un juego de disparos, añadiríamos a la lista de recursos itinerantes las balas, los efectos, etc. que si bien no se están mostrando continuamente, si que es susceptible de aparecer a menudo. Por otro lado, elementos circunstanciales (un jefe final, por ejemplo), podemos asignarles memoria sólo cuando estén presentes en la pantalla.

De este modo me ahorro el poco intuitivo sistema de carga de recursos en OpenGL (http://www.nullterminator.net/gltexture.html), lo cual añade facilidad al desarrollo. Para el futuro se queda el eliminar esa dependencia de SDL, y añadir soporte, si bien ya tiene para gráficos comunes, para formatos específicos definidos por el usuario.

VS2010
Compilar en Windows se convirtió en toda una odisea

Modelo de Entidades

Por otro lado, el sistema de entidades ha quedado más o menos diseñado y resuelto, a falta de añadir soporte para cámaras y demás, y hay ejemplos de código en el repositorio. Todo lo que se mostrará, exceptuando mapas y texturas superpuestas (UI, menúes, etc.), serán entidades. Es decir, un objeto usable, el personaje principal, los enemigos, las partículas, efectos, etc. estarán resueltos sobre el modelo base de entidad en el motor. De este modo, y como ya expliqué en la entrada anterior, podremos hacer uso intensivo de la herencia para crear entidades comunes con pequeños cambios, etc. todo esto forma parte del usuario. El modelo base de entidades resuelve lo siguiente:

  • Proporciona interfaces de métodos comunes a todas las entidades: cargar un recurso, mostrar/ocultar, mover de posición, asignar una cámara, comprobar colisiones, etc.
  • Se garantiza que ciertos métodos (OnRegister, OnCameraChange, OnDelete, OnEvent) serán llamados cuando se produzca, lo cual nos permite definir distintas acciones para las entidades que hereden de aquí.
  • La carga/descarga de recursos se realiza de forma transparente, y el motor es el que se encarga de asignar/liberar memoria de una forma óptima.

Podéis ver el código de este modelo base en CEntity y CEntitymanager.

CResourceManager

Una parte esencial de los motores gráficos es la gestión de los recursos de manera eficiente. Esto se divido en 2 grandes bloques: cargar en el programa la lista de todos los recursos que serán necesarios a lo largo de la ejecución del juego, y cargar en memoria / borrar aquellos elementos que se estén usando en el momento de forma dinámica y eficiente. En el primer bloque, necesitamos primeramente definir la manera en que proporcionaremos estos recursos al motor. En el caso de SeventhEngine, se usará un archivo XML con todos aquellos recursos definidos por el usuario. Tendrá el siguiente formato:

Como véis, es bastante intuitivo y fácil de usar. Con esta información, cargada al inicio del motor, podremos usarla desde todos los módulos del motor para cargar nuestros recursos cuando los necesitemos. Por ejemplo, si tenemos una entidad, que en principio sólo usará una textura como elemento gráfico, desde el ResourceManager tendremos que hacer:

Si a lo largo del juego, necesitamos asignar un animación a la misma entidad, haríamos:

La interfaz es completamente transparente. El gestor de recursos se encargaría de enviar una señal al rendering pipeline de qué elementos tiene que renderizar, de si se ha dejado de usar una textura (y en este caso, comprobar si hay más elementos con la misma textura usándose, etc.), y varias opciones más, de manera que la carga / descarga de recursos se hace de manera transparente. Esto es importante, porque, además de que el usuario no tiene porqué saber nada de como se gestionan los recursos (excepto en casos especiales en dónde una acción del usuario es necesaria para que el motor sepa qué optimizar o no y que dependen del tipo de juego que se tenga que desarrollar), porque ocultar esa información nos permite realizar optimizaciones internas, o incluso cambiar el sistema por completo. Este es un concepto muy importante del desarrollo OOP, Information Hiding (http://en.wikipedia.org/wiki/Information_hiding).

Hay varios casos especiales, como el de los mapas, que usarán un sistema distinto, y que explicaré más detalladamente en otras entradas.

Eso es todo por hoy. Espero volver a coger soltura en las entradas a partir de la semana que viene, con el objetivo de 1 entrada semanal. Además, la primera demo del motor deberá estar disponible para principios de año, y el juego elegido será un Pong. Si tenéis alguna duda, ya sabéis, a los comentarios :)

Diario de desarrollo: motor gráfico en 2D

Hará unos 3 meses me propuse empezar a desarrollar un motor gráfico, mi área favorita del desarrollo de videojuegos. Previamente había leído (y sigo haciendo a diario), muchos materiales y libros sobre el tema. No obstante, siento que es la hora de ponerse realmente a hacer algo. Si bien no es fácil hacer un motor gráfico, me lo he propuesto más que nada como ejercicio de programación, mayormente para mejorar mi nivel de C++, en el cual he avanzado bastante en los últimos meses. Son muchas las ventajas de trabajar en un proyecto así:

  • Por un lado tocas bastantes áreas del desarrollo de juegos en sí, puesto que tienes que diseñar sistemas genéricos, y a menudo probarlo creando un juego real (aunque muy básico).
  • Te ayuda continuamente a mejorar cosas como los patrones de diseño y su aplicación, refactoring, unit testing, y otras técnicas de programación.
  • Ayuda a adecuar tu mente a proyectos de esta magnitud, y a saber llevar un sistema de organización, a todos los niveles.
  • Además, si usas un VCS (cómo svn o git) puede aumentar enormemente tu control sobre ellos, cosa obligatoria hoy en día.
  • Aprender a usar frameworks y librerías externas en relación con tu proyecto.

Cómo he mencionado antes, voy a usar git como sistema de control de revisión, y lo voy a alojar bajo GPL en github. Además, como base voy a usar SDL (Simple Direct Layer) y OpenGL, productos que os tienen que sonar seguro.

tileset

De hecho, empecé a programar las primera base de código hará unos 4 meses. No obstante, me dí cuenta a medida que avanzaba de que el diseño no era el adecuado, y que había cometido errores graves en cuanto a modularización, y un uso prácticamente nulo de patrones. Es por ello por lo que voy a rehacer el proyecto desde 0, solamente conservando un par de snippets que me servirán para la nueva versión (¡si se puede llamar así!). Además, ahora puedo aplicar las buenas prácticas sobre C++ que he ido leido estas semanas. Si queréis echar un vistazo a esta primera tentativa, podéis verla en Github:

https://github.com/AlbertoFEM/SeventhEngine

¿Olvidé mencionarlo? Se llamará SeventhEngine. A lo largo de lo que dure el desarrollo (con vistas a no acabar nunca) iré escribiendo esta especie de Diario, con los problemas que me encuentre, decisiones a nivel de diseño o pequeños trozos de código. Es por un lado bueno para mí, y bueno para aquellos que puedan encontrar algo útil en ellos.

P.D.: No confundir motor gráfico, con su traducción al ingles: graphic engine. En español se suele usar motor gráfico para referirse a un game engine en inglés, lo que realmente en español se diría: motor de videojuego. Pero, ¿a que no queda tan molón? :P