Utilisation de glPolygonStipple

C’est parti pour le premier article technique de cette année.

Comme vous le savez j’apprends l’OpenGL avec le livre officiel dans sa septième édition. Pour le moment, je n’ai lu que 1/10ème du livre en question. Mais je dois reconnaître que ce livre regorge d’informations mais elles sont parfois trop peu approfondies. Je vais donc par le biais de ce post vous présenter la fonction glPolygonStipple qui vous permettra d’appliquer des textures sur différentes surfaces.

Pour faire simple, j’ai opté pour un dessin simple: un smiley. Le but de cet article va donc être d’appliquer une texture sur une surface 2D classique: glRectf.

Mais avant de nous jeter dans le code, il faut tout d’abord savoir ce que va faire notre programme :

  1. Initialisation d’OpenGL et définition du repère de travail
  2. Création d’un tableau de byte représentant notre smiley
  3. Appliquer notre smile sur un glRectf

Pour ce qui est de la première étape d’initialisation d’OpenGL et du repère, il suffit de saisir les lignes suivantes :

/*Define the drawing zone properties*/
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glViewport(0, 0, 10, 10);

//Load identity matrix
glLoadIdentity();

//Define x & y axis
gluOrtho2D((GLdouble) -10, (GLdouble) 10, (GLdouble) -10, (GLdouble) 10);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(1024,100);
glutCreateWindow("OpenGL GLubyte Demo");

init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

Voilà, ce code est assez classique rien d’extraordinaire à expliquer et puis je l’ai déjà fait dans un post précédent. Nous allons pouvoir directement passer à la seconde étape, celle qui nous intéresse le plus: la création du smiley.

Pour ma part, j’utilise un tableur comme celui d’OpenOffice.org pour modéliser le smiley et en faire le découpage en tableau de bytes.

Faîtes une grille de 32×32 soit 1024 cases. Arrangez-vous pour ne pas faire des cases trop grandes et de forme carrée pour que cela tienne sur votre écran (bon effectivement si vous avez un 14″ ça va être dur … :p). Une fois les cases dessinées faites des bordures plus épaisses sur des rectangles de 8×4 (Longueur x Hauteur) pour avoir 4 colonnes (si si je vous assure 4×8 ça fait 32). Pour dessiner notre smiley, il suffit de noircir les cases de la grille pour que l’ensemble ressemble à un smiley.

Comme je suis sympa, vous pouvez prendre mon modèle au format ODS ici.

Vous devriez donc avoir un smiley ressemblant à celui-ci :

Si vous avez téléchargé mon fichier ODS, vous savez ce que nous allons faire: traduire notre smiley en byte. Mais comment faire !? J’ai eu du mal à trouver mais c’est en fait très simple. Il suffit de connaître le principe et ça se fait très vite. Zoomons sur la première partie de l’œil :

Chaque case de dimension 8×4 va vous donner 4 valeurs hexadécimales (une pour chaque ligne) que nous reporterons dans un tableau. La première case de droite vaut 1, la suivante 2, puis 4 et ainsi de suite jusqu’à la dernière qui vaut 80 (128 en décimal). Ici, nous aurons donc les valeurs 0, 0, 1, 3. Je vous laisse vous entrainer avec les autres cases. Si vous avez pris le même exemple que moi, vous avez les valeurs suivantes (à partir du coin de l’œil ci-dessus): 1, 80, 1, 80, 3, C0, 3, C0, 3, C0, 3, C0, 1, 80, 1, 80, 0, 0, 80, 0, … 0, 0E, 70, 0, 0, 3, C0, 0 …

Seulement voilà, si nous utilisions ces valeurs dans notre programme nous aurions un smiley à l’envers car la fonction glPolygonStipple se base sur les bits de poids forts. Ils faut donc inverser chaque groupe de 4 valeurs (les lignes de notre grille) et nous pourrons retourner à notre code. Les valeurs seront donc les suivantes : 0, 3, C0, 0, 0, 0E, 70, 0, …, 0, 0, 80, 0, 1, 80, 1, 80, 3, C0, 3, C0, 3, C0, 3, C0, 1, 80, 1, 80 …

Le plus gros du travail est maintenant terminé, il nous reste à écrire notre fonction display() :

/*Display function*/
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 1.0, 1.0);

    //Our values from the previous step
    GLubyte smile[] = {
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x03, 0xC0, 0x00,
        0x00, 0x0E, 0x70, 0x00,
        0x00, 0x18, 0x18, 0x00,
        0x00, 0x20, 0x04, 0x00,
        0x00, 0x40, 0x02, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00,
        0x00, 0x00, 0xC0, 0x00,
        0x01, 0x80, 0x01, 0x80,
        0x03, 0xC0, 0x03, 0xC0,
        0x03, 0xC0, 0x03, 0xC0,
        0x01, 0x80, 0x01, 0x80,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00
    };

    glEnable(GL_POLYGON_STIPPLE);

    glPolygonStipple(smile);
    //Define the surface where we apply our texture
    glRectf(10, -10, -10, 10);

    glDisable(GL_POLYGON_STIPPLE);
    glFinish();
}

