I. Contributions

Nous recherchons toujours des traducteurs pour finir ce projet de traduction des articles de NeHe. Votre aide serait appréciée ! Vous êtes intéressé ? Alors contactez-nous à l'adresse suivante : nehe@redaction-developpez.com .

II. Tutoriel

II-A. Introduction

Soit l'exemple suivant : nous sommes en train de programmer un jeu qui utilise et manipule des astéroïdes. Chaque niveau du jeu commence avec deux astéroïdes minimum affichés à l'écran. Vous vous asseyez donc avec votre crayon et votre feuille, et vous cherchez comment faire un astéroïde en 3D. Une fois que vous avez entièrement fini, vous construisez votre astéroïde avec OpenGL en utilisant des polygones et des rectangles. Imaginons que cet astéroïde est octogonal (huit côtés). Normalement, vous devriez créer une boucle et dessiner l'astéroïde dans la boucle. Vous devriez y parvenir avec environ 18 (ou plus) lignes de code. Devoir créer l'astéroïde à chaque fois qu'il faut l'afficher à l'écran est lourd pour votre machine. Vous constaterez que c'est d'autant plus vrai que vous manipulez des objets complexes.

La solution se trouve être l'utilisation des listes d'affichage. Avec une liste d'affichage, l'objet est créé une seule et unique fois. Vous pouvez alors lui donner une texture, de la couleur, ce que vous voulez. Donnez un nom à votre liste d'affichage. Comme il s'agit d'un astéroïde, en conséquence nous appellerons cette liste d'affichage 'asteroid'. Ainsi chaque fois que je voudrai dessiner l'astéroïde coloré ou texturé à l'écran, la seule chose à faire sera d'appeler glCallList(asteroid). L'astéroïde précédemment créé apparaîtra directement à l'écran. Puisque l'astéroïde est déjà préexistant dans la liste d'affichage, il sera inutile de le construire dans le programme OpenGL. Il est déjà présent dans la mémoire. Cela permet d'économiser du temps de calcul et ainsi de gagner en rapidité d'exécution.

Alors êtes-vous prêt à apprendre ? :) Nous allons appeler ceci la démo "Liste d'affichage Q-Bert". Nous obtiendrons un écran de type Q-Bert représentant 15 cubes. Chaque cube est en réalité composé d'une boîte et d'un couvercle. Le haut sera placé dans une liste d'affichage à part, ainsi nous pourrons lui ajouter une texture différente (plus sombre). Le cube sera en fait une boîte sans couvercle et vide. (simulé par un couvercle sombre).

II-B. Inclusion

Ce code est basé sur la leçon 6. Une grande partie du code de la leçon 6 est réutilisée, ainsi il sera plus facile d'étudier les quelques modifications. Les lignes ci-dessous sont standards et utilisées dans à peu près toutes les leçons.

En-têtes et déclarations
Sélectionnez
#include    <windows.h>                     // En-tête pour Windows
#include    <stdio.h>                       // En-tête pour les entrées/sorties standards (NOUVEAU)
#include    <gl\gl.h>                       // En-tête pour la bibliothèque OpenGL32
#include    <gl\glu.h>                      // En-tête pour la bibliothèque GLu32
#include    <gl\glaux.h>                    // En-tête pour la bibliothèque GLaux
HDC         hDC=NULL;                       // Contexte privé du système GDI
HGLRC       hRC=NULL;                       // Contexte de rendu permanent
HWND        hWnd=NULL;                      // Contient notre descripteur de fenêtre
HINSTANCE   hInstance;                      // Sauve l'instance de l'application
bool        keys[256];                      // Tableau utilisé pour les routines du clavier
bool        active=TRUE;                    // Drapeau d'activation de la fenêtre
bool        fullscreen=TRUE;                // Drapeau pour le mode plein écran (Vrai par défaut)

II-C. Les variables

À présent nous initialisons nos variables. La première est une variable de stockage pour une texture. Ensuite viennent deux variables pour les deux listes d'affichage. Ces variables sont utilisées comme pointeurs sur la mémoire de stockage des listes d'affichage. Elles sont appelées box et top.

Deux variables, nommées xloop et yloop, sont utilisées pour le positionnement des cubes à l'écran et deux autres nommées xrot et yrot sont utilisées pour la rotation des cubes suivant les axes X et Y.

Déclaration des variables pour les cubes
Sélectionnez
GLuint texture[1];          // Pour stocker une texture
GLuint box;                 // Pour stocker une liste d'affichage
GLuint top;                 // Pour stocker une seconde liste d'affichage
GLuint xloop;               // Boucle sur l'axe des X
GLuint yloop;               // Boucle sur l'axe des Y
GLfloat xrot;               // Rotation des cubes sur l'axe des X
GLfloat yrot;               // Rotation des cubes sur l'axe des Y

II-D. Deux tableaux

Ensuite, ce sont deux tableaux qui sont initialisés, qui contiennent les codes pour les couleurs. Le premier, 'boxcol' stockera les valeurs du taux de brillance rouge, orange, jaune, vert et bleu. Chaque valeur incluse dans les accolades '{}' représente les valeurs des composantes rouge, vert et bleu. Chaque groupe d'accolades correspond à une couleur spécifique.

Le deuxième tableau de couleurs que nous allons créer est pour le rouge foncé, orange foncé, jaune foncé, vert foncé, et bleu foncé. Ces couleurs seront utilisées pour dessiner le haut des boîtes. Nous voulons que le couvercle soit plus sombre que le reste de la boîte.

Déclaration des couleurs des cubes
Sélectionnez
static GLfloat boxcol[5][3]= // Tableau pour la couleur des boîtes
{
    // Brillant : rouge, orange, jaune, vert, bleu
    {1.0f,0.0f,0.0f},
    {1.0f,0.5f,0.0f},
    {1.0f,1.0f,0.0f},
    {0.0f,1.0f,0.0f},
    {0.0f,1.0f,1.0f}
};

static GLfloat topcol[5][3]= // Tableau pour la couleur des faces supérieures
{
    // Sombre : rouge, orange, jaune, vert, bleu
    {.5f,0.0f,0.0f},
    {0.5f,0.25f,0.0f},
    {0.5f,0.5f,0.0f},
    {0.0f,0.5f,0.0f},
    {0.0f,0.5f,0.5f}
};

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Déclaration de WndProc

II-E. La fonction BuildLists

