VII. Utilisation du Mode 4

Dernière modif : 25/01/2002

1) Introduction sur la palette

La palette est un tableau à une dimension, commençant à l'adresse mémoire 0x5000000 (variable PaletteBKG déclarée dans le fichier "GBADraw.h") et contenant 256 éléments de 16 bits. Ces éléments sont les couleurs de la palette.

Pour utiliser la palette, il faut commencer par y charger les 256 couleurs quelle devra contenir. Les images affichées dans ce Mode, ne pourront afficher que les 256 couleurs contenues dans la palette.

2) Utilisation de la mémoire vidéo dans ce mode

Comme pour le Mode 3, on peut considérer la mémoire vidéo comme un tableau à une dimension commençant à l'adresse mémoire 0x6000000 (variable VideoBuffer déclarée dans notre fichier "GBADraw.h"). La différence est qu'un pixel n'utilise qu'un seul octet au lieu de deux. Cet octet contient le numéro d'index dans la palette de la couleur à afficher.

La conséquence est qu'une image occupera moitié moins de place en mémoire vidéo que si elle était affichée en Mode 3. De ce fait, on peut placer simultanément deux images en mémoire vidéo: une à partir de l'adresse 0x6000000 (aussi déclaré comme variable VideoFrontBuffer dans le fichier "GBADraw.h") et l'autre à partir de l'adresse 0x600A000 (variable VideoBackBuffer déclarée dans le fichier "GBADraw.h"). L'intérêt de celà, est que l'on peut manipuler une image en mémoire pendant que l'autre est affichée à l'écran, ce qui procure un gain de vitesse d'exécution du programme. Cette méthode s'appelle le "Double Buffering".

NOTE IMPORTANTE: Bien que dans ce Mode, les pixels n'utilisent qu'un seul octet, on ne peut accéder à la mémoire vidéo qu'en 16 bits!!! Ceci étant dû aux limitations "Hard" de la GBA. Ce qui veut dire que pour écrire un seul pixel en mémoire vidéo: il faudra lire deux pixels en mémoire, masquer le pixel que l'on modifie et renvoyer les deux pixels en mémoire. En général, pour accélérer les choses on écrit/lit deux pixels à la fois.

3) Mise en place des couleurs dans la palette

La structure de la palette est la suivante :

Index
0
1
2
3
4
255
Couleur sur 16 bits
Color0
Color1
Color2
Color3
Color4
...
Color255
Adresse
0x5000000
0x5000002
0x5000004
0x5000006
0x5000008
0x50001FE

Son fonctionnement est très simple, mais comme toujours le plus simple est de s'appuyer sur un exemple:
nous allons placer du vert (0x03E0) dans la palette à l'index 17 avec différentes méthodes.

Si nous avions eu un tableau de 256 éléments de 16 bits contenant les couleurs de la palette, nous aurions pu les placer directement en utilisant la fonction SetPalette_All de la librairie DirectGBA:
u16 pImg_Palette[256]; // tableau contenant les couleurs de la palette
SetPalette_All( pImg_Palette );

4) Affichage d'un pixel à l'écran

Etant donné que la GBA ne peut accéder à la mémoire vidéo qu'en 16 bits, l'affichage se fait en mémoire comme si l'écran n'avait que 120 colonnes de 2 pixels solidaires.

Exemple :

Affichage de deux pixels limitrophes, un rouge contenu dans la palette à l'index 64 et un vert contenu à l'index 17.

Colonne pixel adresse Mémoire -->
0
1
2
...
119
Colonne pixel à l'écran -->
0
1
2
3
4
5
...
238
239
Ligne pixel à l'écran
0
. . . . . . . . .
1
. . . . . . . . .
2
. . . . . . . .
3
. . . .
R
V
. . .
...
. . . . . . . . .
...
. . . . . . . . .
159
. . . . . . . . .

Affichage du pixel Vert

Toutes ces opérations peuvent être automatisées en utilisant la fonction PlotPixel4 de la librairie DirectGBA:
PlotPixel4(5, 3, 17);

Affichage du pixel rouge

La procédure est la même que pour l'affichage du pixel vert à la différence qu'il faut placer l'index de la couleur rouge dans l'octet de poids faible en masquant celui de poids fort:
u16 peek = VideoBuffer[2+3*120]; //emplt mém: lig 3, col 2 (col 4 & 5 à l'écran)
u16 send = (0xFF00 & peek) + 64;
VideoBuffer[2+3*120] = send;

Ici encore ces opérations peuvent remplacées par:
PlotPixel4(4, 3, 64);

Affichage des deux pixels

Le plus rapide est d'envoyer les deux pixels à la fois:
VideoBuffer[2+3*120] = 64 + (17<<8);

