Skip to content

Presentado PFC: Sobresaliente 10

27 septiembre 2011

¡Hola a todos!

Acabo de venir de defender oFlute como Proyecto Fin de Carrera de la Ingeniería Técnica en Informática de Sistemas, con un resultado muy favorable. ¡He obtenido un 10-Sobresaliente de nota!

Muchas gracias a todos por el apoyo😀

My point en la lucha biblioteca vs librería

20 febrero 2011

Se han escrito muchocientos posts sobre si se dice librería o biblioteca cuando intentamos traducir library del inglés en el contexto informático. La traducción directa de library al español es biblioteca, cuando la traducción de librería en inglés es bookshop. Esto está claro, y de aquí se deduce que, en principio, deberíamos decir “la biblioteca boost” en lugar de “la librería boost”.

Ahora bien, mi opinión es que se puede decir de las dos maneras, basándome en una razón puramente semántica más que de traducción directa. Cuando hablamos de una library, utilizamos esa palabra como metáfora del conjunto de clases, funciones, ficheros y demás que la conforman, igual que cuando le decimos a un ávido lector “¡qué biblioteca tan variada tienes!” nos estamos refiriendo al conjunto de libros, no a las estanterías. En definitiva, nos estamos acogiendo a la cuarta acepción de biblioteca en el dRAE.

Si nos vamos al artículo de librería en el mismo dRAE, vemos que su segunda acepción indica que es un sinónimo de la definición previamente mencionada de biblioteca. Por lógica, se concluye que a una colección más o menos numerosa de libros se le puede llamar tanto biblioteca como librería. Quedando clara la equivalencia de ambos términos para ese significado, que es el que se utiliza al traducir library del inglés, queda igualmente validada la posibilidad de usar ambos términos al traducir aquél.

Q.E.D.

Por qué Gosu me está decepcionando

7 febrero 2011

Hola a todos.

Por twitter y a algunos por GTalk les he comentado mis últimas y cambiantes opiniones sobre Gosu. Para los no iniciados, Gosu es una biblioteca open-source y multiplataforma para el desarrollo de videojuegos 2D, con aceleración OpenGL y un esquema de clases sencillísimo de usar. Lo he usado activamente estos últimos dos años, tanto en mi proyecto oflute, como en freegemas y en otros proyectos personales, y además he escrito tres artículos para la edición española de la revista Linux Magazine que trataban sobre los conceptos básicos del desarrollo de videojuegos con Gosu. Por último, estoy preparando un taller sobre Gosu para las VI JOSLUCA. Creo que esto pondrá en perspectiva al lector en cuanto a mi familiaridad con Gosu.

Las razones por las que me está decepcionando son varias. El principal (y único, creo) desarrollador de Gosu es Julian Raschke, un tío con mucho talento que lleva bastantes años detrás del proyecto. Por desgracia, es 100% maquero, y claro, eso se nota en el progreso de Gosu: lógicamente, la plataforma para la que más pulido está es Mac OS y iOS, seguido de Windows (por la obvia superioridad en el mercado de videojuegos) y por último Linux, que es la plataforma menos pulida de todas.

Quede claro que me parece loable el trabajo de Julian en cuanto a llevar hacia adelante el desarrollo en plataformas tan diversas, sobre todo en un tema tan variopinto como es una biblioteca para gamedev. Pero sin duda, se nota que Linux no es la que más atención recibe. El script de autotools, por ejemplo, lleva años sin actualizarse y con muchos errores de compilación

Uno de los problemas con los que me encontré al empezar mi andadura con Gosu fue que, en Linux, no se podían cargar fuentes si no estaban instaladas en el sistema. Es decir, no podías adjuntar un .ttf con tu proyecto con una fuente para tu menú principal, sino que, una de dos, o hacías que el usuario instalara la fuente (que es un coñazo en sistemas GNU/Linux) o convertías los textos a imágenes en tu Photoshop (olvidándote de los textos dinámicos). Este problema llevaba así desde el principio y nadie se había parado a intentar arreglarlo. A mí se me ocurrió adaptar la biblioteca SDL TTF, y le ofrecí un parche a J. Raschke, que amablemente incluyó en la distribución oficial, siendo posible desde entonces usar fuentes TTF en Linux.

