|
|
|
Dernière modif : 25/01/2002
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.
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.
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.
Nous pouvons placer la couleur
directement en utilisant l'adresse de l'index 17 de la palette:
*(u16*) 0x5000022 = 0x03E0;
// 17*2 = 34 = 0x22
Ou en utilisant les déclarations
contenues dans la librairie DirectGBA:
PaletteBKG[17] = RGB(0, 31,
0);
Ou encore en utilisant la
fonction SetPalette_Entry
de la librairie DirectGBA:
SetPalette_Entry(17, RGB(0,
31, 0));
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 );
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.
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
Il faut tout d'abord récupérer
le groupe des deux pixels situés ligne 3, colonne 2 en mémoire
(soit colonnes 4 et 5 à l'écran):
u16 peek = VideoBuffer[2+3*120];
//emplt mém: lig 3, col 2 (col 4 & 5 à
l'écran)
Placer 17 (qui est l'index
de la couleur verte) dans l'octet de poids fort du mot de 16 bits (peek)
que nous venons de récupérer en mémoire, en masquant
l'octet de poids faible:
u16 send = (0x00FF & peek)
+ (17<<8);
Renvoyer les deux pixels contenu
dans send dans leur emplacement mémoire initial:
VideoBuffer[2+3*120] = send;
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));
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 );

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 : Fichiers
à inclure au projet : |
Fichiers
nécessaires à la compilation : Fichiers
à compiler dans le fichier ".MAK" : |
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").
La conversion se fait (comme pour le Mode 3) avec BMP2GBAX.
Pour convertir "Pastel256.bmp" avec BMP2GBAX, il faudra:
Lancer BMP2GBAX
Ouvrir "Pastel256.bmp" en cliquant sur Add Bitmap(s) et en retrouvant l'image sur le disque dur.
Sélectionner Preset 5 (bitmapped, palettized: 256/1), c'est l'option qui permet de convertir l'image pour quelle puisse être utilisée par le Mode 4.
Cocher l'option Export palette (if any) to <filename>.pal, c'est l'option qui permet de créer un fichier, avec comme extension ".PAL", qui contiendra l'ensemble des couleurs de la palette.
Cliquer sur Process et choisir un répertoire de destination et un nom pour son fichier binaire, par exemple "Pastel-8b.raw"
Le fichier binaire "Pastel-8b.raw" et le fichier de palette "Pastel-8b.pal" sont créés. On peut alors quitter BMP2GBAX
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
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:
Pour accéder aux
données contenues dans les tableaux Image_Bkg
et Palette_Bkg
de nos fichiers d'en-tête "Image.h" et "Palette.h",
il suffit de les inclure dans notre programme en C:
#include "Image.h"
#include
"Palette.h"
Image_Bkg
et Palette_Bkg
s'utilisent comme des tableaux tout à
fait normaux, à la différence que l'on ne peut pas y
écrire car ils sont déclarés en tant que constante.

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 : Fichiers
à inclure au projet : |
Fichiers
nécessaires à la compilation : Fichiers
à compiler dans le fichier ".MAK" : |
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?
Il existe deux emplacements ("Buffers") en mémoire vidéo pour y placer les images:
Pour passer d'une image à l'autre, il faut modifier le bit BACKBUFFER du registre DISP_CR :
Si BACKBUFFER
= 0 : c'est le VideoFrontBuffer qui est affiché à
l'écran.
Pour obtenir celà, utiliser la ligne de code suivante:
*(u16*) 0x4000000 &= ~0x10;
ou en utilisant les définitions contenues dans la librairie DirectGBA:
DISP_CR &= ~BACKBUFFER;
ou encore en utilisant les fonctions contenues dans la librairie DirectGBA:
DisableVideoMode(BACKBUFFER);
Si BACKBUFFER
= 1 : c'est le VideoBackBuffer qui est affiché à
l'écran.
Pour obtenir celà, utiliser la ligne de code suivante:
*(u16*) 0x4000000 |= 0x10;
ou en utilisant les définitions contenues dans la librairie DirectGBA:
DISP_CR |= BACKBUFFER;
ou encore en utilisant les fonctions contenues dans la librairie DirectGBA:
EnableVideoMode(BACKBUFFER);
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.
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.
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"
}
}

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 : Fichiers
à inclure au projet : |
Fichiers
nécessaires à la compilation : Fichiers
à compiler dans le fichier ".MAK" : |