Introduction à Vala (2ème partie)

Utiliser des librairies C avec Vala

Introduction

Dans mon précédent article, j'ai présenté Vala, un langage de programmation sous Linux très similaire à C#. Lors de la compilation, Vala génére du code C, qui est à son tour compilé par Gcc. Le code binaire obtenu est donc natif et très rapide, sans imposer l'installation d'un runtime volumineux. Un autre énorme avantage de Vala est qu'il peut donc, de facto, accéder à l'immense catalogue de librairies écrites en C disponibles sous Linux.

Pour pouvoir utiliser une librairie externe en C avec Vala, il faut donc :
  • Installer cette librairie en utilisant un package
  • Installer les fichiers d'entête (.h) de cette librairie (qui seront utilisés lors de la compilation du code C)
  • Installer les fichiers de bindings pour Vala (.vapi)

La dernière fois, nous avons utilisé la commande apt-get pour installer Vala et quelques librairies utiles. Cette méthode peut sembler complexe aux utilisateurs de Windows. Sous Ubuntu 9.10, il est également possible d'utiliser l'outil Synaptic Package Manager, qui offre une interface graphique pour rechercher, télécharger et installer des packages.

Installation de librairies externes

A titre d'exemple, nous allons récupérer deux librairies via cette méthode : GLU (OpenGL Utility Library) et GtkGLext (OpenGL Extension for Gtk+). Ces deux librairies (ainsi que GL qui est déjà installée par défaut) vont nous permettre de faire tourner une petite démo en 3D donnée en exemple sur le site de Vala (http://live.gnome.org/Vala).

Démarrez Synaptic Package Manager via le menu System > Administration. Entrez le mot de passe de l'utilisateur root. La fenêtre suivante apparaît :





La plupart des librairies C sont préfixées par "lib". Tapez gtkglext dans la zone de recherche et validez par Enter. Une liste de packages apparaît. Repérez libgtkglext1. En cliquant sur le nom de la librairie, sa description complète apparaît. Si la case à cocher en face de la librairie n'est pas verte, faites un clic-droit sur celle-ci et choisissez l'option "Mark for installation".

Les librairies de headers sont sufixées par "-dev". Repérez à présent libgtkglext1-dev et marquez-là également pour installation. Idem pour libglu1-mesa et libglu1-mesa-dev. Une fois ces opérations terminées, cliquez sur l'icône "Apply" dans la barre d'outils. Le téléchargement et l'installation des packages sélectionnés va commencer.

Installation des bindings pour Vala

Les fichiers de bindings sont l'équivalent de l'import de fonction Win32 en C#. Ils sont installés par défaut dans le répertoire /usr/share/vala/vapi. Les fichiers manquants peuvent être trouvés sur le site de Gnome, à l'adresse suivante : http://live.gnome.org/Vala/ExternalBindings

Téléchargez les fichiers suivants : gl.vapi, glu.vapi, gtkglext.vapi, glut.vapi et glx.vapi. Copiez-les ensuite dans le répertoire /usr/share/vala/vapi. Si vous êtes nouveau sous Ubuntu et que vous essayez de réaliser cette opération avec l'explorateur de fichier, vous constaterez très vite que vous n'avez pas les droits en écriture sur ce répertoire. Le plus simple est de démarrer un Terminal et de démarrer l'explorateur avec l'utilisateur root en tapant la commande sudo nautilus.

Démonstration

Passons-donc maintenant au test de nos librairies à l'aide de ce petit exemple récupéré sur le site officiel de Vala. Créez un nouveau fichier opengl.vala avec gedit et collez le code ci-dessous.


using Gtk;
using Gdk;
using GL;
using GLU;

public class Sample : Gtk.Window
{
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

static int iShade = 2;
static int iTess = 3;

static const GLfloat[] lightPos = { 0.0f, 0.0f, 75.0f, 1.0f };
static const GLfloat[] specular = { 1.0f, 1.0f, 1.0f, 1.0f };
static const GLfloat[] specref = { 1.0f, 1.0f, 1.0f, 1.0f };
static const GLfloat[] ambientLight = { 0.5f, 0.5f, 0.5f, 1.0f };
static const GLfloat[] spotDir = { 0.0f, 0.0f, -1.0f };

public Sample ()
{
this.title = "OpenGL with GtkGLExt";
this.destroy += Gtk.main_quit;
set_reallocate_redraws (true);

var drawing_area = new DrawingArea ();
drawing_area.set_size_request (800, 600);

var glconfig = new GLConfig.by_mode (GLConfigMode.RGB
| GLConfigMode.DOUBLE
| GLConfigMode.DEPTH);

WidgetGL.set_gl_capability (drawing_area, glconfig, null, true,
GLRenderType.RGBA_TYPE);

drawing_area.realize += on_realize;
drawing_area.configure_event += on_configure_event;
drawing_area.expose_event += on_expose_event;

drawing_area.add_events (Gdk.EventMask.KEY_PRESS_MASK);
drawing_area.can_focus = true;
drawing_area.key_press_event += on_key_press_event;

add (drawing_area);
}

/* Widget gets initialized */
private void on_realize (DrawingArea widget)
{
GLContext glcontext = WidgetGL.get_gl_context (widget);
GLDrawable gldrawable = WidgetGL.get_gl_drawable (widget);

if (!gldrawable.gl_begin (glcontext))
return;

glEnable (GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
glFrontFace (GL_CCW);

glEnable (GL_LIGHTING);

glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight);

glLightfv (GL_LIGHT0, GL_DIFFUSE, ambientLight);
glLightfv (GL_LIGHT0, GL_SPECULAR, specular);
glLightfv (GL_LIGHT0, GL_POSITION, lightPos);

glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 50.0f);

glEnable (GL_LIGHT0);

glEnable (GL_COLOR_MATERIAL);

glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
glMateriali (GL_FRONT, GL_SHININESS,128);

glClearColor (0.0f, 0.0f, 0.0f, 1.0f);

gldrawable.gl_end ();
}

