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

Ce tutoriel est une suite au tutoriel précédent. Dans le tutoriel 13, je vous ai appris comment utiliser les polices Bitmap. Dans ce tutoriel, je vais vous apprendre à utiliser les polices vectorielles.

La façon dont nous créons les polices vectorielles est assez proche de ce que nous avons fait pour les polices Bitmap dans la leçon 13. Toutefois… les polices vectorielles sont 100 fois plus cool ! Vous pouvez dimensionner les polices vectorielles. Les polices vectorielles peuvent être déplacées dans un monde 3D, et les polices vectorielles peuvent avoir une épaisseur ! Plus de caractères 2D plats. Avec les polices vectorielles, vous pouvez transformer n'importe quelle police installée sur votre ordinateur en une police 3D pour OpenGL, y ajouter les normales afin que les caractères s'illuminent d'une belle façon lorsque la lumière brille sur eux.

Une petite note, ce code est spécifique à Windows. Il utilise les fonctions wgl de Windows pour construire la police. Apparemment Apple a un support de agl qui pourrait faire la même chose, et X a glx. Malheureusement, je ne peux garantir que ce code soit portable. Si quelqu'un a un code plateforme indépendant pour dessiner les polices à l'écran, envoyez-le-moi et j'écrirai un autre tutoriel.

Nous commençons par le code typique de la première leçon. Nous allons ajouter l'entête stdio.h pour les opérations d'entrée/sortie standard ; le fichier d'entête stdarg.h pour l'analyse du texte et la conversion de variables à texte et finalement le fichier d'entête math.h qui nous permettra de déplacer le texte avec SIN et COS.

 
Sélectionnez
#include <windows.h>                        // Fichier d'entête pour Windows
#include <math.h>                        // Fichier d'entête pour la bibliothèque mathématique        (AJOUT)
#include <stdio.h>                        // Fichier d'entête pour pour les entrées/sorties    (AJOUT)
#include <stdarg.h>                        // Fichier d'entête pour pour les fonctions à arguments variables    (AJOUT)
#include <gl\gl.h>                        // Fichier d'entête pour la bibliothèque OpenGL32
#include <gl\glu.h>                        // Fichier d'entête pour la bibliothèque GLu32
#include <gl\glaux.h>                        // Fichier d'entête pour la bibliothèque GLaux

HDC        hDC=NULL;                    // Contexte de périphérique privé GDI
HGLRC        hRC=NULL;                    // Contexte de rendu permanent
HWND        hWnd=NULL;                    // Contient notre ID de la fenêtre
HINSTANCE    hInstance;                    // Contient l'instance de l'application

Nous ajoutons deux nouvelles variables. base va contenir le numéro de la première liste d'affichage que nous allons créer. Chaque caractère requiert sa propre liste d'affichage. Le caractère 'A' est 65 dans la liste d'affichage, 'B' est 66, 'C' est 67, etc. Donc 'A' va être dans la liste d'affichage base+65.

Ensuite nous ajoutons une variable rot. rot va être utilisée pour tourner le texte sur l'écran en utilisant SIN et COS. Cela va aussi servir pour les couleurs.

 
Sélectionnez
GLuint    base;                            // Base de la liste d'affichage pour la police de caractères (AJOUT)
GLfloat    rot;                            // Utilisé pour tourner le texte (AJOUT)

bool    keys[256];                        // Tableau utilisé pour la fonction du clavier
bool    active=TRUE;                        // Drapeau de fenêtre active défini à TRUE par défaut
bool    fullscreen=TRUE;                    // Drapeau de plein écran défini en plein écran par défaut

GLYPHMETRICSFLOAT gmf[256] va contenir les informations à propos de l'emplacement et de l'orientation de chacune de nos 256 listes d'affichage de la police vectorielle. Nous sélectionnons une lettre en utilisant gmf[num]. num est le numéro de la liste d'affichage que nous voulons connaître. Plus tard dans le code, je vais vous montrer comment trouver la largeur de chaque caractère pour pouvoir automatiquement centrer le texte sur l'écran. Gardez à l'esprit que chaque caractère peut avoir une largeur différente. glyphmetrics va rendre notre vie plus simple.

 
Sélectionnez
GLYPHMETRICSFLOAT gmf[256];                    // Emplacement pour les informations sur notre police

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

La prochaine section de code construit notre police de la même façon que pour les polices Bitmap. Tout comme dans la leçon 13, cette section de code était la partie la plus difficile à faire.

'HFONT font' va contenir l'ID de la police pour Windows.

Après nous définissons base. Nous faisons ceci par la création d'un groupe de 256 listes d'affichage en utilisant glGenLists(256). Suite à la création des listes d'affichage, la variable base contiendra le numéro de la première liste.

 
Sélectionnez
GLvoid BuildFont(GLvoid)                    // Construit notre police
{
    HFONT    font;                        // ID de police pour Windows

    base = glGenLists(256);                    // Stockage pour 256 caractères

Partie plus amusante. Nous allons créer la police vectorielle. Nous commençons par spécifier la taille de la police. Vous pouvez remarquer que le nombre est négatif. En mettant un moins, nous disons à Windows de nous trouver la police basée sur la hauteur des caractères. Si nous utilisions un nombre positif, nous comparerions la police en se basant sur la hauteur de la cellule.

 
Sélectionnez
    font = CreateFont(    -12,                // Hauteur de la police

Ensuite nous spécifions la largeur de la cellule. Vous pouvez remarquer que j'ai mis zéro. En mettant cette valeur à zéro, Windows va utiliser la valeur par défaut. Vous pouvez jouer avec cette valeur si vous voulez, faire la police large, etc.

 
Sélectionnez
                0,                // Largeur de la police

L'angle d'échappement va tourner la police. L'angle d'orientation, d'après l'aide MSDN, spécifie l'angle en dixièmes de degré, entre chaque base des caractères et l'axe des X du périphérique. Malheureusement, je n'ai aucune idée de ce que cela signifie. :(

 
Sélectionnez
                0,                // Angle d'échappement
                0,                // Angle d'orientation

Le poids de la police est un super paramètre. Vous pouvez entrer un nombre entre 0 et 1000 ou vous pouvez utiliser une des valeurs prédéfinies. FW_DONTCARE est 0, FW_NORMAL est 400, FW_BOLD est 700 et FW_BLACK est 800. Il y a beaucoup plus de valeurs prédéfinies, mais ces quatre-là sont un bon exemple. Plus la valeur est élevée, plus la police est épaisse (plus gras).

 
Sélectionnez
                FW_BOLD,            // Poids de la police

Italique, souligné et barré peuvent être soit TRUE soit FALSE. Basiquement, si souligné est TRUE, la police va être soulignée. Si c'est FALSE, elle ne va pas l'être. Simple :)

 
Sélectionnez
                FALSE,                // Italique
                FALSE,                // Souligné
                FALSE,                // Barré

L'identifieur du jeu de caractères décrit le type du jeu de caractères que vous souhaitez utiliser. Il y en a de trop pour tous les expliquer. CHINESEBIG5_CHARSET, GREEK_CHARSET, RUSSIAN_CHARSET, DEFAULT_CHARSET, etc. ANSI est celui que j'utilise, bien que le DEFAULT marcherait sans doute tout aussi bien.

Si vous êtes intéressés dans l'utilisation des polices comme Webdings ou Wingdings, vous devez utiliser SYMBOL_CHARSET à la place de AINSI_CHARSET.

 
Sélectionnez
                ANSI_CHARSET,            // Identifiant du jeu de caractères

La précision du rendu est très importante. Cela indique à Windows, le type de jeu de caractères à utiliser s'il y en a plus d'un de disponible. OUT_TT_PRECIS indique à Windows que s'il y a plus d'un type de police, de choisir celui avec le même nom, en sélectionnant la version TRUETYPE de la police. Les polices Truetype rendent toujours mieux, précisément lorsque vous les grossissez. Vous pouvez toujours utiliser OUT_TT_ONLY_PRECIS, qui tente TOUJOURS d'utiliser une police TRUETYPE.

 
Sélectionnez
                OUT_TT_PRECIS,            // Précision du rendu

La précision de la coupure est le type de coupure à faire sur la police si celle-ci va en dehors de la région de coupure. Pas grand-chose à dire dessus, laissez-le juste à la valeur par défaut.

 
Sélectionnez
                CLIP_DEFAULT_PRECIS,        // Précision du découpage

La qualité de rendu est très importante. Vous pouvez avoir PROOF, DRAFT, NONANTIALIASED, DEFAULT or ANTIALIASED. Nous savons tous que les polices ANTIALIASED rendent bien. :) L'anticrénelage d'une police a le même effet que vous avez lorsque vous activez la douceur des polices dans Windows. Cela rend tout moins déchiqueté.

 
Sélectionnez
                ANTIALIASED_QUALITY,        // Qualité de rendu

