Nehe Tutorials Leçon 12

Jeff Molofee ( NeHe )

Dans ce tutoriel, je présente l'utilisation des listes d'affichage. Les listes d'affichage n'améliorent pas uniquement la vitesse de rendu du programme, elles réduisent également le nombre de lignes nécessaires. ♪

- Titre : Nehe Tutorials Leçon 12

- Auteur : Jeff Molofee ( NeHe )

- Parution : 21 octobre 2010

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2010 Nehe Gamedev.net. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Contributions

- II. Tutoriel

- II-A. Introduction

- II-B. Inclusion

- II-C. Les variables

- II-D. Deux tableaux

- II-E. La fonction BuildLists

- II-F. Le dessin du cube

- II-G. La deuxième liste

- II-H. Charger les textures

- II-I. L'affichage

- II-J. WinMain

- III. Téléchargements

- IV. Remerciements

- V. Liens

I - Contributions

Remarque : la traduction des autres tutoriels est en cours, mais votre aide serait appréciée ! Si vous voulez aider, n'hésitez pas à envoyer un message privé ou un mail vers nehe arrobase redaction-developpez point com.

II - Tutoriel

II-A - Introduction

Soit l'exemple suivant : nous sommes en train de programmer un jeu qui 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 (8 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 complique beaucoup le programme. 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 pour former une liste d'affichage. Vous donnez alors 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'. En voulant 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 reconstruire à nouveau 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êts à 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 boite 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 boite sans couvercle et vide. (simulée 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é, 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

#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 bibliotheque OpenGL32
#include    <gl\glu.h>                      // En-tête pour la bibliotheque GLu32
#include    <gl\glaux.h>                    // En-tête pour la bibliotheque GLaux
HDC         hDC=NULL;                       // Contexte privé du systeme 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'affichages. Ces variables sont utilisées comme pointeurs sur la mémoire de stockage des listes d'affichages. 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

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

Enfin, 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, verte et bleue. 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 boites. Nous voulons que le couvercle soit plus sombre que le reste de la boite.

Déclaration des couleurs des cubes

static GLfloat boxcol[5][3]= // Tableau pour la couleur des boites
{
// 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 superieures
{
// 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); // Declaration de WndProc

II-E - La fonction BuildLists

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

GLvoid BuildLists() // Construction des listes d'affichage pour les boites
{

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. N'importe où nous allons appeler box, la première liste d'affichage va se dessiner.

Création des listes

box=glGenLists(2); // Construction des deux listes

Ici nous construisons 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. 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

glNewList(box,GL_COMPILE);
// Nouvelle liste d'affichage box

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

Vous pouvez mettre les instructions que vous voulez entre glNewList() et glEndList(). Vous pouvez fixer la couleur, changer les textures, etc. La seule chose que vous ne pouvez pas faire, c'est d'é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, avoir 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

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 de devant
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() est signe pour OpenGL que la création de la liste d'affichage est terminée. Tout ce que se trouve entre glNewList() et glEndList() sera contenu dans la liste d'affichage, tout ce que se trouve avant glNewList() ou après glEndList() ne sera pas pris en compte dans la liste d'affichage courante.

Appel de glEndList

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 1. Le code suivant permet d'utiliser la variable top comme conteneur pour la seconde liste d'affichage.

Mise à jour de top

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 comme 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

glNewList(top,GL_COMPILE); // Nouvelle liste d'affichage compilee top

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

Dessin du haut du cube

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 maintenant créé deux listes d'affichage.

Fin de la liste

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 de 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

if (TextureImage[0]=LoadBMP("Data/Cube.bmp")) // Charge la texture

Le code de redimensionnement est exactement semblable au code de la leçon 6.

Le code d'initialisation a seulement quelques changements. J'ai ajouté la ligne BuildList(). Cela permet de s'affranchir de 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, puis nous créons notre liste d'affichage, ensuite nous pouvons recouvrir notre cube d'une texture déjà créée.

La fonction InitGL

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);         // Regle la profondeur des buffers
glEnable(GL_DEPTH_TEST);    // Active le test de profondeur
glDepthFunc(GL_LEQUAL);     // Selectionne 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éos, 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 originales. glColor3f(r,g,b) n'aura pas d'effet sur la coloration. C'est donc important de l'activer.

Les glEnable

glEnable(GL_LIGHT0);            // Eclairage 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

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

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 c'est encore 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 pourrai 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.

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]);           // Selectionne la texture

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

