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

Bienvenue dans le tutoriel 9. A partir de maintenant vous devez être en mesure de mieux comprendre OpenGL. Vous avez appris tout ce qu'il faut pour créer et initialiser une fenêtre OpenGL, appliquer une texture sur un objet qui tourne en utilisant des effets d'éclairages et de transparences. Ceci sera le premier tutoriel du niveau supérieur. Vous allez apprendre : à bouger une image dans un univers 3D, enlever les pixels noirs autour de l'image (en utilisant le mélange), ajouter des couleurs à une texture noire et blanche, et finalement vous apprendrez comment créer des couleurs sympathiques et des animations en utilisant plusieurs textures colorées ensembles.

II-A. Inclusions et déclarations

Nous allons modifier le code de la première leçon dans ce tutoriel. Nous allons commencer par ajouter quelques nouvelles variables au début du programme. Je vais réécrire la section entière ainsi cela sera plus facile de voir où il y a eu des changements.

En-têtes et déclarations
Sélectionnez
#include    <windows.h>                       // En-tête pour Windows
#include    <stdio.h>                         // En-tête pour les entrees/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 prive 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 utilise pour les routines du clavier
bool        active=TRUE;                      // Drapeau d'activation de la fenetre
bool        fullscreen=TRUE;                  // Drapeau pour le mode plein écran (Vrai par defaut)

Les lignes suivantes sont nouvelles. twinkle et tp sont deux variables booléennes, ce qui signifie qu'elles peuvent soient contenir TRUE ou FALSE. twinkle permet de mémoriser si l'effet de scintillement doit être actif ou non. tp est utilisé pour savoir si la touche 'T' est dans un état pressé ou relâché (touche T pressée : tp = TRUE ; touche T relâchée : tp = FALSE).

Drapeaux d'états
Sélectionnez
BOOL    twinkle;                         // Etoiles brillantes ?
BOOL    tp;                              // Touche 'T' appuyee ?

num va permettre de mémoriser combien d'étoiles seront dessinées sur l'écran. Cette valeur sera stockée dans une constante. Ce qui signifie qu'elle ne pourra pas être changée dans le code. Nous la mettons dans une constante, car vous ne pouvez pas redéfinir la taille d'un tableau. Donc, si nous avons déclaré un tableau avec seulement 50 étoiles, et que nous décidons d'augmenter num à 51 dans le code, le tableau ne peut pas s'agrandir à 51 étoiles, et donc une erreur apparaîtra. Vous pouvez changer cette valeur pour celle que vous voulez uniquement dans la ligne suivante. N'essayez pas de changer la valeur de num plus loin dans le code, car vous risqueriez d'obtenir une erreur.

Constante représentant le nombre d'étoiles à utiliser
Sélectionnez
const    num=50;                             // Nombre d'étoiles à dessiner

Maintenant nous allons créer une structure. Le mot structure est quelque peu intimidant, mais en vérité il n'y a rien de bien compliqué. Une structure est un groupe de données simples (variables, etc) qui, une fois regroupées, permet de définir un ensemble plus complexe. Nous savons que nous devons garder une trace de nos étoiles. Vous allez voir que la 7ème ligne ci-dessous est stars. Nous savons que chaque étoile aura trois valeurs pour définir la couleur, et ces valeurs seront des entiers. La 3ème ligne (int r, g, b) définit trois entiers. Un pour le rouge (r), un pour le vert (g), et un pour le bleu (b). Nous savons que les étoiles seront à différentes distances du centre de l'écran, et qu'elles pourront être placées sur l'un des 360 angles différents à partir du centre. Si vous regardez à la 4ème ligne ci-dessous, vous remarquerez une valeur réelle nommée dist. Elle permettra de mémoriser la distance entre l'étoile et le centre de l'écran. La 5ème ligne crée un réel nommé angle. Cela permet de stocker les angles des étoiles.