Ensuite nous avons les options de famille et de pitch. Pour le pitch vous pouvez avoir DEFAULT_PITCH, FIXED_PITCH et VARIABLE_PITCH, et pour la famille vous pouvez avoir FF_DECORATIVE, FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS, FF_DONTCARE. Jouez avec pour trouver ce que vous voulez faire. J'ai juste défini les deux à défaut.

 
Sélectionnez
                FF_DONTCARE|DEFAULT_PITCH,    // Famille et pitch

Finalement… Nous avons le nom de la police. Lancez Microsoft Word ou un autre éditeur de texte. Cliquez sur le menu ascenseur pour la police et trouvez une police qui vous plaît. Pour utiliser la police, remplacez 'Courier New' avec le nom de la police que vous préférez utiliser.

 
Sélectionnez
                "Courier New");            // Nom de la police

Maintenant, nous sélectionnons la police en la liant à notre DC.

 
Sélectionnez
    SelectObject(hDC, font);                // Sélectionne la police que nous avons créée

Maintenant du code nouveau. Nous construisons la police en utilisant la nouvelle commande wgUseFontOutlines. Nous sélectionnons notre DC, le caractère de début, le nombre de caractères à créer et la 'base' de la liste d'affichage. C'est très similaire à la façon de construire une police Bitmap.

 
Sélectionnez
    wglUseFontOutlines(    hDC,                // Sélectionne le DC courant
                0,                // Caractère de début
                255,                // Nombre de listes d'affichage à construire
                base,                // Début des listes d'affichage

Toutefois, ce n'est pas tout. Nous devons ensuite définir le niveau de divergence. Plus il sera proche de 0.0f, plus la police sera belle. Après avoir défini le niveau de divergence, nous allons définir l'épaisseur de la police. Cela décrit comment la police est sur l'axe des Z. 0.0f va produire une police plate et 1.0f va produire une police avec de l'épaisseur.

Le paramètre WGL_FONT_POLYGONS indique à OpenGL de créer une police solide en utilisant des polygones. Si nous utilisons WGL_FONT_LINES à la place, la police sera en fil de fer (constituée de lignes). Il est important de remarquer que si vous utilisez GL_FONT_LINES, les normales ne seront pas générées donc l'éclairage ne marchera pas correctement.

Le dernier paramètre gmf pointe sur l'adresse du tampon pour les données des listes d'affichage.

 
Sélectionnez
                0.0f,                // Divergence en partant des vrais contours
                0.2f,                // Épaisseur de la police dans l'axe des Z
                WGL_FONT_POLYGONS,        // Utilisation de polygones, et non de lignes
                gmf);                // Adresse du tampon  l'on doit recevoir les données
}

Le code qui suit est très simple. Il supprime les 256 listes d'affichage de la mémoire en commençant par la première liste spécifiée par base. Je ne suis pas sûr que Windows l'aurait fait pour vous, mais c'est mieux d'être prudent que désolé :)

 
Sélectionnez
GLvoid KillFont(GLvoid)                        // Supprime la police
{
     glDeleteLists(base, 256);                // Supprime les 256 listes d'affichage
}

