1. L'écran

L'écran de la GameBoy Advance est symbolisé en mémoire par un tableau de 240*160 valeurs codées sur 16 bits. Nous avons découvert précédemment que l'adresse de ce tableau correspondait à l'adresse physique 0x6000000. En sus de cette adresse particulière, le programmeur doit connaître l'emplacement mémoire réservé à la palette de couleurs. L'adresse 0x5000000 désigne un emplacement mémoire de 256 valeurs sur 16 bits réservées pour spécifier les couleurs de la palette. Comme avec le mode 3, chaque couleur est codée sur 16 bits, chacune des composantes rouge, verte et bleue occupant 5 bits. Le bit de poids fort reste inutilisé. Un exemple simple de fonction créant une palette de couleurs à l'emplacement adéquat se trouve présenté dans le listing un. La macro RGB() provient de l'exemple précédent. Vous retrouverez son code dans les fichiers source. La palette ici calculée se propose de recréer les couleurs employées pour la représentation de terrains en deux dimensions.

 
Sélectionnez

u16* palette = (u16*) 0x5000000;
int i;
for (i = 0; i < 70; i++)
  palette[i] = RGB(0, 0, i + 128);
for ( ; i < 200; i++)
  palette[i] = RGB(0, i, 0);
for ( ; i < 256; i++)
  palette[i] = RGB(i, i, i);

2. Comprendre le Mode 4

Le Mode 4 s'utilise de manière bien particulière par rapport au Mode 3. Nous savons que l'écran est constitué de 240 pixels en largeur et de 160 pixels en hauteur. Aussi pourrions nous penser que l'emploi du Mode 4 ne diffère pas du mode 3 alors que rien n'est plus faux. Considérons la représentation en mémoire de l'écran et celle de la palette. Nous savons que l'écran est matérialisé par un tableau de valeurs sur 16 bits (spécifiés par le type u16, ou unsigned short int dans nos sources). Or la palette de couleurs comprend 256 entrées. Ainsi, pour donner à un pixel la couleur d'une entrée de la palette, une valeur sur 8 bits suffit.

Une image affichée sur la machine
Une image affichée sur la machine

Lorsque nous écrivons ecran[0] = 0; nous indiquons à la machine d'attribuer la couleur de la première entrée de la palette au pixel de coordonnées (0, 0). Nous pourrions bien entendu nous contenter d'appliquer une valeur comprise entre 0 et 255 à chaque pixel de l'écran. Pourtant, notre zone mémoire écran comprenant des plages de 16 bits, n'est-il pas dommage de n'attribuer que des valeurs occupant 8 bits ?

Les concepteurs de la GameBoy Advance ont donc opté pour une solution intéressante : en Mode 4, l'écran virtuel occupe une place de 120*160 pixels. Sa largeur se voit donc divisée en deux. Nous pouvons donc aisément en déduire que chaque segment de 16 bits codera pour deux pixels consécutifs. Ecrire les deux lignes suivantes revient ainsi à allumer les pixels de coordonnées (0, 0), (1, 0), (2, 0) et (3, 0) :

 
Sélectionnez

ecran[0] = 0;
ecran[1] = 0;

Pour allumer les pixels (0, 0) et (1, 0) en employant respectivement les couleurs 16 et 29 de la palette nous devrons rédiger l'instruction suivante :

 
Sélectionnez

ecran[0] = (16 << 8) | 29;

Le principe est donc similaire au calcul des codes couleurs par la macro RGB().

3. Afficher une image

