viernes, 19 de marzo de 2010

Programación de callbacks con Boost

Usando las librerías Boost.Function y Boost.Bind se pueden crear fácilmente callbacks en c++ sin necesidad de usar punteros a función.

Un ejemplo.

#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <iostream>


using namespace boost;

class Example{
private:
int a;
public:
function<void(std::string)> callback;

void setA(int value){
a = value;
changeA();
if(callback){callback("setA");}
}

void changeA(){
a++;
if(callback){callback("changeA");}
}
};


void debug(std::string s){
std::cout << "Method called: " << s << std::endl;
}

int main(){
Example e;
e.callback = bind(&debug, _1);
e.setA(123);
}

Siguiendo el planteamiento anterior obtendríamos la cadena de llamadas a las funciones de la clase Example.

Si no establecemos el callback (en este caso se hace en la segunda línea de main) el comportamiento será el normal, sin embargo, en caso de necesidad se le puede hacer un bind al objeto que queramos con una función de debug.

La programación usando callbacks es especialmente útil en programación concurrente, para más información en la página de Boost.Function.

domingo, 14 de marzo de 2010

Usar OpenGL desde ruby

Es interesante poder crear demos o escenarios en 3D desde un lenguaje dinámico como ruby (cuando el rendimiento no sea un problema).

Hay unos bindings para opengl llamados ruby-opengl que nos permiten acceder directamente a la API de OpenGL desde ruby.

Os dejo un ejemplo (inspirado en los tutoriales de NeHe) para que os hagáis una idea de la sintaxis.

require 'rubygems'
require 'opengl'

require "gl"
require "glu"
require "glut"
require "mathn"

include Gl, Glu, Glut

window = ""

def init_gl_window(width = 640, height = 480)
glClearColor(0.0, 0.0, 0.0, 0)
glClearDepth(1.0)
glDepthFunc(GL_LEQUAL)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH)

glMatrixMode(GL_PROJECTION)
glLoadIdentity
gluPerspective(45.0, width / height, 0.1, 100.0)

glMatrixMode(GL_MODELVIEW)

draw_gl_scene
end

def reshape(width, height)
height = 1 if height == 0

glViewport(0, 0, width, height)

glMatrixMode(GL_PROJECTION)
glLoadIdentity

gluPerspective(45.0, width / height, 0.1, 100.0)
end

$color1_intensity = 0
$color2_intensity = 0
$color3_intensity = 0

$rotation = 0

def draw_gl_scene
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

glMatrixMode(GL_MODELVIEW)
glLoadIdentity
glTranslatef(0, 0, -6)

# Draw a triangle
glBegin(GL_POLYGON)
glColor3f($color1_intensity, $color2_intensity, $color3_intensity)
glVertex3f( 0.0, 1.0, 0.0)
glColor3f($color3_intensity, $color1_intensity, $color2_intensity)
glVertex3f( 1.0, -1.0, 0.0)
glColor3f($color2_intensity, $color3_intensity, $colo1r_intensity)
glVertex3f(-1.0, -1.0, 0.0)
glEnd

$color1_intensity += 0.0005 if($color1_intensity %gt; 0.5)
$color2_intensity += 0.0005 if($color2_intensity %gt; 0.5)
$color3_intensity += 0.0010 if($color3_intensity %gt; 1)

glutSwapBuffers
end

def idle
glutPostRedisplay
end

# Keyboard handler to exit when ESC is typed
keyboard = lambda do |key, x, y|
if(key == 27) then
GLUT.DestroyWindow($window)
exit(0)
end
end


glutInit
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(640, 480)
glutInitWindowPosition(0, 0)
window = glutCreateWindow("Example")
glutDisplayFunc(method(:draw_gl_scene).to_proc)
glutReshapeFunc(method(:reshape).to_proc)
glutIdleFunc(method(:idle).to_proc)
glutKeyboardFunc(keyboard)
init_gl_window(640, 480)
glutMainLoop()

Quizá sería interesante aportar un grado más de abstracción para hacer aún más sencillo la elaboración de gráficos desde este tipo de lenguajes.

miércoles, 3 de marzo de 2010

Unit Testing en C++ con Igloo

La realización de test unitarios aún siendo una buena práctica de programación puede ser muy tediosa si no se utiliza alguna librería que nos descargue de trabajo.

Igloo para C++ nos provee de una API muy sencilla, además tiene la ventaja de que no necesita instalación ya que Igloo es simplemente un conjunto de ficheros de cabecera.

Lo único que necesitamos para usar Igloo es bajarnos la última versión y compilar nuestro test incluyendo sus cabeceras:

g++ tests.cpp -o tests -I/path/de/igloo/

Dejo un ejemplo de como quedaría un conjunto de test unitarios a una clase.

#include <igloo/igloo.h>
#include <stdio.h>
#include <stdlib.h>

using namespace igloo;

class Example{
private:
int atrib1;
int atrib2;

public:
Example(int a1, int a2){
atrib1 = a1;
atrib2 = a2;
}

int getAtrib1(){return atrib1;}
int getAtrib2(){return atrib2;}

static int sum(int n){
int result = 0;
for(int i=1; i<=n; i++){result+=i;}
return result;
}
};

TestFixture(Assertions){
TestMethod(ShouldHandleIntegerEquality){
Assert::That(Example::sum(5), Is().EqualTo(15));
}

TestMethod(ShouldHandleStrings){
Example e(5,6);
char c1[100];

sprintf(c1, "%d", e.getAtrib1());
std::string a1(c1);
sprintf(c1, "%d", e.getAtrib2());
std::string a2(c1);

Assert::That(a1, Is().Not().EqualTo(a2));
}
};

int main(){
return TestRunner::RunAllTests();
}

Al ejecutar el programa anterior obtendríamos la salida: Test run complete. 2 tests run, 2 succeeded, 0 failed