Maintenant ma pratique fonction de texte pour OpenGL. Vous pouvez appeler cette section de code avec la commande glPrint("le message va ici"). Exactement de la même façon que pour les polices Bitmap de la leçon 13. Le texte va être sauvegardé dans la chaine de caractères fmt.

 
Sélectionnez
GLvoid glPrint(const char *fmt, ...)                // Fonction personnalisée OpenGL "Print"
{

La première ligne ci-dessous définit la variable appelée length. Nous allons utiliser cette variable pour trouver la longueur de notre texte. La seconde ligne crée un espace de stockage pour une chaine de caractères de 256 éléments. text est la chaine que nous allons afficher à l'écran. La troisième ligne crée un pointeur pointant sur la liste d'arguments que nous passons avec la chaine de caractères. Si nous envoyons des variables avec le texte, le pointeur va pointer sur celles-ci.

 
Sélectionnez
    float        length=0;                // Utilisé pour trouver la longueur du texte
    char        text[256];                // Contient notre chaine de caractères
    va_list        ap;                    // Pointeur sur la liste d'arguments

Les deux prochaines lignes de code vérifient qu'il n'y a rien à afficher. S'il n'y a pas de texte, fmt va être égale à rien (NULL), et rien ne sera affiché sur l'écran.

 
Sélectionnez
    if (fmt == NULL)                    // S'il n'y a pas de texte
        return;                        // Ne rien faire

Les prochaines lignes de code convertissent les symboles dans le texte en nombres qu'ils représentent. Le texte final et tous les symboles convertis sont stockés dans la chaine de caractères text. Je vais expliquer les symboles en détail un peu plus bas.

 
Sélectionnez
    va_start(ap, fmt);                    // Analyse la chaine de caractères pour les variables
        vsprintf(text, fmt, ap);                // Et convertit les symboles en nombres
    va_end(ap);                        // Le résultat est mis dans text

Merci à Jim Williams pour la suggestion du code ci-dessous. Je centrais le texte manuellement. Sa méthode marche beaucoup mieux :)

Nous commençons par faire une boucle qui va parcourir le texte caractère par caractère. strlen(text) nous donne la taille de notre texte. Après avoir mis en place la boucle, nous allons augmenter la valeur de la longueur par la largeur de chaque caractère. Quand nous avons fini, la valeur gardée dans length va être la largeur de notre chaine de caractères. Donc si nous affichions "hello" et que par chance tous les caractères mesuraient 10 unités de largeur, nous augmenterions la valeur de length par la largeur de la première lettre, 10. Nous vérifierions ensuite la largeur de la seconde lettre. La largeur serait aussi de 10, donc la largeur deviendrait 10+10 (20). Une fois la largeur des cinq lettres vérifiée, elle sera égale à 50 (5*10).

Le code qui nous donne la largeur de chaque caractère est gmf[text[loop]].gmfCellIncX. Rappelez-vous que ce gmf garde les informations de chaque liste d'affichage. Si loop est égal à 0, text[loop] va correspondre au premier caractère de notre chaine. Si loop est égal à 1, text[loop] va correspondre au deuxième caractère de la chaine. gmfCellIncX nous indique la largeur du caractère. gmfCellIncX est en fait la distance du déplacement sur la droite de notre écran après chaque caractère qui a été dessiné pour que les caractères ne soient pas les uns sur les autres. Donc cette distance est notre largeur. :) Vous pouvez aussi trouver la hauteur des caractères avec gmfCellInvY. Ceci peut être pratique si vous dessinez du texte verticalement au lieu d'horizontalement.

NOTE : Curt Werline ajoute : quand vous calculez la dimension de votre chaine de caractères, vous utilisez gmfCellIncX pour la largeur et vous pensez utiliser gmfCellIncY pour la hauteur. Ces valeurs sont les décalages et non les vraies dimensions. Pour avoir les vraies dimensions vous devez utiliser gmfBlackBoxX et gmfBlackBoxY.

 
Sélectionnez
    for (unsigned int loop=0;loop<(strlen(text));loop++)    // Boucle pour trouver la longueur du texte
    {
        length+=gmf[text[loop]].gmfCellIncX;        // Ajoute à la longueur la largeur de chaque caractère
    }

Finalement, nous prenons la longueur que nous avons calculée et nous en faisons un nombre négatif (parce que nous devons nous déplacer sur la gauche du centre de notre texte pour le centrer). Alors nous divisons la longueur par deux. Nous ne voulons pas que tout le texte se déplace sur la gauche du centre, juste la moitié !

 
Sélectionnez
    glTranslatef(-length/2,0.0f,0.0f);            // Centre le texte sur l'écran

Puis nous sauvegardons le GL_LIST_BIT, qui empêche glListBase de modifier les autres listes d'affichage que nous pourrions utiliser dans notre programme.

