La voie du véritable clipping, une histoire de découpe!
Nous allons reprendre notre routine de sprite masquée et ajouter la gestion du clipping vertical en suivant les principes évoqués précedemment mais je vous remets quand même les schémas et les formules à appliquer :

La gestion du clipping haut se place logiquement au tout début de la routine de sprite. On teste le Y et on ajuste au besoin. Et la gestion du clipping bas AUSSI se trouve au début, car elle va se contenter de changer le nombre d'itération (réduire le paramètre correspondant à la hauteur du sprite). AfficheSprite ; BC=page + coordonnée X (0-79) / HL=coordonnée Y (0-199) / DE=adresse des données du sprite ; XL=largeur du sprite en octets / XH=hauteur du sprite en nombre de lignes bit 7,h : jr z,.pasClipHaut ; si le Y est positif ou nul, pas de clipping en haut ; XH est la hauteur affichable, on soustrait le Y négatif push hl : ld a,xh : add l : ld l,a : ld a,h : adc 0 : ld h,a : ld a,xh : ld xh,a : pop hl ; vu qu'on saute des lignes, il faut avancer le pointeur de données ld a,l : ex hl,de : ld d,0 : ld e,xl .sauteLignes add hl,de : inc a : jr nz,.sauteLignes ; +simple qu'une multiplication ex hl,de ; remettre le pointeur dans DE ld hl,0 ; tout est corrigé, on dit qu'on part maintenant de la ligne 0 .pasClipHaut ; pour rester sur des comparaisons 8 bits, on peut soustraire sprHauteur à hauteur et comparer à sprY ld a,200 : sub xh : cp l : jr nc,.pasClipBas ; ld a,200 : sub l : ld xh,a ; nouvelle hauteur +petite .pasClipBas call CalculeAdressePixel ...La suite de la routine est identique, en fait on a modifié à la volée les paramètres d'entrée, à savoir : - la coordonnée Y et l'adresse des données du sprite dans le cas du clipping haut. - la hauteur du sprite dans le cas du clipping bas.
Pour gérer le clipping gauche/droite, il va à nouveau falloir tester en début de routine nos coordonnées. Cette fois on teste le X avec la largeur écran.

