Martes, Febrero 12, 2008

¿woof, woof?

Existe por ahí un script llamado woof usado principalmente para mandar ficheros de una forma sencilla, está escrito en python y bueno, no es que tenga una cruzada contra python, pero tampoco creo que tengamos que hacerlo ahora todo en python por muy de moda que esté. Concretamente woof no va bien en cygwin (o eso dicen), o bueno igual quieres usarlo desde tu fonera hackeada y no quieres/necesitas python… yo que sé, el caso es que hay formas más fáciles de mandar ficheros a-lo-servidor-web. Yo os propongo una que sólo hace uso de netcat (que siempre puedes usar a mano netcateando).

Se llama ncweb (de netcat-web) es muy simplón, no tiene opciones y ocupa más el comentario de la licencia que el propio fichero. La parte graciosa es cómo mandar algo con formato web, es decir cómo nos manda un servidor web un fichero:

# Execute netcat with http header
(
echo -e "HTTP/1.1 200 OK\r"
echo -e "Connection: close\r"
echo -e "Content-Length: $LENGTH\r"
echo -e "Content-Type: $TYPE\r"
echo -e "\r"
cat $1
echo -e "\r"
) | nc -q 1 -l -p $PORT

Para ver cómo se calcula y que son $LENGH, $TYPE, y $PORT mirad el código, el $1 es el argumento que nos pasan al script y poco más hay que decir. Con esto ya tienes para mandar ficheros por red de forma sencilla y rápida.

Por cierto, va bastante más rápido que woof… :)

posteado por PpluX @ 12:41 pm tags:Programación, recetas  

Lunes, Enero 14, 2008

Capturar un frame suelto de un video

Para hacer screenshots de un video, un truco fácil, rápido y sencillo:


ffmpeg -i video.avi -r 1 -ss 00:00:04 -t 00:00:01 -y video%d.jpg

  • – i video.avi : fichero de entrada
  • – r 1 : fija el framerate a 1 por segundo.
  • – ss 00:00:04 : inicio de la secuencia a capturar
  • -t 00:00:01 : duracion de la captura ( como hemos puesto el framerate a 1 solo capturará un frame)
  • video%d.jpg : formato de nombre de salida, el %d se reemplaza por el numero de frame capturado (nota:el %d es obligatorio aquí)
posteado por PpluX @ 11:38 am tags:recetas  

Jueves, Noviembre 8, 2007

Cmake productivo (II) vim + quickfix

Vamos a darle un giro de tuerca a lo que vimos en el post anterior, en este post veremos cómo compilar con cmake usando vim de forma productiva. En primer lugar, necesitamos algo que nos permita compilar un proyecto (de cmake) cuando estamos editando sus ficheros. Mientras editamos los ficheros solemos estar dentro de algún subdirectorio del proyecto con lo que nos bastaría un script que buscara el directorio build y el CMakeLists.txt y lanzara el make.

Es fácil escribir ese script, el mío lo llamo vim-cmake-makeprg y lo tengo accesible en ~/bin . Al ejecutarlo irá subiendo directorios hasta encontrar un CMakeLists.txt y un directorio build. El resultado es que cuando estoy dentro de un proyecto con este comando puedo compilarlo independientemente de donde esté.

Una vez tenemos el script, sólo nos queda decirle a vim que lo utilice para compilar, para ello editamos el ~/.vimrc y añadimos:

set makeprg=vim-cmake-makeprg

Ahora ya podemos trabajar en nuestro proyecto, editamos (con vim) cualquier fichero, empezamos a programar, y para compilar escribiremos:

:make

:make

Aquí es donde comienza la magia de quickfix, en primero se pone a compilar, veremos la salida del proceso de compilación en el buffer de texto de vim. La salida se pasa por un filtro que va capturando los mensajes de error relevantes y los va añadiendo en una lista. Al terminar de compilar vim abrirá el primer fichero que contenga errores y posicionará el cursor en el primer error, también nos mostrará una versión resumida del error:

primer error

Podemos ver la lista completa de errores con el comando cl:

:cc

Finalmente, estos son algunos de los comandos que podemos usar con quickfix:

  • :cl listar los errores
  • :cc mostrar el mensaje completo del error actual
  • :cn moverse al siguiente error
  • :cp moverse al error anterior

Usando vim+quickfix, y cmake tendremos definitivamente una forma mucho más eficiente de programar-compilar-corregir-programar…

posteado por PpluX @ 3:58 pm tags:Programación, Vim, recetas  

Martes, Noviembre 6, 2007

Cmake productivo

Pequeño truco para mejorar nuestra productividad con cmake. La primera recomendación es crear siempre un directorio build dentro de nuestro proyecto. Este directorio no se subiría a ningún repositorio, lo usamos sólo para tener todos los binarios compilados, librerías, etc… separado siempre de nuestro código y cabeceras.