La commande glListBase(base) indique à OpenGL où trouver la bonne liste d'affichage pour chaque caractère.

 
Sélectionnez
    glPushAttrib(GL_LIST_BIT);                // Sauvegarde les bits des listes d'affichage
    glListBase(base);                    // Définit le caractère de base à 0

Maintenant qu'OpenGL sait où les caractères sont, nous pouvons lui dire d'écrire le texte à l'écran. glCallLists écrit la totalité de la chaine de caractères à l'écran, d'un coup, en faisant plusieurs listes d'affichage pour vous.

La ligne ci-dessous fait ce qui suit. Premièrement, cela indique à OpenGL que nous allons afficher des listes d'affichage à l'écran. strlen(text) trouve le nombre de lettres que nous avons à envoyer à l'écran. Ensuite la fonction nécessite de connaitre le plus grand numéro de liste qui va être utilisé. Nous n'envoyons jamais plus de 255 caractères. Donc nous pouvons utiliser un UNSIGNED_BYTE. (Un byte (octet) représente un nombre entre 0 et 255 ce qui correspond exactement à ce dont nous avons besoin). Finalement, nous indiquons ce qu'il faut afficher en donnant la chaine de caractères text.

Dans ce cas vous vous demandez pourquoi les lettres ne tombent pas pile les unes sur les autres. Chaque liste d'affichage connait pour chaque caractère le côté droit de celui-ci. Après que chaque lettre soit dessinée à l'écran, OpenGL se déplace sur le côté droit de la lettre dessinée. La prochaine lettre ou prochain objet va être dessiné en commençant par le dernier emplacement qu'occupe OpenGL, ce qui signifie à droite de la dernière lettre.

Finalement, nous replaçons le GL_LIST_BIT comme avant la mise en place de notre base avec glListBase(base).

 
Sélectionnez
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);    // Dessine le texte des listes d'affichage
    glPopAttrib();                        // Replace le bit des listes d'affichage
}

Le code de redimensionnement est le même que dans la leçon 1 donc nous passons directement à la suite.

Il y a peu de nouvelles lignes à la fin de notre code InitGL. La ligne BuildFont() implémentée dans la leçon 13 est toujours ici, avec un nouveau code qui permet un éclairage rapide et sale. Light0 est prédéfini sur la plupart des cartes et va illuminer la scène d'une belle façon, sans effort de ma part. :)

J'ai aussi ajouté la commande glEnable(GL_Color_Material), car les caractères sont des objets 3D donc vous devez activer la coloration des matériaux, sinon, changer la couleur avec glColor3f(r,g,b) ne va pas changer la couleur du texte. Si vous dessinez sur l'écran vos formes pendant que vous écrivez du texte, activez la coloration des matériaux avant d'écrire le texte, et désactivez-la après avoir écrit le texte, sinon, les objets sur l'écran vont être colorés.

 
Sélectionnez
int InitGL(GLvoid)                        // L'initialisation de OpenGL va ici
{
    glShadeModel(GL_SMOOTH);                // Activation de l'ombre douce
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);            // Fond noir
    glClearDepth(1.0f);                    // Mise en place du tampon de profondeur
    glEnable(GL_DEPTH_TEST);                // Activation du test de profondeur
    glDepthFunc(GL_LEQUAL);                    // Le type de test de profondeur à faire
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    // Calcul de jolies perspectives
    glEnable(GL_LIGHT0);                    // Activation de la lampe 0 (rapide et sale)    (AJOUT)
    glEnable(GL_LIGHTING);                    // Activation de l'éclairage            (AJOUT)
    glEnable(GL_COLOR_MATERIAL);                // Activation de la coloration des matériaux    (AJOUT)

    BuildFont();                        // Construction de la police            (AJOUT)

    return TRUE;                        // L'initialisation s'est bien déroulée 

}

Maintenant le code de l'affichage. Nous commençons par effacer l'écran et le tampon de profondeur. Nous appelons glLoadIdentity() pour tout réinitialiser. Puis nous nous déplaçons de dix unités dans l'écran. Les polices vectorielles rendent bien en perspective. Plus vous vous déplacez dans l'écran, plus la police devient petite. Plus vous le rapprochez vers vous, plus la police devient grande.