Ou plus simplement avec la fonction SendPixels4 de la librairie DirectGBA:
SendPixels4(2, 3, 64 + (17<<8));

5) Mise en oeuvre du Mode 4

Pour activer le Mode 4 sur la GBA, il suffit de placer la valeur 4 dans les bits 0 à 2 du registre DISP_CR. Mais, il faut aussi que le "Background" 2 soit utilisable.
N'oublions pas que dans tous les modes "Bitmaps" il faut que le "Background" 2 soit activé pour permettre l'affichage.

Tout ceci se fait facilement avec la fonction SetVideoMode contenue dans la librairie DirectGBA:
SetVideoMode ( MODE4 | BG2 );

6) Exemple n°4 : Remplissage de l'écran

Dans cet exemple n°4, nous allons afficher pixel par pixel un dégradé de Bleu à l'écran.

Le listing est le suivant:


/********************************************************
*
* Exemple n°4 : Remplissage de l'ecran Mode 4
* Affichage d'un degrade de bleu
*
* Cree le : 20.08.2001
* Par : Edorul (edorul@caramail.com)
*
* Ver. : 1.0
* Modifié le
*
********************************************************/
#include "..\DirectGBA\DirectGBA.h"
// Remplissage des 64 premiers indexs de la palette avec le degrade de bleu
void RemplPalette()
{
    u16 i;
    for(i=0; i<32; i++) {
        SetPaletteBKG_Entry(i, RGB(0, 0, i)); //index 0 a 31:du noir au bleu
        SetPaletteBKG_Entry(i+32, RGB(i, i, 31)); //index 32 a 63:du bleu au blanc
    }
}
       
// Remplissage de l'ecran avec degrade de bleu (Pixel par Pixel)
void RemplEcran()
{
    u16 i, j;
    for (i=0; i<240; i++) //colonne
        for (j=0; j<160; j++) //ligne 
            // Affichage du pixel (i, j) avec une teinte de bleu
            PlotPixel4(i,j,(i*64)/240);
}
void AgbMain(void)
{
    //Mise en place des couleurs dans la palette
    RemplPalette();
    //Mise en place des pixels en memoire video
    RemplEcran(); 
    //activation du Mode 4 et donc affichage
    SetVideoMode(MODE4 | BG2 ); 
    while(1) {
    }
}

Compilation avec ARM SDT
Compilation avec GCC 3.0

Fichiers nécessaires à la compilation :
* boot.asm
* TOUS les fichiers ".H" de la librairie DirectGBA
* main.c

Fichiers à inclure au projet :
* boot.asm
* main.c

Fichiers nécessaires à la compilation :
* crt0.s
* TOUS les fichiers ".H" de la librairie DirectGBA
* main.c

Fichiers à compiler dans le fichier ".MAK" :
* crt0.s
* main.c

7) Affichage d'une image à l'écran

a- Création de l'image

Comme pour la création de l'image en Mode 3, ici il suffit encore d'utiliser un logiciel de dessin du type de Paint Shop Pro ou Photoshop (ou même Paint...) et de créer une nouvelle image de 240x160 en 256 couleurs.
On peut aussi créer l'image en 24 bits et la convertir avec le logiciel de dessin. BMP2GBAX peut aussi convertir une image dans le bon nombre de couleurs en fonction du Mode choisit mais le résultat n'est vraiment pas très bon.
Moralité: toujours convertir l'image en 256 couleurs avant d'utiliser BMP2GBAX .

Lorsque l'image est terminée il faut impérativement l'enregistrer en BMP (dans l'exemple n°5 l'image que nous utiliserons s'appelle "Pastel256.bmp").

b- Convertir l'image

La conversion se fait (comme pour le Mode 3) avec BMP2GBAX.

Pour convertir "Pastel256.bmp" avec BMP2GBAX, il faudra:

c- Utilisation du fichier binaire à l'aide d'un fichier assembleur
(ne fonctionne pas avec GCC)

On ne peut pas utiliser directement nos fichiers "Pastel-8b.raw" et "Pastel-8b.pal" directement dans un programme en C (comme on aurait pu le faire avec un fichier en-tête).

On peut les utiliser en déclarant des variables pointant vers les données de ces deux fichiers au sein d'un programme assembleur. Les étapes à suivre sont les suivantes:

Créer le fichier assembleur "INC_BINS.ASM" suivant:


;
; Surtout garder les tabulations, ne pas les supprimer
; sinon le compilateur assembleur "zarmasm" risque de 
; faire des erreurs de compilation. ;
	AREA bin_data, DATA, READONLY
		EXPORT Image_Bkg
EXPORT Palette_Bkg
Image_Bkg
	INCBIN Pastel-8b.raw
Palette_Bkg
INCBIN Pastel-8b.pal
	END

Ajouter ces nouveaux fichiers au projet (en allant toujours dans le menu Project | Add to project | Files... de VC++).

Pour accéder aux données contenues dans ces fichiers dans notre programme en C, il suffit de déclarer l'image et la palette en variables externes:
extern u16 Image_Bkg; //contient l'image
extern u16 Palette_Bkg; //contient les couleurs de la palette

d- Utilisation du fichier binaire à l'aide d'un fichier d'en-tête
(fonctionne avec GCC et ARM SDT)

A l'aide du programme B2X nous pouvons utiliser ces deux fichiers binaires en créant deux fichiers d'en-tête (".H"). Les étapes à suivre sont les suivantes:

8) Exemple n°5 : Affichage d'une image