Ainsi, maintenant nous avons ce groupement de données qui permet de décrire la couleur, la distance, et l'angle d'une étoile sur l'écran. Par contre nous devons mémoriser les informations de plus d'une étoile. Au lieu de créer 50 valeurs pour le rouge, 50 pour le vert, 50 pour le bleu, 50 pour la distance, et 50 pour l'angle, nous allons juste créer un tableau nommé star. A chaque case dans le tableau star, nous y stockerons une occurrence de la structure stars. Nous créons ce tableau à la 8ème ligne ci-dessous. Voici le détail de la 8ème ligne : stars star[num]. Le type du tableau est stars. stars est une structure. Ainsi le tableau contiendra toutes les informations des structures. Le nom du tableau est star. Le nombre de cases du tableau est [num]. Hors comme num = 50, nous avons maintenant un tableau nommé star. Notre tableau stocke les éléments de la structure stars. C'est beaucoup plus facile ainsi de mémoriser les informations sur les étoiles qu'avec des variables séparées. Ce qui aurait été une chose stupide à faire, et cela ne nous aurait pas permis d'ajouter ou retirer facilement des étoiles en modifiant la valeur constante de num.

Tableau de structures définissant les étoiles
Sélectionnez
typedef struct                      // On cree une structure pour definir une étoile
{
    int r, g, b;                    // Le couleur de l'etoile
    GLfloat dist;                   // La distance de l'etoile par rapport au centre
    GLfloat angle;                  // L'angle courant de l'étoile
}stars;                             // Le nom de la structure est stars

stars star[num];                    // Cree un tableau 'star' de 'num' case contenant des structures 'stars'

Ensuite, nous allons déclarer des variables pour mémoriser à quelle distance sont les étoiles de l'observateur (zoom), et quel est l'angle à partir duquel on voit les étoiles (tilt). Nous créons également une variable nommée spin qui permettra de faire tourner le scintillement de l'étoile sur l'axe des z, comme si elles tournaient sur elle-même.

loop est une variable qu'on utilisera dans le programme pour dessiner les 50 étoiles, et texture[1] permettra de stocker une texture en noir et blanc que nous aurons chargé. Si vous voulez plus de textures, vous devez modifier la valeur de un à autant de texture que vous souhaitez utiliser.

Déclaration des variables globales
Sélectionnez
GLfloat   zoom=-15.0f;                                    // Distance entre l'observateur et les etoiles
GLfloat   tilt=90.0f;                                     // Inclinaison de l'observateur
GLfloat   spin;                                           // Rotation du scintillement des etoiles
GLuint    loop;                                           // Variable globales pour le parcours des etoiles
GLuint    texture[1];                                     // Tableau pour stocker une texture
LRESULT   CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);   // Declaration de WndProc

Après le code ci-dessus, nous allons maintenant ajouter la fonction permettant de charger notre texture. Je n'ai pas besoin d'expliquer en détail le code. C'est le même code que nous avons utilisé dans les leçons 6, 7 et 8. L'image que nous allons charger ce coup-ci se nomme star.bmp. Nous allons générer uniquement une texture par l'intermédiaire de glGenTextures(1, &texture[0]). La texture utilisera le filtrage linéaire.

II-B. La fonction LoadBMP

Fonction pour charger l'image
Sélectionnez
AUX_RGBImageRec *LoadBMP(char *Filename)    // Permet de charger une fichier image Bitmap
{
    FILE *File=NULL;                        // Descripteur de fichier
    if (!Filename)                          // On s'assure qu'un nom de fichier a ete passe en parametre
    {
        return NULL;                        // Sinon on retourne NULL
    }
    File=fopen(Filename,"r");               // On verifie que le fichier existe
    if (File)                               // Est-ce qu'il existe ?
    {
        fclose(File);                       // On ferme le descripteur
        return auxDIBImageLoad(Filename);   // Charge l'image, et retourne un pointeur
    }
    return NULL;                            // Si le fichier n'existe pas, on retourne NULL
}

II-C. La fonction LoadGLTextures

C'est la portion de code qui permet de charger l'image (en appelant le code précédent) et qui la convertit en une texture. Status est utilisée pour indiquer si la texture a bien été chargée et créée.

Charge une image, et la convertie en texture
Sélectionnez
int LoadGLTextures()                                 // Charge une image et la convertie en texture
{
    int Status=FALSE;                                // Indique le bon deroulement de l'operation
    AUX_RGBImageRec *TextureImage[1];                // Cree un emplacement memoire pour la texture
    memset(TextureImage,0,sizeof(void *)*1);         // Reinitialise le pointeur à NULL
    // Charge l'image, verifie les erreurs, on quitte si l'image n'est pas trouvee
    if (TextureImage[0]=LoadBMP("Data/Star.bmp"))
    {
        Status=TRUE;                                 // Initialise Status à TRUE
        glGenTextures(1, &texture[0]);               // Genere une texture
        // Cree une texture filtree lineairement
        glBindTexture(GL_TEXTURE_2D, texture[0]);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, 
            TextureImage[0]->sizeY,0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
    }
    if (TextureImage[0])                            // Si la texture existe
    {
        if (TextureImage[0]->data)                  // Si l'image de la texture existe
        {
            free(TextureImage[0]->data);            // On libere la memoire de l'image de la texture
        }
        free(TextureImage[0]);                      // On libere la structure de la texture
    }
    return Status;                                  // On retourne le statut
}