C’est ici que l’on se rend vraiment compte de l’intérêt du fonctionnement interne d’OpenGL comme une machine à états. La fonction glEnable() permet d’activer GL_POLYGON_STIPPLE en mémoire, d’exécuter la fonction glPolygonStipple() avec les valeurs obtenues à l’étape précédente, d’appliquer notre « tapisserie » sur le glRectf. Une fois que l’on en a plus besoin, on désactive GL_POLYGON_STIPPLE ce qui permet de vraiment optimiser les traitements et la mémoire.

Et voilà, c’est fini ! Vous pouvez compiler votre code est admirer votre travail :

J’espère que cette première partie vous a plu.

A bientôt pour opengellesques aventures ;-) .

OpenGL & MacOS X

Si vous aussi vous avez déjà tenté de développer une application OpenGL sous Mac OS X, vous avez dû être surpris de constater que votre programme refusait de compiler.

En fait, j’ai trouvé 2 méthodes pour pouvoir compiler correctement vos programmes OpenGL.

La première méthode ne nécessite aucune modification du code mais une fois compilée, l’application se lancera dans X11. Pour cela, il suffit de compiler avec les paramètres suivants :

gcc main.c -o testmacx11 -I/usr/X11R6/include -L/usr/X11R6/lib -lGL -lglut

Ici, nous compilons main.c pour qu’il donne le binaire testmacx11 en lui indiquant le chemin vers les includes et les libs de X11.

L’exécution de testmacx11 provoquera le lancement de X11 puis seulement de votre application.

La deuxième méthode consiste, vous l’aurez deviné, à lancer l’application finale avec Cocoa. Pour celà, il faut tout d’abord modifier le code. Pour conserver l’interopérabilité du code et ne pas avoir à le modifier à chaque changement de système d’exploitation, on utilise la directive conditionnelle #ifdef pour déterminer si l’on est ou non sur un Mac. Selon la plateforme, on met les bons headers :

#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glut.h>
#endif

Une fois cette modification de vos sources réalisée, nous allons donc compiler à la mode Mac OS X :

gcc main.c -o testmacocoa -framework GLUT -framework OpenGL -framework Cocoa

Et voilà, quand vous lancez votre application via testmacocoa, celle-ci se lance comme une application MacOS classique.

Enfin, je trouve quand même que la compilation sous Linux est plus aisée :

gcc main.c -o testlinux -lglut

J’espère que ce post vous aidera grandement ;-) .

Premiers pas avec OpenGL

Aujourd’hui, j’ai eu l’occasion de faire mes premiers pas en OpenGL avec du C bien sûr. Voici donc mes premières impressions.

Tout d’abord, avant de commencer à développer, il a fallu que je trouve des documents sur le net. Le site de NeHe est assez réputé, l’adresse de son site est même présente dans le topic du chan ##OpenGL sur Freenode. Eh bien je trouve que pour débuter, son site est très loin d’être le bon endroit. Je m’attendais à beaucoup mieux et l’horrible design qui vous explose les yeux au bout d’un quart d’heure a eu raison de moi.

J’ai donc essayé de trouver d’autres ressources. Et là, je suis tombée sur une très bonne ressource qui vous explique bien les bases: The OpenGL Programming Guide. La ressource en question est en anglais mais est écrite dans un style didactique clair. Mais bon, je suis quand même surprise de constater que les ressources pour apprendre l’OpenGL sont super rares.

Ensuite, après avoir lu l’introduction du site sus-cité, j’ai donc voulu tester le premier code fournit en exemple. Et là, deuxième surprise: MacOS n’utilise pas les mêmes headers concernant OpenGL. Mac OS est vraiment la pire plateforme de développement que j’ai pu tester, même Windows s’en sort mieux face à ce genre de situation… Enfin bref, j’ai donc fait mes premiers tests sur Ubuntu sans aucun problème.

Niveau programmation, je trouve que l’API OpenGL et ses spécifications sont vraiment claires. Je ne regrette pas d’avoir un peu galéré pour découvrir une telle technologie :-) . Un grand merci au Khronos Group. Étant donné la puissance de l’API et l’orientation vers la 3D, il est évident qu’elle est moins facile d’approche que la SDL que j’avais eu l’occasion d’utiliser lorsque j’étais en BTS.

Voici donc ce que j’ai pu obtenir après ces aventures :

test_opengl

Ça reste un début, mais je suis assez contente de moi, je n’ai même pas fini le premier chapitre ! Ce code est issu de l’exemple fournit avec le carré blanc sur fond noir.

Bon week-end à tous :-) .