Le fichier "Albator.Dsk" contient un exemple de slide-show pouvant être généré avec ConvImgCPC.
Pour cela, les images doivent être sauvegardées en mode "compacté". Ensuite, il suffit d'adapter le programme basic pour faire le slide-show.
Le fichier "dpkslide.bin" contient le programme binaire permettant d'afficher une image.
L'utilisation de dpkslide.bin est la suivante :
- Lire l'image compactée à l'adresse #2000
- Faire un CALL #A400 pour afficher l'image.
Le call #a400 décompacte l'image, affecte la palette et affiche l'image. Pour retourner au basic, il faut appuyer sur la touche espace.
Remarque: le programme utilise la plage mémoire #6400-#A3FF comme buffer temporaire de décompactage, avant d'afficher l'image.
Tout ce qui se trouve dans cette plage d'adresse sera donc écrasé.
Lors d'une sauvegarde d'une image non compactée en mode CPC old, la palette est stockée à partir de l'adresse #D7D1, le mode écran est stocké en #D7D0, et une routine d'affichage est appelable par un call &C7D0.
Le programme d'affichage (situé à l'adresse #C7D0) est le suivant :
LD A,(#D7D0)
CALL #BD1C ; Changement de mode sans effacer l'écran
LD HL,#D7D1
LD B,(HL)
LD C,B
CALL #BC38 ; Changement du Border
XOR A
LD HL,#D7D1
BCL:
LD B,(HL)
LD C, B
PUSH AF
PUSH HL
CALL #BC32 ; Changement des Inks
POP HL
POP AF
INC HL
INC A ; passer à la couleur suivante
CP #10 ; 16 couleurs effectuées ?
JR NZ,BCL ; sinon on reboucle
JP #BB18 ; Attente appui d'une touche
Lors d'une sauvegarde d'une image non compactée en mode CPC+, la palette est stockée à partir de l'adresse #D7D1, le mode écran est stocké en #D7D0. Par contre, il n'y a pas de routine d'affichage directement incluse dans l'image.
Voici un exemple de programme d'affichage de la palette des images en mode CPC+ :
LD BC,#BC11 ; Port = #BCXX, 17 données à envoyer
LD HL,UnlockAsic ; Séquence de déverouillage de l'ASIC
SetSeq:
LD A,(HL)
OUT (C),A ; Envoi des données
INC HL
DEC C
JR NZ,SetSeq
LD BC,#7FA0
LD A,(#D7D0) ; Mode écran
OR #8C
OUT (C),A
OUT (C),C
LD BC,#7FB8
OUT (C),C
LD HL,#D7D1 ; Palette CPC+
LD de,#6400
LD BC,17*2
LDIR
Boucle: ; Attendre appui sur touche espace
XOR A
LD BC,#F40E ; Registre 14 du PSG
OUT (C),C
LD BC,#F6C0 ; Ecriture numéro registre
OUT (C),C
OUT (C),A
LD BC,#F792 ; Port A PPI en lecture
OUT (C),C
LD BC,#F645 ; ligne = 5 (pour touche espace)
OUT (C),C
LD B,#F4 ; Lecture registre
IN A,(C) ; Remarque : bit à 0 = appuyé
LD BC,#F782 ; Repasse port A PPI en écriture
OUT (C),C
RLA ; Bit 7 dans Flag C
JR C,Boucle ; Si pas à zéro, attendre
EI
RET
UnlockAsic:
DB #FF, #00, #FF, #77, #B3, #51, #A8, #D4
DB #62, #39, #9C, #46, #2B, #15, #8A, #CD, #EE
On doit ici interdire les interruptions pour maintenir les couleurs de l'Asic. On aurai pu également créer une routine d'interruptions, mais cela aurai alors un peu complexifié le source. J'ai préféré rester dans la simplicité.
Pour les images en "mode 3", l'astuce est de changer les stylots 1, 2, 3 de couleurs deux fois par lignes. Cela nécessite donc 6*200 = 1200 données de couleurs.
Les images en mode 3 ne peuvent être utilisées sur CPC qu'en mode compacté. En effet, sans cela, les images auraient eu une taille de 16384+1200=17584 octets, soit 18 Ko.
J'ai donc préféré utiliser uniquement ces images en mode compacté.
La compression RLE d'OCP ne permettai pas de gains significatifs sur les images. J'ai donc opté pour une compression dérivée du lzw, dont j'ai déjà donné le code source en C il y a quelques temps...
Cette routine de compression a plusieurs avantages :
- Le gain est plus important que la compression RLE,
- Le temps de décompression n'est pas beaucoups plus grand qu'avec une compression RLE,
- La routine de décompression est assez simple et a pu être facilement retranscrite en assembleur Z80.
Cette routine est livrée dans le package de ConvImgCPC dans le fichier "Depklzw.asm".
Voici cette routine :
;
; Entrée :
; - HL = Buffer (fichier compacté)
; - DE = Destination
; Sortie :
; - AF, BC, DE, HL modifiés
;
DepkLzw:
XOR A
LD (BclLzw+1),A
;
TstBitLzw:
LD A,(HL)
INC HL
RRA ; Rotation rapide calcul seulement flag C
SET 7,A ; Positionne bit 7 en gardant flag C
LD (BclLzw+1),A
JR C,TstCodeLzw
LDI
;
BclLzw:
LD A,0
RR A ; Rotation avec calcul Flags C et Z
LD (BclLzw+1),A
JR Z,TstBitLzw
JR C,TstCodeLzw
LDI
JR BclLzw
;
TstCodeLzw:
;
; a = inbuffer[ inbytes ];
;
LD A,(HL)
AND A
;
; Plus d'octets à traiter
; = fini
;
RET Z
INC HL
LD B,A
RLCA
JR NC,TstLzw40
;
; length = 3 + ( ( inbuffer[ inbytes ] >> 4 ) & 7 );
; index = ( inbuffer[ inbytes++ ] & 15 ) << 8;
; index |= inbuffer[ inbytes++ ];
; index++;
;
PUSH HL
LD C,(HL) ; C = poids faible index
LD L,B ; L = inbuffer[inbytes]
RLCA
RLCA
RLCA
AND 7
ADD A,3
LD H,A ; H = length
LD A,L
AND #0F
LD B,A ; B = poids fort index
LD A,H ; A = Length
LD H,D
LD L,E
SBC HL,BC
DEC HL
LD B,0
LD C,A
LDIR
POP HL
INC HL
JR BclLzw
;
TstLzw40:
RLCA
JR NC,TstLzw20
;
; length = 2;
; index = inbuffer[ inbytes++ ] & 0x3f;
; index++;
;
LD C,B
RES 6,C
LD B,0 ; BC = index -1, pas de +1 car flag C = 1
PUSH HL
LD H,D
LD L,E
SBC HL,BC
LDI
LDI
POP HL
JR BclLzw
;
TstLzw20:
RLCA
JR NC,TstLzw10
;
; length = 2 + ( inbuffer[ inbytes++ ] & 31 );
; index = inbuffer[ inbytes++ ];
; index++;
;
PUSH HL
LD A,B
RES 5,A
LD C,(HL) ; C = index
LD B,0
LD H,D
LD L,E
SBC HL,BC
ADD A,2
LD C,A ; C = length
LDIR
POP HL
INC HL
JR BclLzw
;
TstLzw10:
RLCA
JR NC,CodeLzw0F
;
; index = ( inbuffer[ inbytes++ ] & 15 ) << 8;
; index |= inbuffer[ inbytes++ ];
; length = inbuffer[ inbytes++ ] + 1;
; index++;
;
RES 4,B ; B = index(high)
LD C,(HL) ; C = index(low)
INC HL
LD A,(HL) ; A = length - 1
PUSH HL
LD H,D
LD L,E
SBC HL,BC ; Flag C=1 -> hl=hl-(bc+1)
LD B,0
LD C,A
INC BC ; BC = length
LDIR
POP HL
INC HL
JR BclLzw
;
CodeLzw0F:
PUSH HL
LD A,B
CP #0F
JR NZ,CodeLzw02
;
; length = index = inbuffer[ inbytes + 1 ] + 1;
; inbytes += 2;
;
LD C,(HL)
XOR A
LD B,A
INC BC
LD H,D
LD L,E
SBC HL,BC
LDIR
POP HL
INC HL
JP BclLzw
;
CodeLzw02:
LD H,D
LD L,E
CP 2
JR C,CodeLzw01
;
; length = index = inbuffer[ inbytes ];
;
LD C,A
XOR A
LD B,A
SBC HL,BC
LDIR
POP HL
JP BclLzw
;
; length = index = 256;
;
CodeLzw01: ; Ici, A = B = 1
XOR A
LD C,A
DEC H
LDIR
POP HL
JP BclLzw
Pour le mode 3, seul la palette "CPC OLD" peut être utilisée pour le moment.
Pour terminer, voici le source qui permet d'afficher les images compactées en mode 0, 1, 2 ou 3, en version "CPC+" ou "CPC OLD" :
Cette routine est livrée dans le package de ConvImgCPC dans le fichier "DpkSlide.asm".
BuffTmp EQU #6400 ; Buffer décompactage temporaire
BuffCmp EQU #2000 ; Buffer image compactée
ORG #A400
;
; Vérifier fichier est bien image compactée
;
LD HL,BuffCmp
LD A,(HL) ; Vérifier en-tête du fichier
CP 'P'
RET NZ
INC HL
LD A,(HL) ; Doit commencer par "PKS"
CP 'K'
RET NZ
INC HL
LD A,(HL)
CP 'S'
RET NZ
INC HL
LD A,(HL) ; Puis, 4e octet = type d'image
CP 'L' ; 'L' = image "normale"
JR Z,ImgType1
CP 'P' ; 'P' = image CPC+
JR Z,ImgType2
CP '3' ; '3' = image "mode 3"
JR Z,ImgType3
RET ; Si pas identifié, retour...
;
; Image type 1 - CPC "OLD" en mode 0, 1 ou 2
;
ImgType1:
LD HL,BuffCmp+21 ; Données image en #2015
CALL DecompImage
EI
LD A,(BuffCmp+4) ; Mode en #2004
CALL #BD1C ; Chgt Mode sans effacer l'écran
LD HL,BuffCmp+5 ; Palette en #2005
XOR A
SetCol:
PUSH AF
PUSH HL
LD B,(HL)
LD C,B
CALL #BC32 ; Initialisation palette de couleurs
POP HL
POP AF
INC HL
INC A
CP 16
JR C,SetCol
JP #BB18 ; Attendre appui sur une touche
;
; Image type 2 - CPC + en mode 0, 1 ou 2
;
ImgType2:
LD HL,BuffCmp+37 ; Données image en #2025
CALL DecompImage
LD BC,#BC11
LD HL,UnlockAsic ; Séquence de déverouillage de l'ASIC
SetSeq:
LD A,(HL)
OUT (C),A ; Envoi des données
INC HL
DEC C
JR NZ,SetSeq
LD BC,#7FB8
LD A,(BuffCmp+4) ; Mode écran en #2004
OUT (C),A
OUT (C),C
LD HL,BuffCmp+5 ; Palette CPC+ en #2005
LD de,#6400
LD BC,16*2
LDIR
LD HL,BuffCmp+5 ; Border = Couleur 0
LDI
LDI
Boucle:
CALL TstEspace ; Test touche espace appuyée
JR C,Boucle ; Si non, attendre
LD BC,#7FA0
OUT (C),C
EI
RET
;
; Image type 3 - CPC old en mode "3" (Mode 1 avec 6 couleurs/lignes)
;
ImgType3:
LD HL,BuffCmp+1206 ; Données image en #24B6
CALL DecompImage
LD HL,(#38)
LD (RestoreIRQ+1),HL ; Sauvegarde ancien vecteur #38
LD HL,#C9FB
LD (#38),HL ; EI et RET en #38
LD BC,#7F8D
OUT (C),C ; Mode 1
XOR A
OUT (C),A ; Sélectionner couleur 0
LD HL,BuffCmp+4 ; Adresse de la valeur de la couleur 0
OUTI ; Et affecter
BoucleImg3:
LD B,#F5
WaitVBL:
IN A,(C) ; Attendre la VBL
RRA
JR NC,WaitVBL
CALL TstEspace ; test touche espace appuyée
JR NC,FIN ; si oui, fini
EI
HALT ; Attendre 2 interruptions
HALT
DI
LD B,158
Wait1:
LD HL,0 ; Pause pour se synchroniser au début
DJNZ Wait1 ; de l'écran visible
XOR A ; A = 0 pour tester fin des couleurs
LD BC,#7F01 ; C = ink 1
LD HL,BuffCmp+5 ; Palette en #2005
LD DE,#203 ; D = ink 2, E = ink 3
SetCoul:
OUT (C),C ; ink 1
OUTI
OUT (C),D ; ink 2
OUTI
OUT (C),E ; ink 3
OUTI
NOP
NOP ; Temps d'attente
LD BC,#7F01 ; Repositionner registre B
OUT (C),C ; ink 1
OUTI
OUT (C),D ; ink 2
OUTI
OUT (C),E ; ink 3
OUTI
CP (HL) ; Valeur = 0 ?
JR NZ,SetCoul ; Si non, on continue
JR BoucleImg3 ; Boucle attente touche
Fin:
DI
RestoreIRQ:
LD HL,0
LD (#38),HL ; Restaurer ancien vecteur #38
EI
RET
;
; Décompacter l'image dans un buffer temporaire
;
DecompImage:
DI
LD DE,BuffTmp
CALL DepkLzw
;
; Efface l'écran (toutes les couleurs à 0)
;
LD BC,#7F54
LD A,#11
Cls:
DEC A
OUT (C),A
OUT (C),C
JR NZ,Cls
;
; Affiche la nouvelle image
;
LD DE,BuffTmp
LD HL,#C000
Draw1:
LD A,200
Draw2:
EX DE,HL
LDI
EX DE,HL
LD BC,#7FF
ADD HL,BC
JR NC,Draw3
LD BC,#C050
ADD HL,BC
Draw3:
DEC A
JR NZ,Draw2
LD BC,#7CF
SBC HL,BC
LD A,L
CP #50
JR C,Draw1
RET
;
; Lecture clavier (et notamment la touche espace...)
;
TstEspace:
XOR A
LD BC,#F40E ; Registre 14 du PSG
OUT (C),C
LD BC,#F6C0 ; Ecriture numéro registre
OUT (C),C
OUT (C),A
LD BC,#F792 ; Port A PPI en lecture
OUT (C),C
LD BC,#F645 ; ligne = 5 (pour touche espace)
OUT (C),C
LD B,#F4 ; Lecture registre
IN A,(C)
LD BC,#F782 ; Repasse port A PPI en écriture
OUT (C),C
RLA ; Bit 7 dans Flag C
RET
UnlockAsic:
DB #FF, #00, #FF, #77, #B3, #51, #A8, #D4
DB #62, #39, #9C, #46, #2B, #15, #8A, #CD, #EE
read "DepkLzw.asm"
Enfin, concernant les images en overscan, elles modifient les registres du CRTC avec les valeurs suivantes :
Registre 1 = #30 (48)
Registre 2 = #32 (50)
Registre 6 = #22 (34)
Registre 12 = #0D (13)
Une image non compactée est sauvegardée à l'adresse #200.
Le mode de l'image est stocké à l'adresse #800
La palete de l'image est stockée à partir de l'adresse #801
Le code d'affichage se trouve à l'adresse #811 pour une image en mode CPC OLD, et en #821 pour une image en mode CPC +.
Les fichiers "AffOverscan.asm" et "AffOverscan+.asm" contiennent respectivement les routine d'affichage décrites ci-dessus.
Ce code effectue les actions suivantes :
- Modification des registres du CRTC pour prendre en compte l'overscan,
- Initialisation du mode et de la palette de couleurs
- Envoi de la séquence de dévérouillage de l'ASIC en mode CPC+
- Attente l'appui sur la touche ESPACE.
Les images compactées en mode Overscan sont sauvegardée avec la palette et le mode, mais sans la routine d'affichage.
Pour les décompacter, il faut utiliser la routine décrite dans le le fichier "Depklzw.asm", et positionner ensuite le CRTC, le mode et la palette de couleurs.