CODINGSDCC TUT'S PAR STEPHBB75 ★ Put pixel très rapide ★

Sdcc - 12 - Put Pixel Tres RapideCoding Sdcc Tut's Par Stephbb75

Afficher un point très rapidement

On a vue comment afficher un pixel à l'écran avec les fonctions PutPixelMode0, PutPixelMode1 et PutPixelMode2, elles sont déjà rapide, mais on peut encore faire beaucoup plus rapide...
Mais pour cela vous vous en doutez bien, il vas falloir passer pas de l'assembleur.
Je vous propose donc ici 3 fonctions (une pour chaque mode du CPC) pour afficher un pixel de façon ultrarapide, j'ai récupéré les code ASM sur le site The CPC Wiki dans la partie programmation ici

Ce code (les 3 fonctions sont presque identique, juste un changement pour le mode) permet de calculer l'adresse du point et de modifier en mémoire la valeur voulue, elle fait donc la même choses que les fonctions PutPixelModeX, mais en bien plus vite du fait qu'elle ont été faite en ASM.
Petite particularité pour la couleur, en fait le code d'origine utilise une valeur mémoire système qui mémoire la couleur (en fait le GRAPHICS PEN) utilisé, on peut passer par cela ou utiliser une variable globale pour cette couleur, ce que j'ai fait.
Je vous fournie donc aussi la fonction pour initialiser la couleur (attention, elle permet de choisir le No de couleur utiliser, mais de définie pas la couleur)
Aller place au code, j'ai juste francisé les commentaire du code.

Pour le mode 1 :

unsigned char glob_color = 0;

void SetPenM1( unsigned char color )
{
    switch ( color % 4 )
    {
        case 0:
            glob_color = 0;
            break;
        case 1:
            glob_color = 240;  // 0xF0
            break;
        case 2:
            glob_color = 15;  // 0x0F
            break;
        case 3:
            glob_color = 255;  // 0xFF
            break;
    }
}

