Miércoles, Febrero 28, 2007

Bajar las “OpenGL 2.0 Man pages”

Recientemente ha aparecido una nueva sección en la página de OpengL OpenGL/SDK. Sin duda la parte más interesante son las páginas de referencia de las funciones de openGL, “OpenGL 2.1 Reference Pages“, aunque no están para descargar siempre se puede tirar de wget para crearnos una copia local, concretamente la linea mágica es:

wget -p -nH -k -np -r -Popengl2 --cut-dirs=3 --html-extension http://www.opengl.org/sdk/docs/man/

Aunque aun faltarán tres documentos que wget no descubre que hace falta bajar ;)

cd opengl2/xhtml
wget http://www.opengl.org/sdk/docs/man/xhtml/pmathml.xsl
wget http://www.opengl.org/sdk/docs/man/xhtml/ctop.xsl
wget http://www.opengl.org/sdk/docs/man/xhtml/mathml.xsl

PD: También podría dejar colgado un tgz con todo, pero no estoy seguro de si es legal o no, de esta forma cada uno se lo hace por su cuenta y riesgo. Realmente lo interesante es que quien no haya usado wget para hacer un mirror de una página por lo menos ya sabe que se puede.

posteado por PpluX @ 7:54 pm tags:OpenGL  

Miércoles, Febrero 28, 2007

svn:externals re-utiliza tus repositorios.

Los programadores con algo de experiencia tendemos a dar todas las vueltas del mundo necesarias antes de repetir código, por lo que también es normal que tengamos tendencia a separar un proyecto grande en varios más pequeños por aquello de reutilizar código.

Por ejemplo, en un repositorio tengo una librería que utilizo para muchos de mis proyectos, llamada SLB, y en otro repositorio tengo mi proyecto killer-ap1. El proyecto de killer-ap1 utiliza activamente SLB, hasta el punto de que voy haciendo mejoras en SLB según veo que hacen falta en killer-ap1… por lo que suelo copiar SLB enterito dentro de killer-ap1 y compilarlo todo a la vez.

$ls proyectos/killer-ap1
src
include
SLB (mi copia particular)

El problema es que esta copia esta versionada una vez en el repositorio oficial y otras tantas en cada uno de los proyectos donde la uso, concretamente en killer-ap1. Además hay que acordarse de mantener actualizadas todas esas copias… por ello los de subversion idearon una solución mejor, los svn:externals.

La propiedad svn:externals nos permite enlazar en un repositorio con otros externos a este, de forma que cuando se haga un checkout del nuestro automáticamente también se bajará los otros. Ejemplo (de la página del svnbook):

$ svn propget svn:externals calc
third-party/sounds http://sounds.red-bean.com/repos
third-party/skins http://skins.red-bean.com/repositories/skinproj
third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker

Con esto estamos diciendo que el directorio calc tiene dentro tres directorios ‘thir-party/sounds’ ‘third-party/skins’ y ‘third-party/skins/toolkit’ que hacen referencia a repositorios externos(y en el último caso una revisión concreta la 21). También le estamos diciendo a subversion que cuando pase por calc se baje automáticamente los repositorios externos, y que los mantenga sincronizados.

Para mi caso de killer-ap1 y SLB la cosa ha sido así:

svn propset svn:externals “SLB http://svn.pplux.com/SLB/trunk” path/de/killer_ap1

Esta línea dice: “en el raiz de killer-ap1 vas a poner un directorio “SLB” que está sincronizado con el repositorio http://…”

Si en vez de uno tienes varios, los separamos con “\n”, el ejemplo del svnbook hubiera sido algo como:

svn propset svn:externals “third-party/sounds http://sounds.red-bean.com/repos\n third-party/skins http://skins.red-bean.com/repositories/skinproj\n third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker” calc

Un poco largo pero ilustra lo que se pretende, tener más de un external en un mismo directorio.

Y lo mejor de todo, que todas las copias siempre están sincronizadas, ya sean externals o no :D

posteado por PpluX @ 5:57 pm tags:recetas, subversion  

Miércoles, Febrero 7, 2007

Cargar texturas con ImageMagick

Cargar texturas en OpenGL implica leer una textura, crear un objeto de textura y subir los texels a la gráfica. Los dos últimos pasos, el de crear y subir la información, no son complicados o por lo menos siempre se hacen igual, pero leer una imagen de disco suele ser un quebradero de cabeza si pretendemos hacerlo a mano. Claro está, no me refiero a leer de disco a secas, me refiero a leer imágenes con formato ya sea jpg, png, svg, etc.

Típicamente en el mundillo de los gráficos desde tiempos inmemoriales se ha venido usando un set de librerías conocido por DevIL ( que inicialmente se llamaba OpenIL aunque por problemas con SGI cambiaron el nombre). Esta librería es además de práctica muy sencilla de utilizar y entona muy bien con openGL por estar basada en una máquina de estados y estar separada en varios niveles de abstracción IL, ILU, ILUT (como GL, GLU, y GLUT).

