La programmation graphique dans les jeux vidéo sur PC.

    Dans les articles qui suivent, nous apprendrons à effectuer des sorties graphiques sur PC qui soient adaptées aux jeux vidéo. A terme, vous serez capable de mettre au point un moteur 3D du style de celui qui figure à cette page.
    Le langage de programmation utilisé sera le C++ qui sera considéré comme parfaitement connu. Le système d'exploitation considéré est le DOS, mais les conseils données peuvent s'appliquer à Windows 95 en mode console sous certaines restriction. Ces routines n'ont pas été testées sous Linux, mais il ne devrait pas y avoir de probleme.
    Les autres plateformes telles que le Macintosh ne sont pas supportées. Toutefois, un bon programmeur pourra largement s'inspirer des conseils que je donnerai ici pour mettre au point son propre jeu de routine.

    La programmation graphique des jeux vidéo diffère de la programmation graphique standard par sa fluidité. Imaginez ce que serait Doom si chaque image mettait plusieurs secondes à s'afficher. Il en résulte un certain nombre de contraintes :

    • Il n'est pas possible d'utiliser les routines graphiques standard fournie s avec les principaux langages de programmation.
    • La programmation doit s'effectuer au niveau hardware le plus bas, les routines obtenues ne seront pas portables.

    Les régles du programmeur de jeu sont :

    • Si une technique vous permet de gagner ne serait ce quelques pour cent en vitesse, utilisez la, même si elle ferait bondir un programmeur C++ traditionnel.
    • De toute façon votre code ne sera pas portable, alors n'hesitez pas à vous servir des particularités de votre compilateur.
    • Si la création d'une routine spécialisée vous permet de gagner quelques pour cent, créer la, même si elle ne sert que rarement.
    • N'utilisez JAMAIS les calculs en virgule flottante, même si l'ordinateur dispose d'un processeur arithmétique.

    Peut on utiliser les classes C++ dans ce genre de programmation? La souplesse apportée par les classes facilite tellement la programmation qu'il serait dommage de s'en priver. Mais d'un autre côté, les classes rajoutent un overlay qui ralentit les sauts aux différentes routines.
    La réponse est, çà dépend. Si votre programme est destiné à tourner sur un 386, c'est non. Mais si vous compter utiliser un pentium, ne vous en privez pas.
    Et l'assembleur ? Ecrire vos programmes tous en assembleur ne présentera aucun intéret et risque d'etre de toute façon une tache insurmontable. Vous pourrez bien sur utiliser l'assembleur, mais APRES avoir tout ecrit en C/C++ et identifié les points critiques qui méritent une telle transcription. Ces points seront de toutes façon peu nombreux. Il y a quelques exceptions à cette règle que nous verrons au fur et à mesure.

    Dans la suite de cette article, nous allons étudier les différents mode graphique utilisé et la principale interface entre la carte graphique et le programmeur, à savoir le bios vidéo. Les prochains articles traiteront respectivement de :

    • la programmation graphique standard en mode VGA.
    • la gestion des bitmaps en mode 13h
    • les lutins (ndlr: sprites) en mode 13h
    • les bases de la programmation SVGA.
    • les techniques d'optimisations.
    • la programmation 3D

    I) Les modes graphiques utilisés dans les jeux vidéo.

    Traditionnellement, les jeux vidéo utilisent 4 modes graphiques differents, le mode 13h, le mode X et les modes super VGA 256 couleurs 640 X 400 et 640 X 480 (Ces deux derniers se programmant de la même façon, il seront appelés SVGA dans la suite des articles). Tous ces modes ont des avantages et des inconvenients que nous allons étudier. Tous ces modes affichent 256 couleurs au choix parmis 262144

    1) le mode 13h

    C'est le mode VGA traditionnel, 320 X 200, 256 couleurs. A une résolution faible, il associe une grande variete de couleur. La memoire requise pour le faire fonctionner est 64000 octet et tiens donc entièrement dans la fenêtre d'accés situé en A000h. Trés rapide, il est de plus le mode graphique le plus facile à utiliser, toutes cartes confondue.

    2) Le mode X

    C'est le mode roi des programmeurs de jeux, 320 X 200, 256. Ce n'est pas un mode standard, d'ou son nom de X. N'étant pas pris en charge par le bios, il faut donc l'activer en manipulant soi même les registres de la carte VGA. De plus, sa memoire n'est plus organisée linéairement comme pour le mode 13h, il est donc plus difficile à utiliser.
    En revanche, ses avantages sont nombreux. C'est le mode graphique le plus rapide, parfois jusqu'a 4 fois la vitesse du mode 13h. De plus, il dispose de 4 pages graphiques, ce qui permet des, outre le double buffering, de traiter les lutins et bitmaps sans passer par le bus, d'ou une accéleration appréciable. Dans un environnement interactif comme les jeux vidéo, ces qualités sont trés recherchées.

    3) Les modes SVGA

    Les modes SVGA comprennent les modes 16 couleurs à partir de 800 X 600, 256 couleurs à partir de 640 X 400 et les modes à plus de 256 couleurs (HiColor et True Color). Nous ne parlerons ici que des modes 256 couleurs bien que certaines choses puissent s'appliquer aux autres. Fondamentalement, les modes SVGA sont organisés de la même façon que le mode 13h, avec une mémoire linéaire. Mais cette mémoire a une taille supérieure aux 64 Ko de la fenêtre d'accés et ne peut donc pas être adressée en une seule fois. Dans ces modes, la mémoire est donc paginée, les routines d'accés sont donc singulierement compliquées. D'autre part, le nombre de pixels affichés à l'ecran en fait des modes beaucoup plus lent que les autres. Enfin, sur les vieilles cartes SVGA, ils ne sont pas normalisés. Le problème a été résolue avec la norme VESA pour les modes les plus courants. Le principal avantage de ces modes est d'une part leur résolution élevée et d'autre part que ces modes fonctionnant de la même façon, les mêmes routines peuvent fonctionner dans tous. (Ces routines peuvent également être utilisées en mode 13h, si ont considère comme un mode SVGA avec une seule page mémoire, mais elles seront bien moins efficaces et beaucoup plus compliquées que des routines écrites spécialement pour le mode 13h). Enfin, il faut signaler que la structure de la mémoire permet de tamponner facilement les routines en EMS.

    II) Le bios vidéo

    Le bios vidéo est l'interface principale entre l'utilisateur et la carte graphique. Bien que trop lent pour nos besoins, il prodigue des fonctions irremplaçable. L'interruption du bios est accessible a travers l'interruption 10h. Le registre AH doit contenir le numero de la fonction du bios à appeler. En pratique seules quelques fonctions sont utiles dans notre cas.

    fonction 0 Initialisation du mode vidéo
    fonction 0Fh Lecture du mode vidéo
    fonction 10h Gestion de la palette
    fonction 1Ah Reconnaitre une carte VGA
    fonction 4Fh Bios VESA


    1) Reconnaitre une carte VGA

    Avant d'utiliser un mode graphique, il faut d'abord s'assurer que ce mode existe. Le mode 13h existe sur toutes les cartes VGA. c'est la fonction 1Ah du bios vidéo, chargé de la gestion des systèmes multicartes, qui permet d'identifier une telle carte. Dans notre cas, seule la sous fonction 0 est utile. La fonction 1Ah n'existe que si une carte VGA ou plus est installée dans le système. Pour l'utiliser, il faut mettre le numéro de fonction 1Ah dans AH et de sous fonction 0 dans AL puis d'appeller l'interruption 10h. En retour, si le registre AL contient 1Ah, c'est qu'une carte VGA est installée sur le système :

    BOOL IsVga( void )
    {
      union REGS   Regs;    /* Registres pour l'interruption */
    
      Regs.x.ax = 0x1a00;   /* La fonction 1Ah n'existe que pour VGA */
      int86( 0x10, &Regs, &Regs );
      if( Regs.h.al == 0x1a ) return TRUE;
      return FALSE;
    }

    En prime, la fonction retourne deux valeurs en BH et BL correspondant aux cartes graphique installées sur le système, la carte active etant en BL. Les valeurs possibles sont :

    00h = Pas de carte vidéo
    01h = MDA avec écran monochrome
    02h = CGA avec moniteur CGA
    03h = Réservé
    04h = EGA avec moniteur EGA ou Multisync
    05h = EGA avec moniteur monochrome
    06h = Réservé
    07h = VGA avec écran monochrome analogique
    08h = VGA avec écran couleur analogique
    09h = Réservé
    0Ah = Carte MCGA avec moniteur CGA
    0Bh = MCGA avec écran monochrome analogique
    0Ch = MCGA avec écran couleur analogique
    FFh = Carte vidéo inconnue

    Si vous avez detecté une carte VGA, vous pouvez utiliser le mode 13h.

    2) Activer le mode 13h

    La premiere étape dans l'utilisation du mode graphique 0x13 est son activation. Pour cela il suffit d'utiliser la fonction 0 du BIOS vidéo avec le numéro du mode choisi en AL. si vous voulez que le contenu de la RAM vidéo soit conservé après l'activation du mode graphique, vous devez rajouter 80h au registre AL.

    _asm {
         mov ah,0;    // fonction 0 du bios vidéo.
         mov al,0x13; // mode graphique 0x13, RAM effacée.
         int 10;      // appelle le bios vidéo.
    }

    activation du mode 0x13 avec effacement de l'écran


    _asm {
         mov ah,0;    // fonction 0 du bios vidéo.
         mov al,0x93; // mode graphique 0x13,RAM conservée.
         int 10;      // appelle le bios vidéo.
    }

    activation du mode 0x13 sans effacement de l'écran


    La routine ci dessus est écrite directement en assembleur. Sur PC, l'appel des interruptions est une des exceptions quant à son utilisation. Jugez plutot la même fonction écrite en C pur :

    REGS registre;
    registre.h.ah = 0;
    registre.h.al = 0x13;
    intr(&Registre,&Registre);
    

    activation du mode 0x13 avec effacement de l'écran en C++


    D'une part, la transcription en assembleur évite la création de la variable intermédiaire Registre. D'autre part le code compilé ne comprend que quelques instructions en haut et plus d'une centaine en bas, à cause justement du remplissage de cette variable intermédiaire. Les instructions du bas sont donc terriblement inefficaces.

    Après l'appel de la routine ci dessus, la carte vidéo a initialisé le mode graphique 0x13. A la sortie de votre programme, il faudra quitter ce mode. Si vous l'oubliez, le bios est parfaitemnt capable de gerer les sortie texte dans ce mode, l'ordinateur restera donc fonctionnel. Mais vous n'aurez plus qu'une résolution de 40 colonnes X 25 lignes et non les 80 X 25 du mode d'origine.
    En général, le mode texte standard est le mode 0x03. Pour quitter le mode 0x13, il suffit donc d'appeller la routine definie plus haut en remplaçant 0x13 par 0x03. Mais si vous voulez vraiment faire un programme fiable, il est preférable de determiner le mode graphique courant avant d'activer le mode 0x13. Ce travail est pris en charge par la fonction 0x0F du bios vidéo. Le mode actif est retourné dans le registre AL. Vous trouverez un exemple dans le fichier source accompagnant cet article.

    3) Modifier la couleur du cadre de l'écran.

    La dernière fonction du bios a nous être utile est la fonction 10h qui permet de gérer la palette de couleur de la carte. Pour nos besoins, il sera préferable d'accéder directement à l'electronique pour gérer les couleurs. Aussi n'utiliseront nous qu'une seule sous fonction, la sous fonction 1 qui permet un effet peu connu car peu utilisé sur les PC : modifier la couleur de la bordure de l'ecran. Cela se fait en mettant le code couleur dans le registre overscan de la carte. Mais l'accés a ce registre est beaucoup plus facile par le bios.

    Pour changer la couleur du cadre, vous devez appeler l'interruption 10h avec :

  • AH = 10h
  • AL = 1
  • BH = couleur du cadre




  • Dans cette introduction à la programmation graphique, nous avons vu les differents modes graphiques utilisés ainsi que les fonctions du bios vidéo. Dans le prochain article, nous tracerons nos premiers dessins : points, traits lignes, rectangles et polygones. Vous pouvez charger les sources des exemples enoncés plus haut en cliquant ici. Ces sources considèrent les types et les constantes suivants comme définis :

    • unsigned char BOOL;
    • unsigned char BYTE;
    • #define FALSE 0==1
    • #define TRUE 1==1