Revenir au plan du site

Scrolling vertical facile avec l'ASIC


De la même façon que pour le [scrolling horizontal], l'ASIC propose une aide au scrolling vertical. Ça se passe toujours au niveau du SSR qui contient les informations de retard pour la verticale et l'horizontale.

Rappel sur le SSR (Soft Scroll Register) de l'ASIC

Pour scroller en vertical, on fera changer le SSR de #10 en #10 (il est possible de mélanger avec l'horizontale, je simplifie). Les valeurs possibles seront 0, #10, #20, #30, ... , #60 et #70
Soft Scroll Register (registre de scroll) - Adresse dans la page ASIC = #6804
7 6 5 4 3 2 1 0
Si activé, continue d'afficher le border pendant 2 octets Décalage vertical vers le haut(de 0 à 7) Décalage horizontal vers la droite (de 0 à 15)*


Voici un déroulé des valeurs CRTC+SSR lors du scrolling de l'écran (ça fonctionne dans les deux sens)
Note : le scrolling CPC au registre 5 n'est pas évoqué dans ce tableau, ne brûlons pas les étapes ;)
Étapes de scrolling
position Y scroll CPC scroll ASIC + SSR
0 CRTC Adr = #0000 CRTC Adr = #0000   SSR = #00
1 CRTC Adr = #0000   SSR = #10
2 CRTC Adr = #0000   SSR = #20
3 CRTC Adr = #0000   SSR = #30
3 CRTC Adr = #0000   SSR = #40
5 CRTC Adr = #0000   SSR = #50
6 CRTC Adr = #0000   SSR = #60
7 CRTC Adr = #0000   SSR = #70
8 CRTC Adr = largeur/2 CRTC Adr = largeur/2   SSR = #00
9 CRTC Adr = largeur/2   SSR = #10
... ... ...