void PutPixelFastMode1(unsigned int nX, unsigned char nY)
{
// Input: DE = X (0..319), HL = Y (0..199)

__asm

    ; on récupère les paramètres
    LD E, 4(IX)
    LD D, 5(IX)

    LD L, 6(IX)
    LD H,0            ; juste pour être sur.

FPLOT:
    LD A, L            ;A = octet bas de Y
    AND #0x7        ;isole les Bit 0..2  (00000111)
    LD H, A            ;= y MOD 8 vers H
    XOR L            ;A = Bit 3..7 of Y
    LD L, A            ;= (Y\8)*8 vers L
    LD C, A            ;stock dans C
    LD B, #0x60        ;B = &C0\2 = octet haut adresse de deépart de l écran \ 2
                    ; REMARQUE
                    ; si vous voulez dessiner dans un autre écran que celui d'origine en C000 (par exemple 4000)
                    ; il faut changer cette valeur.
        
    ADD HL, HL        ;HL * 2
    ADD HL, HL        ;HL * 4
    ADD HL, BC        ;+ BC = adresse de deépart
    ADD HL, HL        ;de la ligne de pixels
        
    LD A, E            ;octet bas de X dans A
    SRL D            ;calcule X\4, Car
    RR E            ;4 pixels par bit
    SRL E
    ADD HL, DE        ;+ HL = adresse du pixel à modifier
        
    LD C, #0x88        ;masque de bits pour le mode 1 (10001000)
    AND #3            ;A = X MOD 4 (00000011)
    JR Z, NSHIFT    ;-> = 0, aucun deplacement
SHIFT:
     SRL C            ;déplacer masque de pixel
    DEC A            ;compteur de boucle
    JR NZ,SHIFT        ;-position
        
NSHIFT:
    LD A,(#_glob_color); recupere le masque de couleur
                    ; REMARQUE
                    ; La couleur peut etre recupere en memoire a l'adresse B6A3 pour les 664 et 6128 et B338 pour le 464
                    ; moi j'ai préféré passer par un variable globale.
    XOR (HL)        ;XOR octet du pixel
    AND C            ;AND masque de pixel
    XOR (HL)        ;XOR octet du pixel
    LD (HL), A        ;nouveau octet du pixel
    
__endasm;
}


la même choses pour le mode 2 :

unsigned char glob_color = 0;

void SetPenM2( unsigned char color )
{
    switch ( color % 2 )
    {
        case 0:
            glob_color = 0;
            break;
        case 1:
            glob_color = 255;  // 0xF0
            break;
    }
}

void PutPixelFastMode2(unsigned int nX, unsigned char nY)
{
// Input: DE = X (0..319), HL = Y (0..199)

__asm

    ; on récupére les paramètres
    LD E, 4(IX)
    LD D, 5(IX)

    LD L, 6(IX)
    LD H,0            ; juste pour être sur.

FPLOT:
    LD A, L            ;A = octet bas de Y
    AND #0x7        ;isole les Bit 0..2  (00000111)
    LD H, A            ;= y MOD 8 vers H
    XOR L            ;A = Bit 3..7 of Y
    LD L, A            ;= (Y\8)*8 vers L
    LD C, A            ;stock dans C
    LD B, #0x60        ;B = &C0\2 = octet haut adresse de deépart de l écran \ 2
                    ; REMARQUE
                    ; si vous voulez dessiner dans un autre écran que celui d'origine en C000 (par exemple 4000)
                    ; il faut changer cette valeur.
        
    ADD HL, HL        ;HL * 2
    ADD HL, HL        ;HL * 4
    ADD HL, BC        ;+ BC = adresse de deépart
    ADD HL, HL        ;de la ligne de pixels
        
    SRL D            ;calcule X\8, Car
    RR E            ;8 pixels par bit
    SRL D
    RR E
    SRL E
    ADD HL, DE        ;+ HL = adresse du pixel à modifier
        
    LD C, #0x80        ;masque de bits pour le mode 2 (10000000)
    AND #7            ;A = X MOD 8 (00000111)
    JR Z, NSHIFT    ;-> = 0, aucun deplacement
SHIFT:
     SRL C            ;déplacer masque de pixel
    DEC A            ;compteur de boucle
    JR NZ,SHIFT        ;-position
        
NSHIFT:
    LD A,(#_glob_color); recupere le masque de couleur
                    ; REMARQUE
                    ; La couleur peut etre recupere en memoire a l'adresse B6A3 pour les 664 et 6128 et B338 pour le 464
                    ; moi j'ai préféré passer par un variable globale.
    XOR (HL)        ;XOR octet du pixel
    AND C            ;AND masque de pixel
    XOR (HL)        ;XOR octet du pixel
    LD (HL), A        ;nouveau octet du pixel
    
__endasm;
}


Et pour finir, la même pour le mode 0

unsigned char glob_color = 0;

void SetPenM0( unsigned char color )
{
    switch ( color % 16 )
    {
        case 0:
            glob_color = 0;
            break;
        case 1:
            glob_color = 192;  // 0xC0
            break;
        case 2:
            glob_color = 12;  // 0x0C
            break;
        case 3:
            glob_color = 204;  // 0xCC
            break;
        case 4:
            glob_color = 48;  // 0x30
            break;
        case 5:
            glob_color = 240;  // 0xF0
            break;
        case 6:
            glob_color = 60;  // 0x3C
            break;
        case 7:
            glob_color = 252;  // 0xFC
            break;
        case 8:
            glob_color = 3;  // 0x03
            break;
        case 9:
            glob_color = 195;  // 0xc3
            break;
        case 10:
            glob_color = 15;  // 0x0F
            break;
        case 11:
            glob_color = 207;  // 0xCF
            break;
        case 12:
            glob_color = 51;  // 0x33
            break;
        case 13:
            glob_color = 243;  // 0xF3
            break;
        case 14:
            glob_color = 63;  // 0x3F
            break;
        case 15:
            glob_color = 255;  // 0xFF
            break;
    }    
}

void PutPixelFastMode0(unsigned int nX, unsigned char nY)
{
// DE = X (0..159), HL = Y (0..199)

__asm

    ; on récupére les paramètres
    LD E, 4(IX)
    LD D, 5(IX)

    LD L, 6(IX)
    LD H,0            ; juste pour être sur.

FPLOT:
    LD A, L            ;A = octet bas de Y
    AND #0x7        ;isole les Bit 0..2  (00000111)
    LD H, A            ;= y MOD 8 vers H
    XOR L            ;A = Bit 3..7 of Y
    LD L, A            ;= (Y\8)*8 vers L
    LD C, A            ;stock dans C
    LD B, #0x60        ;B = &C0\2 = octet haut adresse de deépart de l écran \ 2
                    ; REMARQUE
                    ; si vous voulez dessiner dans un autre écran que celui d'origine en C000 (par exemple 4000)
                    ; il faut changer cette valeur.
        
    ADD HL, HL        ;HL * 2
    ADD HL, HL        ;HL * 4
    ADD HL, BC        ;+ BC = adresse de deépart
    ADD HL, HL        ;de la ligne de pixels

    
    SRL E            ;calcule X\2, Car 2 pixels par bit
        
    LD C, #0xAA        ;masque de bits pour le mode 0 (10101010)
    JR Z, NSHIFT    ;-> = 0, aucun deplacement
SHIFT:
    LD C,#0x55        ;masque pour les autres pixel de droite (01010101)
    
     SRL C            ;déplacer masque de pixel
    DEC A            ;compteur de boucle
    JR NZ,SHIFT        ;-position
        
NSHIFT:
    ADD HL, DE        ;+ HL = adresse du pixel à modifier
    LD A,(#_glob_color); recupere le masque de couleur
                    ; REMARQUE
                    ; La couleur peut etre recupere en memoire a l'adresse B6A3 pour les 664 et 6128 et B338 pour le 464
                    ; moi j'ai préféré passer par un variable globale.
    XOR (HL)        ;XOR octet du pixel
    AND C            ;AND masque de pixel
    XOR (HL)        ;XOR octet du pixel
    LD (HL), A        ;nouveau octet du pixel
    
__endasm;
}

Pour faire une comparaison, j'ai repris le code fait pour la fonction PutPixelMode1, il suffit de mettre la nouvelle fonction. Tout est dans le ZIP, voici le résultat ....

Les animations sont fidèles en temps vis à vis d'un CPC
A Gauche avec la fonction PutPixelFastMode1 et à droite avec la fonction PutPixelMode1


 


stephbb75

ANNÉE: 2013
★ AUTEUR: Stephbb75

Page précédente : Sdcc - 11 - Attaquer le Crtc

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 081 millisecondes et consultée 1134 fois

L'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.