Pero claro, de aquí surgió otro problema: ahora las fuentes no aparecían exactamente igual en los diferentes sistemas. De hecho, en Windows y en Linux, para un mismo tamaño de fuente, el renderizado era diferente. Teóricamente, esto se arregló en una de las últimas versiones, pero yo no estoy del todo convencido.

Otro problema que encontré hace poco es un pequeño bug, también solo de Linux, en el el método para ocultar el puntero del ratón no tenía efecto alguno, mostrándose siempre. Propuse una solución en el foro y supongo que para la próxima versión se incluirá.

Pero la gota que casi ha colmado el vaso ha sido en el tema del sonido. En este aspecto, Linux también andaba atrasada respecto a las otras plataformas. En particular, era Linux el único SO en el que a los sonidos no se les podía modificar el tono. En un intento por arreglar esto y unificar el back-end de sonido de Windows y Linux, se portó el sistema a la biblioteca Audiere. Pero, ay amigos, fue peor el remedio que la enfermedad. Audiere solo funciona con OSS, y esto la limita a que solo pueda haber un programa accediendo al dispositivo de sonido a la vez, por lo que si, por ejemplo, tenemos un vídeo de youtube abierto, no podremos lanzar nuestro juego. He hablado con Raschke y la decisión más probable es que se volverá a SDL Mixer mientras se buscan otras soluciones, basadas principalmente en OpenAl.

A mí Gosu me encanta, me parece facilísimo de usar y probablemente siga usándolo a medida que vayan mejorando. Pero todas estas cosas, que siempre pasan en la plataforma donde más trabajo, que es Linux, hacen que me esté planteando buscar otra opción con una comunidad más fuerte y mayor estabilidad, además de que me joden mucho, porque he dado mucha caña con Gosu y siempre me ha parecido una opción muy buena.

Lógicamente no voy a dar un paso atrás y volver a la SDL, ni tampoco voy a desechar el trabajo hecho con Gosu, que aún funciona. Pero quiero abrirme otras puertas que sean más sólidas.

Novedades y puesta al día

13 septiembre 2010

Buenas, queridos y poco numerosos lectores.

Estamos a 13 de septiembre, que casualmente es el día número 256 del año, lo cual lo convierte, por iniciativa popular, en el Programmer Day. Sentíos orgullosos.

Dejando de lado las festividades de dudosa relevancia, os pongo un poco al día del estado de oFlute:

  • Tenía pensado (y aún guardo alguna esperanza) presentar el proyecto a finales de septiembre. Para ello tendría que entregar la memoria, como muy tarde, este viernes día 17, cosa harto improbable, ya que la escritura de documentos repletos de morralla no es mi fuerte, además de que la ingeniería del software es una de las materias peor impartidas en mi carrera, por lo que no estoy muy al día. Pero bueno.
  • A pesar del punto anterior, voy a matricularme en el segundo ciclo de ingeniería informática, aquí en la Universidad de Cádiz. Se da la casualidad de que es posible matricularse sin tener la ingeniería técnica acabada, así que allá vamos. Entre el pseudo-gap-year que me he tomado, que el 99% del feedback que obtengo sobre el segundo ciclo es negativo y que todas las clases son por la tarde, no tengo muy claro cómo me va a ir este año. De todas formas tengo cierto proyecto secreto que tal vez me permita evadirme un poco.
  • En cuanto al proyecto, las siguientes novedades respecto a la última vez:
    • La parte del software podría decirse que está terminada, aunque cada día lo miro y retoco algunas cosillas.
    • Deseché mi sistema de traducción bananero y le eché valor al tema, adaptando exitosamente el proyecto a gettext, que al fin y al cabo es muy sencillo de utilizar.
    • Adapté el algoritmo de drop-shadows de esta web y ahora puedo crear sombras al más puro estilo Photoshop de forma dinámica. Fijaos en el antes y después:

    • What else… Bueno, la parte de las canciones está terminada. Hago un llamamiento para que busquéis en vuestros cajones los cuadernos de pauta con canciones de flauta, que falta me hacen🙂 aunque probablemente acabe metiendo, de oído, canciones de videojuegos famosos😀
  • Y algunas cosillas más que se me escapan.

¡Os mantendré informados!

Dependencias en los makefiles

6 agosto 2010

Saludos veraniegos. Con la calor, es difícil acordarse de todas las dependencias de cada fichero, y a menudo se nos escapan algunas al escribir nuestro Makefile. Mi compañero David me comentó la existencia de makedepend, una herramienta para la gestión automática de dependencias que había visto de refilón en algún makefile ajeno pero que apenas conocía.

Leyendo su entrada en Wikipedia y algunos comentarios en StackOverflow, vi que actualmente se desaconseja su uso, prefiriéndose las alternativas que la mayoría de compiladores ofrecen de forma nativa. Así fue como conocí la opción -MM de gcc, cuyo cometido es el mismo que el de makedepend: generar, en formato makefile, una lista de dependencias para cada fichero, basándose en las cabeceras incluidas. El funcionamiento es sencillo:

gcc -MM $(CXXFLAGS) ficherosFuente

Es importante pasarle las flags de compilación, ya que suelen incluir directivas como -I, que indican las carpetas en las que buscar ficheros de cabecera.

Problema 1: utilización de las dependencias generadas

La utilidad makedepend automáticamente actualizaba el makefile que la ejecutaba, añadiendo al final del fichero las dependencias generadas. Sin embargo, gcc -MM muestra su resultado en la salida estándar (o en un fichero que indiquemos), en lugar de añadirlo al Makefile actual, por lo que había que buscar una forma de incluir el resultado en nuestro Makefile. Con utilizar

-include dependencias.dep

Podremos incluir cualquier fichero en nuestro Makefile como parte del mismo.

Problema 2: rutas en el fichero generado

En mi caso, tengo tres carpetas que cuelgan de la raíz del proyecto: src, obj e include, en las que se guardan los cpp, los ficheros objeto y las cabeceras respectivamente. El problema de gcc -MM es que, al generar las dependencias, quita la ruta de la cabecera de las reglas, esto es, si tenemos un fichero objeto obj/main.o que depende de main.cpp, en el fichero generado aparecería así:

main.o: src/main.cpp

Por ahora, la única solución que he encontrado es utilizar sed para añadir al inicio la ruta correspondiente, aunque me habría gustado que gcc incluyera una opción al respecto.