Pero si queremos usar algo más potente de DevIL podemos usar ImageMagick. Con ImageMagick ganaremos no sólo un cargador, además ganamos un editor, compositor y conversor de imágenes con la ventaja de que ImageMagick probablemente ya viene instalada en las ubuntu/debian/*nix normales ( y si no viene, sólo hay que enseñar a usar convert o cualquiera de las command-line-tools de ImageMagick ).

Veamos un breve, rapidísimo tutorial de cómo cargar una imagen con Imagemagick. Vamos a usar la interfaz “C” de magick-wand, también existe una para C++ (así como para python, perl, php,…) pero implicaría tener que añadir una dependencia extra… y la verdad es que Magick-Wand es suficientemente fácil de usar por sí misma.


#include <wand/magick_wand.h>
int main(...) {
MagickWandGenesis();
MagickWand *wand = NewMagickWand();
// ...
wand = DestroyMagickWand(wand);
MagickWandTerminus();
}

Las llamadas MagickWandGenesis y MagickWandTerminus inicializan y finalizan la librería, una vez hecho con NewMagickWand y DestroyMagickWand podemos crear y liberar varitas (mágicas) para trabajar con imágenes, transformalas, etc… Lo siguiente consiste en cargar la imagen de un fichero o un BLOB de memoria:


// opcion 1: leer de fichero dado un path
MagickBooleanType status = MagickReadImage ( wand, path );
// opcion 2: leer de un puntero a memoria (data) de tamaño conocido (size)
MagickBooleanType status = MagickReadImageBlob( wand, data, size );
if ( status != MagickFalse )
{
}

Las dos llamadas de MagickReadImage[Blob] hacen lo mismo, leen una imagen y además lo hacen identificando el tipo de imagen que es. Esto lo digo concretamente por la versión “blob”, no hay que decirle si es un png, jpg, ppm, svg… Imagemagick lo identificará por la cabecera del fichero, si usáis vuestro propio cargador de ficheros no tenéis más que leer el fichero entero sin preocuparos del tipo de fichero y MagickReadImageBlob intentará leerlo.
También existe la versión MagickReadImageFile que recibe un descriptor de fichero tipo FILE*
nota: en vuestro caso particular sólo hay que usar una de las dos opciones, claro está :)

El resultado es un booleano, si todo a ido bien sólo queda recuperar esa información y subirlo a la textura. En este caso vamos a tener en cuenta si la imagen tiene alfa o no (para ImageMagick es ver si tiene opacidad):


unsigned long width = MagickGetImageWidth( wand );
unsigned long height = MagickGetImageHeight( wand );
unsigned char *data = 0;
MagickFlipImage( wand );
// reservamos para una textura y la activamos
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if ( MagickGetImageChannelDepth(wand, OpacityChannel) > 1 )
{
// con alfa
data = new unsigned char[width*height*4];
MagickGetImagePixels(wand, 0,0, width, height, "RGBA", CharPixel, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
else
{
// sin alfa
data = new unsigned char[width*height*3];
MagickGetImagePixels(wand, 0,0, width, height, "RGB", CharPixel, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
delete[] data;

Este ya es un buen cacho, primero obtenemos ancho y alto de la imagen, hacemos un flip de la imagen (ya que en OpenGL las imágenes empiezan abajo a la izquierda – pitfall 12) y reservamos una textura de OpenGL. Después preguntamos a la varita si la imagen tiene alfa, en realidad le preguntamos si la profundidad del canal de opacidad es mayor que 1, si es así reservamos espacio para guardarnos la información de la imagen en formato RGBA y lo subimos a la textura. Si no tiene alfa pues lo mismo pero en formato RGB. Y como somos muy limpios, al final un delete[] para liberar la memoria temporal donde guardamos la imagen.

Y finalmente el ejemplo más o menos completo del tema… Para compilarlo en linux no hay que olvidar que tenemos un mágico `Wand-config --cppflags --cflags --ldflags --libs` para ayudarnos.


#include <GL/gl.h>
#include<wand/magick_wand.h>
int main(...) {
// inicializamos openGL o lo que haga falta...
GLuint texture = 0; // nuestra textura
MagickWandGenesis();
MagickWand *wand = NewMagickWand();
// opcion 1: leer de fichero dado un path
MagickBooleanType status = MagickReadImage ( wand, path );
// opcion 2: leer de un puntero a memoria (data) de tamaño conocido (size)
MagickBooleanType status = MagickReadImageBlob( wand, data, size );
if ( status != MagickFalse )
{
unsigned long width = MagickGetImageWidth( wand );
unsigned long height = MagickGetImageHeight( wand );
unsigned char *data = 0;
MagickFlipImage( wand );
// reservamos para una textura y la activamos
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if ( MagickGetImageChannelDepth(wand, OpacityChannel) > 1 )
{
// con alfa
data = new unsigned char[width*height*4];
MagickGetImagePixels(wand, 0,0, width, height, "RGBA", CharPixel, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
else
{
// sin alfa
data = new unsigned char[width*height*3];
MagickGetImagePixels(wand, 0,0, width, height, "RGB", CharPixel, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
delete[] data;
}
wand = DestroyMagickWand(wand);
MagickWandTerminus();
}

posteado por PpluX @ 1:12 pm tags:C/C++, OpenGL, Programación, recetas  

Miércoles, Febrero 7, 2007

Manejo de paquetes en *nix

Buscando cómo se miraban las dependencias inversas de un paquete ( quién depende del paquete $blah ) en Debian/Ubuntu, encontré esta página de un wiki con mucha más información de la que buscaba, pero muy útil: Debian basics – Packet management of *nix .

Por cierto, las dependencias inversas se miran con apt-cache rdepends nombre_paquete .

posteado por PpluX @ 10:19 am tags:linux/unix, recetas  

Gestionado con WordPress