Saturday, March 24, 2018

Tutoriel libgeds - jour 2

Bon, avant de voir comment le moteur 'GEDS' peut charger des images dans la mémoire vidéo de la Nintendo DS, il faut que je vous explique un peu comment son processeur graphique construit les images que l'on voit à l'écran. J'utilise le mode "texte", ici, où les images sont composées d'élément de 8x8 pixels appelés "tiles" (prononcez 'taïlesz') que l'on dispose sur une grille.

Vous avez tous déjà utilisé un éditeur de donjons RPG où l'on travaille carré par carré (je crois qu'on dis volontiers des 'chips' ?) plutôt que de mettre un arbre ou une maison d'un coup. Le mode texte de la DS va un cran plus loin: la mémoire de la machine elle-même est découpée en une région pour retenir des pavés de 8x8 (le 'tileset') et une région pour indiquer quel pavé montrer à quel endroit (la 'map' de l'écran, couvrant généralement 256x256 pixels pour la DS). Parfois, on mettra le même tile à plusieurs endroit de l'écran (en inscrivant juste son numéro dans plusieurs cases de la map), et parfois un tile ne sera pas repris (pour l'instant). C'est une technique a peu près aussi vieille que les machines 8-bit et qui a perduré pendant toute la période 16-bit (mais ça, c'est une autre histoire). Ce qui a changé au fil du temps, c'est le nombre de couleurs autorisées par tile (de 3 pour la NES à 255 pour la NDS) et le nombre de calques que l'on peut superposer pour obtenir l'image souhaitée (jusqu'à 4 sur la NDS).

Les fichiers .spr créés par le SpriteEditor pour DS sont principalement une sauvegarde du contenu de la mémoire vidéo tel qu'on voudrait l'avoir pendant le jeu. Du coup, il n'y a vraiment pas grand-chose à faire pour pouvoir les importer dans son programme.

Code:
  SpriteRam myRam(WIDGETS_CHARSET(512));
  SpriteSet mySet(&myRam, BG_PALETTE);

  mySet.Load("efs:/bg.spr");
Et voilà. quelques précisions pour dire au moteur de jeu où mettre les graphismes (ici, sur l'écran "du haut", en laissant 512 emplacement pour une police de caractère et pour les 'maps' des différents calques) et où mettre la palette de couleur présente dans le fichier .spr (également dans la mémoire de palette de l'écran supérieur). La classe SpriteSet du moteur de jeu s'occupe de manipuler le fichier et d'en reconnaître le format. On pourrait aussi prendre le contrôle de toute la mémoire vidéo en utilisant directement myRam(BG_GFX), mais c'est un peu moins confortable pour la suite.

Bon, malheureusement, avoir des graphismes en mémoire ne suffit pas pour les avoir à l'écran. La démo n°2 doit aussi configurer la puce graphique pour qu'elle utilise nos données et remplir la grille/map d'un des calques.

Code:
REG_DISPCNT|=DISPLAY_BG2_ACTIVE;
REG_BG2CNT=BG_MAP_BASE(GEBGROUND)|BG_TILE_BASE(0)|BG_COLOR_256;
La configuration, on va régler ça en programmant directement les registres de la puce graphique. C'est tellement facile sur DS . J'active le bit correspondant au calque n° 2 (j'l'aime bien, celui-là) dans le contrôle principal de l'écran (REGister_DISPlayCoNTrol), puis je donne les paramètres de ce calque dans son registre à lui: les données des tiles seront interprétées comme ayant 256 couleurs, quelle grille utiliser comme map, et si je veux ajouter automatiquement un décalage à tous les numéros de tiles de la map (BG_TILE_BASE) par rapport à la position dans la mémoire du tileset (ce que je ne fais pas ici).

La bibliothèque 'libgeds' donne des paires de noms à différentes grilles: un nom pour la configuration de BG_MAP_BASE, et un nom pour le tableau correspondant dans la mémoire vidéo (WIDGETS_BACKGROUND). Du coup avec la configuration qu'on vient de faire, on peut changer le pavé en haut à gauche de l'écran en écrivant dans WIDGETS_BACKGROUND[0]. Dans celui en haut à droite avec WIDGETS_BACKGROUND[31] (parce qu'il y a 32x8 dans 256 ) et WIDGETS_BACKGROUND[32] sera le pavé juste en-dessous de WIDGETS_BACKGROUND[0]. Et ainsi, ligne après ligne. Bref, avec un peu de sucre et une feuille de papier, vous arriverez rapidement à voir que WIDGETS_BACKGROUND[32*ligne+colonne] vous permet de modifier n'importe quel emplacement de l'écran.

Code:
for (int l=0; l<32; l+=2) {
  for (int b=0; b<8; b+=2) {
    WIDGETS_BACKGROUND[b+l*32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +1 ]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +33]=tile++;
  }
}
Moi, j'avais envie de montrer l'ensemble des graphismes de mon fichier .spr, tels qu'on les voit dans l'éditeur. Et dans le quart le plus à gauche de l'écran (une zone de 64x192 pixels). Il reste un petit truc à régler: l'éditeur travaille par blocs de 16x16 pixels, pour le confort du graphiste. En interne, un bloc est composé de 4 tiles de 8x8 pixels, agencés eux aussi suivant le mode "une ligne, puis l'autre". Si je veux que les blocs ne se retrouvent pas coupés en 2, je dois respecter cet agencement au moment de remplir la grille:
Code:
/* 0 1
 * 2 3
 */
D'où les boucles qui passent une ligne sur deux et les quatres écritures à WIDGETS_BACKGROUND par itération.

Voilà. Le code est sur github, donc. Avec le fichier .spr (creative common)


N'hésitez pas à me ralentir avec quelques questions si ça va trop vite pour vous.

No comments: