❤ 0
Chapitre 4 : Décryptage du premier code source !
Le compilation se passe bien, vous avez lancé le fichier binaire dans un émulateur, vous avez un hello world à l'écran. Mais vous avez rien bitté au deux fichier c. Le main et le font ! Pas de panic nous allons en parler, et en même temps commencer à apprendre le langage C. Enfin la Base, car je ne suis pas un spécialiste. Mais je vais vous apprendre ce que je sais faire ! Après ça sera à vous de continuer sur le chemin de la création, en vous documentant bien comme il le faut sur les différents site, livre, et autre pour vous améliorer dans ce langage.
Histoire du C
Le C est un langage de programmation des années 70. Il fut inventé pour réécrire unix. (Wiki est mon ami). C'est un peu le papa de beaucoup de langage. Son auteur est Dennis Ritchie est possèdes plusieurs norme. ANSI C,C89,C11... Pour faire simple, une norme c'est la façon d'écrire le C
Le C est un langage structuré,procédural et impératif. Ce qui veux dire en gros, qu'il faut bien structurer sa programmation avec divers fichiers, des conditions, des boucles et éviter de se balader d'un point à un autre avec la fonction GOTO qui rend son code illisible. (Ah le Basic chez les débutants).
Procédural car on va construire son programme avec des sous programmes qui peuvent être appellé de n'importe ou.
(Je simplifie bien sur la vision)
La C contrairement à son petit fréro, le C++ ou d'autre langage de programmation comme le C#, le ruby, le javascript, le java... n'est pas un langage object.
Un sous programme, si on lui passe pas des paramètres, ne va pas intégrer les données d'un autre sous programme comme ça...
Le C à la falculté de travailler directement dans la mémoire de l'ordinateur. C'est un langage dit Bas niveaux pour cette partie. Proche des éléments éléctronique de l'ordinateur. Moins que l'assembleur mais quand même. Avec le C on manipule beaucoup la mémoire,et les adresse mémoire de la machine cible. Les pointeurs. Ce qui permet d'économiser de la mémoire dans ses programmes.
Le C permet donc pour ça de choisir des "Variables" de différente taille. Allant d'un octet pour les variables dit de type Char à 8 octets ,16,32... Ce n'est pas le seul langage à proposer ça. Pour information, l'amos sur Amiga, une variable numérique c'est 4 octets, il n'y pas beaucoup de typage de variable, c'est pareil avec Second Basic pour créer des jeux avec le langage Basic sur Megadrive !
Le C est donc un langage de choix sur les petits systèmes et donc adapté pour les machines rétro que nous voulons programmer. Le choix du C est beaucoup utilisé pour les SDK amateur de nos vielle machine.
Fichier main.c
1
2
3
| // Intégration du fichier SMSlib.h
// la bibliotheque du DevKitSMS.
#include "header/SMSlib.h" |
Débutons avec ceci. La fonction #include permet d’intégrer un fichier dans un autre fichier.
La pour notre exemple quand on va passer les fichiers à la moulinette avec le compilateur, le contenu du fichier SMSlib.h qui se trouve dans le dossier header, sera ajouté dans ce fichier même.
En principe un fichier.h contient des tas de choses importante comme indiquer au compilateur: attention je vais utiliser cette espace mémoire pour pouvoir utiliser une fonction qui va permettre de déplacer mon sprite ! Le compilateur est prévenu, il va donc bloquer une plage mémoire dans son programme pour ça ! Je simplifie bien sur mais l'idée est la.
1
2
3
| // En tête de la rom pour que cela soit lisible sur Master System.
SMS_EMBED_SEGA_ROM_HEADER(0,0);
SMS_EMBED_SDSC_HEADER(0,0,2018,01,02,"Monos","Hello_World","Test") ; |
Voici deux fonctions de notre bibliotheque adoré. C'est tous simplement l'entete du fichier binaire obligatoire pour la master system.
On reviendra dessus plus tard !
1
2
3
4
5
| void main (void)
{
…….
}
|
Voici la fonction la plus importante du programme. C'est quoi une fonctions ? C'est tous simplement un morceau d'un programme (ici main) avec du code dedans, qui peut être appelé ! On peux lui injecter des donnés et une fonction peut retourner une résultat. (Un et un Seul!!!)
Le petit mot en bleu void veux dire "Rien", "néant" "nada", placer devant le nom, veux dire le type de donné que la fonction va retourner, et renvoyer. La c'est rien, la fonction main ne vas rien renvoyer ! On parle aussi dans ce cas la de Procédure. Le void entre parenthèse veux dire aussi qu'il n'attend rien comme donnée quand on appelle main ! …
La fonction main est un peux spécial, c'est le début du programme, il est obligatoire.
Ensuite nous avons les deux accolades. { }
En C, une fonction/procedure doit avoir une accolade ouvrante qui marque le début et une accolade fermente qui merque la fin ! C'est un "bloc". A vrais dire beaucoup d'instruction sont comme ça. Ah ah.
1
| extern unsigned char Font_Namco[]; |
Alors la il est placé dans main ! Au début du main.
Extern veux dire : va cherche le truc à l'extérieur de ce fichier pour que je puisse l'utiliser. C'est une variable Global ! La phylosophye du C c'est déviter au maximum ce genre de variable quand nous le pouvons.
Unsigned char c'est un typage de variable. char veux dire que la variable va prendre une case mémoire. Donc 1 octet. Une valeur entre 0 et 255 soit 256 possibilité. Si on ne place pas le mot unsigned, ba le compilateur va comprendre grosse merdo une valeur entre -127 et 127. Un bit pour indiquer le signe et 7 bites pour la valeur. Le unsigned élimine tout ça et permet de gérer les 8 bits de la case.
Font_Namco[] c'est tout simplement le nom d'un tableau ! Une série de variable tous simplement. C'est la série de valeur contenu dans le fichier font.c, on va donc le placer ici pour qu'il soit lisible dans le programme main !
1
2
| SMS_setBGPaletteColor(0, RGB(0,0,0)); // couleur 0
SMS_setBGPaletteColor(1, RGB(2,2,2)); // couleur 1 |
Ayez on entre dans le domaine de la Master System.
On va appeler deux fois une fonction de la bibliotheque devkitsms "SMS_setBGPaletteColor(a,b)"
cette fonction, permet tout simplement de remplacer la couleur à une position voulu avec la couleur voulu, dans la palette dédié au Background ! (Donc palette tiles).
La master System possède deux palettes, une pour les tiles, et une pour les sprites. Chaque palette permet de mémoriser 16 couleurs. (De 0 à 15).
La on mémorise l'index 0 et l'index 1 de la palette des tiles !
Notons qu'une instruction doit se terminer par un ;
C'est un piège à con et une source d'erreur monumentale donc faite bien attantion.
1
| SMS_loadTiles (Font_Namco, 1, 0x38*32); |
Cette fois si on va injecter dans la mémoire vidéo de la master system, les graphismes voulu qui sont présent dans le tableau Font_Namco. Nous allons débuter à la position 1, et le 0x38*32 c'est la taille en octet des données.
Il y a 0x38 tiles de 8*8 pixelq .le 0 x c'est pour annoncer au compilateur que nous allons parler en Hexadécimal. Ce qui fait 56 tiles à mémoriser. Et *32 car un tile à pour taille, 32 octets. Ce qui fait donc 1792 octets, (1,8ko). On peux remplacer 0x38*32 par 1792 ou 0x1792 ou 0b11100000000
0b c'est pour annoncer que nous injectons une valeur en langage binaire.
Une fonction pour "allumer" l'écran de la master system. Le Off permet de l'éteindre.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
SMS_setTileatXY(7,7,18) // H
SMS_setTileatXY(8,7,15) // E
SMS_setTileatXY(9,7,22) // L
SMS_setTileatXY(10,7,22)// L
SMS_setTileatXY(11,7,25)// P
SMS_setTileatXY(13,7,33)// W
SMS_setTileatXY(14,7,25)// O
SMS_setTileatXY(15,7,28)// R
SMS_setTileatXY(16,7,22)// L
SMS_setTileatXY(17,7,14) // D
|
SMS_set_TileatXY(x,y,id)
C'est une fonction qui permet d'afficher le numéro du tile(id) en mémoire à la position X et Y de l'écran.
Mais attention, les positions X et Y sont exprimés en Case et non en pixel.
Dans mon exemple, le W de World, il est posé à la 13em case en Largeur ( et 7em case en hauteur (Y) . Enfin pour être exacte c'est la 14em cases en X et 8em cases en Y, la première case débute à 0. Enfin 33, c'est la place en mémoire ou se trouve l'élément graphique qui représente le W.
Ah, j'avais dit qu'il fallait des ; à chaque fin d'instruction. Le "SMS_set_TileatXY(x,y,id)" qui se trouve dans la bibliothèque estune Défine. Ce n'est donc pas une "fonction" a proprement parlé mais un morceau de code qui sera remplacer par une vrais fonctions ou un autre morceau de code. Et l'auteur a placé un ; dans le morceau remplacé. donc pas besoin de ; à la fin de cette "fonction".
Pour information le "SMS_set_TileatXY(x,y,id)" sera remplacé à la compilation par :
SMS_setAddr(XYtoADDR((x),(y)));
SMS_setTile(tile); Qui sont aussi des défine (ou macro) qui sera remplacé par autre chose bref un tas de noeux, mais sans trop d'importance...
1
2
3
4
5
6
|
while (1)
{
SMS_waitForVBlank();
}
|
Ah une boucle. While() c'est une boucle. Nous avons toujours les accolades d'ouverture et de fermeture. En gros quand on va à l'accolade de fermeture dans une boucle, on repart au début ! Il y a un petit test et si c'est vérifié, on continu à exécuter la boucle.
Ici nous avons un 1 entre parenthèse. Ce qui veux dire que c'est toujours vrais !
Donc la boucle va se jouer à l'infini ! C'est une boucle infini quoi.
Attention c'est le MAL ! Source de bug xd mais bon nous sommes sur console et comment on quitte un jeu sur console ? Ba avec le bouton power off ! Donc si c'est la boucle principale (ou boucle du jeu) du programme sur console, nous pouvons faire ça, pour 99% des autres cas, c'est bien sur déconseillé !
Cette fonction permet tout simplement d'attendre que le balayage de l'écran reviennent en haut pour continuer le programme !
(Tips : Sur Master System on le place aussi avant d'afficher des graphismes, chose que je n'ai pas fais ici... bouhhh)
Fichier font.c
Aller un petit tour dans le fichier font.c
1
| const unsigned char Font_Namco[]={….} ; |
Alors plusieurs chose la pour débuter.
Const : c'est tous simplement un petit mot qui veux dire constante donc que nous allons mémoriser ça dans la ROM. Cela protège en "écriture" Et sur console par exemple cela évite que les données partent dans la Ram de travaille.
Unsigned char, c'est le typage de notre tableau. Unsigned veux dire non signé, donc on va pas dans les valeurs négative. Et char c'est tous simplement pour dire que chaque élément aura pour taille 1 octet donc 8 bits.
Font_Namco veux dire ceci est un tableau qui à pour nom Font_Namco.
[] : Normalement on doit intégrer le nombre d'élément du tableau mais ça marche bien sans les mettre pour sdcc.
={} ; ne pas oublier le égale, les accolades et le point virgule dans les tableaux.
Dans le tableau en lui même nous avons des valeurs et des virgules.
0x1C ,0x00 , ….
Chaque élément du tableau est séparé par une virgule.
Et le 0xValeur veux tous simplement dire que c'est une valeur héxadécimale.
Le tableau Font_Namco contient tous simplement les graphismes représentant une police de caractère que j'ai vite fait arrangé pour que cela soit lisible pour notre exemple.
Voilà pour le décryptage des fichier. Nous reviendrons bien sur sur les éléments avec plus de détaille et d'explication car la ce n'est qu'un survole du petit code source.
Pour le prochain tuto, je parlerais des couleurs de la master system, et comment encoder notre premier tiles de 8 pixel dans la mémoire! Car c'est peut être le truc le plus important et le plus dure à comprendre au départ.
Rassurez vous, un peu plus tard nous aurons pas besoin d'encoder à la main les graphismes du jeu !
|