II-D. La fonction InitGL

Maintenant nous allons initialiser OpenGL pour qu'il fasse ce qu'on veut. Nous n'utiliserons pas de test de profondeur dans ce projet, donc assurez vous, si vous utilisez le code de la leçon un, d'enlever glDepthFunc(GL_LEQUAL); et glEnable(GL_DEPTH_TEST); sinon vous n'obtiendrez pas de résultats concluant. Nous allons utiliser le plaquage de texture dans ce code, donc assurez vous de ne pas laisser de lignes de code présentes dans la leçon 1.Vous remarquerez également que l'on active le plaquage de texture, ainsi que le mélange.

Initialisation d'OpenGL
Sélectionnez
int InitGL(GLvoid)                                   // Tous les reglages d'OpenGL se font ici
{
    if (!LoadGLTextures())                           // On appelles notre fonction pour charger les textures
    {
        return FALSE;                                // Si les textures ne se sont pas chargees, on retourne FALSE
    }
    glEnable(GL_TEXTURE_2D);                         // Activation de l'application de textures
    glShadeModel(GL_SMOOTH);                         // Active les ombres douces
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);            // Fond d'ecran noir
    glClearDepth(1.0f);                              // Configuration du tampon de profondeur
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);     // Pour avoir des jolis calculs de perspective
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);                // Positionne la fonction de melange sur la transparence
    glEnable(GL_BLEND);                              // Activation du melange

Le code suivant est nouveau. Il permet d'initialiser l'angle, la distance et la couleur de chaque étoile au démarrage. Remarquez comment il est facile de changer les informations dans une structure. La boucle parcourt les 50 étoiles. Pour changer l'angle de star[1], vous avez juste à écrire star[1].angle = {un nombre}. C'est simple !

Début de la boucle sur les étoiles
Sélectionnez
    for (loop=0; loop<num; loop++)     // Cree une boucle sur les etoiles
    {
        star[loop].angle=0.0f;         // Initialise l'angle des etoiles à zero

Je calcule la distance en prenant l'index de l'étoile courante (donc la valeur de loop) et en le divisant par le maximum d'étoiles présentes. Ensuite, je le multiplie le résultat par 5.0f. Pour résumer, cela permet de bouger chaque étoile un petit peu plus loin que la précédente. Quand loop sera égale à 50 (la dernière étoile), loop divisé par num sera égale à 1.0f. La raison pour laquelle je multiplie par 5.0f est parce que 1.0f * 5.0f est égale à 5.0f. 5.0f est l'extrémité de l'écran. Je n'ai pas envie que des étoiles soient en dehors de l'écran, donc 5.0f est parfait. Si vous fixez le zoom plus loin dans l'écran, vous feriez mieux d'utiliser une valeur plus grande que 5.0f, mais vos étoiles seront un peu plus petite (à cause de la perspective).

Vous remarquerez que les couleurs de chacune des étoiles est attribuées suivant des valeurs aléatoires comprises entre 0 et 255. Vous devez être surpris que l'on puisse utiliser des valeurs aussi grandes, alors que habituellement elles sont comprises entre 0.0f et 1.0f. Quand nous fixons la couleur, nous utilisons glColor4ub au lieu de glColor4f. ub signifie Unsigned Byte. Un octet peut contenir n'importe quelle valeur comprise entre 0 et 255. Dans ce programme, c'est plus facile d'utiliser des octets que des nombres réels pour obtenir des valeurs aléatoires.

Initialisation de la position et de la couleur
Sélectionnez
        star[loop].dist=(float(loop)/num)*5.0f;          // Calcul la distance depuis le centre
        star[loop].r=rand()%256;                         // Donne a star[loop] une valeur aleatoire pour le rouge
        star[loop].g=rand()%256;                         // Donne a star[loop] une valeur aleatoire pour le vert
        star[loop].b=rand()%256;                         // Donne a star[loop] une valeur aleatoire pour le bleu
    }
    return TRUE;                                         // L'initialisation s'est correctement deroulee
}