Maintenant nous allons construire la vraie liste d'affichage. Vous avez sans doute remarqué que tout le code pour construire la boîte est dans la première liste, et que tout le code pour construire le haut de la boîte est dans l'autre liste. Je vais essayer de détailler les explications pour cette partie.

 
Sélectionnez
GLvoid BuildLists() // Construction des listes d'affichage pour les boîtes
{

Nous commençons par dire à OpenGL que nous avons besoin de deux listes. glGenLists(2) va créer l'espace nécessaire pour ces deux listes et retourner un pointeur sur la première liste. 'box' va mémoriser l'endroit de cette première liste. Dès que nous appellerons box, la première liste d'affichage sera dessinée.

Création des listes
Sélectionnez
    box=glGenLists(2); // Construction des deux listes

Ici nous allons construire notre première liste. Nous avons déjà alloué la mémoire pour deux listes, et nous savons que box pointe sur la mémoire prévue pour la première liste. À présent, il faut simplement donner à OpenGL la destination et le type de liste voulu.

Pour cela, nous utilisons la procédure glNewList(). Remarquez que box est le premier paramètre de cette procédure. Ce paramètre indique à OpenGL l'emplacement mémoire pour le stockage de cette première liste. Le deuxième paramètre, GL_COMPILE, indique à OpenGL que nous voulons que la liste soit préexistante dans la mémoire à l'exécution du programme. Ainsi, OpenGL n'a pas besoin d'utiliser la procédure de fabrication de l'objet à chaque fois qu'on souhaite l'afficher.

L'utilisation de GL_COMPILE est similaire à ce qui se passe lorsque l'on utilise un compilateur pour faire un programme. Si vous n'utilisez pas GL_COMPILE, cela est équivalent à écrire un programme et à devoir le compiler avant chaque utilisation. Si le programme compilé est déjà préexistant dans un fichier .EXE, vous avez simplement à cliquer sur cet exécutable pour utiliser le programme. Pas de compilation nécessaire. Une fois qu'OpenGL a compilé les listes d'initialisation, elles sont prêtes à être utilisées, plus besoin de compilation. Ainsi, les listes d'affichage permettent de gagner en vitesse, en gardant en mémoire les objets du jeu sans devoir les recréer à chaque fois.

Création de la liste d'affichage box
Sélectionnez
    glNewList(box,GL_COMPILE);
    // Nouvelle liste d'affichage box

La partie suivante du programme va dessiner la boîte sans son couvercle. Elle n'apparaîtra pas à l'écran. Elle sera stockée dans une liste d'affichage.

Vous pouvez insérer n'importe quelle instruction entre glNewList() et glEndList(). Vous pouvez fixer la couleur, changer les textures, etc. La seule chose que vous ne pouvez pas faire, c'est écrire du code qui modifierait la liste d'affichage à la volée. Une fois que la liste d'affichage est construite, vous ne pouvez plus la modifier.

Vous pourriez penser par exemple que, en ajoutant la ligne glColor3ub(rand()%255,rand()%255,rand()%255) dans le code suivant, vous obtiendriez une nouvelle couleur à chaque lancement du programme. Mais, puisque la liste est créée une fois pour toutes, la couleur ne changera pas à chaque fois que vous le redessinerez à l'écran. La couleur aléatoire utilisée dans la première création de l'objet sera non-modifiable par la suite.

Si vous voulez changer la couleur de la liste d'affichage, vous devez le faire avant de dessiner votre liste d'affichage. J'en parlerai plus tard de manière approfondie.

II-F. Le dessin du cube

dessin du cube
Sélectionnez
    glBegin(GL_QUADS); // Début du dessin du cube

    // Face inférieure
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // En haut à droite de la texture et du quadrilatère
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // En haut à gauche de la texture et du quadrilatère
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // En bas à gauche de la texture et du quadrilatère
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // En bas à droite de la texture et du quadrilatère

    // Face avant
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // En bas à gauche de la texture et du quadrilatère
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // En bas à droite de la texture et du quadrilatère
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // En haut à droite de la texture et du quadrilatère
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // En haut à gauche de la texture et du quadrilatère

    // Face arrière
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // En bas à droite de la texture et du quadrilatère
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // En haut à droite de la texture et du quadrilatère
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // En haut à gauche de la texture et du quadrilatère
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // En bas à gauche de la texture et du quadrilatère

    // Face de droite
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // En bas à droite de la texture et du quadrilatère
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // En haut à droite de la texture et du quadrilatère
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // En haut à gauche de la texture et du quadrilatère
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // En bas à gauche de la texture et du quadrilatère

    // Face de gauche
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // En bas à gauche de la texture et du quadrilatère
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // En bas à droite de la texture et du quadrilatère
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // En haut à droite de la texture et du quadrilatère
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // En haut à gauche de la texture et du quadrilatère

    glEnd(); // Fin du dessin du cube

La commande glEndList() signifie pour OpenGL que la création de la liste d'affichage est terminée. Tout ce qui se trouve entre glNewList() et glEndList() sera contenu dans la liste d'affichage, tout ce qui se trouve avant glNewList() ou après glEndList() ne sera pas pris en compte dans la liste d'affichage courante.

Appel de glEndList
Sélectionnez
    glEndList(); // Fin de la construction de la liste pour le cube

II-G. La deuxième liste

À présent, nous allons créer notre deuxième liste d'affichage. L'emplacement de notre seconde liste est à l'adresse suivant celle pointée par box. On utilise la valeur de l'emplacement de la première liste d'affichage (box) et lui ajoutons une unité. Le code suivant permet d'utiliser la variable top comme conteneur pour la seconde liste d'affichage.

Mise à jour de top
Sélectionnez
    top=box+1; // La liste d'affichage de top est la liste d'affichage de cube + 1

Maintenant que nous avons un emplacement pour stocker notre seconde liste d'affichage, nous pouvons la construire. Nous faisons ceci de la même manière que précédemment, mais cette fois l'emplacement mémoire sera indiqué par la variable 'top' au lieu de la variable 'box'.

Nouvelle liste
Sélectionnez
    glNewList(top,GL_COMPILE); // Nouvelle liste d'affichage compilée top

La portion de code suivante dessine le couvercle de la boîte. C'est un carré contenu dans le plan des Z (plan xOy).

Dessin du haut du cube
Sélectionnez
    glBegin(GL_QUADS); // Début du dessin de rectangle

    // Face supérieure
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // En haut à gauche de la texture et du quadrilatère
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // En bas à gauche de la texture et du quadrilatère
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // En bas à droite de la texture et du quadrilatère
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // En haut à droite de la texture et du quadrilatère

    glEnd(); // Fin du dessin du rectangle

À nouveau, la fin de la construction pour cette liste d'affichage est faite avec l'instruction glEndList(). C'est aussi simple que ça. Nous avons réussi à créer deux listes d'affichage.

Fin de la liste
Sélectionnez
    glEndList(); // fin de la construction de la liste d'affichage top
}

II-H. Charger les textures

Pour charger et initialiser les textures, reprenons le code des tutoriels précédents. Nous voulons une texture couvrant les six faces de chaque cube. J'ai décidé d'utiliser le MIP mapping pour avoir un meilleur aspect lisse des textures. Je n'aime pas voir les pixels. La texture utilisée est 'cube.bmp', stockée dans 'data'. Reprenez la fonction LoadBMP et changez la ligne qui ouvre le fichier pour qu'elle devienne :

Chargement de la texture
Sélectionnez
if (TextureImage[0]=LoadBMP("Data/Cube.bmp")) // Charge la texture

Le code de redimensionnement est exactement le même que la leçon 6.

Le code d'initialisation a seulement quelques changements. J'ai ajouté la ligne BuildList(). Cela permet d'appeler la section de code qui construit la liste d'affichage. Remarquez que l'appel à BuildList() est placé après celui à LoadGLTextures(). Il est important de connaître l'ordre dans lequel ces opérations doivent être placées. Tout d'abord, nous construisons les textures, ce qui permet lors de la création des listes d'affichage de pouvoir les recouvrir des textures ainsi créées.

La fonction InitGL
Sélectionnez
int InitGL(GLvoid)              // Toute l'initialisation OpenGL est faite ici
{
    if (!LoadGLTextures())      // Appelle la procédure de chargement des textures.
    {
        return FALSE;           // Si les textures ne s'affichent pas, retourner la valeur FALSE.
    }
    BuildLists();               // Appelle la procédure de création de la liste d'affichage
    glEnable(GL_TEXTURE_2D);    // Active le 'mapping' de texture
    glShadeModel(GL_SMOOTH);    // Active le 'Smooth Shading'
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Place un fond de scène noir
    glClearDepth(1.0f);         // Règle la profondeur des buffers
    glEnable(GL_DEPTH_TEST);    // Active le test de profondeur
    glDepthFunc(GL_LEQUAL);     // Sélectionne le type de test de profondeur

Les trois lignes de code suivantes activent un éclairage rapide et sale. Light0 est une valeur prédéfinie sur la plupart des cartes vidéo, ce qui nous évite la difficulté d'initialiser l'éclairage. Après avoir sélectionné light0, nous activons l'éclairage. Si light0 ne fonctionne pas sur votre carte vidéo (c'est-à-dire que vous voyez un écran noir), désactivez simplement l'éclairage.

La dernière ligne GL_COLOR_MATERIAL nous permet d'ajouter des couleurs pour les textures des objets. Si nous n'activons pas le coloriage matériel, les textures garderont toujours leurs couleurs d'origine. glColor3f(r,g,b) n'aura pas d'effet sur la coloration. C'est donc important de l'activer.

Les glEnable
Sélectionnez
    glEnable(GL_LIGHT0);            // Éclairage vite fait, mal fait (cela suppose que Light0 est actif)
    glEnable(GL_LIGHTING);          // Activation de l'affichage
    glEnable(GL_COLOR_MATERIAL);    // Activation du coloriage matériel

Finalement nous activons la correction de perspective pour avoir un rendu sympathique, et nous retournons la valeur TRUE pour faire savoir au programme que l'initialisation s'est bien passée.

La perspective
Sélectionnez

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Activation de la correction de perspective
    return TRUE;    // L'initialisation a réussi
}

II-I. L'affichage

À présent, c'est le code de tracé qui est abordé. Comme d'habitude, je vais utiliser quelques mathématiques ardues. Pas de sinus et cosinus, mais cela reste un peu étrange. Nous débutons, comme d'habitude, en effaçant l'écran et en vidant le buffer de profondeur.

Ensuite, nous lions une texture au cube. Je pourrais ajouter cette ligne dans la création de la liste d'affichage, mais la laisser à l'extérieur me permet de la modifier à n'importe quel moment. Si j'avais ajouté la ligne glBindTexture(GL_TEXTURE_2D,texture[0]) à l'intérieur de la liste d'affichage, l'affichage aurait été non modifiable, et aurait utilisé la couleur que j'avais choisie lors de la création de l'objet.

 
Sélectionnez
int DrawGLScene(GLvoid) // C'est ici que tout le dessin est fait
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Efface l'écran et le buffer de profondeur
    glBindTexture(GL_TEXTURE_2D, texture[0]);           // Sélectionne la texture

