1. Introduction▲
L'épisode précédent de nos folles aventures à l'intérieur de la GameBoy Advance a marqué la description des cartes et des tiles au sein du matériel. Pour mémoire, les données relatives aux tiles se trouvent présentes dans les "character base blocks" et les informations de la carte sont placées dans les "screen base blocks". Nous avons à notre disposition quatre "character base blocks" de 16ko chacun et 32 "screen base blocks" de 2ko chacun. L'exemple étudié ici utilise uniquement un background en mode rotation et en 256 couleurs. Le cas particulier des backgrounds en mode texte sera étudié plus tard.
Les données de la carte sont représentées par un ensemble d'octets désignant chacun un tile. Ainsi, puisque chaque tile se voit numéroté sur un octet, nous ne pouvons employer plus de 256 tiles distincts. Puisque la représentation de chaque tile nécessite 64 octets, nous pouvons vérifier par le calcul la taille des "character base blocks" : 256 * 64 = 16 384 octets, soit 16ko.
La taille maximale en pixel d'une carte est de 1024 pixels par 1024. Or chaque tile occupe une surface de 8 pixels par 8. Nous ne pouvons donc avoir au maximum que (1024 / 8) * (1024 / 8) = 16 384 tiles pour une carte. Puisque chaque tile se voit désigné dans la carte par un octet, une carte occupe au maximum 16ko, soit la taille exacte d'un "character base block".
2. Contrôle des backgrounds▲
Pour contrôler un background, qui désigne une surface d'affichage pour une carte et ses tiles, le programmeur doit manipuler un registre de 16 bits. Il existe quatre registres de contrôle, pour les quatre backgrounds possibles : les registres REG_BG*CNT. Les deux premiers bits de ces registres définissent la priorité d'affichage (entre 0 et 3) du background. Les deux bits suivants désignent le "character base block" choisi. Puis les bits 4 et 5 restent inusités. Viennent deux bits concernant les drapeaux de mosaïque et de couleur. Le drapeau de mosaïque permet de réaliser les effets de pixellisation couramment employés dans les jeux. Le second drapeau définit le nombre de couleurs des tiles, la valeur 1 correspondant au mode 256 couleurs et la valeur 0 au mode 16 couleurs. Les bits 8 à 12 spécifient le numéro de "screen base block" sélectionné. Le bit 13 constitue le drapeau de retour de flot (ou "wraparound"). Si ce bit possède la valeur 1, la carte sera répétée lorsqu'un des bords sera atteint par défilement, autrement rien n'apparaît. Enfin, les deux derniers bits servent à sélectionner la taille de la carte. Le tableau numéro un précise la taille prise par la carte pour les différentes valeurs de ces bits.
Taille | 0 | 1 | 2 | 3 |
Rotation | 256*256 | 512*256 | 256*512 | 512*512 |
Texte | 128*128 | 256*256 | 512*512 | 1024*1024 |
Pour simplifier la création et la manipulation des cartes, particulièrement lors de rotations et de mises à l'échelle, nous créons une structure relativement simple décrite dans le listing numéro un. Les noms des différents attributs de la structure sont suffisamment explicites pour que vous en compreniez le rôle. Les deux pointeurs tileData et mapData ne sont pas indispensables à la création et à l'affichage d'une carte. Toutefois, ils trouvent leur utilité si vous souhaitez modifier la carte en temps réel. Ainsi, pour accéder au tile de coordonnées (x, y) de la carte, vous pourrez rédiger la ligne de code suivante :
monBackground->
mapData[x +
y *
64
] =
tileNo;
La multiplication par 64 possède une explication très simple si nous considérons une carte de taille 2 en mode rotation, soit une carte de 512 pixels par 512. Avec de telles données, la carte possède (512 / 8) = 64 lignes de tiles contenant chacune (512 / 8) = 64 colonnes. L'accès aux éléments des cartes se veut aisé avec les backgrounds en mode rotation. Pour les backgrounds en mode texte, qui ne peuvent employer de vecteur linéaire puisque n'étant pas "carrés", les choses se compliquent un peu.
/* Listing 1 */
typedef
struct
t_Background
{
u16*
tileData;
u16*
mapData;
u16 size;
u8 mosaic,
colorMode,
number,
charBaseBlock,
screenBaseBlock,
wrapAround;
}
Background, *
pBackground;
3. Création et affichage d'une carte▲
La création d'une carte suppose en premier lieu de se munir d'une planche de tiles. Il s'agit simplement d'une image carrée dont les dimensions sont multiples de 8. A l'aide d'un outil de conversion de sprites en code C nous créons les données relatives aux tiles. Nous devons ensuite nous saisir d'un éditeur de carte. Celui-ci permet de charger la planche de tile, de choisir la taille de la carte, de dessiner la carte à l'aide des tiles puis d'exporter le résultat sous forme de fichier C. Les différents éléments relatifs à la génération de notre carte trouvent place sur le CD-Rom dans le sous-répertoire "tools/" de notre programme. Nous générons ainsi les fichiers tiles.c et map.c.
Une fois créée notre structure de background, nous devons procéder à son affichage. L'ensemble de ces opérations se trouve dans la fonction initBackground() du fichier main.cpp du programme. Dans notre exemple, nous créons le background 2 d'une taille de 512 pixels par 512, adressé au "character base block" 3 et au "screen base block" 31. La méthode enableBackground() de l'en-tête background.h active la carte en remplissant le registre approprié. Ainsi pour notre background 2 nous exécuterions :
REG_BG2CNT =
bg->
size |
(
bg->
charBaseBlock <<
8
) |
(
bg->
screenBaseBlock <<
2
) |
bg->
colorMode |
bg->
mosaic;
Souvenez-vous cependant de la mise en place du mode graphique. Jusqu'à présent, nous utilisions les modes graphiques 3 et 4 pour afficher des images. Vous devez donc modifier l'instruction de sélection du mode graphique pour activer le mode 2, qui autorise les backgrounds de type rotation.
REG_DISPCNT =
MODE_2 |
BG2_ENABLE |
OBJ_ENABLE |
OBJ_MAP_1D;
Remarquez également la mise en place du drapeau BG2_ENABLE. En omettant ce drapeau, notre background ne pourrait apparaître. Si vous modifiez le numéro de background associé à la structure, pensez également à modifier le drapeau d'activation des backgrounds.
Même si tout a été mis en place correctement jusqu'à présent, notre programme n'a aucune chance d'afficher une carte. Il manque en effet le chargement des données de la carte en mémoire. Le listing deux présente cette étape en détail. Ces quelques lignes chargent dans l'ordre la palette de couleur des tiles, les tiles eux-mêmes (avec des instructions DMA) puis la carte. La division par deux est justifiée par le fait que nos copies agissent sur des segments de 16 bits de données tandis que les zones mémoire sources recèlent des données enregistrées sur 8 bits.
/* Listing 2 */
for
(
int
i =
0
; i <
256
; i++
)
palette[i] =
tilesPalette[i];
REG_DMA3SAD =
(
u32) tilesData;
REG_DMA3DAD =
(
u32) bg2->
tileData;
REG_DMA3CNT =
tiles_WIDTH *
tiles_HEIGHT /
2
|
DMA_16NOW;
u16*
temp =
(
u16 *
) map;
for
(
int
i =
0
; i <
64
*
64
/
2
; i++
)
bg2->
mapData[i] =
temp[i];
4. Téléchargements▲
Nous vous recommandons de télécharger l'exemple associé à cet article.
Version PDF de l'article (20 Ko).
Liens :