Si l'assembleur permet un gain en vitesse très important par rapport au RPL, c 'est au niveau du graphisme que celui-ci est le plus évident en effet l'assembleur nous donne la possibilité de gérer au mieux l'affichage chose impossible en RPL .
Routine d'affichage d'un point à un endroit précis
Le principe:
.On veut allumer un pixel de l'écran aux
coordonnées que l'on veut. Pour cela il faut tout
d'abord récupérer l'adresse de l'écran ( celle
qui pointe sur le pixel haut gauche de l'écran )
, puis on doit calculer le décalage a apporter à
cette adresse pour quelle pointe sur le pixel
désiré à 4 prés car une adresse pointe un
quartet donc 4 bits correspondant à quartes
pixels.
Sachant qu'une ligne ( pour un grob de la taille
de l'écran ) comporte 136/4=34 quartets, la
première partie du calcul consiste à faire Y*34
, bon la on est sur la ligne de notre pixel
maintenant il reste à se déplacer sur cette
ligne jusqu'au groupe de 4 pixels qui contient
notre pixel, il suffit donc de faire X/4. L'étape
suivante à pour but d'allumer le bon pixel,
l'astuce pour y parvenir et de regarder les deux
bits de poids faible de X car en effet si l'on a
#00b alors notre pixel est le premier des quatre ,
si on a #01b c'est le deuxième , #10b pour le
troisième et #11b pour le quatrième.
.Ce qui donne le code suivant :
on pointe sur "@écran+Y*34+X/4" puis on
met a "1" le bit 0 de A comme ça
"LA 1" enfin on teste le bit 0 de X si
il est à "1" alors on réalise un
décalage a gauche ( multiplication par 2 ) et si
le bit 1 de X si il est à "1" alors on
réalise deux décalages à gauche (
multiplication par 2 ) .
" % le coin haut gauche de l'écran étant le point (0,0) DCCP 2 X_Position % deux quartets pour stocker le décalage horizontal (en pixels) DCCP 2 Y_Position % deux quartets pour stocker le décalage vertical (en pixels) DCCP 5 Ecran % cinq quartets pour stocker l'adresse de l'écran SAVE % sauve de contexte D0=(5)X_Position % on initialise X_Pos à 131/2 -> #42h LC 42 DAT0=C.B D0=(5)Y_Position % on initialise X_Pos à 64/2 -> #20h LC 20 DAT0=C.B SCREEN % routine qui retourne dans A.A l'adresse actuelle de l'écran D0=(5)Ecran DAT0=A.A % on sauvegarde cette adresse *La_boucle_principale % ici commence notre boucle d'affichage D0=(5)Y_Position % on récupère notre position Y C=0.A % attention C=0.A est très important car on va additionner notre décalage à une C=DAT0.B % adresse de 5 quartets donc notre décalage doit être codé aussi sur 5 quartets A=C.A A+A.A % on fait Y*2 CSL.A C+C.A A+C.A % et (Y*16)*2 puis Y*2+(Y*16)*2=> 34*Y ( voir TUTorial multiplication ) D0=(5)X_Position % on récupère notre position X C=0.A % attention (même remarque) C=DAT0.B B=C.B % adresse de 5 quartets et on sauve pour la suite X dans le registre B CSRB.A CSRB.A % on fait X/4 A+C.A % on a "Y*34+X/4" D0=(5)Ecran % on récupère notre Ecran C=DAT0.A % notre adresse Ecran sur 5 quartets A+C.A D0=A % voila D0 pointe sur "@écran+Y*34+X/4" donc le bon groupe de quartes pixels C=B.B % on récupère notre X (plus rapide qu'une nouvelle lecture en mémoire) LA 1 % on met à "1" le bit 0 ?CBIT=1.0 % si le bit 0 est à "1" ( codage pour un bit 1 ou 3 ) -> { A+A.P } % dans ce cas un décalage ?CBIT=1.1 % si le bit 1 est à "1" ( codage pour un bit 2 ou 3 ) -> { A+A.P A+A.P} % dans ce cas deux décalages DAT0=A.P % et voila on écrit la contenu de A.P qui allume donc le pixel BRAVO !!! LC 001 OUT=C=IN % si on presse DROP ?CBIT=1.6 -> { LOADRPL } % alors on quitte le programme GOTO La_boucle_principale @"Bon c'est clair la première chose qu'on dit un voyant ce source c'est MAMAN !! c'est un truc de fou moi je préfères le RPL et son << {#42h #20h} PIXON >> :) bon fait un jeu en RPL, bien tu reviendra vite fait vers l'ASM si tu veux le réaliser tel qu'il est dans tes rêves...
Bon si on veut afficher une image maintenant à la place de notre pixel...
Routine d'affichage "d'un sprite" à un endroit précis
Bon, en fait y a presque rien à changer il suffit de récupérer de récupérer l'adresse ou se trouve notre sprite on peut faire ça facilement avec A=PC GOINC Sprite .... bon vous voulez que je remette tout pfff ...
" % le coin haut gauche de l'écran étant le point (0,0) DCCP 2 X_Position % deux quartets pour stocker le décalage horizontal (en pixels) DCCP 2 Y_Position % deux quartets pour stocker le décalage vertical (en pixels) DCCP 5 Ecran % cinq quartets pour stocker l'adresse de l'écran SAVE % sauve de contexte D0=(5)X_Position % on initialise X_Pos à 131/2 -> #42h LC 42 DAT0=C.B ( ....) D0=(5)Ecran % on récupère notre Ecran C=DAT0.A % notre adresse Ecran sur 5 quartets A+C.A D0=A % voila D0 pointe sur "@écran+Y*34+X/4" donc le bon groupe de quartes pixels %% c'est ici la nouveauté A=PC GOINC Sprite % on récupère l'adresse du sprite ( voir la fin du source ) A=A+C.A D1=A % et hop la voila pointé par D1 LC 3 D=C.P % D nous servira de compteur , notre sprite à 4 lignes donc "compteur=nbr ligne-1" C=B.B % on récupère notre X (plus rapide qu'une nouvelle lecture en mémoire) { A=0.B % car même si une ligne ne fait que 4 pixels après décalage elle peut faire 3 pixel de plus A=DAT1.P % on lit une ligne du sprite ?CBIT=1.0 % et on décale .. -> { A+A.B } % pour être ?CBIT=1.1 % décalé de façon -> { A+A.B A+A.B } % à afficher au DAT0=A.B % bon endroit :) D0+34 D1+4 % on passe à la ligne de l'écran et du sprite suivante D-1.P UPNC } % on affiche les quartes lignes LC 001 OUT=C=IN % si on presse DROP ?CBIT=1.6 -> { LOADRPL } % alors on quitte le programme GOTO La_boucle_principale *Sprite $60F0F060 % donné d'un grob de 4*4 pour l'avoir faire GROB 4 4 60F0F060 @"Routine de déplacement "d'un sprite" à un endroit précis
.Bon alors la c'est très simple, il suffit de
rajouter des lignes du type:
(!!!!ATTENTION!!!! de pas le faire sans avoir fini
de lire ce paragraphe )
LC 040 OUT=C=IN % si on presse DROITE ?CBIT=1.0 -> { D0=(5)X_Position % on augmente la valeur X de "1" C=DAT0.B C+1.B DAT0=C.B } % alors déplacement à droite LC 040 OUT=C=IN % si on presse GAUCHE ?CBIT=1.2 -> { D0=(5)X_Position % on diminue la valeur X de "1" C=DAT0.B C-1.B DAT0=C.B } % alors déplacement à gauchede même pour les déplacements verticaux mais pour D0=(5)Y_Position ...
LC 0F000 { C-1.A UPNC }ensuite il faut tester si X et Y restent dans les limites, le plus simple est de faire ça ( blocage par la limite )
LC 040 OUT=C=IN % si on presse DROITE ?CBIT=1.0 -> { D0=(5)X_Position % si on n'est pas en limite droite C=DAT0.B LA 7F % "Largeur écran-largeur sprite" alors ?A!=C.B -> { C+1.B } % on augmente la valeur X de "1" DAT0=C.B } % alors déplacement à droite LC 040 OUT=C=IN % si on presse GAUCHE ?CBIT=1.2 -> { D0=(5)X_Position % si on n'est pas en limite gauche C=DAT0.B % "0" alors ?A!=0.B -> { C-1.B } % on diminue la valeur X de "1" DAT0=C.B } % alors déplacement à gauchevoila et il faut procéder de la même façon pour les déplacements verticaux ...
.Sinon on peut faire comme dans HPBubble c'est à dire téléportation de l'autre coté de l'écran
LC 040 OUT=C=IN % si on presse DROITE ?CBIT=1.0 -> { D0=(5)X_Position % si on n'est pas en limite droite C=DAT0.B C+1.B LA 7F % "Largeur écran-largeur sprite" alors ?A=C.B -> { C=0.B }% on augmente la valeur X de "1" DAT0=C.B } % alors déplacement à droite LC 040 OUT=C=IN % si on presse GAUCHE ?CBIT=1.2 -> { D0=(5)X_Position % si on n'est pas en limite gauche C=DAT0.B C-1.B % "0" alors ?A=0.B -> { LC 7F }% on diminue la valeur X de "1" DAT0=C.B } % alors déplacement à gaucheMais il reste toujours un problème
.Ceux qui ont réalisé les exemples
précèdent ont du s'en rendre compte en effet
lorsque le sprite se déplace sur l'écran il
laisse une traînée derrière lui cela vient du
fait que l'écran n'est pas effacé entre deux
affichages du sprite.
On peut réaliser facilement l'effacage de
l'écran de la manière suivante, en écrivant des
"0" sur les 64 lignes de 131 pixels ...
non 136 oui tout a l'heure j'ai déjà parlé de
136 pixels alors que l'écran de la HP n'en a que
131 de large et bien ce la viens du fait des
quartets ( 4 pixels ) on ne peut avoir qu'un
multiple de quatre pixels. Donc pour 34 quartets
ça nous fait 136 pixels . Les 136-131=5 pixels
sont bien la mais non affichés.
heuu... ha oui effacer l'écran bien voila à
mettre juste après la temporisation pour que le
moment où l’image est là soit plus long que le
moment ou il est effacé.
D1=(5)Ecran A=0.W LC 87 { % on efface l'écran DAT1=A.W % soit 136*64 pixels D1+16 % ou 136*64/4 quartets C=C-1.B % et donc (136*64/4)/16 groupes de 16 quartets UPNC } % d'ou une boucle répétée 88 et compteur =87 INTON LOADRPLMais toujours problème puisque notre effacage de l'écran et visible et se traduit par un clignotement du sprite:
Le double buffering
.Technique qui consiste à fabrique l'image à affiché dans une zone mémoire a part et juste mettre a jour l'affichage en recopiant l'image terminé ainsi ne sont affichée que des images où le sprite est présent: l'image est nette.
.Le truc c’est donc de trouver en mémoire une zone mémoire bon la solution que j’utilise est d’appeler la routine MakeSTR qui réserve en mémoire un espace donné par C.A et retourne dans D0 un pointeur vers cette zone on a donc :
DCCP 5 Mémoire LC 00890 % on donne la taille ici pour un écran de 131*64 avec une marge de sécurité GOSBVL 05B7D % (ou bien GOSBVL MAKE$N ) A=D0 % D0=Position D0=(5)Mémoire % DAT0=A.A % et on sauvegardevoila on ajoute ces deux lignes au source précédant et on utilise l’adresse “Mémoire” à la place de “Ecran” pour le calcul puis une fois que l’image est finie on copie cette image à l’écran.
Avec un autre GRob comme fond d’écran ( méthode imparfaite )
.Bon là c’est déjà mieux maintenant ce que l’on voudrait ce serait que notre sprite puisse évoluer sur un décors donc on utilise soit un GRob pré calculé soit un grob réalisé précédemment par le programme.
La plus besoin d’effacer a chaque fois l’écran
il suffit de procéder de la manière suivante :
on recopie le GRob décors dans notre zone
mémoire puis on calcul et affiche notre sprite au
bon endroit enfin on fait la copie a l’écran
.... et on recommence.
Avec un autre GRob comme fond d’écran
.Le problème est que si notre sprite n’a pas une forme carré ou même simplement si il se déplace pixel par pixel il se trouve entouré d’une zone blanche qui efface le décors. La méthode pour contrer ce problème est d'utiliser une fonction d'affichage de type "ou " (OR). On prend d’une part la zone du décors qui se trouve sous le sprite d’autre part le sprite lui même on fait notre OU qui a pour effet de laisser tous les pixels allumés dans leur états allumé (d’ou conservation du fond ) et on affiche le résultat a l’écran.
Le principe du Masque (pour la transparence)
.Bon mais c’est pas top comme méthode si l’on
a un sprite qui n’est pas plein , comment faire
la différence entre un zone du sprite qui est
transparente d’une qui ne l’ai pas et bien
franchement je me l’a suis posé longtemps cette
question et une nuit la révélation ( je blague
pas la ) il me faut deux sprites évidement un qui
représente le personnage par exemple et un autre
(masque) qui représente le pourtour du sprite
donc qui nous donne les zones de transparences
donc notre séquence d’affichage devient:
copie du décors en Mémoire , utilisation du
sprite masque pour effacer dans le décors la
forme interne du personnage, puis on affiche le
personnage et on balance sur l’écran .
Là, on a un bon résultat avec un sprite qui peut se déplacer sur un décors....
Reste a régler un petit détaille la Vsync
.Cette valeur ne peut être que lue et est
codée sur 6 bits en #128h . Elle indique le
numéro de la ligne en cour d’affichage et est
décroissante . Le rafraîchissement complet de l’écran
se fait en 1/64 ieme de seconde.
Donc pour avoir l’image la plus nette possible
il faut attendre que la Vbl passe à 0 (
rafraîchissement de la ligne 64 en cours puis des
que la Vbl est différente de zéro un réalise le
transfert Mémoire vers écran.
Cela peut se coder ainsi :
D0=00128 *VBL % on attend que vbl=0 A=DAT0.B ABIT=0.6 ABIT=0.7 ?A!=0.B -> VBL *VBL1 % des que vbl != 0 A=DAT0.B ABIT=0.6 ABIT=0.7 ?A=0.B -> VBL1 % on peut passer a l’affichage
Gandalf_le_mage (Florent), le samedi 3
février 2001
email : gandalf_le_mage@yahoo.com
site d’origine : Gandalf-home.fr.st