Voici maintenant les choses intéressantes. Une boucle aura pour variable itérative yloop. Cette boucle est utilisée pour positionner les cubes sur l'axe des Y (haut et bas). Nous souhaitons avoir cinq lignes de cubes, de haut en bas, donc nous allons faire une boucle pour laquelle yloop va de un jusqu'à cinq.

Boucle externe
Sélectionnez
    for (yloop=1;yloop<6;yloop++) // Boucle au travers du plan y
    {

Nous avons une autre boucle appelée xloop. Elle est utilisée dans le positionnement des cubes sur l'axe des X (de gauche à droite). Le nombre de cubes dessinés de gauche à droite dépend de la ligne où nous nous trouvons. Si nous sommes en haut d'une ligne, xloop va aller seulement de 0 à 1 (pour dessiner un seul cube). La ligne d'après ira de 0 à 2 (pour dessiner deux cubes), etc.

Boucle interne
Sélectionnez
        for (xloop=0;xloop<yloop;xloop++) // Boucle de parcours dans le plan X
        {

Nous réinitialisons la vue avec glLoadIdentity().

Réinitialisation
Sélectionnez
            glLoadIdentity(); // Réinitialise la vue

La ligne suivante effectue une translation à un emplacement spécifique de l'écran. Cela peut sembler étrange, mais ça ne l'est pas vraiment. Sur l'axe des X, il se passe la chose suivante.

Nous nous déplaçons vers la droite de 1,4 unité, afin de placer la pyramide au centre de l'écran. Nous multiplions alors l'indice de boucle xloop par 2.8 et nous lui ajoutons 1.4. (Nous le multiplions par 2.8 afin que les cubes ne soient pas aux sommets les uns des autres. (2,8 est approximativement la largeur d'un cube lorsqu'il a subi une rotation de 45 degrés.) Finalement nous soustrayons yloop*1.4. Cela déplace les cubes à gauche, en fonction de la ligne que nous traitons. Si nous ne le bougions pas vers la gauche, la pyramide s'appuierait sur le côté gauche (ce ne serait pas vraiment la pyramide que nous souhaitons avoir).

Suivant l'axe des Y nous soustrayons yloop à 6.0f, autrement la pyramide serait construite à l'envers. Le résultat est ensuite multiplié par 2.4. Autrement les cubes se chevaucheraient les uns les autres sur l'axe des Y (2.4 est approximativement la hauteur de chaque cube). Puis nous soustrayons 7. Ainsi, la pyramide débute au pied de l'écran et monte au fur et à mesure.

Finalement, suivant l'axe Z, nous déplaçons la scène de vingt unités. De cette manière, la pyramide remplit exactement l'écran.

Translation
Sélectionnez
            // Positionnement des cubes à l'écran
            glTranslatef(1.4f+(float(xloop)*2.8f)-(float(yloop)*1.4f),((6.0f-float(yloop))*2.4f)-7.0f,-20.0f);

À présent nous réalisons la rotation suivant l'axe des X. Nous inclinons le cube vers le bas de 45 degrés moins 2*yloop. Le mode perspective incline le cube automatiquement, donc je fais une soustraction pour compenser l'inclinaison. Ce n'est pas le meilleur moyen, mais ça marche.

Finalement, nous ajoutons xrot. Cela nous donne un contrôle du clavier sur l'angle (c'est drôle de s'amuser avec ça).

Après avoir effectué la rotation suivant l'axe des X, nous effectuons une rotation de 45 degrés sur l'axe des Y, et nous ajoutons la valeur de yrot pour avoir un contrôle clavier sur l'axe des Y.

Rotations
Sélectionnez
            glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f); // Incline le cube de haut en bas
            glRotatef(45.0f+yrot,0.0f,1.0f,0.0f);              // Tourne le cube de gauche à droite

Maintenant nous sélectionnons une couleur (brillante) avant de dessiner la partie 'boîte ' du cube. Remarquez que nous utilisons la procédure glColor3fv(). L'effet produit est le chargement de la couleur à partir des valeurs (rouge, vert et bleu) contenues dans les accolades. 3fv représente trois valeurs flottantes, v est un pointeur sur un tableau. Nous sélectionnons la couleur avec un indice de tableau qui vaut yloop-1, ce qui attribue une couleur différente à chaque ligne de cube. Si nous avions utilisé xloop-1 nous aurions une couleur différente pour chaque colonne.

Couleur
Sélectionnez
            glColor3fv(boxcol[yloop-1]); // Sélectionne la couleur d'une boîte

Maintenant que la couleur est initialisée, il nous reste à dessiner notre boîte. Au lieu d'écrire le code de dessin d'une boîte, nous appelons simplement notre liste d'affichage. Nous faisons cela avec la commande glCallList(box). box signifie que nous choisissons d'appeler la liste d'affichage box, qui est le cube sans son sommet.

La boîte sera dessinée en utilisant la couleur que nous avons sélectionnée avec glcolor3fv(), à la position à laquelle nous nous sommes déplacés.

Le rendu
Sélectionnez
            glCallList(box); // Dessine la boîte

Maintenant nous sélectionnons une couleur pour le sommet de la boîte (plus sombre) avant de le dessiner. Si vous vouliez réaliser Q-Bert (le jeu) il faudrait changer cette couleur après passage du personnage. (Le but du jeu est de passer sur toutes les boîtes).

La couleur
Sélectionnez

            glColor3fv(topcol[yloop-1]); // Sélectionne la couleur du sommet

Finalement, la seule chose qui nous reste à faire est le dessin de la liste d'affichage. Ceci va ajouter une couleur sombre. C'est très facile.

Le haut
Sélectionnez
            glCallList(top); // Dessine le haut
        }
    }
    return TRUE; // Retour
}