II-E. La fonction DrawGLScene

Le code pour redimensionner la fenêtre est le même, donc nous allons passer directement à la partie où on dessine. Si vous utilisez le code de la leçon une, supprimer la fonction DrawGLScene, et copiez juste ce qu'il y a en dessous. Il y a uniquement deux lignes de code dans la leçon un de toute façon, donc vous n'avez pas beaucoup de choses à supprimer.

Fonction de dessin
Sélectionnez
int DrawGLScene(GLvoid)                                    // C'est ici que l'on fera tous les dessins
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Efface l'écran et le tampon de profondeur
    glBindTexture(GL_TEXTURE_2D, texture[0]);              // Selectionne notre texture
    for (loop=0; loop<num; loop++)                         // Boucle sur nos etoiles
    {
        glLoadIdentity();                                  // Reinitialise la vue avant de dessiner chacune des etoiles
        glTranslatef(0.0f,0.0f,zoom);                      // Zoom dans l'écran (En utilisant la valeur de 'zoom')
        glRotatef(tilt,1.0f,0.0f,0.0f);                    // Tourne la vue (En utilisant la valeur de 'tilt')

Maintenant nous allons bouger les étoiles. Les étoiles partent du milieu de l'écran. La première chose à faire est de tourner la scène sur l'axe des x. Si on tourne de 90 degrés, l'axe des x n'ira plus de gauche à droite, mais d'avant vers l'arrière de l'écran. Voici un exemple pour clarifier un peu le problème. Imaginez que vous êtes au milieu d'une pièce. Maintenant imaginez qu'il y a écrit -x sur le mur à gauche de vous, -z sur le mur devant vous, +x sur le mur à droite de vous, +z sur le mur derrière vous. Si la pièce tourne de 90 degrés vers la droite, mais que vous ne bougez pas, sur le mur en face de vous il n'y aura plus écrit -z mais -x. Tous les murs auront bougés. -z sera à droite, +z sera à gauche, -x sera devant et +x derrière vous. Vous comprenez ? En applicant une rotation sur votre scène, vous changez les directions des plans x et z.

La seconde ligne de code permet de bouger vers d'une valeur positive sur le plan des x. Normalement une valeur positive sur x devrait nous faire bouger vers la partie droite de l'écran (où est +x habituellement), mais comme nous avons fait une rotation sur le plan des y, le '+x' peut se trouver n'importe où. Si nous appliquons une rotation de 180 degrés, il sera sur le coté gauche de l'écran au lieu de la partie droite. Donc lorsque vous allez bouger d'une valeur positive sur le plan des x, vous pouvez donc bouger vers la gauche, la droite, l'avant ou l'arrière.

Rotation et déplacement
Sélectionnez
    glRotatef(star[loop].angle,0.0f,1.0f,0.0f);         // Tourne l'étoile selon son angle
    glTranslatef(star[loop].dist,0.0f,0.0f);            // Bouge d'une valeur positive sur le plan des X

Maintenant nous allons passer à une partie un peu plus délicate. L'étoile est en fait une texture plate. Maintenant si vous dessinez un rectangle plat au centre de l'écran et que vous le texturez, il sera joli. Il vous fera face. Mais si vous appliquez une rotation sur l'axe des y de 90 degrés, la texture sera face aux côtés droits et gauches de l'écran. La seule chose que vous verrez sera une ligne fine. Nous ne voulons pas que cela arrive. Nous voulons que les étoiles soient face à l'écran en permanence, peu importe si cela nous oblige à faire plus de rotation ou d'inclinaison de l'écran.

On fait ceci en annulant la rotation que nous avons fait précédemment, juste avant de dessiner l'étoile. Vous annulez la rotation dans le sens inverse. Dans la partie précédente, nous avons incliné l'écran, et ensuite nous avons appliqué une rotation aux étoiles en fonction d'un angle. Dans l'ordre inverse, nous devons faire une rotation inverse aux étoiles de l'angle adéquat. Pour ce faire, nous allons utiliser la valeur négative de l'angle, et appliquer la rotation avec ce nouvel angle. Ainsi, si nous avions tourné l'étoile de 10 degrés, en appliquant une rotation de -10 degrés, l'étoile sera de nouveau en face de l'écran. Donc la première ligne ci-dessous annule la rotation sur l'axe des y. Ensuite nous avons besoin d'annuler l'inclinaison de l'écran sur l'axe des x. Pour faire ceci, nous inclinons juste l'écran d'une valeur de -tilt. Après avoir annuler les rotations en x et en y, l'étoile fera face de nouveau complètement à l'écran.

Annulation des rotations précédentes
Sélectionnez
    glRotatef(-star[loop].angle,0.0f,1.0f,0.0f);     // Annule la rotation de l'angle
    glRotatef(-tilt,1.0f,0.0f,0.0f);                 // Annule l'inclinaison de l'ecran

Si twinkle est égale à TRUE, nous dessinerons une étoile qui ne tourne pas à l'écran. Pour obtenir une couleur différente, nous prenons le nombre maximum d'étoiles (num) et le soustrayons à l'index courant pour les étoiles (loop), ensuite on soustrait 1 car notre boucle (loop) ne va que entre 0 et num-1. Si le résultat est égal à 10, nous utiliserons la couleur de l'étoile numéro 10. De cette manière, les couleurs de deux étoiles seront différentes. Ce n'est pas la meilleure manière de faire, mais elle est efficace. La dernière valeur est la valeur alpha. Plus la valeur sera petite, plus l'étoile sera sombre.

Si twinkle est égale à TRUE, chaque étoile sera dessinée en double. Cela ralentira le programme légèrement, selon l'ordinateur que vous avez. Si twinkle est activé, les couleurs des deux étoiles se mélangeront en créant des couleurs vraiment sympathiques. De plus comme cette étoile ne tournera pas, elle apparaîtra comme si elle était animée lorsque twinkle sera activé (regardez par vous-même si vous ne comprenez pas ce que je dis).

Remarquez également comment il est facile d'ajouter des couleurs à la texture. Même si la texture est blanche et noire, elle prendra sa véritable apparence en fonction de la couleur que l'on sélectionne avant de dessiner la texture. De plus, prenez note que nous utilisons des octets pour les valeurs de la couleur plutôt que des nombres réels. Même la valeur de la composante alpha est un octet.

Dessin du scintillement
Sélectionnez
        if (twinkle)                           // Si le scintillement est active
        {
            // Applique une couleur en utilisant des octets
            glColor4ub(star[(num-loop)-1].r,star[(num-loop)-1].g,star[(num-loop)-1].b,255);
            glBegin(GL_QUADS);                 // Commence a dessiner notre carre texture
                glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
                glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
                glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
                glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
            glEnd();                           // Fin du dessin de notre carre texture
        }

Maintenant nous allons dessiner l'étoile principale. La seule différence avec le code précédent est que l'étoile est toujours dessinée et cette étoile tourne autour de l'axe des z.

Dessin de l'étoile principale
Sélectionnez
        glRotatef(spin,0.0f,0.0f,1.0f);          // Applique une rotation a l'etoile sur l'axe des Z
                                                 // Applique une couleur en utilisant des octets
        glColor4ub(star[loop].r,star[loop].g,star[loop].b,255);
        glBegin(GL_QUADS);                       // Commence a dessiner notre carre texture
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
        glEnd();                                // Fin du dessin de notre carre texture

Ici est la partie où nous effectuons tous les mouvements. Nous tournons l'étoile normale en incrémentant la valeur de spin. Ensuite on change l'angle de chacun des angles. L'angle de chaque étoile est incrémenté de loop/num. Ce qui fait que les étoiles tournent plus vite si elles sont éloignées du centre. Les étoiles les plus proches du centre tourneront moins vite. Et enfin, on décrémente la distance entre chaque étoile et le centre de l'écran. Nous aurons l'impression que les étoiles se font aspirer vers le centre de l'écran.

Mouvement des étoiles
Sélectionnez
        spin+=0.01f;                                // Change la valeur d'inclinaison des etoiles
        star[loop].angle+=float(loop)/num;          // Change l'angle de l'etoile
        star[loop].dist-=0.01f;                     // Change la distance entre l'etoile et le centre

Les lignes suivantes vérifient si les étoiles sont arrivées au centre de l'écran ou non. Quand une étoile touche le centre de l'écran, on lui attribue une nouvelle couleur, et on la bouge de 5 unités du centre, ainsi elle peut reprendre son parcours vers le centre comme si c'était une nouvelle étoile.

Traitement des étoiles arrivées au centre de l'écran
Sélectionnez
        if (star[loop].dist<0.0f)            // Est-ce que l'etoile est arrivee au centre ? 
        {
            star[loop].dist+=5.0f;           // Bouge l'etoile de 5 unités loin du centre
            star[loop].r=rand()%256;         // Attribution d'une nouvelle composante rouge
            star[loop].g=rand()%256;         // Attribution d'une nouvelle composante verte
            star[loop].b=rand()%256;         // Attribution d'une nouvelle composante bleue
        }
    }
    return TRUE;                             // Tout s'est bien deroule
}