En un escenario típico se entra en el directorio build, se ejecuta “cmake ..”, después make, después bin/nuestro_programa… una y otra y otra vez. Esto lo haremos en una terminal sólo para compilar+ejecutar, en otra terminal o donde sea, tendremos el código que iremos desarrollando. A mi me tiene pasado que no distingo la terminal donde tengo el building del resto, incluso he llegado a cargarme cosas sin querer por culpa de esto. Para evitarlo me he escrito un fichero de aliases de bash que activo cuando estoy en mi directorio de build. El fichero lo podéis descargar de aquí y tiene esta pinta:

cmake-aliases screenshot

se activa escribiendo en el directorio de build:

. cmake-aliases

El punto(.) es importante, indica al shell actual que vamos a incorporar las definiciones de ese fichero. Nota, ese fichero tiene que estar accesible desde el path, o bien os toca poner la ruta completa donde lo tengáis.

Cosas que tiene definidas:

  • cambia el prompt, para hacerlo claramente distinguible. También permite ver más fácilmente los errores de compilación hasta donde llegan.
  • una función “help” para recordarnos que hay definido
  • escribiendo sólamente c, ejecuta cmake ..
  • escribiendo m, ejecuta make -j2 (-j2 para compilar con dos procesos)
  • escribiendo t, ejecuta make test
  • se desactiva “cd” para no cambiar de directorio accidentalmente
  • se pone LANG=”C” para obviar problemas de internacionalización
  • se añade el bin al path, para poder ejecutar rápidamente lo que estemos desarrollando

Espero que a alguno le sirva, como me sirve a mi :)

posteado por PpluX @ 4:05 pm tags:Programación, recetas  

Viernes, Octubre 5, 2007

Cómo detectar herencia de clases en C++ ( en tiempo de compilación )

Como todo programador de C++ sabe, no existe función alguna para comprobar en tiempo de compilación si una clase A hereda de otra B. En tiempo de ejecución podemos usar dynamic_cast, pero con mucho cuidado:

  1. dynamic_cast permite saber si un puntero de una clase base es en realidad de una clase hija, esto ya presupone que las dos clases a comparar están “emparentadas”. De no ser así, el compilador nos soltará un warning (en el mejor de los casos) diciendo que la conversión nunca tendrá éxito.
  2. dado que dynamic_cast está pensado para usarse en el caso anterior, la clase a convertir tiene que ser obligatoriamente polimórfica.
  3. dynamic_cast es… lento, y requiere soporte de RTTI.

Escribiendo plantillas nos podemos encontrar que necesitamos saber si una clase hereda de otra, por ejemplo, para especializar la plantilla con un código optimizado. En esta circunstancia sólo nos sirve de verdad si somos capaces de tomar la decisión en tiempo de compilación, y dado que C++ no ofrece nada para ello Alexandrescu nos revela este truco.

¿ Se puede saber si una instancia de tipo A se puede convertir (automáticamente) en otra de tipo B ?

Cuando los tipos A y B son clases estamos hablando de si la clase A hereda de B, pero el truco funciona igual de bien para cualquier par tipos, por ejemplo, para saber si un int se puede convertir a float o mejor si una clase A tiene conversión definida a otra B (explicit conversion).

La respuesta es ¡sí!, y todo se lo debemos curiosamente a sizeof.

sizeof es realmente potente, se puede aplicar a cualquier expresión, sin importar lo compleja que esta sea, sizeof devolverá el tamaño de esta sin llegar a evaluar la expresión en tiempo de compilación. Esto significa que sizeof tiene presente la sobrecarga, la especialización de plantillas, reglas de conversión … absolutamente todo lo que pueda aparecer en una expresión de C++ . En realidad, sizeof es capaz de deducir el tipo de una expresión; desechando la expresión pero devolviendo su tamaño.Alexandrescu

Evaluar el valor de una expresión implica hacerlo en tiempo de ejecución, pero evaluar el tamaño del tipo devuelto por una expresión es algo que se debe realizar en tiempo de compilación. Lo que Alexandrescu nos viene a decir es que sizeof es precisamente capaz de esto, y al hacerlo desecha el valor de la expresión y “calcula” solamente el tamaño del tipo devuelto.

El truco consiste en tener un par de funciones de test sobrecargadas, una que acepta el tipo objetivo (B) y otra que acepte cualquier otra cosa. Cada función devuelve un tipo de tamaño diferente, al intentar llamar a la función test con el tipo A si existe la conversión de A a B se utilizará una función y si no, la otra. Tranquilos que los detalles siguen a continuación.

Primero creamos dos clases de tamaños diferentes, Alexandrescu nos recomienda algo como:

// Esta, por definición, ocupa 1 byte
typedef char S_True;
// Esta no se sabe cuanto ocupa, pero seguro que > 1
class S_False { char dummy[2]; }

Ahora necesitamos un par de funciones sobrecargadas, una que acepte B y devuelva S_True:

S_True Test(B);

