Toi aussi, deviens demomaker avec les shadebobs!
Le shadeBob est un effet d'addition/saturation de couleur sur l'écran. L'algorithme peut se résumer à : - Pour chaque pixel non transparent du sprite, on augmente de 1 le numéro de l'encre écran sur lequel on doit poser ce pixel. - Si le résultat de l'addition dépasse 15, on revient à zéro
Dans un premier temps, ça sera déjà pas mal. Pour réaliser cet effet, il va nous falloir une table de lookup. Ainsi on pourra faire du MMX! Enfin presque. On fera deux additions en même temps (un octet en mode 0 contenant 2 pixels, on aurait deux additions à faire, une par pixel, voir [table dans l'article sur la structure écran]). Préparons notre table. align 256 ; on va lire les données directement avec le poids faible comme index shadeINC startingindex 0 ; pour démarrer la valeur du compteur du REPEAT à zéro repeat 256,x ; à partir de la valeur de l'octet dans x, on éclate les bits pour connaitre l'index d'encre pixleft=((x&128)>>7)|((x&8)>>2)|((x&32)>>3)|((x&2)<<2) pixright=((x&64)>>6)|((x&4)>>1)|((x&16)>>2)|((x&1)<<3) ; on ajoute 1 à l'encre, on gère la saturation si on fait le tour du compteur pixleft+=1 : if pixleft==16 : pixleft=0 : endif pixright+=1 : if pixright==16 : pixright=0 : endif ; enfin on recombine nos bits pour construire l'octet pl=((pixleft&1)<<7)|((pixleft&2)<<2)|((pixleft&4)<<3)|((pixleft&8)>>2) pr=((pixright&1)<<6)|((pixright&2)<<1)|((pixright&4)<<2)|((pixright&8)>>3) ; et on écrit pour chaque octet/valeur, un résultat correspondant à l'ajout de 1 sur chaque pixel defb pl|pr rendOn va reprendre le même genre de sinus que l'article sur les sprites illimités pour définir une petite trajectoire et appelerune routine qui parcourt un petit rectangle de 2 octets de large sur 4 lignes de haut. Cette routine sera du code pur, pas de données! shadePut ; HL=adresse écran de départ ld b,hi(shadeINC) : ld d,4 .loop ld c,(hl) : ld a,(bc) : ld (hl),a : inc hl : ld c,(hl) : ld a,(bc) : ld (hl),a : dec hl ld a,h : add 8 : ld h,a ; ajouter #800 à HL jr nc,.next ; pas de retenue, on est toujours dans le même bloc de lignes ld a,80 : add l : ld l,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant ld a,#C0 : adc h : ld h,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000) .next dec d : jr nz,.loop ret BUILDSNA : BANKSET 0 ORG #100 RUN #100; création d'une macro pour le passage à la ligne, ça évitera de copié-coller du code macro NextLineHL ld a,h : add 8 : ld h,a ; ajouter #800 à HL jr nc,@next ; pas de retenue, on est toujours dans le même bloc de lignes ld a,80 : add l : ld l,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant ld a,#C0 : adc h : ld h,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000) @next mend ld bc,#7F80+%1100 : out (c),c ; MODE 0 ld hl,shade_palette : ld bc,#7F00 setPalette out (c),c : inc c : inc b : outi : ld a,(hl) : or a : jr nz,setPalette BouclePrincipale ld b,#F5 .vbl in a,(c) : rra : jr nc,.vbl call ExecuteBob jr BouclePrincipale ExecuteBob lireX ld hl,sinuzix : ld c,(hl) : inc l : ld b,0 phase ld a,0 : inc a : and 15 : ld (phase+1),a : jr nz,.noADD : inc l : .noADD ld (lireX+1),hl lireY ld hl,sinuziy : ld a,(hl) : inc l : ld (lireY+1),hl : ld l,a : ld h,0 CalculeAdressePixel ; BC=coordonnée X (0-159) ; HL=coordonnée Y (0-199) ; adresse de la ligne dans HL en résultat ld de,tableau add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2 add hl,de ld a,(hl) : inc hl ld h,(hl) : ld l,a add hl,bc ; ajouter la position en OCTETS ! shadePut ; HL=adresse écran de départ ld b,hi(shadeINC) : ld d,2 ; plutôt que revenir à la ligne, on va dessiner en zig-zag, un coup à droite, un coup à gauche .loop ld c,(hl) : ld a,(bc) : ld (hl),a : inc hl : ld c,(hl) : ld a,(bc) : ld (hl),a NextLineHL (void) ; macro de passage à la ligne suivante ld c,(hl) : ld a,(bc) : ld (hl),a : dec hl : ld c,(hl) : ld a,(bc) : ld (hl),a NextLineHL (void) ; macro de passage à la ligne suivante dec d : jr nz,.loop ret ;------------------- adresse_ecran=#C000 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 ; on va lire les données directement avec le poids faible comme index shadeINC startingindex 0 ; pour démarrer la valeur du compteur du REPEAT à zéro repeat 256,x pixleft=((x&128)>>7)|((x&8)>>2)|((x&32)>>3)|((x&2)<<2) pixright=((x&64)>>6)|((x&4)>>1)|((x&16)>>2)|((x&1)<<3) pixleft+=1 : if pixleft==16 : pixleft=0 : endif pixright+=1 : if pixright==16 : pixright=0 : endif pl=((pixleft&1)<<7)|((pixleft&2)<<2)|((pixleft&4)<<3)|((pixleft&8)>>2) pr=((pixright&1)<<6)|((pixright&2)<<1)|((pixright&4)<<2)|((pixright&8)>>3) defb pl|pr rend align 256 sinuziy ang=0 repeat 256 defb sin(ang)*80+80 : ang=ang+360/256 rend sinuzix ang=0 repeat 256 defb sin(ang)*35+35 : ang=ang+360/256 rend shade_palette defb #54,#5C,#58,#4C,#4E,#47,#4A,#43,#4B,#5B,#53,#5F,#57,#5D,#55,#44,#54,0 Pas mal pour un début non? 
Mais pour limiter les pâtés, il faudrait nous faire deux autres tables : Une avec seulement le pixel droit d'incrémenté, l'autre pour le gauche. En les utilisant dans notre routine de sprite, on pourrait arrondir les anglesen haut et en bas de notre rectangle. Ça parait rien comme ça d'enlever 4 pixels, mais ça va tout lisser! Histoire de compléter les améliorations, on va augmenter la taille des tables de sinus, on va augmenter leur nombre, on va basculer d'une table à l'autre!Bon, ok, on pousse un peu plus que d'habitude, ne vous inquiétez pas, vous reviendrez plus tard sur ce dernier source ;) BUILDSNA : BANKSET 0 ORG #38 : EI : RET ORG #100 RUN #100macro NextLineHL ld a,h : add 8 : ld h,a ; ajouter #800 à HL jr nc,@next ; pas de retenue, on est toujours dans le même bloc de lignes ld a,80 : add l : ld l,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant ld a,#C0 : adc h : ld h,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000) @next mend ld sp,#100 : ei ld bc,#7F80+%1100 : out (c),c ; MODE 0 ld hl,shade_palette : ld bc,#7F00 setPalette out (c),c : inc c : inc b : outi : ld a,(hl) : or a : jr nz,setPalette BouclePrincipale .phase1init ld a,hi(sinuzix) : ld (lireX+2),a : ld (resetX+1),a : add 2 : ld (cmpx+1),a : call clearScreen ld hl,0 : ld (.phase1+1),hl .phase1 ld hl,0 : inc hl : ld a,h : and 15 : cp 15: ld (.phase1+1),hl : jr z,.phase2init halt : call ExecuteBob : jr .phase1 .phase2init ld a,hi(sinuzix)+2 : ld (lireX+2),a : ld (resetX+1),a : add 2 : ld (cmpx+1),a : call clearScreen ld hl,0 : ld (.phase2+1),hl .phase2 ld hl,0 : inc hl : ld a,h : and 15 : cp 15: ld (.phase2+1),hl : jr z,.phase3init halt : call ExecuteBob : jr .phase2 .phase3init ld a,hi(sinuzix)+4 : ld (lireX+2),a : ld (resetX+1),a : add 2 : ld (cmpx+1),a : call clearScreen ld hl,0 : ld (.phase3+1),hl .phase3 ld hl,0 : inc hl : ld a,h : and 15 : cp 15: ld (.phase3+1),hl : jr z,.phase4init halt : call ExecuteBob : jr .phase3 .phase4init ld a,hi(sinuzix)+6 : ld (lireX+2),a : ld (resetX+1),a : add 2 : ld (cmpx+1),a : call clearScreen ld hl,0 : ld (.phase4+1),hl .phase4 ld hl,0 : inc hl : ld a,h : and 15 : cp 15: ld (.phase4+1),hl : jp z,.phase1init halt : call ExecuteBob : jr .phase4 clearScreen ld hl,#C000 : ld de,#C001 : ld bc,16335 : ld (hl),l : ldir : ret ExecuteBob lireX ld hl,sinuzix : ld c,(hl) : inc l : ld b,0 : phase ld a,0 : inc a : and 15 : ld (phase+1),a : jr nz,.noADD : inc l : .noADD ld a,h : cmpx cp #12 : jr z,noReset : resetX ld h,#12 : noReset ld (lireX+1),hl lireY ld hl,sinuziy : ld e,(hl) : inc hl : ld a,hi(sinuziy)+2 : cp h : jr nz,.pokeY : ld h,hi(sinuziy) : .pokeY ld (lireY+1),hl ld l,e : ld h,0 CalculeAdressePixel ; BC=coordonnée X (0-159) ; HL=coordonnée Y (0-199) ; adresse de la ligne dans HL en résultat ld de,tableau add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2 add hl,de ld a,(hl) : inc hl ld h,(hl) : ld l,a add hl,bc ; ajouter la position en OCTETS ! shadePut ; HL=adresse écran de départ ld b,hi(shadeINC) : ld d,2 ld c,(hl) : ld a,(bc) : ld (hl),a : inc hl : ld c,(hl) : inc b : ld a,(bc) : inc b : ld (hl),a : NextLineHL (void) .loop ld c,(hl) : ld a,(bc) : ld (hl),a : dec hl : ld c,(hl) : ld a,(bc) : ld (hl),a : NextLineHL (void) ld c,(hl) : ld a,(bc) : ld (hl),a : inc hl : ld c,(hl) : ld a,(bc) : ld (hl),a : NextLineHL (void) dec d : jr nz,.loop ld c,(hl) : dec b : ld a,(bc) : ld (hl),a : dec hl : ld c,(hl) : dec b : ld a,(bc) : ld (hl),a ret ;------------------- adresse_ecran=#C000 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 ; on va lire les données directement avec le poids faible comme index shadeINC startingindex 0 ; pour démarrer la valeur du compteur du REPEAT à zéro repeat 256,x pixleft=((x&128)>>7)|((x&8)>>2)|((x&32)>>3)|((x&2)<<2) pixright=((x&64)>>6)|((x&4)>>1)|((x&16)>>2)|((x&1)<<3) pixleft+=0 : if pixleft==16 : pixleft=1 : endif pixright+=1 : if pixright==16 : pixright=1 : endif pl=((pixleft&1)<<7)|((pixleft&2)<<2)|((pixleft&4)<<3)|((pixleft&8)>>2) pr=((pixright&1)<<6)|((pixright&2)<<1)|((pixright&4)<<2)|((pixright&8)>>3) defb pl|pr rend repeat 256,x pixleft=((x&128)>>7)|((x&8)>>2)|((x&32)>>3)|((x&2)<<2) pixright=((x&64)>>6)|((x&4)>>1)|((x&16)>>2)|((x&1)<<3) pixleft+=1 : if pixleft==16 : pixleft=1 : endif pixright+=0 : if pixright==16 : pixright=1 : endif pl=((pixleft&1)<<7)|((pixleft&2)<<2)|((pixleft&4)<<3)|((pixleft&8)>>2) pr=((pixright&1)<<6)|((pixright&2)<<1)|((pixright&4)<<2)|((pixright&8)>>3) defb pl|pr rend repeat 256,x pixleft=((x&128)>>7)|((x&8)>>2)|((x&32)>>3)|((x&2)<<2) pixright=((x&64)>>6)|((x&4)>>1)|((x&16)>>2)|((x&1)<<3) pixleft+=1 : if pixleft==16 : pixleft=1 : endif pixright+=1 : if pixright==16 : pixright=1 : endif pl=((pixleft&1)<<7)|((pixleft&2)<<2)|((pixleft&4)<<3)|((pixleft&8)>>2) pr=((pixright&1)<<6)|((pixright&2)<<1)|((pixright&4)<<2)|((pixright&8)>>3) defb pl|pr rend
align 512 sinuziy ang=0 repeat 512 defb sin(ang)*80+80 : ang=ang+180/256 rend sinuzix ang=0 repeat 512 defb sin(ang)*35+35 : ang=ang+360/256 rend ang=0 repeat 512 defb sin(ang)*35+35 : ang=ang+720/256 rend ang=0 repeat 512 defb 76-abs(sin(ang)*75) : ang=ang+360/256 rend ang=0 repeat 512 defb sin(ang)*35+35 : ang=ang+888/256 rend shade_palette defb #54,#5C,#58,#4C,#4E,#47,#4A,#43,#4B,#5B,#53,#5F,#57,#5D,#55,#44,#54,0 Voilà, c'est un peu mieux et ça passe d'une courbe à l'autre, just for fun :) 
CPCrulez[Content Management System] v8.732-desktop Page créée en 487 millisecondes et consultée 13 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. |
|