Revenir au plan du site

Scroll, moche et méchant


On va repartir de notre [ rupture stable ] sous interruption. Notre écran est déjà découpé, attaquons le sujet!

Pour rappel, nous allons ajouter des lignes, il faut donc commencer par modifier notre code de référence pour que l'écran du bas ait par défaut 8 lignes (un bloc donc) de moins. Ça se passe dans l'interruption 04 avec l'envoi du registre 4!

ld bc,#BC04 : out (c),c : ld bc,#BD00+18 : out (c),c ; le deuxième écran "complet" fait 19 blocs de base pour avoir 39 au total avec la compensation

Au niveau de l'interruption 02, qui définit le bloc écran du haut, application du R5 en accord avec celui qui suit la VBL.
ld bc,#BC05 : out (c),c
r5value ld a,0 : inc b : out (c),a ; envoyer le registre 5

On revient dans l'interruption 04, la compensation qui suit la VBL précède celle du bloc du haut! /!\
on ajoute notre R5 qui augmente (et visuellement fait monter l'écran) ici car nous sommes juste après la VBL et que les valeurs R5 + complément doivent être raccords d'une VBL à l'autre (essayez donc de changer l'incrémentation de place ;).
ld bc,#BC05 : out (c),c
ld a,(r5value+1) : inc a : and 7 : ld (r5value+1),a
ld c,a : ld a,8 : sub c : inc b : out (c),a ; envoyer (8-r5value)

Voici notre écran qui monte!!!



Déplacer le pointeur vidéo


Notre écran monte mais rien n'est injecté en bas et surtout, tout ceci boucle à l'infini.

Il faut changer le départ de l'écran toutes les 8 lignes, quand la valeur de R5 du bloc passe de 7 à 0. C'est dans l'interruption 06 que nous forçons l'adresse de départ du CRTC de l'écran du haut. Il faut changer ça.

Le code suivant
ld bc,#BC00+12 : out (c),c : ld bc,#BD30 : out (c),c ; écran du haut en #C000

devient (code repris de l'article scroll vertical facile avec l'ASIC)
ld hl,0 : adresseCRTCcourante=$-2 : ld bc,40 : CRTCaddition=$-2: 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

On modifie l'interruption 04 pour additionner les 40 mots uniquement lors du passage de 7 à 0.
ld a,(r5value+1) : inc a : and 7 : ld (r5value+1),a
ld c,a : ld a,8 : sub c : inc b : out (c),a ; envoyer (8-r5value)
; mettre à jour l'addition pour le CRTC (ou pas)
ld a,c : or a : ld a,40 : jr z,.noAdd : xor a : .noAdd : ld (CRTCaddition),a

Ainsi que le forçage du registre 13 sinon le chien va bouger avec!
ld bc,#BC00+13 : out (c),c : inc b : out (c),0 ; écran suivant en #8000



Actualiser le contenu des nouvelles lignes!


Aller, on termine cet article avec une bête copie de la ligne sortante vers la ligne entrante!

L'adresse de la ligne du haut est #C000 et l'adresse de celle à venir est #C5F0 (On peut le voir facilement à l'explorateur graphique mais ça se calcule tout aussi bien). Écran de 80 octets de large et 19 blocs de haut => #5F0 en hexa :)

On peut réaliser la copie dans l'interruption 05 qui ne fait rien pour le moment et on verra le highlight grossir un peu! Attention, un simple LDIR ne suffira pas, rappelez-vous, et en particulier sur des écrans dont la largeur n'est pas une puissance de deux, qu'il faut gérer le rebouclage de bloc, potentiellement sur tous les octets!

Dans notre cas, écran de 80 de large, le rebouclage n'est à gérer que tous les 8 octets, puissance de deux maximum multiple de notre largeur (80). Allez c'est parti. Je fais volontairement quelque chose de poussif, histoire de mieux vendre les scrollings verticaux avec des largeurs de 64 octets, comme la quasi totalité des scrollings de ce type. On gagne vraiment beaucoup car on évite tous les tests coûteux en temps machine.

Il vous faudra les images [chien] et [chat] pour continuer ;)
buildsna : bankset 0
org #100 : run #100
ld sp,#100 : ld hl,#C9FB : ld (#38),hl : ei ; init pile+INT

ld bc,#BC06 : out (c),c : ld bc,#BD00+19 : out (c),c

ld bc,#7F00 : out (c),c : ld a,#54 : out (c),a
ld bc,#7F01 : out (c),c : ld a,#4E : out (c),a
ld bc,#7F02 : out (c),c : ld a,#43 : out (c),a
ld bc,#7F03 : out (c),c : ld a,#4B : out (c),a

call LaPause

