Site

. Les News
. Le Forum
. L'équipe et les projets
. Les Tutoriaux
. IRC
. La boite à outils
. Les routines et algos indispensables
. Les liens


Les News de TI-FR


 



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.