SPRITES
1)
Afficher un sprite à l'écran.
D'abord, il faut définir le mot "sprite". Car en réalité, ce n'est
qu'une succession de bits qui sont déplacés d'une mémoire à une
autre. Le meilleur exemple pour bien comprendre la méthode d'affichage
est d'utiliser un bout de poème (la poésie de l'assembleur ?). Si
j'écris :
D'une mémoire
à l'autre et avec des rotations ton sprite en position tu vois comme
les autres... (c'est nul, mais bon...)
Vu comme ça, on imagine mal que c'est un bout de poème. Mais si
on passe à la ligne :
D'une mémoire
à l'autre
Et avec des rotations
Ton sprite en position
Tu vois comme les autres...
Cette fois la rime "abba" saute aux yeux, tout simplement parcequ'on
est allé à la ligne. Et bien losrque l'on copie le sprite vers l'écran,
c'est la même chose, il faut aller à la ligne pour que l'on puisse
voir quelque chose. Il suffit juste de remplacer les lettres par
0 ou 1.
2) Définition
d'un sprite.
Dans n'importe
quel guide sur le 68000, il y a ce genre d'explication. Donc je
ne vais pas m'étendre là dessus car de toute façon il suffit juste
de copier :
dc.b
%01010101 (8 bits)
dc.w
%0101010101010101 (16 bits)
dc.l
%01010101010101010101010101010101 (32 bits)
Il est sous-entendu
que derrière les %, on met ce que l'on veut du moment que c'est
compris en 0 et 1. Et pour définir plusieurs lignes, et bien on
les empilent...
dc.b %01010101
dc.b %01010101
dc.b %01010101
(...)
Mais voilà le
plus amusant dans la programmation, c'est que l'on peut représenter
la même chose de nombreuses manières ainsi :
dc.l %01010101010101010101010101010101
est équivalent
à :
dc.w %0101010101010101
dc.w %0101010101010101
ou aussi équivalent
à :
dc.w
21845 (21845 en décimal représente 0101010101010101 en binaire )
dc.w 21845
Conclusion :
un nombre est une suite de 0 et de 1. Une suite de 0 et de 1 constitue
des données. Des données peuvent servir à représenter un sprite.
Un nombre peut donc convenir pour définir un sprite...
3) Obtenir
l'adresse du sprite et l'adresse de l'écran
Pour pouvoir
afficher un sprite à l'écran, il faut bien sûr savoir où est placer
le début du sprite en mémoire, idem pour l'écran. Pour celà on va
définir un label unique pour chaques sprites, et demander l'adresse
de l'écran grâce à une variable qui est faite pour celà.
Le label se note
:
nom_du_label:
En dessous du
label on définit le sprite :
nom_du_label:
dc.b
%01010101 (8 bits)
Et donc lorsque
l'on veut obtenir l'adresse du sprite, et que l'on veut par exemple
que le registre a0 (qui n'est rien d'autre qu'une varible dont on
ne peut pas choisir le nom) contienne cette adresse, il suffit de
mettre dans son code source :
lea nom_du_label,a0
LEA signifiant
Load Effective Adress, celà veut dire que l'on "charge" nom_du_label
dans a0, ou plus simplement que l'on demande au processeur de placer
l'adresse du début de sprite dans le registre d'adresse a0.
Et pour obtenir
l'adresse de l'écran, c'est tout simplement en déplaçant la valeur
de la variable LCD_MEM dans a0 (au fait, je dis a0, mais ça peut-être
n'importe lequel des registres entre a0 et a6. On peut utiliser
a7 mais c'est extrêmement déconseillé, à moins de le remettre comme
vous l'avez trouvé en finissant).
Pour obtenir
l'adresse de l'écran, on utilise l'instruction move.l et la variable
s'appelle LCD_MEM. On déplace ça dans a0 aussi (ou dans a1 si jamais
on a l'adresse du sprite dans a0). On fait donc :
move.l
#LCD_MEM,a0
4) Obtenir
la position du sprite
C'est là que
les choses se compliquent, on a l'adresse de l'écran et du sprite.
Et l'on connait les coordonnées où l'on veut placer le sprite :
a0 = Adresse
du sprite
a1= Adresse de l'écran
d0= Coordonnées X du sprite (généralement entre
0 et 159, ou entre 0 et 239 selon la calculatrice)
d1= Coordonnées Y du sprite (généralement entre
0 et 99, ou entre 0 et 127 selon la calculatrice)
Donc il faut
copier tout ce qu'il y a dans a0 vers a1, mais d'abord on doit positionner
a1 au bon endroit car sinon on va copier en haut à gauche de l'écran.
5) Méthodes
de calculs pour obtenir la ligne de l'écran
a) Multiplication avec l'instruction MULU
D'abord, il faut
positionner a1 (début de la mémoire vidéo) sur la bonne ligne. Pour
celà on va tout simplement multiplier les coordonnées Y du sprite
par le nombre d'octets nécessaires pour faire une ligne sur votre
calculatrice. Sur une Ti89, l'écran fait 160 pixels de large, mais
comme la mémoire vidéo est la même que sur une Ti92, on va admettre
qu'il y a 30 octets en largeur
Exemple de multiplication
par 30 sur le registre d0:
mulu #30,d1
Après ça, d1
contient le nombre d'octets à ajouter à a1 pour obtenir la bonne
ligne.
add d1,a1
Et voilà a1 est
correctement positionné sur la ligne.
b) Multiplication
avec l'instruction LSL
Le seul intérêt
de cette opération est la rapidité par rapport à l'instruction MULU.
Mon but n'est pas d'apprendre l'assembleur donc il faut juste savoir
que LSL est une rotation vers la gauche de x bits, et que ce x permet
de multiplier par 2^x. Et ça à cause de la nature même du codage
binaire...
Pour multiplier
d1 par 30 :
move.l d1,d2
; d1 et d2 contiennent la même valeur
lsl.l
#5,d1 ; On multiplie
d1 par 2^5, soit 32
lsl.l
#1,d2 ; On multiplie
d2 par 2^1, soit 2
sub
d2,d1 ; On soustrait
d1*32 et d2*2, en factorisant on a d1*(32-2) d'ou d1*30 !
Et comme pour
MULU, on ajoute d1 à a1 :
add d1,a1
Et voilà a1 est
correctement positionné sur la ligne.
6) Méthodes
de calculs pour obtenir la colonne de l'écran
a) Division
avec DIVU et SWAP
Maintenant, il
faut obtenir la position de la colonne où afficher le sprite. Pour
celà on va diviser d0 par 8 pour obtenir le nombre d'octets à ajouter
puis faire une rotation du sprite avec le reste. En effet on doit
copier des octets à une adresse en octets, donc si l'on ne veut
pas que le sprite se déplace de 8 en 8, et bien il faut positionner
le sprite avec une rotation.
divu #8,d0
; On divise d0 par 8
move.w
d0,d2 ; On copie
la partie basse de d0 (ou de poids faible) dans d2 (le quotient)
swap
d0
; On inverse partie haute et partie basse de d0
Il faut faire
attention avec d0 car la partie haute contient toujours le quotient,
et la partie basse seulemeent contient le reste.
En effet, l'instruction
DIVU donne le quotient et le reste du nombre divisé dans le même
registre, d'ou l'utilité du SWAP.
b) Division
avec LSR, LSL
move.l d0,d2
; On copie d0 dans d2
lsr
#3,d0
; On divise d0 par 2^3, soit 8 donc d0 est le quotient.
move.l
d0,d3
lsl
#3,d3
; On multiplie d3 par 2^3, soit 8 ce qui nous donne d2 moins le
reste.
sub
d3,d2
; On soustrait d3 à d2, et donc d2 = reste
Et voilà une
méthode plus rapide que DIVU (beaucoup plus...). Mais il y a encore
mieux !
c) Division
avec LSR, AND
move.l d0,d2
; On copie d0 dans d2
lsr
#3,d0 ; On
divise d0 par 2^3 soit 8
and
#7,d2 ; l'instruction
AND permet grâce à un miracle de la nature d'obtenir le reste de
d2/8
Et donc d2 =
reste, et d0 = quotient.
Il n'y a pas
de méthodes plus rapide pour diviser un nombre par 8 à ma connaissance.
Enfin, on ajoute le quotient à a1.
add d0,a1
; Ajout du reste à a1
Désormais, l'adresse
a1 est positionné à l'octet près, il ne reste plus qu'à afficher
le sprite à l'écran.
7) Affichage
du sprite à l'écran
On va admettre
que le sprite mesure 16*16 bits. Donc avec par exemple :
nom:
dc.b %10000001
dc.b %01000010
dc.b %00100100
dc.b %00011000
dc.b %00011000
dc.b %00100100
dc.b %01000010
dc.b %10000001
Le contenu des
variables est :
a0= adresse du
sprite (avec l'instruction "lea nom_du_label")
a1= adresse de l'écran positionné (grâce aux méthodes précédentes)
+ 1
d0= registre vide (tampon pour le
sprite)
d1= Valeur de la boucle (8-1 = 7)
d2 = 8 - Valeur du reste (calculé
avec la méthode précédente)
Le code à l'intérieur
de la boucle est alors :
boucle:
clr.w d0
move.b (a0)+,d0
lsl.w d2,d0
move.w d0,(a1)
add #20,a1
dbra.b d1,boucle
En théorie vous
devriez avoir votre sprite à l'écran...
8) Routine
d'affichage complète de sprites 8*8
Cette routine
est simple et routine, mais ne permet que d'afficher un sprite de
petite taille, en noir et blanc et sans masque. La vitesse d'affichage
est largement supérieur à 1000 par secondes, et s'utilise généralement
dans des jeux comme JezzBall (pour afficher les balles) ou même
dans Phoenix pour l'affichage des tirs.
Paramètres :
d0.l :
Coordonnées X
d1.l : Coordonnées Y
lea
croix,a0
; Il semblerait que le compilateur rajoute le (PC) automatiquement...
move.l #LCD_MEM,a1
; Mémoire de la vidéo
move.l d1,d2
; d1 et d2 contiennent la même valeur
lsl.l
#5,d1 ; On multiplie
d1 par 2^5, soit 32
lsl.l
#1,d2 ; On multiplie
d2 par 2^1, soit 2
sub
d2,d1 ; On soustrait
d1*32 et d2*2, en factorisant on a d1*(32-2) d'ou d1*30 !
move.l d0,d2
; On copie d0 dans d2
lsr
#3,d0 ; On divise
d0 par 2^3 soit 8
and
#7,d2 ; l'instruction
AND permet grâce à un miracle de la nature d'obtenir le reste de
d2/8
add d0,d1
; Ajout du reste à d1
add
#1,d1
add
d1,a1 ; Ajout
du total à a1
move.b #8,d3
sub
d2,d3
move.w #7,d1
boucle:
clr.w d0
move.b (a0)+,d0
lsl.w
d3,d0
move.w d0,(a1)
add
#20,a1
dbra d1,boucle
croix:
; Placer les données en fin de programme avec les autres variables.
dc.b %10000001
dc.b %01000010
dc.b %00100100
dc.b %00011000
dc.b %00011000
dc.b %00100100
dc.b %01000010
dc.b %10000001
©Tous les programmes presents
sur ce site sont soumis à l'autorisation de leur programmeurs
respectifs pour toutes modifications. La mise en page a necessité
un certain travail, il serait donc plus correct de ne pas la plagier.
|