Maintenant nous allons ajouter le code qui vient vérifier si une touche a été pressée. Allez plus bas au niveau de la fonction WinMain(). Regardez la ligne SwapBuffers(hDC). Nous allons ajouter le code qui vérifier les touches juste en dessous de cette ligne.

II-F. La gestion clavier

Les lignes suivantes vérifient si la touche 'T' a été pressée. Si elle a été appuyée et qu'elle n'est pas maintenue pressée, ce qui suit sera exécuté. Si twinkle est égale à FALSE, on lui attribuera TRUE, sinon on lui attribuera FALSE. Lorsque 'T' sera pressée, tp prendra la valeur TRUE. Cela permet d'éviter que le code soit exécuté encore et encore durant la période où la touche 'T' est pressée.

Activation du scintillement
Sélectionnez
        SwapBuffers(hDC);               // Echange les tampons (Double Buffering)
        if (keys['T'] && !tp)           // Si 'T' est pressee et tp est egal a FALSE
        {
            tp=TRUE;                    // Si oui, on affecte TRUE à tp
            twinkle=!twinkle;           // On affecte a twinkle l'oppose de ce qu'il est
        }

Le code qui suit vérifie si vous avez relâché la touche 'T'. Si c'est le cas, tp prend la valeur FALSE. En appuyant sur la touche 'T' cela ne fera rien tant que tp n'est pas égale à FALSE. Donc cette portion de code est très importante.

