2013-10-13
Objectif : afficher un contexte OpenGL dans une fenêtre GTK+3 sous Windows.

Il y a quelque mois, j'ai eu besoin d'afficher une scène 3D - rendue, bien sûr, via OpenGL - dans une fenêtre GTK+3 sous Windows.
Je me souvenais bien que des bibliothèques tierces permettaient de le faire, et une petite recherche m'en a localisée deux :
Elle fournissent toutes les deux plus ou moins la même API : l'on crée un widget dédié dans lequel la scène OpenGL va s'afficher. Il y a une gestion automatique du déplacement et du redimensionnement ; cependant certaines commodités (comme la mise à l'échelle) doivent être effectuées manuellement.
À mon grand désespoir, cependant, elles ne fonctionnaient toutes deux qu'avec GTK+2...
J'ai donc décidé d'effectuer quelques modifications au code de GtkGLArea, et voilà finalement ce que ça donne :

GtkGLArea3 modifié, dans toute sa splendeur sous Windows !
Comme mon application était écrite en Vala, j'en ai profité pour écrire les VAPI, empaqueter la bibliothèque et la fournir dans mon dépôt ValaWinPKG 😉.
Bref, voici ci-dessous comment l'utiliser !
Si vous ne les avez pas déjà, nous allons installer le dernier Vala et ValaWinPKG pour Windows :
Nous lançons ValaWinPKG depuis le menu Démarrer de Windows.
Nous cochons ensuite le paquet "GtkGLArea3" et cliquons sur le bouton "Update !".

Nous allons d'abord afficher un triangle dans un widget OpenGL.
Dans ce code source Vala, l'on remarque :
var glarea = new GLArea (attrlist);
glarea.set_size_request (100, 100);
glarea.realize.connect (on_glarea_realize_event);
glarea.draw.connect (on_glarea_draw_event);
Nous créons un objet GLArea de taille 100x100, et lui attachons 2 callbacks : realize et draw.
realize : exécuté uniquement au 1er affichage de la GLArea.void on_glarea_realize_event (Widget widget)
{
[...]
if (glarea.make_current () == true)
{
[...]
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0,100, 100,0, -1,1);
glMatrixMode (GL_MODELVIEW);
}
draw : sera rappelé à chaque fois que la fenêtre est rafraîchie et/ou redimensionnée.bool on_glarea_draw_event (Widget widget, Cairo.Context cr)
{
[...]
if (glarea.make_current () == true)
{
[...]
// Draw simple triangle
glBegin (GL_TRIANGLES);
glVertex2f (10,10); // side 1
glVertex2f (10,90); // side 2
glVertex2f (90,90); // side 3
glEnd ();
// Swap backbuffer to front
glarea.swap_buffers (); // refresh!
Notez l'appel final à glarea.swap_buffers () pour rafraîchir la scène : rien ne s'affichera sans cela.
Notez aussi que nous utilisons glarea.make_current () à la fois comme un test (le contexte est-il toujours valide ?) et une validation (c'est dans ce contexte que nous voulons dessiner !).
Compilons et exécutons :
valac --pkg gtkgl-3.0 gtkglarea3-triangle.vala -o gtkglarea3-triangle.exe
gtkglarea3-triangle

L'autre code source est moins spectaculaire, mais introduit la gestion des polices
(fournie par GtkGLArea3 par-dessus OpenGL, qui de base ne propose rien de tel) :
GLuint fontbase;
fontbase = glGenLists (128);
Pango.FontDescription fontdesc = Pango.FontDescription.from_string ("Sans 10");
Gdk.gl_use_pango_font (fontdesc, 0, 128, fontbase);
Nous créons une liste OpenGL de 128 éléments identifiée par un GLuint : ce sera notre liste de glyphes.
Nous référons ensuite à une police TrueType très commune via le composant Pango de GTK+3 : Sans (taille 10).
Finalement, nous lions les deux, ce qui enclenche un processus complexe de "glyphes-vers-textures"... et la magie peut opérér !
Il ne nous reste qu'à écrire avec :
/* Text to display */
string fonttext = "GTKGLAREA";
[...]
glColor3f (1,1,0); // red + green == yellow
glRasterPos2f ((100-charwidth*fonttext.length)/2, (100-charheight)/2); // center position
glListBase (fontbase); // use list of textures
glCallLists (fonttext.length, GL_UNSIGNED_BYTE, (GL.GLvoid[])fonttext); // render 'fonttext' with textures
Compilons et exécutons :
valac --pkg gtkgl-3.0 gtkglarea3-text.vala -o gtkglarea3-text.exe
gtkglarea3-text

Et voilà !
Le port Linux est toujours en chantier (la gestion des polices y est bien plus compliquée) et sortira sous peu.
Cependant, et sans en dire trop, voilà où ça en est aujourd'hui...

... il me reste à corriger ces pixmaps de texte en bas à droite 😉.
(P.S.: : j'ai appris récemment que GtkGLExt avait un port GTK+3 en chantier... dommage que je sois allé si vite !)