L'affichage d'une image en plein écran, pour simplifier les choses, par le biais du Mode 4 impose de posséder les informations concernant l'image sous une forme aisément utilisable. Nous pourrions, lors de la phase de link, inclure l'image et sa palette de couleurs sous forme non codée à l'exécutable. Toutefois, nous choisirons une solution différente pour bien appréhender le concept du Mode 4. De nombreux utilitaires fleurissent sur Internet pour intégrer facilement des images et leurs palettes à vos codes source GBA. Dans notre exemple, nous avons fait appel à un outil intitulé pcx2gba. Comme ses nombreux congénères, pcx2gba travaille avec des images au format PCX. Ce format vieillissant a connu ses heures de gloire en raison sa simplicité. Son autre intérêt réside dans sa gestion de l'image puisqu'il encode l'image avec palette de 256 couleurs. La conversion d'un fichier PCX vers des données exploitables par un programme C se révèle simple. Une fois le travail de conversion achevé, nous obtenons un header comprenant deux tableaux constants de type unsigned short int. Le premier accueille les données de l'image et le second la palette de couleurs.

Notre programme dans l'émulateur
Notre programme dans l'émulateur

L'exemple proposé comprend un header nommé arcane.h correspondant à un simple logo. L'outil pcx2gba crée un tableau de type u16 pour les données de l'image. Cela signifie que chaque élément du tableau correspond déjà à deux pixels. Nous pourrons ainsi nous affranchir du travail de conversion de deux données 8 bits en une donnée 16 bits. La première étape de l'affichage d'une image en Mode 4 consiste à activer ledit Mode 4. Pour les mêmes raisons que le Mode 3, nous activons également le background 2 :

 
Sélectionnez

*mode = MODE_4 | BG2;

La constante MODE_4 correspond à la valeur 0x4. Nous devons ensuite copier la palette de couleurs de l'image dans l'emplacement mémoire système réservé à cet usage :

 
Sélectionnez

for (int i = 0; i < 256; i++)
  palette[i] = arcanePalette[i];

Une solution bien plus rapide et efficace existe pour réaliser la copie. Nous y reviendrons dans l'article suivant. Maintenant que la console se trouve dans le mode graphique désiré et que la palette se trouve prête, nous pouvons effectuer la copie de l'image sur l'écran.

 
Sélectionnez

for (int y = 0; y < SCREEN_HEIGHT; y++)
  for (int x = 0; x < SCREEN_WIDTH / 2; x++)
    ecran[x + y * SCREEN_WIDTH / 2] = picture[x + y * SCREEN_WIDTH / 2];

Notez la division par deux de la largeur de l'écran. Nous utilisons bien ici un espace mémoire de 120*160 plages de 16 bits. Puisque seule la moitié de la mémoire réservée à l'écran se trouve employée, la seconde moitié doit pouvoir se révéler utile.

4. Double buffering

Du fait se son usage mémoire modéré, le Mode 4 s'avère parfait pour mettre en ouvre un système de double buffering. Cette méthode simple consiste à effectuer les opérations de dessin de l'image suivant en mémoire tandis que l'image courante se voit affichée.

Principe du double buffering
Principe du double buffering
 
Sélectionnez

#define BACKBUFFER 0x10
#define videoFrontBuffer (u16*) 0x6000000
#define videoBackBuffer (u16*) 0x600A000

Les définitions videoFrontBuffer et videoBackBuffer désignent les adresses mémoires correspondant à l'écran et à la zone mémoire inutilisée normalement en Mode 4. Pour passer d'un buffer à l'autre, un drapeau sera activé ou désactivé dans le registre du mode d'affichage. Nous désignons ce drapeau sous le terme de BACKBUFFER. Le changement de buffer s'effectue lors de l'appel à la méthode flipBuffers. Le passage d'un buffer à l'autre devra se faire entre deux rafraîchissements de l'écran.

 
Sélectionnez

void flipBuffers()
{
  if (*mode & BACKBUFFER)
  {
    *mode &= ~BACKBUFFER;
    videoBuffer = videoBackBuffer;
  } else {
    *mode |= BACKBUFFER;
    videoBuffer = videoFrontBuffer;
  }
}

5. Téléchargements

Vous trouverez le code source des exemples présentés dans l'archive suivante : cours2.zip. L'outil de conversion d'une image PCX en header C se trouve ici : pcx2gba.zip.

Version PDF de l'article (78 Ko).

Liens :