Relâchement de la touche 'T'
Sélectionnez
        if (!keys['T'])                   // Est-ce que la touche 'T' a ete relachee ?
        {
            tp=FALSE;                     // Si oui, tp devient egal a FALSE
        }

Le reste du code vérifie si les touches flèche haut, flèche bas, page haut ou page bas sont pressées.

Vérification de l'état des touches
Sélectionnez

        if (keys[VK_UP])                // Est-ce que la touche 'fleche haut' est pressee ?
        {
            tilt-=0.5f;                 // Incline l'ecran vers le haut
        }
        if (keys[VK_DOWN])              // Est-ce que la touche 'fleche bas' est pressee ?
        {
            tilt+=0.5f;                 // Incline l'ecran vers le bas
        }
        if (keys[VK_PRIOR])             // Est-ce que la touche 'page haut' est pressee ?
        {
            zoom-=0.2f;                 // Zoom vers l'interieur
        }
        if (keys[VK_NEXT])              // Est-ce que la touche 'page bas' est pressee ?
        {
            zoom+=0.2f;                 // Zoom vers l'exterieur
        }

Comme pour tous les précédents tutoriels, assurez vous que le titre de la fenêtre est correct.

Modification du titre de la fenêtre
Sélectionnez
        if (keys[VK_F1])                    // Est-ce que la touche 'F1' est pressee ? 
        {
            keys[VK_F1]=FALSE;              // Si oui, on la remets 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 textures, l'eclairage et le clavier",640,480,16,fullscreen))
            {
                return 0;                   // On quitte si la fenetre ne s'est pas creee
            }
        }
    }
}

II-G. Conclusion

Dans ce tutoriel, j'ai essayé de vous expliquer avec le plus de détails possibles comment charger une image en noir et blanc, supprimer les espaces noirs autour de l'images (en utilisant la transparence), ajouter des couleurs à l'image, et bouger l'image dans la scène en 3D. Je vous ai également montré comment créer de jolies couleurs et des animations en se faisant chevaucher une seconde copie de l'image au-dessus de l'image originale. Une fois que vous avez bien compris tous ce que j'ai expliqué jusqu'ici, vous ne devriez pas avoir de problème pour réaliser vos propres demos 3D. Toutes les bases d'OpenGL ont été parcourues !

Enfin, voici une petite image de ce que vous devez voir :

Image de l'application
Image de l'application

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 :

IV. Remerciements

Merci à fearyourself et à jc_cornic pour leur relecture.

V. Liens