novbl ld b,#F5
.vbl in a,(c) : rra : jr nc,.vbl
.novbl in a,(c) : rra : jr c,.novbl
ld b,0 : djnz $
; il nous reste presque 2000 nops avant l'interruption à venir
; largement le temps de préparer notre vecteur, mais attention!
; le point critique reste l'initialisation!
di ; facultatif ici car on SAIT
ld a,#C3 : ld hl,int01
ld (#38),a : ld (#39),hl
ei ; idem

;***********************************
programmeInterruptible
;***********************************
jr programmeInterruptible

LaPause
ld bc,0 : ld a,5
.unepause djnz $ : dec c : jr nz,.unepause : dec a : jr nz,.unepause
ret

;***********************************
; pool d'interruptions
;***********************************
align 256
int01 push hl : ld hl,int02 : ld (#39),hl : pop hl : ei : ret
int02 push af,bc
ld bc,#BC07 : out (c),c : ld bc,#BD00+255 : out (c),c ; desactiver la VBL
ld bc,#BC06 : out (c),c : ld bc,#BD00+19 : out (c),c ; notre écran visible fait 19 blocs
ld bc,#BC04 : out (c),c : ld bc,#BD00+18 : out (c),c ; notre écran "complet" fait 19 blocs (R4=19-1)
ld bc,#BC05 : out (c),c
r5value ld a,0 : inc b : out (c),a ; envoyer le registre 5
ld bc,int03 : ld (#39),bc
pop bc,af : ei : ret
int03 push af : ld a,lo(int04) : ld (#39),a : pop af : ei : ret
int04 push af,bc
; changer l'adresse de l'écran suivant AVANT qu'il arrive!
ld bc,#BC00+12 : out (c),c : ld bc,#BD20 : out (c),c ; écran suivant en #8000
ld bc,#BC00+13 : out (c),c : inc b : out (c),0 ; écran suivant en #8000
; attendre 16 lignes soit 16x64 nops ou 4x256 nops, le DJNZ qui saute prend 4 nops
ld b,0 : djnz $
ld bc,#7F02 : out (c),c : ld a,#47 : out (c),a ; petit changement de couleur
ld bc,#BC07 : out (c),c : ld bc,#BD00+11 : out (c),c
ld bc,#BC06 : out (c),c : ld bc,#BD00+8 : out (c),c ; on raccourci le deuxième écran visible
ld bc,#BC04 : out (c),c : ld bc,#BD00+18 : out (c),c ; le deuxième écran "complet" fait 19 blocs de base pour avoir 39 au total avec la compensation
ld bc,#BC05 : out (c),c
ld a,(r5value+1) : inc a : and 7 : ld (r5value+1),a
ld c,a : ld a,8 : sub c : inc b : out (c),a ; envoyer (8-r5value)
; mettre à jour l'addition pour le CRTC (ou pas)
ld a,c : or a : ld a,40 : jr z,.noAdd : xor a : .noAdd : ld (CRTCaddition),a
ld bc,int05 : ld (#39),bc
pop bc,af : ei : ret

int05 push af,bc,de,hl,ix
ld hl,int06 : ld (#39),hl
ld hl,#C000 : copieSrc=$-2 : ld de,#C5F0 : copieDest=$-2
ld xl,10 ; copier 10 fois 8 octets
.copieLigne
ldi 7 ; copier 7 octets + incréments HL/DE
ld a,(hl) : ld (de),a ; copie un 8è
; rebouclage de bloc sur la ligne (code poussif)
ld a,h : and %11111000 : ld c,a ; Mettre les 5 bits supérieurs de HL dans C
inc hl
ld a,h : and 7 : or c : ld h,a ; ne récupérer que la position dans le bloc et forcer le bloc
ld a,d : and %11111000 : ld c,a ; Mettre les 5 bits supérieurs de DE dans C
inc de
ld a,d : and 7 : or c : ld d,a ; ne récupérer que la position dans le bloc et forcer le bloc
dec xl
jr nz,.copieLigne

; prochain appel s'occupera des lignes en dessous!
ld hl,(copieSrc)
ld a,h : add 8 : ld h,a : jr nc,.dessousSrc
ld a,80 : add l : ld l,a : ld a,#C0 : adc h : ld h,a : res 3,h
.dessousSrc
ld (copieSrc),hl
ld hl,(copieDest)
ld a,h : add 8 : ld h,a : jr nc,.dessousDest
ld a,80 : add l : ld l,a : ld a,#C0 : adc h : ld h,a : res 3,h
.dessousDest
ld (copieDest),hl
pop ix,hl,de,bc,af : ei : ret
int06 push af,bc,hl
ld bc,#7F02 : out (c),c : ld a,#43 : out (c),a ; petit changement de couleur pendant la VBL :)

ld hl,0 : adresseCRTCcourante=$-2 : ld bc,40 : CRTCaddition=$-2 : 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

ld hl,int01 : ld (#39),hl ; et on revient à la première INT
pop hl,bc,af : ei : ret

teucha defb #54,#4E,#43,#4B


org #8000 : incbin 'iench.bin'
org #C000 : incbin 'teucha.bin' ; petite image





Et après? Qu'est-ce qu'on fait?


Comme vous le voyez rapidement, si la jonction entre la zone de scrolling et le HUD est bonne et sans bavure, on voit que le premier bloc de lignes de l'écran de scroll remonte avec l'écran! C'est dégueulasse...

Mais alors, comment font les vrais, les warriors?

Hé bien pareil en fait! C'est dégueulasse mais vous ne le voyez pas parce que c'est à peu près caché. Par exemple, dans mission génocide, le haut de l'écran est vraiment en limite du cadre du moniteur mais si on fait attention, on peut voir les vaisseaux qui apparaissent hors de la zone de scroll, l'apparition du décor est camouflée par des lignes noires.



Voyons dans [L'article suivant] comment cacher la misère :)