Cet exemple ne fait qu'afficher à l'écran un pastel de Jackie Simmonds nommé "Marche de Pollenca, Mojorque" en 256 couleurs. Pour celà nous utilisons la fonction DrawImg4 de DirectGBA qui affiche directement la totalité de l'image.

"main.c" :


/********************************************************
*
* Exemple n°5 : Affichage d'une image en Mode 4
* (Pastel de Jackie Simmonds "Marche de Pollenca, Mojorque")
*
* Cree le : 26.08.2001
* Par : Edorul (edorul@caramail.com)
*
* Ver. : 1.0
* Modifié le
*
********************************************************/
#include "..\DirectGBA\DirectGBA.h"
extern u16 Palette_Bkg; //variable declaree dans "inc_bins.asm"
extern u16 Image_Bkg; //variable declaree dans "inc_bins.asm"
// Remplissage de tous les index de la palette avec les couleurs de l'image
void RemplPalette()
{
    SetPaletteBKG_All(&Palette_Bkg); //index 0 a 255
}
       
// Remplissage de l'ecran avec l'image
void RemplEcran()
{
    DrawImg4(&Image_Bkg);
}
void AgbMain(void)
{
    //Mise en place des couleurs dans la palette
    RemplPalette();
    //Mise en place des pixels en memoire video
    RemplEcran(); 
    //activation du Mode 4 et donc affichage
    SetVideoMode(MODE4 | BG2 ); 
    while(1) {
    }
}

Compilation avec ARM SDT
Compilation avec GCC 3.0

Fichiers nécessaires à la compilation :
* boot.asm
* inc_bins.asm

* TOUS les fichiers ".H" de la librairie DirectGBA
* main_arm_sdt.c
* Pastel-8b.raw
* Pastel-8b.pal

Fichiers à inclure au projet :
* boot.asm
* inc_bins.asm
* main_arm_sdt.c

Fichiers nécessaires à la compilation :
* crt0.s
* TOUS les fichiers ".H" de la librairie DirectGBA
* Image.h
* Palette.h
* main_gcc.c

Fichiers à compiler dans le fichier ".MAK" :
* crt0.s
* main_gcc.c

9) Utilisation du "Double-Buffering"

Comme nous avons vu précédemment, la mémoire vidéo offre suffisament de place, dans ce mode, pour y stocker 2 images à la fois. On peut, donc, manipuler une image en mémoire pendant que l'autre est affichée à l'écran, ce qui procure une gain de vitesse lors de l'exécution du programme.

Les questions qui se posent maintenant sont où placer ces 2 images et comment passer de l'une à l'autre?

a- Où placer les images ?

Il existe deux emplacements ("Buffers") en mémoire vidéo pour y placer les images:

b- Comment passer de l'une à l'autre ?

Pour passer d'une image à l'autre, il faut modifier le bit BACKBUFFER du registre DISP_CR :

Pour permuter les deux images il est recommandé d'attendre la "Synchro-Verticale" (l'instant où l'affichage passe du bas au haut de l'écran) ce qui évite de désagréables effets de clignotement de l'affichage.

c- Attente de la Synchro-Verticale (V-BLANK)

La ligne en cours d'affichage est en permanence indiquée par le registre DISP_Y, situé à l'adresse 0x4000006.
Il suffit alors de lire ce registre et d'attendre que la totalité des lignes soient affichées, c'est à dire que la valeur de DISP_Y soit égale à 160 (les lignes de l'écran qui sont réellement affichées sont numérotées de 0 à 159).

Dans le fichier "GBADraw.h", nous avons la fonction WaitVBLANK qui réalise celà :


#define DISP_Y			*(volatile u16*)0x4000004
void WaitVBLANK(){
while(DISP_Y < 160){}
}

Nous remarquons que DISP_Y est déclaré en tant que volatile (ce qui permet d'indiquer au compilateur que cette variable peut être modifiée à tout instant) car au sein de la boucle while elle n'est pas modifiée, le compilateur pensant bien faire ne laissera pas le programme vérifier si sa valeur change au cours de son exécution.

d- Assembler tout celà pour que ça marche

Jusqu'à présent lorsque nous avons manipulé la mémoire vidéo (que ce soit directement ou à l'aide de la librairie DirectGBA) nous ne nous sommes jamais inquiétés de savoir quelle partie de la mémoire vidéo nous adressions...
Pourquoi ? Parce-que nous (ainsi que DirectGBA) utilisions la variable VideoBuffer qui par défaut pointe vers VideoFrontBuffer. Ceci est parfait et nous allons donc continuer comme celà: il suffira de modifier la valeur de VideoBuffer en fonction de la zone mémoire que nous voudrons lire/modifier.

Ainsi, pour basculer l'affichage d'un "Buffer" à l'autre, nous utiliserons la fonction Flip suivante (contenue dans "GBADraw.h"):


void Flip(){
WaitVBLANK();
if (DISP_CR & BACKBUFFER){
DISP_CR &= ~BACKBUFFER;
VideoBuffer = VideoBackBuffer;
}
else {
DISP_CR |= BACKBUFFER;
VideoBuffer = VideoFrontBuffer;
}
}

Après avoir attendu la Synchro-Verticale, cette fonction vérifie quel "Buffer" est actuellement affiché à l'écran:

Un programme utilisant le "Double Buffering" a en général la structure suivante:


void AgbMain(void)
{

	Init();	// initialisation du programme

	
	while(1) // boucle infinie

	{
		ChoixJoueur(); // obtention des ordres du joueur
		AI();	// mouvements joueur, ennemis, physique du jeu...
		Affichage();  // modification du "Buffer" qui n'est pas affiché
		Flip();	// basculement des deux "Buffers"
	}
}

10) Exemple n°6 : Animation

Cet exemple affiche l'animation d'un Walker de Star-Wars.
L'animation est réalisée par l'affichage successif de 17 images. Ces images sont d'un format de 240x160 pixels en 256 couleurs. Ces images ont été converties au format GBA par BMP2GBAX, les 17 images images sont converties ensembles et le résultat est placé dans 2 fichiers: "Mov_Frames.raw" qui contient la totalité de l'animation et "Mov_Frames.pal" qui contient la palette de couleurs.

La copie d'écran suivante permettra de comprendre la manipulation à effectuer avec BMP2GBAX:

 

"main.c" :


/********************************************************
*
* Exemple n°6 : Affichage de l'animation (17 Frames)
* d'un Walker de StarWars en
* double-buffering
*
*
* Cree le : 21.10.2001
* Par : Edorul (edorul@caramail.com)
*
* Ver. : 1.0
* Modifié le
*
********************************************************/
#include "..\DirectGBA\DirectGBA.h"
extern u16 Palette_Bkg; //variable declaree dans "inc_bins.asm"
						// contenant la palette des images
extern u16 Image_Bkg; 	//variable declaree dans "inc_bins.asm"
						// contenant les images des differentes Frames
// Remplissage de tous les index de la palette avec les couleurs de l'image
void RemplPalette()
{
	SetPaletteBKG_All(&Palette_Bkg); //index 0 a 255
}
         
// Remplissage de l'ecran avec l'image
void RemplEcran(u16 *pImage_Bkg)
{
	DrawImg4(pImage_Bkg);
}
void AgbMain(void)
{
	u16 Frame=0;
	//Mise en place des couleurs dans la palette
	RemplPalette();
	//activation du Mode 4 et donc affichage
	SetVideoMode(MODE4|BG2); 
	while(1) {
		//Mise en place des pixels dans la partie de la 
		// memoire video non à l'écran
		RemplEcran(&Image_Bkg + Frame*19200); //19200 = taille d'une image
		//Inversion des deux parties de la mémoire vidéo
		Flip();
		Frame=(Frame+1)%17;
	}
}
       

Compilation avec ARM SDT
Compilation avec GCC 3.0

Fichiers nécessaires à la compilation :
* boot.asm
* inc_bins.asm

* TOUS les fichiers ".H" de la librairie DirectGBA
* main_arm_sdt.c
* Mov_Frames.raw
* Mov_Frames.pal

Fichiers à inclure au projet :
* boot.asm
* inc_bins.asm
* main_arm_sdt.c

Fichiers nécessaires à la compilation :
* crt0.s
* TOUS les fichiers ".H" de la librairie DirectGBA
* Image.h
* Palette.h
* main_gcc.c

Fichiers à compiler dans le fichier ".MAK" :
* crt0.s
* main_gcc.c