J'avais besoin d'une routine de sessin de sprite spécifique pour mon je de zelda et j'ai programmé celle-là (une version pour ti 89 et une version pour ti92+/v200). J'aimerais avoir votre avis.
| Assembly Source File
| Created 26/08/2003; 23:34:07
.global sprite_draw_masked_89
.data
| dessine un sprite avec du clipping
| J'ai décidé de faire une version différente selon la machine car c'était le moyen d'avoir le code le plus rapide
| étant donné les différences de l'affichage du jeu entre la ti89 et les TI92+ et V200
| void sprite_draw_masked(void *plane0, void *plane1, short x, short y, const unsigned short *sprite_data);
sprite_draw_masked_89:
|illegal
movem.l %d0-%d7/%a0-%a6,-(%sp)
| lecture de x et de y
move.w 72(%sp),%d0 | je stocke la variable x dans d0
moveq.l #0,%d1 | la partie haute de d1 sera ansi vide
move.w 74(%sp),%d1 | et y dans d1
| Teste la visibilité.
| si le sprite est complètement hors de la zone visible, la routine se termine immédiatement
cmpi.w #-16,%d0 | test de x par la gauche
jble _sprt_msk_89_end
cmpi.w #160,%d0 | test de x par la droite
jbge _sprt_msk_89_end
cmpi.w #-16,%d1 | test de y par le haut
jble _sprt_msk_89_end
cmpi.w #100,%d1 | test de y par le bas
jbge _sprt_msk_89_end
| Tous les tests ont été passés, donc on peut continuer normalement
move.l 64(%sp),%a0 | Je stocke plane0 dans a0
move.l 68(%sp),%a1 | et plane1 dans a1
move.l 76(%sp),%a2 | Je stocke sprite_data dans a2
moveq.l #16,%d2 | J'initialise le compteur de la boucle dans d2 (je fais ça maintenant car c'est nécéssaire)
| Si y est négatif, je dois commencer à dessiner plus bas
tst.w %d1
jbge _sprt_msk_89_y_test_2 | je saute directement au deuxième test
add.w %d1,%d2 | Il faut garder en mémoire que d1 ne sera jamais plus petit que -15 donc d2 sera tjrs positif
neg.w %d1
lsl.w #1,%d1 | Multiplication par 2 puisque le sprite fait 2 octets par ligne
adda.l %d1,%a2 | J'augmente le pointeur du sprite (la hauteur du dessin a diminué)
moveq.l #0,%d1 | Je mets d1 (y) à 0 pour le calcul des addresses dans les plans
jbra _sprt_msk_89_calculate_addresses | Le test suivant n'est pas nécéssaire, daonc on le saute
| Si le sprite dépasse un peu en bas, je dois diminuer la hauteur du dessin
_sprt_msk_89_y_test_2:
cmpi.w #85,%d1 | 85 + 16 = 101 et 101 > 100
jblt _sprt_msk_89_calculate_addresses
move.l %d1,%d3 | d3 était inutilisé jusqu'à maintenant (utilisation temporaire)
sub.w #84,%d3
sub.w %d3,%d2 | Je diminue le compteur
| Partie suivante: calcul du décalage par rapport aux adresses des plans
_sprt_msk_89_calculate_addresses:
moveq.l #0,%d3
mulu #30,%d1 | d1 est obligatoirement positif, donc mulu convient très bien
move.l %d1,%d3
move.l %d0,%d1
lsr #3,%d1 | divise x par 8 pour obtenir l'adresse de l'octet qui contient le premier pixel du sprite
bclr.b #0,%d1 | S'assure d'obtenir une adresse paire (pour pouvoir utiliser des longs...)
add.w %d1,%d3
| Ajoute le décalage calculé dans d3 aux pointeurs plane0 et plane1
adda.l %d3,%a0
adda.l %d3,%a1
| Calcule les adresses des deux autres "plans" du sprite (foncé et masque) - on peut se passer de ça et faire autrement (utiliser 32(%a2) et 64(%a))
movea.l %a2,%a3
adda.l #32,%a3
movea.l %a3,%a4
adda.l #32,%a4
| Calcule le nombre de bits à décaler vers la gauche
move.w %d0,%d1 | Je dois toujours préserver d0, donc je le copie dans d1
and.w #0xF,%d1
neg.w %d1
addi.w #16,%d1 | Le calcul du nombre de décalages vers la gauche est ausi simple que ça :)
| Teste si le sprite dépasse vers la gauche
tst.w %d0
jbge _sprt_msk_89_x_test_2
move.l #0xFFFF,%d3 | Masque pour ne pas endommager les autres données placé dans d3
| Teste si le sprite dépasse vers la droite
_sprt_msk_89_x_test_2:
cmpi.w #145,%d0
jblt _sprt_msk_89_drawnormal
move.l #0xFFFF0000,%d3 | Le masque est mis dans d3
_sprt_msk_89_out_of_screen:
moveq.l #0,%d5 | Efface d5 en entier
move.l %d5,%d6
move.l %d6,%d7
| Charge une ligne complète du sprite et la décale vers la gauche
| Puis lui applique le masque contenu dans d3
move.w (%a2)+,%d5
lsl.l %d1,%d5
and.l %d3,%d5
move.w (%a3)+,%d6
lsl.l %d1,%d6
and.l %d3,%d6
move.w (%a4)+,%d7
lsl.l %d1,%d7
and.l %d3,%d7
not.l %d7 | Inverse d7
| Traîtement du light plane
move.l (%a0),%d4
and.l %d7,%d4
or.l %d5,%d4
move.l %d4,(%a0)
adda.l #30,%a0
| Traîtement du dark plane
move.l (%a1),%d4
and.l %d7,%d4
or.l %d6,%d4
move.l %d4,(%a1)
adda.l #30,%a1
subq #1,%d2
bne _sprt_msk_89_out_of_screen
jbra _sprt_msk_89_end
_sprt_msk_89_drawnormal:
moveq.l #0,%d5 | Efface d5 en entier
move.l %d5,%d6
move.l %d6,%d7
| Charge une ligne complète du sprite et la décale vers la gauche
move.w (%a2)+,%d5
lsl.l %d1,%d5
move.w (%a3)+,%d6
lsl.l %d1,%d6
move.w (%a4)+,%d7
lsl.l %d1,%d7
not.l %d7 | Inverse d7
| Traîtement du light plane
move.l (%a0),%d4
and.l %d7,%d4
or.l %d5,%d4
move.l %d4,(%a0)
adda.l #30,%a0
| Traîtement du dark plane
move.l (%a1),%d4
and.l %d7,%d4
or.l %d6,%d4
move.l %d4,(%a1)
adda.l #30,%a1
subq #1,%d2
bne _sprt_msk_89_drawnormal
_sprt_msk_89_end:
movem.l (%sp)+,%d0-%d7/%a0-%a6
rts
