Tutorial : Les sprites sur Coleco
Sur Coleco il y à en gros 3 zones de mémoire :
La RAM : 1 ko au total, mais beaucoup moins (600 octets ?) avec la librairie de Daniel Bienvenue
La ROM : 32 ko, ou on va stocker les graphismes, la musiques, les données que l'on a besoin mais qui n'évoluent pas.
La VRAM : la mémoire vidéo qui est composée ainsi :
#define chrtab 0x1800 /* écran en linéaire */
#define chrgen 0x0000 /* table des caractères */
#define coltab 0x2000 /* couleur des caractères */
#define sprtab 0x3800 /* sprite_pattern_table */
#define sprgen 0x1b00 /* sprite_attribute_table */
#define buffer 0x1c00 /* écran 2 en linéaire */
Ce qui nous intéresse pour les sprites c'est :
sprtab : zone de mémoire qui va contenir les dessins (composé de patterns) des sprites
sprgen : zone de mémoire qui va contenir la définition des sprites (x,y,pattern,colour)
Dessiner des sprites :
On utilise l'outil de Daniel Bienvenu ICVGM303.exe qui permet de dessiner des dessins de sprites de 16x16 pixels. Un dessin de sprite de 16x16 est composé en fait de 4 patterns.
Un pattern est une zone de 8x8 pixels.
Donc, le 1er dessin commence au pattern 0 et est composé des patterns 0,1,2,3
Le second dessin commence au pattern 4 et est composé des patterns 4,5,6,7
et ainsi de suite.
Injecter les sprites en mémoire :
Avec l'outil de Daniel, il faut générer un fichier C, compressé en RLE (case à cocher). Ce qui nous intéresse c'est la zone :
byte SPATTERNRLE[] = {
0x88, 0x00, 0x06, 0x01,...};
C'est la définition des patterns de sprites. IMPORTANT : injecté dans notre programme on doit ABSOLUMENT ajouter un const.
const byte SPATTERNRLE[] = {
0x88, 0x00, 0x06, 0x01,...};
Sinon à terme il y auras des plantages, car les patterns seront n'importe ou en mémoire, et pas en ROM.
Maintenant, il faut injecter ce tableau en VRAM avec la commande :
rle2vram(SPATTERNRLE,sprtab);
NMI :
Dans le programme en C, il faut absolument créer une fonction
void nmi()
{
}
Mème si elle est vide, cette fonction va s’exécuter 50 fois par seconde sur une Coleco PAL et 60 fois par seconde sur une Coleco NTSC. On va voir ensuite à quoi ça va nous servir.
Manipuler les sprites en RAM :
Dans la librairie de Daniel les sprites ont déjà leur objet définit à savoir :
typedef struct
{
byte y;
byte x;
byte pattern;
byte colour;
} sprite_t;
sprite_t sprites[32];
{
byte y;
byte x;
byte pattern;
byte colour;
} sprite_t;
sprite_t sprites[32];
il n’y à donc pas besoin de redéclarer le tableau !! Par contre il est conseillé de rendre invisible les sprites.
Void initSprites()
{
byte i ;
for (i=0 ;i<32 ;i++) sprites[i].y = 204 ;
}
En fait, au dessus d’un y > 192, le sprite est invisible. Attention : Eviter y=203, en effet cette valeur signale à la Coleco qu'il n'y à plus de sprites à traiter après celui-ci.
Ensuite, on définit comme on veux les sprites :
sprites[0].p = 8 ; // Le sprite 0 aura le dessin n°2 (Dessin 0 = 0 ;Dessin 1 = 4 ; Dessin 2 = 8)
sprites[0].colour = 3 ; // Avec un code couleur 3
sprites[0].x = 0 ;
sprites[0].y = 100 ;
Puis on le fais bouger
while(1)
{
sprites[0].x ++ ;
}
Problème, avec ça on ne vois rien bouger … NORMAL !!
Transférer les informations de la RAM vers la VRAM :
put_vram (0x1b00,sprites,128) ; // copie le tableau sprites vers la sprgen 4 attributs (x,y,colour,p) * 32 sprites = 128 octets
Sauf, qu’il faut faire cela, à chaque changement dans le tableau en RAM . Et donc pour faire simple, il suffit de faire cela, 50 ou 60 fois pas seconde.
Bref, on claque ça dans la NMI et on est tranquille !!
void nmi()
{
put_vram (0x1b00,sprites,128) ;
}
Le flickering :
La Coleco à une sale contrainte c’est qu’elle ne peut pas afficher plus de 4 sprites en simultané sur une ligne horizontale.
Si on veux afficher les sprites suivants sur la même ligne :
0 1 2 3 4 5
seul les sprites 0 1 2 3 seront affiché, en fait, les sprites avec les n° les plus petits sont prioritaires !
En gros si tu veux faire afficher plus de 4 sprites par ligne, il va falloir changer la priorité des sprites. J’utilise une technique, qui permet d’afficher au moins 8 sprites par lignes
D'abord une routine qui ramène le n° d'un sprite libre (y==204), on recherche à chaque fois à partir d'une position de début différente. Ramène -1 si il n'y à plus de sprites de libre.
#define INACTIF 204
byte odd ; // variable globale a mettre en dehors du main
byte currentFlicker;
sprite_t bsprites[32]; // seconde Zone de sprites en RAM
char getFreeSprite()
{
byte i;
odd+=8;
if (odd>=32) odd = 0;
for (i=odd;i<32;i++)
if (sprites[i].y==INACTIF)
return i;
for (i=0;i<odd;i++)
if (sprites[i].y==INACTIF)
return i;
return -1;
}
Dans la Nmi on va copier en VRAM, une fois les sprites dans l'ordre
0......31
Et une fois
16,17....31 0,1,2,...15
void nmi()
{
// Si currentFlicker = 2 alors on copie les sprites de 0 à 31, priorité normale
if (currentFlicker==0) {put_vram (0x1b00,sprites,128); currentFlicker=1;}
else // Sinon les sprites 16 à 31 sont copié à partir de 0 et le reste à partir de 16, on intervertit les priorités.
{
memcpyb(bsprites,sprites+16,64);
memcpyb(bsprites+16,sprites,64);
put_vram (0x1b00,bsprites,128);
currentFlicker = 0;
}
}
Voilà, j'essayerais de faire un autre tuto pour déterminer quand écrire dans la VRAM sans risque, chose plutôt délicate à appréhender sur Coleco.
A bientôt !
Beau tuto bfg ;-)
RépondreSupprimerTOUKO.