Donde vamos a llegar con TTs como #hijostrospidos
#hijostrospidos fue un trending topic de Twitter para criticar el programa de Cuatro “¿Quién quiere casarse con mi hijo?”. Con permiso (implícito) de XKCD.
Keep screen aspect ratio with different resolutions using libGDX
There’s something in that “Screen Resolution” game menu that possesses me. I’ve always fancied making a game with different screen resolutions, but the task is far from trivial. These notes are the result of a weekend spent looking for the solution (with help from the JGO community). You can download the source code from here.
Problem
Imagine you are developing a game and start supporting the 480×320 resolution because it fits nice in your smartphone. You align the menus, place the sprites, and do some nasty hacks (that we all have done sometimes) to make your game look pretty. In the end, you have a game that has been developed, literally, for your own phone! (or phone screen resolution). It will look distorted in other phones with different screen resolutions
What do you want to is to support multiple screen resolutions without hardcoding all the layout for every single screen resolution that exists (there are lots of them).
(My) Solution
The solution I’ve found it’s not TEH solution, but it works good enough for me.
I’m working with libGDX. This library has a OrthographicCamera class (doc, code) that fits nice for 2D games. This class is responsible to 1) define the volume of the game scene (which in OpenGL argot is called frustum) and 2) to project it orthographically into a plane: the scene image. In addition, libGDX also provides a wrapper to the OpenGL function glViewport(), which transforms the scene image obtained with the camera class into the device screen.
The plan is the following:
- Define a virtual resolution to work with (align menus, place sprites, etc.).
- Set the camera to use the virtual resolution.
- Use glViewport() to adjust our scene image to the physical resolution of the device screen (keeping the aspect ratio of course).
To define the virtual resolution, it is fine to define static final fields in your AplicationListener game class (I’m using libGDX argot). The camera, a Rectangle defining our viewport, and the SpriteBatch, which all of them we will be using later, are also (non-static) fields of the class.
public class MyAwesomeGame implements ApplicationListener { private static final int VIRTUAL_WIDTH = 480; private static final int VIRTUAL_HEIGHT = 320; private static final float ASPECT_RATIO = (float)VIRTUAL_WIDTH/(float)VIRTUAL_HEIGHT; private Camera camera; private Rectangle viewport; private SpriteBatch sb;
When our game starts, it will first execute the method create() and then resize(int, int) with the width and height of the window as input parameters. In create() we should initialize all the fields required further. In particular, we will initialize the camera and the SpriteBatch (canvas of each frame).
@Override public void create() { sb = new SpriteBatch(); camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); }
In resize() we should setup the Rectangle that we will be using later to set the viewport. And here it is the trick. Let’s see this function slowly. First we declare and initialize some local variables.
@Override public void resize(int width, int height) { // calculate new viewport float aspectRatio = (float)width/(float)height; float scale = 1f; Vector2 crop = new Vector2(0f, 0f);
They are quite intuitive, for instance, aspectRatio holds the ratio width/height of the device screen (physical resolution), scale is the factor to which scale our scene image, and crop (do not confuse with crap) is the amount of pixels to be cropped from the viewport in order to keep the aspect ratio of the scene image.
Now, if aspectRatio is greater than the virtual aspect ratio it is because the physical resolution is wider (proportionally) than the virtual resolution. Therefore, we should match the height of both resolutions (virtual and physical) and crop in the X direction since our virtual scene image wont fill the whole screen. Conversely, if aspectRatio is lesser than ASPECT_RATIO then we should match the width of both resolutions and crop in the Y direction.
if(aspectRatio > ASPECT_RATIO) { scale = (float)height/(float)VIRTUAL_HEIGHT; crop.x = (width - VIRTUAL_WIDTH*scale)/2f; } else if(aspectRatio < ASPECT_RATIO) { scale = (float)width/(float)VIRTUAL_WIDTH; crop.y = (height - VIRTUAL_HEIGHT*scale)/2f; } else { scale = (float)width/(float)VIRTUAL_WIDTH; } float w = (float)VIRTUAL_WIDTH*scale; float h = (float)VIRTUAL_HEIGHT*scale; viewport = new Rectangle(crop.x, crop.y, w, h); }
Finally, we just have to modify the render() method (which is used to render our scene, of course) to update the camera, set the viewport, and draw our objects/entities.
@Override public void render() { // update camera camera.update(); camera.apply(Gdx.gl10); // set viewport Gdx.gl.glViewport((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height); // clear previous frame Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // DRAW EVERYTHING }
And that’s it. Let’s see it in action.
Some images
To illustrate this tips I’m rendering a scene that consists on two rectangles. One green that fills all the scene (just to know where exactly our scene image is), and one square red just to detect visually aspect ratio violations. We use 480×320 as our virtual resolution, as our smartphone uses it natively. Therefore, in our phone we should see everything and without distortion, just as this screenshot I just took:
Now imagine I send this awesome game to my friend @notch (any similarity with real characters/persons is fictional) which is really rich and has a smartphone with greater resolution. He will see this flawed game:
Notice that the square has been distorted into another rectangle (non-squared). My friend is loosing part of the feeling of my game! And most important, the artist that is making such awesome graphics is really pissed off…
Using the method of this tutorial he will just get the right game:
Ok, it is true. He’s not using his whole smartphone screen (btw, who told him to spend that much money in a fancy new smartphone in the first place) but at least the aspect ratio is correct and the game graphics artist is happy again.
Further approximation to perfection
I have discovered nothing new, but at least I won’t doubt again how to perform this tedious but mandatory task. You must know that there are, for sure, better approaches to solve the resolution problem. For instance, I just came up with the idea of having two/three versions of the game with different aspects ratios (say 4:3, 16:9, and 16:10). Then, you viewport the layout corresponding to the aspect ratio that is closer to the physical aspect ratio, and hence, minimizing the ugly black bands.
If you have any comment/suggestion/praise/curse, do not hesitate to leave a comment here or say something in Twitter.
Compilar Assimp 2.0 en VC++ 2010 Express
Assimp (a.k.a. Open Asset Import Library) son unas librerías multiplataforma y de código abierto para importar modelos 3D de diferentes formatos (MD2, MD5, COLLADA, etc.). Compilar estas librerías usando VC++ 2010 Express puede ser muy complicado si no se siguen unos pasos concretos.
Satisfacer las dependencias: Boost y DirectX SDK
La compilación de Assimp depende de las librerías Boost. Además, el visor de modelos Assimp View necesita las librerías de DirectX d3d9.lib y d3dx9.lib.
Boost
Boost se puede descargar desde su página principal de descargas (aquí). Simplemente habrá que descomprimir y desempaquetar la versión más reciente (a día de hoy la versión 1.47.0) en un directorio conocido. En nuestro caso utilizaremos
C:\dev\boost\1.47.0
y nos refereriremos a esa ruta en el resto de este tutorial como $(BOOST_PATH).
DirectX SDK
DirectX son unas APIs (application programming interface) de Microsoft especialmente preparadas para crear juegos. El visor de Assimp View está construido utilizando dichas librerías, y por tanto, tenemos que tenerlas instaladas en el ordendor para poder compilarlo.
Para ello simplemente hay que descargarse el SDK (software development kit) más moderno de su página de descargas (aquí) e instalarlo haciendo doble clic. En nuestro caso es la versión de Junio 2010 y la instalamos en la ruta
C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)
que a partir de ahora llamaremos $(DIRECTX_PATH).
Descargar del código fuente
El código fuente de Assimp se puede descargar de su página principal de descargas (aquí). A día de hoy, la que nos interesa es de assimp 2.0 (de noviembre de 2010), el fichero “Any platform: ZIP archive, full source code” (no pongo enlace porque no puedo garantizar su persistencia).
Descomprimir y desempaquetar el código fuente
Hay que descomprimir y desempaquetar el fichero descargado en un directorio conocido. En este caso utilizaremos
C:\dev\assimp\2.0.863
A partir de ahora nos refereriremos a esta ruta como $(ASSIMP_PATH). Si utilizas una ruta diferente, asegúrate de cambiar todas las demás rutas que dependan de ésta. Como comprobación adicional deberías tener los archivos INSTALL, LICENSE y README en el directorio $(ASSIMP_PATH).
Modificar los proyectos de VC9
De momento Assimp soporta ser compilado por VC9 a través de una solución (.sln) y unos proyectos (.vcproj) incluidos en el directorio $(ASSIMP_PATH)\workspaces\vc9. La forma de compilarlo con VC10 es convertir la solución para VC9.
Sin embargo, cuando se hace esto directamente aparece un problema con la arquitectura x64, concretamente el mensaje de error “Failed to upgrade platform ‘x64′. Please make sure you have it installed under ‘%vctargetspath%\platforms\x64′“. Probablemente esto se deba a que la versión de MVC++ 2010 Express, que es gratuita, no permite compilar para la arquitectura x64.
Para solucionarlo hay que modifcar a mano, con un editor externo (por ejemplo el excelente Notepad++), el archivo de solución y los de proyectos.
Este paso es muy tedioso si no sabes automatizarlo (yo no sé). Así que os dejo los ficheros de la versión VC9 sin los bloques de “x64″ para que os podáis saltar este paso. Simplemente reeemplaza los archivos de tu ordenador con los descargados.
En caso de que seáis valientes, seguid los siguientes pasos:
Archivo de solución assimp.sln
Hay que buscar la palabra “x64″ y eliminar todas las líneas donde aparezcan en el archivo assimp.sln. En total hay 144 ocurrencias. Las hay de dos tipos:
debug|x64 = debug|x64
{B17B959B-BB8A-4596-AF0F-A8C8DBBC3C5E}.debug|x64.ActiveCfg = debug|x64
Con eso habremos terminado con este fichero.
Archivos de proyectos
De forma similar hay que encontrar los bloques que contengan la palabra “x64″ de los archivos de proyecto (assimp.vcproj, assimp_cmd.vcproj, assimp_view.vcproj y UnitTest.vcproj). Hay un total de 171 ocurrencias. Los hay de varios tipos. En el principio siempre hay un bloque con la forma:
<Platform Name="x64" />
Otros más largos son de la forma:
<Configuration
Name="debug|x64"
OutputDirectory="./../../bin/$(ProjectName)_$(ConfigurationName)_$(PlatformName)"
IntermediateDirectory="./../../obj/$(ProjectName)_$(ConfigurationName)_$(PlatformName)"
ConfigurationType="1"
InheritedPropertySheets=".\shared\UnitTest.vsprops"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
// ETC ...
</Configuration>
Por último hay otro tipo:
<FileConfiguration Name="debug|x64" > <Tool Name="VCCLCompilerTool" UsePrecompiledHeader="0" /> </FileConfiguration>
Una vez quitados todos los bloques que incluyan la palabra “x64″ ya estamos listos para importar el proyecto a VC10.
Convertir el proyecto a VC10
Ahora hay que ejecutar VC++ 2010. Al pinchar en el menú “Archivo”->”Abrir”->”Proyecto o solución”, aparecerá un diálogo donde hay que seleccionar la solución (.sln) que se encuentra en $(ASSIMP_PATH)\workspaces\vc9\ (la que acabamos de modificar). Se abrirá un “Asistente para conversión de Visual Studio”. Pinchando en siguiente, siguiente y finalizar, abriremos una solución con cuatro proyectos: assimp, assimpcmd, assimpview y unit.
En caso de que este paso no te funcione por alguna razón, dejo colgados los ficheros de la solución y los proyectos para VC10.
Modificar el código (pequeño parche)
Por alguna razón, VC10 incluye el archivo de cabecera stdint.h desde una cabecera estándar. Este archivo es imcompatible con pstdint.h que se proporciona con Assimp. Por lo tanto hay que asegurarse de que Assimp no incluye pstdint.h o saltarán las alarmas.
Leyendo los foros de Assimp (aquí) se propuso el siguiente parche: en la línea 59 del fichero AssimpPCH.h cambiar
#ifdef _MSC_VER
por
#if defined(_MSC_VER) && (_MSC_VER < 1600)
Con eso ya podemos compilar Assimp con la seguridad de que pstdint.h no se incluirá cuando usemos VC10.
Configurar los proyectos
El último paso es configurar los proyectos para que encuentren las rutas de las dependencias (Boost y DirectX) y para solucionar un error con el fichero de salida.
Para incluir las rutas adecuadas hay que abrir las propiedades de cada uno de los cuatro proyectos. Hay que elegir en la parte superior izquierda “Todas las conf.” y después, en el árbol de configuraciones, hay que pinchar en el elemento “Propiedades de configuración”->”Directorios de VC++”. Ahí hay que cambiar las propiades “Directorios de archivos de inclusión” y “Directorio de archivos de bibliotecas” para que incluyan las cabeceras y librerías de Boost y DirectX.
Los directorios de inclusión en nuestro caso son:
$(BOOST_PATH) $(DIRECTX_PATH)\Include
Mientras que los de librerías son:
$(BOOST_PATH)\lib $(DIRECTX_PATH)\Lib
Recuerda cambiar cada variable $(*_PATH) por el directorio que corresponda en cada caso.
Esto es suficiente para que encuentre todas las dependencias de Boost y DirectX. Sin embargo, el nombre de los proyectos no coincide con el nombre que el enlazador espera a la salida, por lo que falla al generar las librerías compartidas (los .DLL) y las estáticas (las .LIB).
Para solucionar este problema hay que abrir las propiedades del proyecto assimp y para la configuración “debug-dll” (parte superior izquierda) hay que pinchar en la configuración “Propiedades de configuración”->”General”. La entrada “Nombre de destino” debe cambiarse a “Assimp32d” (sin las comillas y ojo con la ‘d’ final). La misma entrada para la configuración “release-dll” debe cambiarse por “Assimp32″ (ojo con la ‘d’ del final).
Y con eso ya está listo todo para compilarse. Las librerías de “debug-dll”, “release-dll”, “debug-st” y “release-st” aparecerán el el directorio $(ASSIMP_PATH)\lib.
Como prueba de que todo ha salido bien puedes intentar compilar Assimp View y cargar un modelo. Por ejemplo, puedes cargar $(ASSIMP_PATH)\test\models\Collada\duck.dae y obtener algo parecido a esto
Elecciones mayo 2011: cartas a la basura
Como vengo haciendo en todas las elecciones que he vivido (que no son muchas), leo toda la propaganda electoral que me llega. Eso sí, con infinita paciencia y con la seguridad que los argumentos para votar a un partido u otro no los voy a encontrar ahí.
Esta mañana me ha llegado la carta electoral de un partido que no voy a desvelar (pista: el color de IU no es el rojo). He leído seis palabras. No más. Ni ahora ni después.
Una cosa es que algunos políticos no sepan hablar inglés (ojo, conozco al menos una que lo habla correctamente), pero español… ¡Hombre! Que está muy feo no saber esas cosas.
Ya, ya, es cosa de un chico o chica de marketing al que se le va a caer el pelo, y lo que el lector quiera. Pero lo que está claro es que un candidato ha* perdido su oportunidad (virtual y postal) de convencerme para que le vote.
* Tanto criticar y luego voy y no le pongo la hache al verbo haber… Supongo que yo he perdido la oportunidad de convencerte de lo importante que es escribir correctamente. En esta entrada perdemos todos.
Ejecutar aplicaciones a través de SSH
¿Te ha pasado alguna vez el tener que ejecutar una aplicación que se encuentra en el ordenador del trabajo?
Con un poco de suerte, te basta con abrir una terminal, hacer una conexión SSH, ejecutar la aplicación y esperar el resultado. Sin embargo, en otras ocasiones necesitas que el programa se siga ejecutando cuando te desconectes del ordenador, o, peor aún, que quieras manipular la interfaz gráfica de la aplicación.
Como estoy harto de buscar en Google cómo hacer cada cosa, me voy a hacer una pequeña receta con los tres casos, a ver si te sirve a ti también.
Ejecutar aplicación en consola
En este caso lo que se quiere hacer es:
- Conectarse al ordenador remoto vía SSH.
- Ejecutar una aplicación.
- Esperar que finalice la aplicación.
- Desconectarse del ordenador remoto.
Esto es bastante sencillo y buscando por Internet (y leyendo las páginas del manual del comando “ssh”) es fácil encontrar la solución.
Para conectarte al ordenador remoto basta con hacer una llamada del estilo:
localhost$ ssh usuario@servidor.es
donde ‘usuario’ es el nombre de usuario que quieres utilizar en el ordenador identificado por su nombre de dominio ‘servidor.es’. Después de introducir tu password cuando te lo pida, te mostrará un terminal en el ordenador remoto. Ahí podrás ejecutar la aplicación que desees:
servidor.es$ uname -srv Linux 2.6.37-ARCH #1 SMP PREEMPT Fri Feb 25 07:53:43 CET 2011
Una vez terminada la ejecución del programa podemos introducir ‘exit’ o pulsar control+D para salir.
Ejecutar una aplicación persistente en consola
Este caso es muy parecido al anterior. Sólo se diferencia en que ahora no existe el paso 3., es decir, queremos que la aplicación se siga ejecutando después de habernos desconectado del ordenador remoto. Para ello utilizamos el comando POSIX “nohup” en el ordenador remoto.
servidor.es$ nohup make & servidor.es$ ^D
Eso nos garantiza que la aplicación se seguirá ejecutando aún cuando le llegue la señal hangup (HUP), que indica que el usuario que ejecutó la orden se ha desconectado de la máquina. Este comando es especialmente útil para compartir ficheros por redes P2P (con un programa torrent por consola) o para hacer grandes actualizaciones remotamente.
Ejecutar una aplicación X
El último caso es cuando queremos ejecutar un comando en el ordenador remoto que cree una ventana en nuestro ordenador local. Por tanto, tendremos que iniciar una sesión X en el ordenador local, lo que en la mayoría de casos significa que debes haber iniciado sesión en Gnome, KDE, PekWM o el entorno de escritorio que utilices.
Los pasos a seguir son muy similares. Primero habrá que conectarse por SSH como en el primer caso, pero añadiendo la opción ‘-X’:
localhost$ ssh -X usuario@servidor.es
El resultado será el mismo, tendremos una terminal remota en el servidor ‘servidor.es’. Todo igual, salvo que al ejecutar una aplicación gráfica todas las llamadas al servidor X se hacen a la máquina local (donde estás tú) no a la máquina remota (donde ejecutas la aplicación).
Por ejemplo, si ejecuto la aplicación ‘kcalc’ (la calculadora del escritorio KDE) en mi máquina wigner (ordenador del trabajo):
[alejandro@wigner ~]$ kcalc
en maxwell (mi ordenador personal) aparece la siguiente ventanita:
Las tres recetas las he obtenido de diferentes sitios en Internet que ya no recuerdo. El último caso lo aprendí aquí, en un tutorial de Van Emery.
Winter College 2011 en Trieste
Este año he tenido la suerte de poder asistir al Winter College que se celebra en el ICTP (International Centre for Theoretical Physics) de Trieste, Italia. Es realmente una suerte porque ha cambiado la forma en la que veía mi trabajo hasta ahora.
Lo primero a tener en cuenta es que el ICTP es un centro de investigación financiado por la ONU y el Gobierno de Italia que tiene como propósito principal ayudar a jóvenes investigadores procedentes de países en vías de desarrollo (yo tuve que pagar porque no se creyeron que España es del tercer mundo). Es decir, este lugar es el punto de encuentro de personas de culturas radicamente diferentes. Simplemente por el hecho de comer con ellas ya se aprende más de lo que se puede asimilar en un día.
Por otro lado, un Winter College es un evento académico donde se dan cita expertos en un tema concreto. A lo largo de algunas semanas preparan una serie de lectures (clases magistrales) donde desarrollan su área de experiencia. Nada que ver con un catedrático contándote la quinta lección de ese temario que le tocó por sorteo en consejo de departamento. Esta gente sabe de lo que habla y realmente quiere contarte lo que te cuenta. En resumidas cuentas, es un curso avanzado e intensivo de los temas que a ti te interesan.
Las cosas que estoy aprendiendo, los contactos que estoy haciendo, la inspiración que estoy recibiendo. Nada de eso puede expresarse con palabras. Es una revolución de las ideas.
Ecuaciones en tus presentaciones
Foto tomada por tkamenick.
A veces es imprescindible incorporar expresiones matemáticas en tus presentaciones hechas con Powerpoint, Keynote, OpenOffice Impress o Google Presentations. Pero no queda claro qué programa usar para hacerlo.
Por un lado, el editor de ecuaciones de MathType es muy útil y es una solución a tener en cuenta cuando trabajemos con Powerpoint. Sin embargo, las ecuaciones generadas con él no pueden ser exportadas a otros programas (al menos que yo sepa).
Por otro lado, para Mac existe un software llamado LaTeXiT que usé durante mucho tiempo y que funciona muy bien. Lo que hace (por detrás de la interfaz gráfica) es básicamente dos cosas: 1) crea un archivo TeX mínimo a partir del cual se imprime la ecuación en DVI y 2) exporta este DVI a un formato que sea soportado por el programa de presentaciones (en mi caso me conformo con PNG). Si usas Mac lo tienes hecho. Si usas GNU/Linux no (de nuevo que yo sepa). Así que lo que propongo es un script que hace a manubrio lo que hace LaTeXiT de forma bonita.
Lo primero es tener una plantilla de LaTeX que sea mínima. Como sólo vamos a crear ecuaciones, incluiremos en el los paquete necesarios para algunos símbolos (de la AMS).
\documentclass{article}
\usepackage{amsmath,amsthm,amssymb}
\pagestyle{empty}
\begin{document}
\begin{equation*}
% Aquí va la ecuación que queremos incorporar a la presentación
\end{equation*}
\end{document}
Por otro lado, tendremos que tener el siguiente script que convierte a cada ecuación en una imagen PNG:
#!/bin/bash ELATEX=/usr/bin/latex EDVIPS=/usr/bin/dvips ECONVERT=/usr/bin/convert RES=600 $ELATEX $1.tex $EDVIPS $1 -o $ECONVERT -units PixelsPerInch -density $RES -trim -transparent \#000080 \ -type PaletteMatte +repage $1.ps $1.png rm $1.dvi $1.ps
Del script, lo único que hay que tocar son las rutas a los ejecutables latex, dvips y convert (latex y dvips suelen venir en tu distribución de LaTeX preferida, y convert es una utilidad de ImageMagick) y la resolución de la imagen generada, RES. Para ejecutarlo hay que guardarlo (yo elegí el nombre latex2png) y para usarlo sobre un archivo llamado prueba.tex hay que usar `latex2png prueba` sin las comillas simples.
Con el anterior script la forma de trabajar que a mí me funciona es un editor de texto abierto para cambiar la fórmula, una consola para ejecutar el script y un navegador de archivos (dolphin de KDE) para arrastrar el PNG a la presentación. En caso de que uses Emacs puedes ahorrarte la consola si defines un macro para ejecutar el script sobre el archivo que estás editando. Y si eres un master-programming, ¿por qué no te curras una interfaz gráfica para el anterior script al estilo LaTeXiT?
Para muestra, un botón. Este es el resultado de la ecuación:
\mathfrak{F}^\alpha\left[f\right]\left(\mathbf{p}\right)
= \iint_{\mathbb{R}^2}\mathrm{d}\mathbf{r}\ f\left(\mathbf{r}\right)K^\alpha
\left(\mathbf{r},\mathbf{p}\right)







