Afficher un sprite à
l'écran ... |
I à qui s'adresse cette
doc ?
cette doc s'adresse à ceux qui ont des notions de
bases (mais vraiment
la base de la base !) mais qui ne savent pas
programmer en asm c'est
ultra détaillé , je pense que tut le monde peut
comprendre (même moi ,
j'ai compris ce que j'ai écrit !)
Mais s'il y a un truc que vous ne comprenez pas ,
demandez à quelqu'un
qui s'y connaît , ou écrivez moi
(superbebert2000@yahoo.fr)
II Qu'est ce qu'un sprite ?
Un sprite est un objet graphique de petite taille
qu'on affiche à
l'écran , et qui est "fait" pour
bouger.
Dans cette doc , on expliquera seulement comment
afficher un sprite à
un endroit précis de l'écran.
III Ce qu'il faut absolument savoir
Je pars du principe que vous avez lu VOYAGE AU
CENTRE DE LA HP48 G/GX
de la page 69 à la page 129 .
Si vous ne l'avez pas fait , faudrait le faire
(vous pouvez télécharger
VCHP sur http://www.courbis.com/voyage48g.html
Si vous ne voulez pas le lire , bon , bah c pas
grave , mais il faut
quand même que vous sachiez ce que c'est un
registre , un champ , un
pointeur , une adresse , le champ P , le prologue
d'un objet etc ...
Autre chose : l'écran de la calculatrice ne peut
recevoir des données
que par "paquets" de 4 bits , la largeur
de votre sprite doit donc être
un multiple de 4 , si ce n'est pas le cas, il faut
ajouter des colonnes
de pixels blancs au début ou à la fin du grob.
Quelques notations que j'utiliserais :
x : abscisse
y : ordonnée
@ : adresse de l'écran de la pile
h : à la fin des nombres en base hexadécimal (ex
: 34h )
d : à la fin des nombres en base décimal (ex :
131d)
Dans cette documentation , je prendrais comme
exemple un grob de 8*16
pixels.
IV Le plat de résistance : Choucroute au plomb
Voici le source du programme commenté :
GOSBVL 0679B | on sauve les registres |
LA
00001 LC 00001 |
on
stocke 00001 dans les registres A et C ; A est l'abscisse x du sprite ( -1<x<131 ) , C est l'ordonnée y ( -1<y<64 ) , x et y sont des naturels |
R0=A
A R1=C A |
On
sauvegarde A et C dans R0 et R1 pour les avoir toujours sous la main en cas de besoin |
D0=8068D C=DAT0 A |
à
l'adresse 8068D , y'a l'adresse du grob qu'est affiché sur la pile D0 pointe vers 8068D C=DAT0 va chercher ce qu'il y a en 8068D (l'adresse du grob de la pile ) |
RSTK=C | RSTK
, c une sorte de pile , pratique pour sauver TEMPORAIREMENT des données ici , on sauve l'adresse de l'écran... |
C=R1
A C=C+C A A=C A CSL A A=A+C A C=RSTK C=C+A A A=R0 A B=A P ASRB A ASRB A C=C+A A D0=C |
on
met y dans C On fait C*2 (décalage d'un bit) C=y*2 On copie y*2 dans A On fait A*10h=A*16d donc A=y*20h=y*32h On fait A=A+C (A=y*2+y*32=y*34 !!! ) On met dans C l'adresse @ de l'écran note (ça enlève l'adresse de RSTK) avec ça , C=@+y*34 A=x B=A=x A=A/2=x/2 (on décale d'un bit ...) même chose : A=A/2=x/2/2=x/4 C=@+y*34 + x/4 maintenant , D0 pointe vers : @ + y*34 + x/4 |
Bah voila !!!
Maintenant qu'on a fait tout ça , on peut quand
même se poser une
question : Pourquoi faire pointer D0 (qui est un
pointeur) vers
@ + y*34 + x/4 ???
Eh bien , c'est une bonne question !
Vous avez le choix entre quatre réponses :
-réponse A : la grande Muraille de Berlin
-réponse B : 3.14159...
-réponse C : hum humm
-réponse D : eh bien , c très compliqué , mais
je vais quand même
expliquer : que veux t on faire ?
ON VEUT AFFICHER UN PETIT GROB A L'ECRAN CHEF !
l'écran de la pile,
c un grob normal (une suite de 0 et de 1 ; 0=blanc
, 1=noir ) ...
Or , l'écran fait 131 * 64 pixels , même plus :
136 * 64 car il ne
fonctionne qu'avec des paquets de 8 bits (des
octets) , donc , au bout
de chaque ligne , y'a 5 pixels qu'on voit jamais ,
mais ils sont bien
là . Donc , pour afficher un image à l'écran ,
il faut 136*64=8704 bits
(soit 2176 quartets ; 1 quartet = 4 bits )
c compliqué ! Mais comment fait la calculatrice
pour affiche run grob à
l'écran ? eh bien , d'abord , elle va voir à
l'adresse 8068D , à cette
adresse , y'a l'adresse du grob qu'on veut
afficher : la caltos lit
l'adresse et va voir ce qu'il y a à cet endroit :
ce sont les données
du grob à afficher , arrivée là , elle se prend
pas la tête pendant 3
heures : elle lit les données si le 1er bit est 1
, elle allume le
premier pixel de l'écran , si c'est 2 (euh non !
, si c ZERO ) , elle
l'éteint et ainsi de suite pour chaque pixel ...
Bon , avec tout ça , comment va t on faire pour
afficher un petit grob
sur la pile ? Bah , le grob de l'écran , il est
quelque part dans la
mémoire , son adresse , on la récupère (voire
plus haut ) : c'est @ ,
et on va remplacer les bits du grob de l'écran
par les bits de notre
grob qu'on veut afficher ... , mais comme notre
grob est supposé plus
petit que l'écran , faut pas fouttre le bordel et
remplacer tous les
bits, il faut remplacer les BONS bits (ceux qu'on
été bénis par Dieu !)
pour trouver les bons bits , c simple ! Dans un
grob , les bits de
chaque ligne sont mis les uns au bout des autres
(ex: pour avoir les
bits de la ligne 1 , on utilise un nombre entre 0
et 136 , pour la
ligne 2 , entre 137 et 2*136=272 ...) Nous , on
veut la ligne y , alors
on fait 34*y (34=136*4 , car tout se fait avec des
quartets : un
pointeur pointe sur un quartet précis , pas sur
un bit ) , avec ça, on
la ligne qu'il faut (l'ordonnée) , pour avoir le
bon quartet sur la
ligne , on ajoute x/4 , voila , on l'adresse du
quartet à partir duquel
on doit remplacer des bits (i.e. allumer les
pixels correctement pour
que ça fasse le dessin qu'on veut !)
Ouf ! 34 lignes !!! Je crois que je me suis
enflammé ...
Bon , la réponse D est un peu plus longue que les
autres , j'espère que
cela n'influencera pas vostre choix :)
Maintenant , y'a encore un autre problème (pfffffff
:( )
On connaît le quartet à partir duquel il faut
remplacer des bits , mais
peut être qu'on veut remplacer des bits à partir
du 3ème bit du quartet,
et le pointeur pointe sur le début du quartet (le
1er bit) , comment
faire pour pouvoir recopier à partir du 3ème ,
ou du 2ème ... bit ???
eh bien , c'est simple : si on veut recopier à
partir de 3ème bit , par
exemple , on va quand même recopier à partir du
premier bit , mais on
va décaler les quartets qu'on veut recopier de 2
bits , ainsi , les 2
premiers bits seront des 0 , et à partir du 3ème
, y'aura les bons bits
de notre grob !!!!
Bon , maintenant , on va essayer de savoir de
combien de bits il faut
décaler : =>
*DECALAGE: LC 3 C=C&B P |
Un nom de
label qui sert à rien On met 3 dans C , 3 = 0011 en binaire P=0, par défaut puis on fait le et logique : 1&1=& 1&0=0 0&1=0 0&0=0 dans B , on avait x on fait x&3 si le dernier quartet de x est : 0000 alors x&3=0000 =>pas de décalage 0001 alors x&3=0001 => on décale de 1 0010 alors x&3=0010 => on décale de 2 0011 alors x&3=0011 => on décale de 3 logique ! le & , ici , nous permet de récupérer les 2 bits de poids faible de B , qui correspondent à l' "abscisse" dans le quartet , donc au décalage en bit |
P=C 0 C=P 15 |
% on stocke
le décalage dans P C=P 15 % puis on le stocke dans le dernier % quartet de C |
Désormais , on connait l'adresse du quartet à
partir duquel il faut
modifier le grob , et le nombre de décalages d'un
bit qu'il faut faire
pour afficher l'image au pixel près . On a tout
ce qu'il nous faut pour
afficher notre sprite ... Tout ? NOOOOOOOON , bien
sur , il nous faut
aussi notre sprite ...
Bon , on va considérer que vous avez déjà un
grob de petite taille
stockée dans une variable globale . Supposons que
le nom de cette
variable est : DESSINDUSPRITE :)
Bon , maintenant , fa ut qu'on intègre les
données du sprite dans le
prog en asm ... c facile
*ADRESSE.DONNEES.SPRITE GOSUB DATAS.SPRITE |
un label qui
sert à rien on demande au prog daller au label qui s'appelle DATAS.SPRITE note:ça met l'adresse du truc qu'y'a après le gosub dans RSTK |
$4040E0A0E111F111F191F11 1FF1FE322E323E764E7E7202 0202020202020E1E1 *DATAS.SPRITE C=RSTK |
ici , ce sont
les données du sprite en quartets (sans prologue) le label DATAS.SPRITE on rappelle l'adresse des données du sprite |
D1=C | et D1 pointe vers cette adresse |
Ce coup là , on a tout ce qu'il nous faut ; On
va pouvoir lancer la
grosse machine de Guerre : l'algorithme de copiage
des données !
Bon , jusqu'ici , c'était facile , maintenant ,
on va passer aux choses
sérieuses ! :)
Bon , je fais quoi , je parle tout de suite des
pixels transparents ,
ou je fais un truc simple avec des pixels blancs
et des pixels noirs ?
Bon ,on va commencer par un truc simple
Tout d'abord , on va copier le grob ligne par
ligne (car , comme notre
sprite est plus petit que l'écran , entre deux
lignes , il faut faire
un saut de 34h ( la "longueur" d'une
ligne )
P=0 | P va servir
de compteur de ligne inconvénient : on ne peux pas afficher de sprite de plus de 16 lignes , si on veut afficher un grob de plus de 16 lignes , il faut utiliser un champ d'un registre comme compteur ... |
*COPY.LINE A=0 A |
un nom de
label qui sert à qqch (le début d'une boucle ... ) pour virer tout les déchets de A |
A=DAT1 B | dans A champ
, on on copie les données du sprite |
Bon, là , il risque d'y avoir quelques
problèmes !
le champ X fait 3 quartets (=12 bits=12 pixels),
et dans cet exemple
précis, j'ai décidé d'afficher un sprite de
8*16 , pourquoi ai-je
décidé d'utiliser un champ plus grand ???
Et bien , c simple : une adresse sert à désigner
un quartet bien précis
, donc quand on écrit à un adresse , on écrit
au début d'un quartet ,
de plus , un quartet ne code pas un pixel , mais 4
(logique 1 quartet = 4 bit ...)
Donc , si on écrit à l'adresse de l'écran , ça
écrira au début d'un
"groupe" de quatre pixels ... bon , tout
ça je l'ai déjà expliqué plus
haut , donc on va décaler tous les bits dans le
champ considéré (ici:X)
Car si on décale le champ B (2 quartets) vers la
gauche , comme notre
image fait 2 quartets de large, les bits de poids
faible seront décalés,
et les bits de poids fort seront
irrémédiablement perdus
Alors que si on décale les bits de notre grob
dans le champ X (=12 bits)
notre ligne de grob (8 bits) ne sera pas amputée
, (car le décalage
maximum est de 3 bits et 8+3 < 12 ...)
Bon , vous avez compris , je pense
A retenir : toujours utiliser un champ plus grand
pour faire les
décalages.
Rem: si vous ne souhaitez pas afficher au pixel
près , et si vous
souhaitez écrire "tous les 4 pixels" ,
bien sur , vous n'estes pas
obligé de faire de décalage, et le programme est
beaucoup plus
simple !!!
:)
D1=D1+2 A=C S |
On copie
ligne par ligne ,ici , D1 pointe sur la 1ère ligne de 8 pixels On le fait pointer sur la ligne suiv. On met la valeur du décalage dans C.S |
A=A-1 S GOC DECALAGE.OK A=A+A X |
On
décrément A.S si A.S=0 => pas de décalage => la carry passe à 1 avec la décrémentation et on va à DECALAGE.OK sinon , As est décrémenté , et on exécute c'qu'y après l'GOC DECALA... On décale de 1 bit vers la gauche |
A=A-1 S GOC DECALAGE.OK A=A+A X A=A-1 S GOC DECALAGE.OK A=A+A X |
On refait
ceci encore 2 fois Au cas où il faudrait faire 3 A=A+A X % décalages ... |
ça y est ! la ligne de pixels a été
décalée le nombre de fois qu'il
faut, maintenant , on peut commencer le recopiage
sur l'écran de la
pile
Rem : les décalages ont un inconvénient : cela
créeras une ou plusieurs
colonne blanche à gauche du sprite , mais on
verras plus tard comment
empêcher cela !!!
*DECALAGE.OK DAT0=A X |
Bon
, voila , on peut recopier D0 pointe vers l'adresse où il faut recopier , et on recopie (enfin) |
D0=D0+34 | On
passe à la ligne suivante dans le grob de la pile : une ligne =136 pixels = 34 quartets |
P=P+1 | On
incrémente P , si P passe à 0, ( on vient alors de recopier la denière ligne ) alors la carry passe à 1 |
GONC COPY.LINE | Si
la carry n'est pas à 1 (i.e il reste des lignes à copier , alors on retourne à COPY.LINE pour copier la ligne suivante |
Maintenant , on peut conclure , mais si on fait
comme cela , le grob
qu'on va afficher va recouvrir le grob qui est
affiché sur la pile
(d'autant plus qu'il y a les décalages) et peut
être qu'on ne veut pas
que certains pixels soient recouverts ...
Illustration:
l'écran , avec un grob de décor déjà affiché
:
************************
*
*
*
*
*
*
*
*
************************
*
*
*
*
************************
Le grob qu'on veut afficher ; un bonhomme :
***
* *
***
*
*
**
On affiche le bonhomme (sans décalage)
************************
*
*
*
***
*
*
*
*
*
*
***
*
********* * ************
*
*
*
*
***
*
************************
Deux pixels du décor ont été effacé !!!
Pire : avec un décalage de 3 :
************************
*
*
*
***
*
*
*
*
*
*
***
*
******
* ************
*
*
*
*
***
*
************************
!!!!
Bon , heureusement , quelqu'un a trouvé une
solution : les pixels
transparents !!!!!
C'est un technique très simple :
D'abord , il faut faire un "double" grob
du bonhomme avec d'abord
l'ombre du bonhomme , et ensuite le dessin du
bonhomme ; c'est un grob
en double largeur
exemple:
******
**** *
******
* *
* *
** **
Attention: le dessin du bonhomme doit avoir une
largeur multiple de 8 ,
donc , le grob avec l'ombre sera un multiple de 16
, si votre dessin
n'a pas une largeur multiple de 4 , complétez
avec des pixels blancs
dans le dessin, et AUSSI dans l'ombre
exemple :
***
*** |
*** *
* |
***
*** |
*
* |
*
* |
**
** |
voila , je vous ai mis une petite limite ( | ) à
droite
Bon ,en suite , on copie d'abord l'ombre dans B ,
puis le dessin
dans A , on fait le décalage pour les deux champs
et au label
DECALAGE.OK , on ne se contente pas de copier de
données.
On copie dans C les données du décor (qui est
affiché sur l'écran de la
pile ) , on inverse B (l'ombre) ; on fait
C=C&B , donc les pixels noirs
dans l'ombre et noirs sur le décor seront notés
0 , les pixels blancs
dans le décor seront notés 0 , les pixels blancs
dans l'ombre
(le "tour" du bot) et noirs dans le
décor seront notés 1
Ensuite : C=C!A (C=C ou A)
-Les pixels blancs dans l'ombre , noirs dans le
décor et blancs sur
le dessin du bot seront notés 1 donc noirs ,c ce
qu'on voulais, si si !
-Les pixels noirs sur le dessin du bot seront
noirs de toute façon
-Les pixels noirs dans l'ombre , noirs dans le
décor et blancs sur le
dessin du bot seront notés 0 donc blancs , c ce
qu'on voulais aussi,
croyez moi !
Bref , ça marche !!!
Bon , c un peu difficile à voir comme ça en le
lisant , mais vous pouvez
faire des dessin sur du papier (oui , ça existe
encore !) pour voir un
peu ce que ça donne.
Ensuite on copie C sur l'écran de la pile , et
là , ça marche !!!
*COPY.LINE A=0 A C=0 A C=DAT1 B B=C A D1=D1+2 |
On fait le
ménage ... On copie l'ombre On la met dans B On passe aux données du dessin du bot qui sont juste "à côté" de celles de l'ombre |
A=DAT1 B D1=D1+2 A=C S A=A-1 S GOC DECALAGE.OK A=A+A X B=B+B X A=A-1 S GOC DECALAGE.OK A=A+A X B=B+B X A=A-1 S GOC DECALAGE.OK A=A+A X B=B+B X |
on les met
dans A on passe à la ligne suivante On fait les décalages A=A+A X % Pour A et B ... |
*DECALAGE.OK C=DAT0 X B=-B-1 X C=C&B X C=C!A X DAT0=C X |
On fait les opérations logiques sus-décrites |
D0=D0+34 P=P+1 GONC COPY.LINE |
on passe à
la ligne suivante (dans le grob de la pile) On teste P On boucle ... |
Maintenant que le grob est copié (ce qui se
fait très rapidement) , on
peut mettre une boucle pour qu'on puisse le voir
pendant quelques
secondes , ici , j'ai fait un truc simple , mais
on peut aussi faire
une boucle infinie , avec un test de touche pour
quitter le programme
LA FFFFF {A=A-1 A UPNC} |
on met FFFFFh=1048575d
dans A champ A on décrémente A (si A=0 , la carry est armée ) on retourne au début de l'accollade (UP) si la carry n'est pas armée (NC) |
GOVLNG 05143 | enfin ,on
restaure les registres comme ils étaient avant que le prog soit exécuté , si on le fait pas , la calculatrice est "déboussolée" et ça plante :( |
V Conclusion
Les explications sont super détaillées
Mais s'il y a un truc que vous ne comprenez pas ,
vous pouvez m'écrire
et je répondrais à vos question en 2 semaines au
plus
mon email : superbebert2000@yahoo.fr
La semaine , je n'ai pas accès à Internet , mais
vous pouvez aller sur
un forum ou sur un chat
Je vous conseille un site : www.hp-sources.com
Voila , c'était ma première doc , écrivez moi
pour me dire ce que vous
en pensez !
@+