Les polices vectorielles peuvent aussi être dimensionnées avec la commande glScalef(x,y,z). Si vous voulez une police deux fois plus grande, utilisez glScalef(1.0f, 2.0f, 1.0f). Le 2.0f est sur l'axe des Y, ce qui indique à OpenGL de la dessiner deux fois plus grande. Si le 2.0f était sur l'axe des X, les caractères seraient deux fois plus larges.

 
Sélectionnez
int DrawGLScene(GLvoid)                        // Le code pour dessiner se trouve ici
{
    glClear(GL_COLOR_BUFFER_BIT

 | GL_DEPTH_BUFFER_BIT);    // Nettoie l'écran et le tampon de profondeur
    glLoadIdentity();                    // Réinitialise la vue
    glTranslatef(0.0f,0.0f,-10.0f);                // Se déplacer de 10 unités dans l'écran

Après s'être déplacé dans l'écran, nous voulons que notre texte tourne. Les trois prochaines lignes tournent l'écran sur les trois axes. Je multiplie rot avec des nombres différents pour que chaque rotation ait une vitesse différente.

 
Sélectionnez
    glRotatef(rot,1.0f,0.0f,0.0f);                // Rotation sur l'axe des X
    glRotatef(rot*1.5f,0.0f,1.0f,0.0f);            // Rotation sur l'axe des Y
    glRotatef(rot*1.4f,0.0f,0.0f,1.0f);            // Rotation sur l'axe des Z

Maintenant le cycle de couleurs psychédéliques. Comme d'habitude, je vais utiliser les variables compteurs (rot). Les couleurs vont avoir des pulsations grâce à COS et SIN. Je divise la valeur de rot par différents nombres pour avoir une vitesse d'incrémentation différente pour chaque couleur. Le résultat final est joli.

 
Sélectionnez
    // Pulsation des couleurs basée sur la rotation
    glColor3f(1.0f*float(cos(rot/20.0f)),1.0f*float(sin(rot/25.0f)),1.0f-0.5f*float(cos(rot/17.0f)));

Ma partie préférée… Écrire le texte sur l'écran. J'ai utilisé la même commande que nous avions utilisée pour écrire les polices Bitmap à l'écran. Tout ce que vous avez à faire pour écrire le texte à l'écran est glPrint("{n'importe quel texte que vous voulez}"). C'est aussi simple que ça !

Dans le code ci-dessous nous allons afficher NeHe, un espace, un tiret, un espace et finalement, le nombre de la variable rot divisé par 50 (pour ralentir un peu le compteur). Si le nombre est plus grand que 999.99 le quatrième chiffre va être coupé (nous ne demandons que trois chiffres à gauche du symbole décimal). Seulement deux chiffres vont être affichés dans la partie décimale.

 
Sélectionnez
     glPrint("NeHe - %3.2f",rot/50);                // Affiche du texte OpenGL à l'écran

Ensuite nous incrémentons la variable de rotation pour que les couleurs aient des pulsations et que le texte tourne.

 
Sélectionnez
    rot+=0.5f;                        // Incrémente la variable de rotation
    return TRUE;                        // Tout s'est bien passé
}

La dernière chose à faire est d'ajouter KillFont() à la fin de KillGLWindow() tout comme je le montre ci-dessous. C'est important d'ajouter cette ligne. Cela nettoie les choses avant de quitter le programme.

 
Sélectionnez
    if (!UnregisterClass("OpenGL",hInstance))        // Pouvons-nous désenregistrer la classe
    {
        MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hInstance=NULL;                    // Définit hInstance à NULL
    }

    KillFont();                        // Détruit la police
}

À la fin de ce tutoriel, vous devez être capable d'utiliser les polices vectorielles dans vos propres projets OpenGL. Tout comme la leçon 13, j'ai recherché sur internet pour trouver un tutoriel similaire à celui-ci, et je n'ai rien trouvé. Peut-être mon site est-il le premier à couvrir ce sujet avec plein de détails, en expliquant tout dans un code C facile à comprendre ? Bon tutoriel, et bon code !


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 Winjerome pour sa relecture ainsi que ClaudeLELOUP pour ses corrections.

V. Liens