/* Widget is resized */
private bool on_configure_event (DrawingArea widget, EventConfigure event)
{
GLContext glcontext = WidgetGL.get_gl_context (widget);
GLDrawable gldrawable = WidgetGL.get_gl_drawable (widget);

if (!gldrawable.gl_begin (glcontext))
return false;

int w = widget.allocation.width;
int h = widget.allocation.height;

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();

GLfloat fAspect = (GLfloat) w / (GLfloat) h;
gluPerspective (35.0f, fAspect, 1.0f, 500.0f);

glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glTranslatef (0.0f, 0.0f, -250.0f);

gldrawable.gl_end ();
return true;
}

/* Widget is asked to paint itself */
private bool on_expose_event (DrawingArea widget, EventExpose event)
{
GLContext glcontext = WidgetGL.get_gl_context (widget);
GLDrawable gldrawable = WidgetGL.get_gl_drawable (widget);

if (!gldrawable.gl_begin (glcontext))
return false;

if (iShade == 1)
glShadeModel (GL_FLAT);
else
glShadeModel (GL_SMOOTH);

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix ();
glRotatef (xRot, 1.0f, 0.0f, 0.0f);
glRotatef (yRot, 0.0f, 1.0f, 0.0f);

glLightfv (GL_LIGHT0, GL_POSITION, lightPos);
glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, spotDir);

glColor3ub (255,0,0);

glTranslatef (lightPos[0], lightPos[1], lightPos[2]);
GLDraw.cone (true, 4.0f, 6.0f, 15, 15);

glPushAttrib (GL_LIGHTING_BIT);

glDisable (GL_LIGHTING);
glColor3ub (255,255,0);
GLDraw.sphere (true, 3.0f, 15, 15);

glPopAttrib ();

glPopMatrix ();

glColor3ub (0, 0, 255);

if (iTess == 1) {
GLDraw.sphere (true, 30.0f, 7, 7);
} else {
if (iTess == 2)
GLDraw.sphere (true, 30.0f, 15, 15);
else
GLDraw.sphere (true, 30.0f, 50, 50);
}

if (gldrawable.is_double_buffered ())
gldrawable.swap_buffers ();
else
glFlush ();

gldrawable.gl_end ();
return true;
}

/* A key was pressed */
private bool on_key_press_event (DrawingArea drawing_area, EventKey event)
{
string key = Gdk.keyval_name (event.keyval);

if (key == "Up")
xRot-= 5.0f;

if (key == "Down")
xRot += 5.0f;

if (key == "Left")
yRot -= 5.0f;

if (key == "Right")
yRot += 5.0f;

if (xRot > 356.0f)
xRot = 0.0f;

if (xRot < -1.0f) xRot = 355.0f; if (yRot > 356.0f)
yRot = 0.0f;

if (yRot < -1.0f) yRot = 355.0f; queue_draw (); return true; } public static void main (string[] args) { Gtk.init (ref args); Gtk.gl_init (ref args); var sample = new Sample (); sample.show_all (); Gtk.main (); } }



Pour compiler ce programme, tapez la ligne de commande suivante dans le Terminal :

valac --pkg glu --pkg gtk+-2.0 --pkg gl --pkg gtkglext-1.0 opengl.vala

Lancez maintenant le programme via l'explorateur de fichier ou en tapant ./opengl




Conclusion

Voici qui clôture ce second article consacré à Vala sous Ubuntu 9.10. S'il n'est pas encore mature, Vala s'avère être un langage très riche. Conçu à l'origine pour la programmation Gnome, il pourrait devenir un langage généraliste très populaire sous Linux, sans imposer la lourdeur de l'installation d'un environnement runtime dédié.

Pour plus d'informations :


Commentaires