Le problème avec les sprites (les
chtits dessins qu'on affiche à l'écran : vaisseau spatial,
missile...) c'est que leur zone de mémoire est rectangulaire
et l'image ne l'est pas. Il faut donc pouvoir définir une
couleur invisible, transparente, le cadre rectangulaire
entourant le dessin à afficher. |
Une solution souvent utilisée est
de définir le noir comme étant cette couleur, et avant d'afficher
un pixel, de le comparer avec le noir et de ne l'afficher
que si il est effectivement différent de cette couleur.
C'est facile et pas cher, mais est-ce efficace? |
. |
Parce que bon, nous on nous dit
que nos processeurs sont des processeurs 32bits, et qu'ils
sont donc capables d'afficher 4pixels d'un coup dans un
mode 256couleurs, alors que dans cette méthode on ne peut
en afficher qu'un à la fois, vu qu'il y a une condition
différente à chaque pixel (sans parler de la lenteur de
la comparaison elle-même) |
Ce qui serait bien, c'est de pouvoir
afficher (avec le même résultat) ce sprite 32bits par 32bits,
et sans conditions. Ben croyez-le ou ne le croyez pas, mais
ya moyen. |
Celui qui a déjà joué avec un compilo
proposant des routines d'affichage de zones mémoire à l'écran
connait le résultat d'un affichage avec combinaison OR avec
le fond. D'accord le noir entourant le sprite n'apparait
plus, mais les couleurs du sprites sont altérées par le
même fond, plutot moche... |
. |
Souvenons-nous d'une propriété du
OR : a OR 0=a. Si on arrivait à remplir en noir la zone
que le sprite occupera avant de l'afficher en OR (la vraie
zone, pas la zone rectangulaire), les bords noirs du sprites
seraient invisibles et les couleurs du sprites ne seraient
pas altérées. |
Et comment effacer la zone qui nous
dérange? Facile, on ressort un autre opérateur binaire,
le AND, qui a deux autres propriétés remarquables : |
255 AND a=a et 0 AND a=0 |
. |
Si on affiche avec la combinaison
AND un sprite qui a la couleur 0 là ou l'on désire "nettoyer"
le fond, et 255 ailleurs, on obtient exactement le résultat
demandé. Ce nouveau sprite s'appelle le masque, à chaque
sprite correspond un masque. |
Au final : Couleur=(Fond AND Masque)
OR Sprite |
L'avantage de cette méthode, même
si elle demande deux passes et d'avantage de mémoire (vu
que le Masque doit être stocké quelque part), à l'avantage
de pouvoir traiter 4pixels à la fois en 32bits et de se
passer de conditions. |
. |
Bien sur le sprite doit avoir une
taille multiple de 4. |
Code optimisé pour 32bits mode protégé,
TailleX et TailleY sont des constantes. |
MOV edi, BaseAdr ;Ecran+X+Y*320
|
XOR esi, esi ;On commence au début
du sprite |
MOV ebx, TailleY ;La hauteur |
ForY: |
MOV ecx, TailleX/4 ;La longueur
|
ForX: |
MOV eax, [edi+ecx*4-4] ;On charge
le fond |
AND eax, [esi+ecx*4-4+Offset Masque]
;Application du masque |
OR eax, [esi+ecx*4-4+Offset Sprite]
;Application du sprite |
MOV [edi+ecx*4-4], eax ;Modification
du fond |
DEC ecx ;4pixels suivants |
JNZ ForX |
ADD edi, 320 ;Ligne suivante |
DEC ebx |
JNZ ForY |
. |
Un code en 16bits et mode réel.
Dans cet exemple on suppose que le sprite et le masque sont
contigus en mémoire. |
MOV ax, ScreenSeg |
MOV es, ax |
MOV di, BaseAdr |
MOV si, SpriteOfs |
MOV ax, SpriteSeg |
MOV ds, ax |
MOV bx, TailleY |
ForY: |
MOV cx, TailleX/4 |
ForX: |
MOV ax, es:[di] |
AND ax, [si+TailleX*TailleY] |
OR ax, [si] |
MOV es:[di], ax |
MOV ax, es:[di+2] |
AND ax, [si+TailleX*TailleY+2] |
OR ax, [si+2] |
MOV es:[di+2], ax |
ADD si, 4 |
ADD di, 4 |
DEC cx |
JNZ ForX |
ADD di, 316-TailleX |
DEC bx |
JNZ ForY |
. |
ATTENTION : je n'ai pas testé
ces deux codes, j'espère qu'ils marchent :) Sinon, bah trouver
leurs erreurs fera un très bon exercice pratique :) |
Vous voulez encore plus rapide?
Bah alors je vous donne un truc à Red_Spider (un pote à
moi pour celui qui ne serait pas encore au courant) : faire
une routine qui analyse le sprite au chargement, et créer
du code excécutable en fonction de ce sprite, donc recréer
une routine qui affiche ce sprite et rien que ce sprite.
Je vous laisse imaginer comme ça peut tracer, et comment
ça peut être la mort à écrire |
|