Boucle externe

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

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

Nous réinitialisons la vue avec glLoadIdentity()

Réinitialisation

glLoadIdentity(); // Réinitialise la vue

La ligne suivante correspond à 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 déplaçons vers la droite de 1,4 unité, ainsi la pyramide se place au centre de l'écran. Alors nous multiplions 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 tourné 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 à chaque ligne. Alors le résultat est 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). Alors 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

// Positionement 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 fait une 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

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 'boite' 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 contient 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

glColor3fv(boxcol[yloop-1]); // Sélectionne la couleur d'une boite

Maintenant que la couleur est initialisée, nous devons dessiner notre boite. Au lieu d'écrire le code de dessin d'une boite, 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 boite 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

glCallList(box); // Dessine la boite

Maintenant nous sélectionnons une couleur pour le sommet de la boite (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 de jeu est de passer sur toutes les boites).

La couleur

glColor3fv(topcol[yloop-1]); // Selectionne 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

glCallList(top); // Dessine le haut
}
}
return TRUE; // Retour
}

II-J - WinMain

Les autres modifications sont dans WinMain(). Le code a été rajouté 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

SwapBuffers(hDC); // Echange 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

if (keys[VK_F1])                    // Est-ce que la touche 'F1' est pressée ?
{
keys[VK_F1]=FALSE;                // Si oui, on la remet a FALSE
KillGLWindow();                    // On detruit notre fenetre courante
fullscreen=!fullscreen;            // On inverse le mode Plein ecran / Mode fenetre
// On Recree notre fenetre OpenGL
if (!CreateGLWindow("Tutoriel de NeHe sur les listes d'affichages",640,480,16,fullscreen))
{
return 0;                    // On quitte si la fenetre ne s'est pas creee
}
}
}
}
-->

À la fin de ce tutoriel, vous devriez avoir acquis le fonctionnement des listes d'affichages, comment les créer et les utiliser. Les listes d'affichages sont vraiment utiles. Pas seulement pour simplifier le codage d'objets complexes, elles vous permettent également de gagner de la 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 à le comprendre :

- Borland C++ Builder 6 (Conversion par Christian Kindahl)

- C# (Conversion par Brian Holley)

- Code Warrior 5.3 (Conversion par Scott Lupton)

- CygWin (Conversion par Stephan Ferraro)

- Delphi (Conversion par Michal Tucek)

- Dev C++ (Conversion par Dan)

- Euphoria (Conversion par Evan Marshall)

- Game GLUT (Conversion par Milikas Anastasios)

- Irix (Conversion par Rob Fletcher)

- Java (Conversion par Jeff Kirby)

- Jedi-SDL (Conversion par Dominique Louis)

- JOGL (Conversion par Nicholas Campbell)

- LCC Win32 (Conversion par Robert Wishlaw)

- Linux (Conversion par Richard Campbell)

- Linux GLX (Conversion par Mihael Vrbanec)

- Linux SDL (Conversion par Ti Leggett)

- LWJGL (Conversion par Mark Bernard)

- Mac OS (Conversion par Anthony Parker)

- Mac OS X/Cocoa (Conversion par Bryan Blackburn)

- MASM (Conversion par Nico (Scalp))

- VC++/OpenIL (Conversion par Denton Woods)

- Pelles C (Conversion par Pelle Orinius)

- Visual Basic (Conversion par Ross Dawson)

- Visual Studio

- Visual Studio NET (Conversion par Grant James)

IV - Remerciements

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

V - Liens

Sommaire

Tutoriel précédent : L'effet drapeau