— Basé sur l'article publié dans Quasar CPC numéro 8, Demomaking, par SNN.
– Pour faciliter la compréhension de l'effet il serait de bon ton d'ajouter des captures d'écrans (en gif-anim ?) de l'effet issu des 3 sources citées ci-dessous.
Cet effet a été rendu célèbre par The Demo dans deux parties : la Megalomaniak de Digit et la Phoenix Part de Longhost. Il s'agit en fait d'un sprite qui s'enroule et se tortille à l'écran. Techniquement, il peut être réalisé de diverses manières aussi bien en soft qu'en hard (notamment à l'aide de la rupture ligne-à-ligne).
Je vous propose ici d'en étudier une version 100% soft codée par OffseT pour la part de Quasar CPC 31) qui contenait la rubrique “Perfectionnement à l'Assembleur”. Le source dérivé de cette implémentation du Rolling Sprite se trouve ci-dessous et nous allons donc étudier pas à pas comment cela fonctionne.
Tout d'abord, on sauve la pile (1). Anodin, certes, mais indispensable puisque nous allons nous en servir par la suite comme pointeur de mot2) sachant qu'un mot pointera sur une adresse écran calculée dans la partie (2) du programme. Pour cela, on prend les adresses Y dans ”TableY
”, soit en &4300
et les X en &5000
dans ”TableX
”.
Les données sont fournies par le programme BASIC à exécuter au préalable. La dernière valeur fournie par le BASIC sera suivie par &FF
, dans chaque table, pour indiquer à l'assembleur la fin de la table. Le petit programme BASIC poke également un sprite tout bidon en &4000
juste pour tester le programme ; c'est toujours plus agréable que d'avoir une infâme bouillie d'octets à l'écran.
Le calcul de l'adresse en Y est on ne peut plus simple : on prend la coordonnée Y dans les bras velus de l'accu (0 correspond au haut de l'écran), on transfère tout dans B, on fait une boucle qui descend d'autant de lignes que B en contient par des CALL BC26
sur HL3). Le tout est sauvé dans HL.
Puis, pour X, on charge A avec le contenu de la ”TableX
”, on transporte le tout dans C. On annule la valeur de B, et on fait ADD HL,BC
(3) ; c'est-à-dire qu'on ajoute A à HL, quoi. On décale donc notre adresse écran vers la droite après être descendu. Paf ! On a notre adresse dans HL. On la sauve grâce à la pile par un PUSH HL
. La pile décrémente alors de 2 octets. Ainsi de suite, en ayant pris soin de décaler nos pointeurs (INC DE
et une mini-automodif' pour HL, très facile à comprendre). Quand c'est fini, on remet tout en ordre dont le pointeur de HL (au cas où on voudrait relancer le pré-calcul) (4).
Je rappelle qu'il faut, pendant toute la manœuvre, supprimer les interruptions (par un DI
) car elles utilisent SP elles aussi ! Mais il faut aussi faire attention à ne pas oublier le EI
final.
Je ne vous ferai pas l'affront de détailler l'attente du signal VBL (ok, je le fais : on attend que le bit 0 du port B du PPI, donc en &F5xx
soit à 0 pour lancer la suite du programme) ou le test clavier qui suit le schéma expliqué ici. Le label ”Offset
” (mégalo !) est, tout comme la saucisse, la clé du mystère.
Bon, pour commencer, on charge avec la pile la dernière valeur précalculée (qui se trouve donc être la première, magique non ?). Ensuite, HL reçoit dans la tronche les valeurs que la pile récupère (toujours mot par mot, 2 octets par 2 octets). Si le poids fort de cette adresse écran est nul (H=0), alors on lance le plan de secours qui fait boucler : ”Init04
” (5). Celui-ci remet la pile sur le début de la table et lit presto une nouvelle valeur (si on avait gardé la dernière, les restarts en auraient pris plein la poire !). Puis, vient, dans tous les cas, l'affichage d'une ligne du sprite, avec autant de LDD
que le sprite contient d'octets de large (ce sont les 4 petites lignes au tout début du programme qui s'occupe de poker le bon nombre de LDD
ici).
Arrêtons-nous sur l'utilité du label ”Init042
”. Supposons que notre sprite fasse 20 lignes de haut et qu'une fois arrivé à la dixième, nous sommes à la fin de la table ! Diable ! Que faire ? Eh bien, en bon stratège qu'il est, Offset remet la pile sur le droit chemin et, tout comme ”Init04
”, lit derechef une valeur correcte. Quand on a tout affiché, on rend la main au programme principal qui va lancer le test clavier. C'est fini.
Petite indication tout de même quant au ”BC26
” : modifiez la valeur de ”LargeurEcran
” pour faire fonctionner cette routine en overscan (LargeurEcran
=2*valeur du registre 1 du CRTC).
Afin d'éviter de tagger votre écran avec une infâme bouillie, pensez également à laisser une ligne vide au début de votre sprite afin que celle-ci efface automatiquement la dernière ligne affichée à la frame précédente.
Bon, à présent j'ai deux choses à dire : la première c'est que tout ce que j'ai dit, je ne l'ai pas pris d'une quelconque anti-sèche qu'aurait pu me donner Offset : j'ai dû me taper de comprendre ce programme et de vous le pré-digérer. La deuxième, c'est que j'avais prévu un tout petit texte. Je me suis fait remballer par Offset, gêné, au téléphone qui m'a dit : “On a rien compris.” Résultat : je me retape tout ça, dans le noir, pendant que mes parents pensent que je travaille. Merci Offset.
Ceci dit, ce programme est génial, tapez-le, profitez-en, n'abusez pas dans la taille des sprites et remerciez-moi. Bien fait pour Offset si mon texte est trop long, ça lui fera les pieds.
Télécharger le programme BASIC.
10 ' Calcul des tables 20 ' 30 DEG 40 DEFINT a-z 50 SYMBOL AFTER 256 60 MEMORY &3FFF 70 MODE 2 80 ' 90 ' En Y 100 ' 110 adr=&4800 120 FOR x=0 TO 359 130 POKE adr+x,80*(COS(2*x)+1) 140 PLOT x,10 150 NEXT 160 POKE adr+x,255 170 ' 180 ' En X 190 ' 200 adr=&5000 210 FOR x=0 TO 359 220 POKE adr+x,5*(COS(x*2)+SIN(x)+2) 230 PLOT x,20 240 NEXT 250 POKE adr+x,255 260 ' 270 ' Création d'un sprite bidon 280 ' 290 MODE 2 300 PRINT"------------------------------" 310 PRINT"* << PETIT SPRITE DE TEST >> *" 320 PRINT"* >> TEST DE SPRITE PETIT << *" 330 PRINT"------------------------------" 340 adr=&4000 350 FOR y=0 TO 31 360 ecran=&C000+&800*(y MOD 8)+80*(y\8) 370 FOR x=0 TO 29 380 POKE adr,PEEK(ecran+x) 390 adr=adr+1 400 POKE ecran+x,255 410 NEXT x 420 NEXT y
Télécharger le listing au format Maxam 1.5
; "Rolling Sprite" ; ; Par OffseT 1993 / Quasar CPC 3 ; Adapté par SNN pour Quasar CPC 8 Org &9000 Nolist Limit &a000 LargeurEcran Equ &50 TableX Equ &5000 ; Table Ox TableY Equ &4800 ; Table Oy TableAdr Equ &8000 ; Adresses Sprite Equ &4000 ; Sprite Largeur Equ 30 ; Largeur Hauteur Equ 32 ; Hauteur Taille Equ largeur*hauteur OffAdr Equ taille+sprite-1 ; ; Initialisation ; ; Pokage des LDD ld hl,pokeldd ld de,pokeldd+2 ld bc,2*largeur-2 ldir ; Génération de la table d'adresses di ld (pile),sp ; (1) ld sp,tableadr ld hl,0 push hl ld de,tabley ; (2) LoopT40 ld hl,&c000+largeur+10 ld a,(de) or a jp z,saute cp 255 jp z,nextt4 ld b,a LoopT4 push bc call bc26 pop bc djnz loopt4 Saute ld a,(tablex) push bc ld c,a ld b,0 add hl,bc ; (3) pop bc push hl ld hl,(saute+1) inc hl ld (saute+1),hl inc de jp loopt40 NextT4 ld (start),sp ld sp,(pile) ld hl,tablex ; (4) ld (saute+1),hl ld hl,(start) ld (posit4),hl ei ; ; Programme principal ; Prog ld b,&f5 Synchro in a,(c) rra jr nc,synchro call offset ; Test clavier di ld bc,&f40e out (c),c ld bc,&f6c0 out (c),c xor a out (c),a ld bc,&f792 out (c),c ld bc,&f645 out (c),c ld b,&f4 in a,(c) ld bc,&f782 out (c),c ld bc,&f600 out (c),c ei rla jp c,prog ; Exit ret ; Affichage du Rolling Sprite Init04 ld sp,(start) ; (5) pop hl jp return1 Init042 ld sp,(start) pop hl jp return2 Offset di ld (pile),sp ld sp,(posit4) pop hl ld a,h or l jr z,init04 Return1 ld (posit4),sp ld de,offadr ld b,hauteur Loop1 ex de,hl PokeLDD ldd ds 2*largeur-2 ex de,hl pop hl ld a,h or l jr z,init042 Return2 djnz loop1 ld sp,(pile) ei ret BC26 ld a,h add a,8 ld h,a ret nc ld bc,&c000+largeurecran add hl,bc ret ; ; Data ; Posit4 dw 0 Start dw 0 Pile dw 0
LDD
, voir plus loin… compris ?