gcc -MM $(CXXFLAGS) $(shell ls -t $(SRCDIR)/*.cpp) | sed 's/^\([a-zA-Z]\+.o:\)/$(OBJDIR)\/\1/g' > $(DEPFILE)

La explicación de la expresión regular es muy sencilla: Simplemente, cada vez que encuentre al inicio de la línea el nombre de un fichero objeto, que añada el nombre del directorio de los objetos (OBJDIR) y luego el nombre del fichero. Se utilizan grupos, primero agrupando el nombre con paréntesis y luego haciendo referencia al grupo con \1.

Por último, comentar que he puesto como dependencia del binario final al archivo de dependencias, y como dependencia del archivo de dependencias (valga la redundancia) todos los ficheros de código. El objetivo es que, si modifico algún fichero de código, puede que los includes cambien, así que hay que regenerar las dependencias. Tal vez acabe quitando esta dependencia cruzada, ya que estar regenerando las dependencias constantemente es un rollo. Otra opción que tal vez baraje es la de tener un archivo de dependencias por cada fichero objeto, así la regeneración no será tan pesada.

Opciones hay muchas.

[Boost en español] Ejemplo rápido de aplicación de Bind

15 julio 2010

Justo ayer, peleándome un rato con freegemas, me surgió la necesidad de iterar por un vector y borrar los elementos que tuvieran cierta propiedad. A primera vista puede parecer sencillo, pero la solución no es trivial:

  • Si utilizas un bucle for, al borrar un elemento el tamaño y los índices de los elementos también, por lo que la variable de seguimiento (típicamente size_t i) ya no vale.
  • Si utilizas iteradores, al eliminar un elemento aquellos quedan invalidados.

Estuve pensando un poco cómo hacerlo y se me ocurrieron algunas formas poco ortodoxas o que podrían llevar a error. Una de las formas que encontré por internet fue la siguiente, con iteradores y un for algo especial:

for (iterator it = v.begin(); 
     it != v.end(); 
    ) 
{ 
    if (condition) 
	it = v.erase(it); 
    else 
	++it; 
}

Si os fijáis, el for no tiene tercer parámetro, sino que somos nosotros los que movemos el iterador manualmente. Para evitar la invalidación, utilizamos el valor de retorno de erase.

Pero otra forma de hacerlo, más elegante a mi parecer, era utilizar el algoritmo remove_if y un predicado adecuado. En mi caso, el contenedor tenía objetos de una clase con un método que devolvía un booleano tal que, si es verdadero, el elemento debería borrarse. En un primer intento hice

remove_if(contenedor.begin(), contenedor.end(), boost::bind<bool>(&Clase::Comprobar, _1));

Pero los elementos no se borraban. «Qué raro», pensé. Resulta que el funcionamiento de remove_if no es el de borrar directamente los elementos, sino que reordena los elementos a borrar al final del contenedor y devuelve un iterador que apunta al primero de esos elementos a borrar. Así, junto al método erase del vector, tenemos:

contenedor.erase(remove_if(contenedor.begin(), contenedor.end(), boost::bind<bool>(&Clase::Comprobar, _1)), contenedor.end());

Esto se conoce como el Erase-remove idiom y tiene hasta su propio artículo en la Wikipedia. Muy curioso.

[Boost en español III] Tuplas

14 julio 2010

Las tuplas en C++ son una versión generalizada de std::pair, en las que podremos almacenar un número arbitrario de valores de distinto tipo.

Al formar parte de TR1, podréis encontrarlas:

  • En la cabecera boost/tuple/tuple.hpp, como boost::tuple.
  • En la biblioteca estándar, en la cabecera tr1/tuple, como std::tr1::tuple.

Las tuplas se declaran de manera similar a los pares, indicando la cantidad y tipos de los datos contenidos como parámetros de plantilla. Podemos inicializar los datos pasándole los valores al constructor.

boost::tuple<int, string, string> miTupla (1, "Cisco", "Pepe");

Para los pares, se utilizaba first y second para acceder a los datos, pero al tener un número variable de elementos, con las tuplas hace falta alguna forma más genérica. Para ello se proporciona la función paramétrica get, que recibe como parámetro de plantilla el índice el elemento al que queremos acceder. Al devolver una referencia, nos servirá tanto de getter como de setter.

string cadena = miTupla.get<1>();
miTupla.get<0>() = 5;

Otra de las utilidades que vienen con las tuplas es tie, que nos permitirá darle valor a varias variables de una vez, incluso utilizando el valor de retorno de una función. Además, tie funciona tanto con tuplas como con los pares tradicionales.

pair<int, int> fun (){
    return make_pair(5, 3);
}

int main(int argc, char *argv[])
{
    int a, b;
    tr1::tie(a, b) = fun();
    printf("a:%i, b:%i\n", a, b);
}

Las tuplas traen muchas más funciones y utilidades, como por ejemplo para personalizar los operadores de flujos facilitando la entrada y salida, y muchas otras opciones que podéis observar en la documentación oficial.

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.