À la verticale, les contraintes d'affichage sont différentes, plus souples qu'à l'horizontale. Sur un scrolling horizontal il est plus fastidieux de répartir la charge d'affichage entre les différentes étapes (celle inévitable où il faut rafraichir la colonne entière (même si un seul pixel de cette colonne est visible) et les autres ou on se contente de changer le registre, il est possible de fragmenter l'affichage de la colonne). Sur le scrolling horizontal, on affiche autant de lignes que le déplacement demandé, il n'y a pas d'étape sans affichage.

Pour cet exemple, nous allons utiliser une [TileMap] qu'on fera reboucler. Si vous avez suivi le scrolling horizontal, il n'y a aucun problème avec cet exemple car l'ASIC est d'une aide précieuse pour le scrolling, on aura juste changé quels bits du SSR on incrémente.

J'utilise toujours mon outil de conversion convgeneric qui va analyser la map globale et fabriquer l'atlas de tiles ainsi que la tileMap.
convgeneric.exe -m 0 -g -tiles -size 8x16 Map16.png

Je récupère toutes les informations de l'outil (téléchargez [Map16.bin] et [Map16.tilemap]
paletteplus: defw #213,#231,#223,#333,#342,#443,#453,#554,#564,#664,#684,#777,#8A4,#AD6,#CD8,#FFE
304 sprites extracted => ça, ça veut dire qu'on aura une tileMap 16 bits et non 8 bits ;)
et le fichier tilemap contenant les DEFW des tuiles

À titre informatif, l'outil exporte l'atlas utilisé pour la tileMap, cela permet parfois d'optimiser son export.


Par exemple, je pouvais avoir une tileMap avec moins de 256 sprites mais la conséquence aurait été d'augmenter la quantité graphiques de tuiles. L'outil convgeneric permet de tester différentes combinaisons de tuiles, charge à vous d'optimiser votre affichage selon le niveau (ou pas). Quoi qu'il en soit, convgeneric ne va pas limiter un atlas de tuiles à 256 tuiles, les limites ne servent à rien :p
Un dernier mot sur le formatage écran choisi, comme notre map faisait 112 pixels de large (56 octets), cela nous permet de nous étaler verticalement sur les 272 lignes du moniteur (16384/56=292)
BUILDSNA : BANKSET 0
SNASET CPC_TYPE,4 ; modèle 6128+ conseillé
ORG #100 : RUN #100
;*** RMR2 tags + macro ***
ASICOFF equ 0 : ROM0000 equ 0 : ROM4000 equ %01000 : ROM8000 equ %10000 : ASICON equ %11000
ROM0 equ 0 : ROM1 equ 1 : ROM2 equ 2 : ROM3 equ 3 : ROM4 equ 4 : ROM5 equ 5 : ROM6 equ 6 : ROM7 equ 7
macro RMR2 tags
ld a,{tags}+%10100000
ld b,#7F
out (c),a
mend

ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0
call UnlockAsic : RMR2 ASICON
ld hl,palettePlus : ld de,#6400 : ld bc,32 : ldir : ld hl,#000 : ld (#6420),hl ; +border noir

ld bc,#BC00+1 : out (c),c : ld bc,#BD00+28 : out (c),c ; Notre map fait 112 pixels de large, adaptez selon VOS besoins
ld bc,#BC00+2 : out (c),c : ld bc,#BD00+39 : out (c),c ; Centrer l'écran en X
ld bc,#BC00+6 : out (c),c : ld bc,#BD00+34 : out (c),c ; Hauteur de l'écran visible en lignes de caractères
ld bc,#BC00+7 : out (c),c : ld bc,#BD00+35 : out (c),c ; Centrer l'écran en Y
ld bc,#BC00+12 : out (c),c : ld bc,#BD30 : out (c),c ; adresse par défaut
ld bc,#BC00+13 : out (c),c : ld bc,#BD00 : out (c),c

LaBoucle
call WaitVBL
RMR2 ASICON : ld hl,#6804 ; activer la page ASIC, précharger l'adresse du SSR
ld a,0 : decalageCourant=$-1 : add #10 : and #70 : ld (decalageCourant),a : ld (hl),a ; on incrémente le décalage vertical
; si on a rebouclé de #70 à #00, alors le flag Z a été monté par le AND #70
jr nz,pasCRTC
ld hl,0 : adresseCRTCcourante=$-2 : ld bc,28 : add hl,bc : res 2,h : ld (adresseCRTCcourante),hl
ld bc,#BC00+12 : out (c),c : inc b : ld a,h : or #30 : out (c),a : dec b : inc c : out (c),c : inc b : out (c),l
pasCRTC
RMR2 ASICOFF ; on ferme la page puisqu'on ne la nécessite plus et que nos données sous dessous!
; nos tiles font 8x16, il faut gérer le 'curseur' à l'intérieur des tiles et on en a 14 en largeur...
ld hl,(adresseTuileEcran) : ld (adresseTuileCourante),hl
ld ix,tileMap : adresseTileMap=$-2
ld b,14 ; on a 14 tuiles à parcourir
AfficheLigneTuile
exx ; on met le compteur dans les registres secondaires
ld hl,(ix+0) : inc lx : inc ix ; index de la tuile 16 bits car +256 tuiles
; HL = index x 64 / au lieu de décaler 6 fois vers la gauche, je décale deux fois à droite et je permute les registres (équivalent à 8 décalages - 2)
xor a : srl hl : rra : srl hl : rra : ld h,l : ld l,a
ld de,tuiles : add hl,de ; HL=adresse de la tuile courante
ld a,(ligneTuileCourante) : add a : add a ; ligne x 4
add l : ld l,a : ld a,h : adc 0 : ld h,a ; c'est vraiment pas optimisé tout ce code :p
ld de,(adresseTuileCourante)
; afficher la ligne courante de la tuile courante
ldi 4 ; copie de la largeur de la tuile, à la bonne ligne
; besoin impératif d'ajuster DE au cas où on se retrouve sur le rebouclage de la ligne de bloc!
; si la partie de l'adresse correspondant à la position dans le bloc (0-#7FF) est nulle, alors on vient de reboucler
ld a,d : and 7 : or e : jr nz,.pasDeRebouclage : ld a,d : sub 8 : ld d,a : .pasDeRebouclage
ld (adresseTuileCourante),de ; on garde la position
exx
djnz AfficheLigneTuile
; ligne de tuiles terminée, on prépare la prochaine adresse, ligne en dessous!
ld hl,(adresseTuileEcran) : ld a,h : add 8 : ld h,a : jr nc,.novf
ld a,56 : add l : ld l,a
ld a,#C0 : adc h : ld h,a
res 3,h ; rebouclage de bloc en plein début de ligne, ça PEUT arriver
.novf ld (adresseTuileEcran),hl ; prêt pour la nouvelle ligne
ld a,(ligneTuileCourante) : inc a : and 15 : ld (ligneTuileCourante),a : jr nz,.memesTuiles
ld hl,(adresseTileMap) : ld de,14*2 : add hl,de : ld (adresseTileMap),hl ; changer de ligne sur la tileMap
ld a,(hl) : inc a : jr nz,.memesTuiles : inc l : ld a,(hl) : inc a : jr nz,.memesTuiles ; test du marqueur de fin
ld hl,tileMap : ld (adresseTileMap),hl ; Rebouclage de la tileMap !
.memesTuiles
jp LaBoucle

UnlockAsic
ld bc,#BCFF
out (c),c
out (c),0
ld hl,%1001000011101010
.loop
out (c),c
ld a,h:rlca:ld h,l:ld l,a
srl c:res 3,c
and #88
or c
ld c,a
cp #4D
jr nz,.loop
ld a,#CD
out (c),a : out (c),a
ret

WaitVBL
ld b,#F5 : noVBL in a,(c) : rra : jr c,noVBL
VBL in a,(c) : rra : jr nc,VBL : ret

palettePlus defw #213,#231,#223,#333,#342,#443,#453,#554,#564,#664,#684,#777,#8A4,#AD6,#CD8,#FFE
adresseTuileEcran defw #C000+56*34 ; avant le premier scroll, cette adresse correspond à la 272 ligne (hors écran, 1 ligne dessous)
adresseTuileCourante defw 0
ligneTuileCourante defb 0
tuiles incbin 'Map16.bin'
align 2 : tileMap include 'Map16.tilemap' : defw #FFFF ; marqueur de fin

C'était un peu fastidieux car on n'a pas choisi la facilité avec un écran de 64 octets de large, le notre fait 56 octets, obligeant à ajuster pour le rebouclage de bloc. Hey! Au moins vous avez une méthode pour gérer proprement ce rebouclage (et on parlera de moyens de l'optimiser plus tard).