Y otra para “todo lo demás”, y que tenga menos prioridad. De esta forma si el objeto de tipo A no se puede convertir de ningúna forma a B se utilice esta función. Para ello utilizamos la construcción de varargs que por definición siempre será el último recurso a utilizar.


S_False Test(...);

Ahora ya podemos averiguar si el tipo A se puede transformar en B, sin más que comparar el tamaño de evaluar la llamada de Test:

const bool existe_conversion = sizeof( Test(A()) ) == sizeof(S_True) ;

Y ya está!! ya tenemos una constante booleana que nos indica si la conversión es posible en tiempo de compilación… pero ¿cómo funciona? Recordemos lo que hemos venido comentando:

sizeof sólo evalúa el tamaño de una expresión sin necesidad de realizar llamadas reales, esto permite que no haga falta implementar nada en absoluto, nunca se van a llamar a ninguna función Test, ni al constructor de A(), ni nada… sizeof evalúa la expresión para ver qué tamaño tendrá el tipo del resultado.

Un pequeño problema es que la expresión “A()” tiene que ser válida lo que supone que el constructor por defecto debe existir en el tipo A. Como esto no tiene por qué ser cierto, vamos a darle un pequeño giro de tuerca.


A CrearInstancia();
const bool existe_conversion = sizeof( Test(CrearInstancia()) ) == sizeof(S_True) ;

La función CrearInstancia no hay que implementarla, nuevamente sizeof sólo la usa para saber que el parámetro de vuelvo es de tipo A, de esta forma evitamos tener que usar el constructor de A.

Con todo esto, ya tenemos para hacernos un template que nos diga si una clase es convertible a otra.

template <class A, class B>
class Conversion
{
typedef char S_True;
class S_False { char dummy[2]; }
static A CrearInstancia();
static S_True Test(B);
static S_False Test(...);
public:
enum {
existe = ( sizeof(Test(CrearInstancia())) == sizeof(S_True) )
};
};

Como ejemplo…

#include <iostream>
#include <vector>
int main() {
std::cout
<< Conversion<double,int>::existe << ' '
<< Conversion<char, char*>::existe << ' '
<< Conversion<size_t ,vector<int> >::existe << ' '
}

Y el resultado ‘1 0 0′ … Finalmente para detectar la herencia de clases (como decíamos en el tíutlo del post) lo que debemos es usar punteros constantes a los tipos:

Conversion<const clase1*, const clase2*>::existe

¡¡¡ Todo esto gracias a Alexandrescu y al power of sizeof !!!

posteado por PpluX @ 6:20 pm tags:C/C++, Programación, recetas  

Martes, Julio 10, 2007

Snapshots automáticos de SVN

Los repositorios de subversion tienen, además de una base de datos con toda la información, un directorio especial por repositorio llamado hooks donde podemos escribir scripts que se ejecutarán en diferentes situaciones. Estos scripts (bueno, o programas) pueden desde abortar un commit, a cambiar cosas, añadir información, cambiar propiedades, etc… En nuestro caso vamos a usar el hook de post-commit para generar un snapshot automático con cada nuevo tag.

Vamos a suponer que tenemos un repositorio con múltiples proyectos, cada uno de ellos con sus correspondientes ‘trunk’, ‘tags’, ‘branches’ como dice el libro de subversion. De algunos de ellos queremos hacer snapshots cuando se marque un nuevo tag, así que pondremos en el directorio hooks el siguiente script llamado post-commit ( se tiene que llamar así y además tiene que ser ejecutable, chmod +x):


#!/bin/bash
export PATH=/usr/bin:/bin
REPOS="$1"
REV="$2"
PREFIXES="/proyecto1 /proyecto2 /proyectoN"
OUTPUT_DIR=/path/donde/se/guardara/el/zip
for PREFIX in $PREFIXES; do
for tag in $(\
svn log -v -r $REV file://$REPOS | \\
awk '/^ *A */{if ($2~/'${PREFIX//\\//\\\\/}'\\/tags\\/[^\\/]*$/) print $2;}/^$/{exit}'\\
); do
file=${tag##*/}
svn -r $REV export file://$REPOS/$tag $file
zip -rm $OUTPUT_DIR/$file.zip $file
done
done

(bajar) versión completa

Si tu repositorio sólo tiene un proyecto, se puede simplificar un poco más:


#!/bin/bash
export PATH=/usr/bin:/bin
REPOS="$1"
REV="$2"
OUTPUT_DIR=/path/donde/se/guardara/el/zip
for tag in $(\
svn log -v -r $REV file://$REPOS | \\
awk '/^ *A */{if ($2~/\\/tags\\/[^\\/]*$/) print $2;}/^$/{exit}'\\
); do
file=${tag##*/}
svn -r $REV export file://$REPOS/$tag $file
zip -rm $OUTPUT_DIR/$file.zip $file
done

(bajar) versión simplificada

posteado por PpluX @ 4:44 pm tags:recetas, subversion  

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  
« Entradas anterioresEntradas siguientes »

Gestionado con WordPress