II-J. WinMain

Les modifications restantes ont toutes été effectuées dans WinMain(). Le code a été ajouté juste après la ligne SwapBuffer(hDC). Il vérifie si les touches gauche, droite, haut ou bas ont été pressées et fait tourner les cubes en conséquence.

Gestion du clavier
Sélectionnez
SwapBuffers(hDC); // Échange les tampons (Double Buffering)

if (keys[VK_LEFT]) // Est-ce que la touche 'flèche gauche' est pressée ?
{
    yrot-=0.2f; // Incline le cube vers la gauche
}
if (keys[VK_RIGHT]) // Est-ce que la touche 'flèche droite' est pressée ?
{
    yrot+=0.2f; // Incline le cube vers la droite
}
if (keys[VK_UP]) // Est-ce que la touche 'flèche haut' est pressée ?
{
    xrot-=0.2f; // Incline le cube vers le haut
}
if (keys[VK_DOWN]) // Est-ce que la touche 'flèche bas' est pressée ?
{
    xrot+=0.2f; // Incline le cube vers le bas
}

Comme pour tous les précédents tutoriels, on s'assure que le titre de la fenêtre est correct.

Gestion de F1
Sélectionnez
        if (keys[VK_F1])                    // Est-ce que la touche 'F1' est pressée ?
        {
            keys[VK_F1]=FALSE;                // Si oui, on remet à FALSE
            KillGLWindow();                    // On détruit notre fenêtre courante
            fullscreen=!fullscreen;            // On inverse le mode Plein écran/Mode fenêtre
                                                    // On recrée notre fenêtre OpenGL
            if (!CreateGLWindow("Tutoriel de NeHe sur les listes d'affichage",640,480,16,fullscreen))
            {
                return 0;                    // On quitte si la fenêtre ne s'est pas créée
            }
        }
    }
}
-->

À la fin de ce tutoriel, vous devriez avoir acquis le fonctionnement des listes d'affichage, comment les créer et les utiliser. Les listes d'affichage sont vraiment utiles. Pas seulement pour simplifier le codage d'objets complexes, elles vous permettent également de gagner en vitesse d'exécution nécessaire pour conserver un nombre de FPS élevé.

J'espère que vous avez apprécié ce tutoriel. Si vous avez des questions ou si quelque chose n'est pas clair, contactez-moi par mail.

Jeff Molofee ( NeHe )

III. Téléchargements

Compte tenu du nombre de versions de codes sources pour les tutoriels NeHe, nous les laissons en anglais. En principe, si vous avez compris le code présenté dans ce tutoriel (et les tutoriels antérieurs), vous n'aurez pas de mal à les comprendre :

IV. Remerciements

Merci à MrDuChnok, kromartien, LittleWhite, mabu, Winjerome, fearyourself et ClaudeLELOUP pour leur relecture.

V. Liens