On va reprendre le code à partir du label .pasClipBas .pasClipBas xor a ; offsetDebut par défaut bit 7,c : jr z,.pasClipGauche ld a,c : add xl : ld xl,a ; nouvelle largeur ld a,c : neg ; nouvel offsetDebut ld c,0 ; nouveau X en zéro .pasClipGauche ld (offsetDebut),a ; soit zéro, soit celui calculé lors du clipping ld a,c : add xl : cp 81 ; largeur+1 rapport à la comparaison souhaitée ld a,0 : jr c,.pasClipDroite ; A=0 au cas où on n'ait pas de clipping, pour reset offsetFin ld a,xl : exa ; on met la largeur du sprite de côté ld a,80 : sub c : ld xl,a ; nouvelle largeur de sprite exa ; on récupère la largeur d'origine sub xl .pasClipDroite ld (offsetFin),acall CalculeAdressePixelVous remarquez qu'on patche deux zones de code avec les labels offsetDebut et offsetFin, qui sont des décalages qui vont nous permettre à chaque ligne de bien caler les donnéesque l'on lit rapport au clipping en court (ou zéro si pas de clipping). Plaçons nos deux additions dans la boucle principale. Vous aurez compris que la valeur #12 est remplacée par le codequi teste le clipping, dans un cas comme dans l'autre. ld a,e : add #12 : offsetDebut=$-1 : ld e,a : ld a,d : adc 0 : ld d,a .pixelMasque ld a,(de) ; lire le sprite ld l,a ; octet du sprite dans L ld a,(bc) ; on récupère l'octet de l'écran and (hl) ; on applique le masque or l ; on fusionne avec la donnée du sprite ld (bc),a ; on remet dans l'écran inc bc inc de ; et on incrémente data+ecran dec yl jr nz,.pixelMasque ld a,e : add #12 : offsetFin=$-1 : ld e,a : ld a,d : adc 0 : ld d,aEt voilà, nos deux additions encapsulent la boucle principale. Réalisons un BREF test pour valider que tout est ok. BUILDSNA : BANKSET 0 ORG #38 : EI : RET ORG #100 : RUN #100ld sp,#100 : ei ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0 ld hl,palette : ld bc,#7F00 setPalette out (c),c : inc c : inc b : outi : ld a,(hl) : or a : jr nz,setPalette ld bc,#C000+#FC : ld hl,60 ; à quatre octets du bord gauche ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSpriteld bc,#C000+76 : ld hl,100 ; à quatre octets du bord ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite ld bc,#C000+26 : ld hl,-18 ; à moitié ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite ld bc,#C000+46 : ld hl,184 ; à moitié ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite; Et maintenant les coins!!! ld bc,#C000+#FC : ld hl,-18 ; à quatre octets du bord gauche ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite ld bc,#C000+#FC : ld hl,184 ; à quatre octets du bord gauche ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite ld bc,#C000+76 : ld hl,-18 ; à quatre octets du bord gauche ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite ld bc,#C000+76 : ld hl,184 ; à quatre octets du bord gauche ld xl,9 : ld xh,36 : ld de,donnees_sprite ; dimensions du sprite largeur/lignes call AfficheSprite jr $ AfficheSprite ; BC=page + coordonnée X (0-79) / HL=coordonnée Y (0-199) / DE=adresse des données du sprite ; XL=largeur du sprite en octets / XH=hauteur du sprite en nombre de lignes bit 7,h : jr z,.pasClipHaut ; si le Y est positif ou nul, pas de clipping en haut ; XH est la hauteur affichable, on soustrait le Y négatif push hl : ld a,xh : add l : ld l,a : ld a,h : adc 0 : ld h,a : ld a,l : ld xh,a : pop hl ; vu qu'on saute des lignes, il faut avancer le pointeur de données ld a,l : ex hl,de : ld d,0 : ld e,xl .sauteLignes add hl,de : inc a : jr nz,.sauteLignes ; +simple qu'une multiplication ex hl,de ; remettre le pointeur dans DE ld hl,0 ; tout est corrigé, on dit qu'on part maintenant de la ligne 0 .pasClipHaut ; pour rester sur des comparaisons 8 bits, on peut soustraire sprHauteur à hauteur et comparer à sprY ld a,200 : sub xh : cp l : jr nc,.pasClipBas ; ld a,200 : sub l : ld xh,a ; nouvelle hauteur +petite .pasClipBas xor a ; offsetDebut par défaut bit 7,c : jr z,.pasClipGauche ld a,c : add xl : ld xl,a ; nouvelle largeur ld a,c : neg ; nouvel offsetDebut ld c,0 ; nouveau X en zéro .pasClipGauche ld (offsetDebut),a ; soit zéro, soit celui calculé lors du clipping ld a,c : add xl : cp 81 ; largeur+1 rapport à la comparaison souhaitée ld a,0 : jr c,.pasClipDroite ; A=0 au cas où on n'ait pas de clipping, pour reset offsetFin ld a,xl : exa ; on met la largeur du sprite de côté ld a,80 : sub c : ld xl,a ; nouvelle largeur de sprite exa ; on récupère la largeur d'origine sub xl .pasClipDroite ld (offsetFin),a call CalculeAdressePixel ; HL=destination écran ; DE=toujours l'adresse source des données ld bc,hl ; on utilise BC comme destination écranld h,hi(tableTransparence) .afficheLignes ld a,xl : ld yl,a ; chargeur la largeur d'une ligne dans YL push bc ; on met l'adresse de début de la ligne de côté ld a,e : add #12 : offsetDebut=$-1 : ld e,a : ld a,d : adc 0 : ld d,a .pixelMasque ld a,(de) ; lire le sprite ld l,a ; octet du sprite dans L ld a,(bc) ; on récupère l'octet de l'écran and (hl) ; on applique le masque or l ; on fusionne avec la donnée du sprite ld (bc),a ; on remet dans l'écran inc bc inc de ; et on incrémente data+ecran dec yl jr nz,.pixelMasque ld a,e : add #12 : offsetFin=$-1 : ld e,a : ld a,d : adc 0 : ld d,a pop bc ; on récupère l'adresse du début de ligne ; et on calcule le passage à la ligne suivante ; notre routine de passage à la ligne suivante, adaptée pour BC ld a,b : add 8 : ld b,a ; ajouter #800 à DE and #38 ; on teste si on déborde de la bank (passage de page+#3800 à page+#0000) jr nz,.nextLine ; pas zéro, on est toujours dans le même bloc de lignes ld a,80 : add c : ld c,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant ld a,#C0 : adc b : ld b,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000) .nextLine dec xh ; notre compteur de lignes jr nz,.afficheLignes ret CalculeAdressePixel ; B=page vidéo #00, #40, #80 ou #C0 ; C=coordonnée X (0-79) ; HL=coordonnée Y (0-199) ; adresse de la ligne dans HL en résultat add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2 ld a,lo(tableau) : add l : ld l,a : ld a,h : adc hi(tableau): ld h,a ld a,(hl) : inc hl ld h,(hl) : ld l,a add hl,bc ; ajouter la position X en octets et la page! ret ;------------------- adresse_ecran=#0000 largeur_ecran=80 tableau repeat 25 repeat 8 defw adresse_ecran adresse_ecran+=#800 rend adresse_ecran+=largeur_ecran adresse_ecran-=#4000 rend align 256 tableTransparence repeat 256,x px=x-1 ; car le compteur va par défaut de 1 à 256 et non 0 à 255 masque=0 if (px & (128|32|8|2))==0 masque|=128|32|8|2 ; pour cet octet on conservera les données écran endif if (px & (64|16|4|1))==0 masque|=64|16|4|1 ; pour cet octet on conservera les données écran endif defb masque rend palette defb #4D,#54,#56,#5C,#46,#5E,#40,#47,#43,#4E,#4B,#4C,0 ; Rose en zéro donnees_sprite incbin 'hibouZero.bin' org #C000 : incbin 'foretZero.bin'Et hop! 
Est-ce que la routine est terminée? Celle-ci oui! Mais elle n'est pas capable de gérer si le sprite est totalement en dehors de l'écran. Le plus efficace est de le tester avant de l'appeler, avec des coordonnées complètes (16 bits). Si le sprite est en dehors de l'écran, on n'aura pas besoin de pré-charger l'adresse des données ou la page en cours. Rendez-vous dans [la deuxième partie de ce cours] Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 275 millisecondes et consultée 23 foisL'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko. |
|