Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » Zoom + Rotation avec MonochromeLib !
Ninestars Hors ligne Membre Points: 2448 Défis: 24 Message

Zoom + Rotation avec MonochromeLib !

Posté le 11/02/2015 22:26

Et voilà je viens d'achever un défi personnel : écrire une fonction pour agrandir ou réduire une image !

Les fonctions sont incorporées dans la libraire de PierrotLL comme toutes les autres que nous connaissons bien.
Il suffit de modifier MonochromeLib.c et MonochromeLib.h par les nouveaux en pièce jointe.

Les prototypes :
void ML_bmp_or_zoom(const unsigned char *bmp, int x, int y, int width, int height, float zoom_w, float zoom_h);
void ML_bmp_and_zoom(const unsigned char *bmp, int x, int y, int width, int height, float zoom_w, float zoom_h);
void ML_bmp_xor_zoom(const unsigned char *bmp, int x, int y, int width, int height, float zoom_w, float zoom_h);

void ML_bmp_or_rotate(const unsigned char *bmp, int x, int y, int width, int height, int angle);
void ML_bmp_and_rotate(const unsigned char *bmp, int x, int y, int width, int height, int angle);
void ML_bmp_xor_rotate(const unsigned char *bmp, int x, int y, int width, int height, int angle);


Explications :
Il suffit de mettre en argument :
- le pointeur du bmp
- la position en x
- la position en y
- la largeur d'origine
- la hauteur d'origine

- le coefficient de zoom en largeur ou l'angle de rotation
- le coefficient de zoom en hauteur

Infos complémentaires :
Les coefficients de zoom sont des flottants compris entre 0 et l'infini
- entre 0 et 1 -> réduction
- plus de 1 -> agrandissement
L'angle est un entier en degrés et dans le sens trigo (anti-horaire)
L'image tourne autour de son centre.

Nouvelle version du zoom 3x plus rapide !

Ajout des rotations

La librairie est toujours libre.

Aussi simple que ça !

Fichier joint


Ninestars Hors ligne Membre Points: 2448 Défis: 24 Message

Citer : Posté le 06/08/2015 14:26 | #


C'est vrai que l'antialiasing en niveau de gris ça serait pas mal
Lephenixnoir Hors ligne Administrateur Points: 21343 Défis: 149 Message

Citer : Posté le 18/08/2015 21:21 | #


Dark storm a écrit :
Sinon, à quand la version avec anti-aliasing en niveaux de gris ? Pour peu que le moteur de Lephe devienne très fonctionnel (à priori j'ai confiance là-dedans), ça peut être cool

Non. Le gris ne devrait être utilisé que pour le pixel art. L'antialiasing ne fonctionnera jamais avec de si gros pixels.
J'ai essayé.
Dark storm Hors ligne Labélisateur Points: 11549 Défis: 176 Message

Citer : Posté le 18/08/2015 21:45 | #


Tant pis alors
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Matt36230 Hors ligne Membre Points: 1888 Défis: 0 Message

Citer : Posté le 26/01/2016 18:48 | #


Ce midi je me demandais si c'était possible de faire tourner un sprite... Et la je tombe par hasard la dessus !
Je vais bien m'en servir merci
Yatis Hors ligne Membre Points: 564 Défis: 0 Message

Citer : Posté le 04/09/2018 11:52 | #


j'arrive à avoir un gain de ~50fps sur ML_bmp_or_rotate() en modifiant légèrement son code comme ceci:


void ML_bmp_rota(const unsigned char *bmp, int x, int y, int width, int height, int angle)
{
    char    i;
    char    j;
    char    bit;
    char    nb_width;
    int        ox;
    int        oy;
    int        dx;
    int        dy;
    int        xr;
    int        yr;
    int        sinus;
    int        cosinus;
    char*    vram;
    
    if (bmp)
    {
        i = -1;
        ox = x + (width >> 1);
        oy = y + (height >> 1);
        nb_width = width + 7 >> 3;
        vram = (char*)asm_get_vram();
        cosinus = cos_table[angle % 360];
        sinus = cos_table[(angle + 90) % 360];
        while (++i < width)
        {
            j = -1;
            dx = x + i - ox;
            bit = 0x80 >> (i & 7);
            while (++j < height)
            {
                dy = y + j - oy;
                xr = ox + (dx * cosinus - dy * sinus >> 14);
                yr = oy + (dx * sinus + dy * cosinus >> 14);
                if (!(yr & 0xffffffc0 || xr & 0xffffff80) && bmp[(i >> 3) + nb_width * j] & bit)
                    vram[(yr << 4) + (xr >> 3)] |= 128 >> (xr & 7);
            }
        }
    }
}


la table de cosinus pré-calculé:

static const cos_table[360] =
{
    16384, 16381, 16374, 16361, 16344, 16321, 16294, 16261, 16224,
    16182, 16135, 16082, 16025, 15964, 15897, 15825, 15749, 15668,
    15582, 15491, 15395, 15295, 15190, 15081, 14967, 14848, 14725,
    14598, 14466, 14329, 14188, 14043, 13894, 13740, 13582, 13420,
    13254, 13084, 12910, 12732, 12550, 12365, 12175, 11982, 11785,
    11585, 11381, 11173, 10963, 10748, 10531, 10310, 10086, 9860,
    9630, 9397, 9161, 8923, 8682, 8438, 8191, 7943, 7691, 7438, 7182,
    6924, 6663, 6401, 6137, 5871, 5603, 5334, 5062,
    4790, 4516, 4240, 3963, 3685, 3406, 3126, 2845,
    2563, 2280, 1996, 1712, 1427, 1142, 857, 571,
    285, 0, -285, -571, -857, -1142, -1427, -1712,
    -1996, -2280, -2563, -2845, -3126, -3406, -3685, -3963,
    -4240, -4516, -4790, -5062, -5334, -5603, -5871, -6137,
    -6401, -6663, -6924, -7182, -7438, -7691, -7943, -8192,
    -8438, -8682, -8923, -9161, -9397, -9630, -9860, -10086,
    -10310, -10531, -10748, -10963, -11173, -11381, -11585, -11785,
    -11982, -12175, -12365, -12550, -12732, -12910, -13084, -13254,
    -13420, -13582, -13740, -13894, -14043, -14188, -14329, -14466,
    -14598, -14725, -14848, -14967, -15081, -15190, -15295, -15395,
    -15491, -15582, -15668, -15749, -15825, -15897, -15964, -16025,
    -16082, -16135, -16182, -16224, -16261, -16294, -16321, -16344,
    -16361, -16374, -16381, -16384, -16381, -16374, -16361, -16344,
    -16321, -16294, -16261, -16224, -16182, -16135, -16082, -16025,
    -15964, -15897, -15825, -15749, -15668, -15582, -15491, -15395,
    -15295, -15190, -15081, -14967, -14848, -14725, -14598, -14466,
    -14329, -14188, -14043, -13894, -13740, -13582, -13420, -13254,
    -13084, -12910, -12732, -12550, -12365, -12175, -11982, -11785,
    -11585, -11381, -11173, -10963, -10748, -10531, -10310, -10086,
    -9860, -9630, -9397, -9161, -8923, -8682, -8438, -8191,
    -7943, -7691, -7438, -7182, -6924, -6663, -6401, -6137,
    -5871, -5603, -5334, -5062, -4790, -4516, -4240, -3963,
    -3685, -3406, -3126, -2845, -2563, -2280, -1996, -1712,
    -1427, -1142, -857, -571, -285, 0, 285, 571,
    857, 1142, 1427, 1712, 1996, 2280, 2563, 2845,
    3126, 3406, 3685, 3963, 4240, 4516, 4790, 5062,
    5334, 5603, 5871, 6137, 6401, 6663, 6924, 7182,
    7438, 7691, 7943, 8192, 8438, 8682, 8923, 9161,
    9397, 9630, 9860, 10086, 10310, 10531, 10748, 10963,
    11173, 11381, 11585, 11785, 11982, 12175, 12365, 12550,
    12732, 12910, 13084, 13254, 13420, 13582, 13740, 13894,
    14043, 14188, 14329, 14466, 14598, 14725, 14848, 14967,
    15081, 15190, 15295, 15395, 15491, 15582, 15668, 15749,
    15825, 15897, 15964, 16025, 16082, 16135, 16182, 16224,
    16261, 16294, 16321, 16344, 16361, 16374, 16381,
};


et le asm_get_vram() ressemble à ça:

.extern _asm_get_vram

_asm_get_vram:
        mov.l #h'80010070, r1
        mov.l #h'0135, r0
        jmp @r1
        nop
        rts
        nop


Je donne ça ici en sachant qu'il est surement possible d'optimiser encore un peu et que Ninestars doit avoir un algo encore plus optimiser x)
D'ailleurs au passage j'ai essayé d'optimiser la fonction ML_clear_Vram() et ML_display_vram(), voila ce que j'ai réussie à obtenir (malheureusement je n'ai pas pu tester si c'est plus rapide ou plus lent mais sait-on jamais).
Ha oui et il faut leur mettre en paramètre l'address de la vram (parce que...je fais des tests de gris et moi j'ai 2 vrams donc voila)

    _asm_clear_vram:    ; r4 = address vram
        mov.w #h'03fc, r6
        add r4, r6
        mov r6, r7
        mov #4, r5
        mov #3, r1
        sub r5, r4
        and r5, r1
        add r5, r7
        cmp/pl r5
        bf/s while_long
        mov #0, r3
        
        while_char:            ; paddig management
            mov.b r3, @r4
            mov.b r3, @r7
            add #1, r4
            add #-1, r5
            cmp/eq r3, r5
            bf/s while_char
            add #1, r7
        add #-1, r4
        
        while_long:
            mov.l r3, @r4
            add #4, r4
            cmp/hs r7, r4
            bf while_long
        
        rts
        nop
        
    _asm_display_vram:    ;r4 = address vram
        mov r13, @-r15
        mov r12, @-r15
        mov r11, @-r15
        mov r10, @-r15
        mov r9, @-r15
        mov r8, @-r15
        mov #192, r13
        mov #0, r12
        mov #7, r11
        mov #4, r10
        mov #16, r9
        mov #0, r8
        mov.l #h'b4000000, r1             ;LCD_register_selector
        mov.l #h'b4010000, r2             ;LCD_data_register
        mov #0, r0
        loop_64:
        
            mov.b r10, @r1            ;LCD_register_selector = 4
            mov.b r13, @r2            ;LCD_data_register = r3
            mov.b r10, @r1            ;LCD_register_selector = 4
            mov.b r12, @r2            ;LCD_data_register = 0
            mov.b r11, @r1            ;LCD_register_selector = 7
            
            mov #0, r3
            loop_16:
                
                mov.b @r4+, r6
                mov.b r6, @r2
                add #1, r3
                cmp/eq r9, r3
                
            bf loop_16
            add #1, r0
            cmp/eq #64, r0
            
        bf/s loop_64
        add #1, r13                ;delay slot
        mov @r15+, r8
        mov @r15+, r9
        mov @r15+, r10
        mov @r15+, r11
        mov @r15+, r12
        mov @r15+, r13
        rts
        nop

Voilà voila c'est tout j'espère pas avoir fait trop n'importe quoi pour ML_clear_vram() et ML_display_vram()
Lephenixnoir Hors ligne Administrateur Points: 21343 Défis: 149 Message

Citer : Posté le 04/09/2018 12:01 | #


(Note : Tu peux utiliser [inlinecode] ou plus simplement des backticks pour écrire du texte monotypé sans utiliser l'horrible Courier. Par exemple `code`.)

Le pré-calcul est une bonne idée. Dans l'ensemble, mon avis personnel est que les rotations ne sont pas extrêmement fidèles à cause du peu de pixels et de l'absence d'interpolation

J'ai lu le code en 30 secondes ; apparemment pour ML_clear_vram(), tu as fait un memset() intelligent qui utilise des long. L'idée est bonne mais tu peux réduire sensiblement tes boucles. Par exemple la boucle principale qui fait les écritures peut s'écrire :

while_long:
    dt r[counter]
    bf.s while_long
    mov.l r3, @r4+

Tu gagnes deux cycles car tu as une instruction de moins, et tu utilises un delay slot (évite une bulle dans le pipeline). Il faut faire attention à ce que l'adresse de la boucle soit 4n + 2 pour que le mov.l soit sur une adresse non multiple de 4, ça permet de gagner un cycle sur la contention entre IF et MA dans le pipeline (conflit d'accès mémoire entre lire la prochaine instruction et écrire la donnée demandée).

Tu peux également optimiser parce que tu sais que tu dois faire au moins 63 * 4 long d'affilée, donc tu peux mettre plusieurs mov.l r3, @r4+ à la suite sans tester la condition à chaque fois. gint fait ça.

Pour ML_display_vram(), d'abord bravo : tu as probablement (je n'ai pas testé) réécrit un driver simple pour l'écran monochrome. Tu fais plus de modifications de registres que nécessaire, il me semble. Et pareil, tu peux unroll ta boucle dans le loop_16, ça te remplacerait 6 lignes de code par 16, soit 20 octets de mémoire ; pour peut-être 2 à 3 fois plus de vitesse d'exécution.

Ajouté le 04/09/2018 à 12:03 :
J'ai oublié de préciser que les techniques que tu as mises en œuvre là sont aussi utilisées par PLL, donc sur le principe ça ne devrait pas être beaucoup plus rapide ; on peut dire que le gain vient entièrement de la façon dont tu l'as codé.
Ninestars Hors ligne Membre Points: 2448 Défis: 24 Message

Citer : Posté le 04/09/2018 12:57 | #


Hmmm bien joué si tu arrives à optimiser l'affichage
Ton tableau static const cos_table[360] n'est pas typé explicitement.

Cette lib est veille, il faudrait que je la mette à jour. Les techniques que j'ai utilisé dans Windmill serait parfaites pour refaire un algo de zoom et surtout un algo de rotation. Car celui là laisse des trous. Et aussi un algo de zoom+rotation. (En fait se serait même algo pour tous )
Yatis Hors ligne Membre Points: 564 Défis: 0 Message

Citer : Posté le 02/10/2018 18:48 | #


Lephé: ça donnerait un truc du genre ?

_asm_clear_vram:    ! r4 = address vram
    mov.w 1f, r6
    add r4, r6
    mov r6, r7
    mov #4, r5        ! met 4 dans r5
    mov #3, r1        ! met 3 dans r1
    sub r5, r4        ! 4 - vram
    and r5, r1        ! (4 - vram) & 3
    add r5, r7
    cmp/pl r5        ! si r5 <= 0 ...
    bf/s while_long
    mov #0, r3        ! met 0 dans r3

    while_char:        ! paddig management
        mov.b r3, @r4
        mov.b r3, @r7
        add #1, r4
        add #-1, r5
        cmp/eq r3, r5
        bf/s while_char
        add #1, r7
        add #-1, r4

    while_long:
    mov.l r3, @r4
    add #4, r4
    cmp/hs r7, r4
    bf while_long

    rts
    nop
1:    .word 0x03fc

_asm_display_vram:    ! r4 = address vram
    mov.l r13, @-r15
    mov.l r12, @-r15
    mov.l r11, @-r15
    mov.l r10, @-r15
    mov #192, r13
    mov #0, r12
    mov #7, r11
    mov #4, r10
    mov.l LCD_register_selector, r1
    mov.l LCD_data_register, r2
    mov #64, r0        ! axe y
    loop_64:

        mov.b r10, @r1            ! LCD_register_selector = 4
        mov.b r13, @r2            ! LCD_data_register = r3
        mov.b r10, @r1            ! LCD_register_selector = 4
        mov.b r12, @r2            ! LCD_data_register = 0
        mov.b r11, @r1            ! LCD_register_selector = 7
    
        mov #16, r3
        loop_16:

            mov.b @r4+, r6
            dt r3
            bf.s loop_16
            mov.b r6, @r2
    
        dt r0        ! rn - 1 --> rn

    bf.s loop_64
    add #1, r13        ! delay slot
    
    mov.l @r15+, r10
    mov.l @r15+, r11
    mov.l @r15+, r12
    mov.l @r15+, r13
    rts
nop


Ninestars a écrit :

Hmmm bien joué si tu arrives à optimiser l'affichage
Ton tableau static const cos_table[360] n'est pas typé explicitement.

effectivement je n'avais pas vu, c'est chose faite maintenant

Ninestars a écrit :

Cette lib est veille, il faudrait que je la mette à jour. Les techniques que j'ai utilisé dans Windmill serait parfaites pour refaire un algo de zoom et surtout un algo de rotation. Car celui là laisse des trous. Et aussi un algo de zoom+rotation. (En fait se serait même algo pour tous )

Je serais curieux de voir l'algo que tu utilises pour Windmill parce que c'est incroyablement trop jolie <3
Juste à titre d'information, il est plus "lent" que l'ancien algo ?
Lephenixnoir Hors ligne Administrateur Points: 21343 Défis: 149 Message

Citer : Posté le 02/10/2018 20:29 | #


Je crois que tu t'es planté sur la gestion des octets individuels au début et à la fin de la zone : il n'y en a pas autant de chaque côté, au contraire plus il y en a d'un côté et moins il y en a de l'autre.

Laisse-moi te suggérer plus con :
- Tu écris 4 octets nuls au début de la zone.
- Tu écris 4 octets nuls à la fin de la zone.
- Tu écris 0x3fc octets par paquets de 4 sur une zone au milieu.

Comme ça, tu vas écrire certains octets plusieurs fois, mais on s'en fout. Actuellement le temps que tu passes sur les calculs et les tests est trop long, ce n'est pas très productif. Mieux vaut faire quelques écritures en plus si c'est plus rapide que de calculer le nombre minimal qu'on peut en faire.

Pour le display vram, c'est le principe ; je n'ai pas lu assez en détail pour te dire "ça marche" ou "ça va planter" : disons que si ça marche alors tu peux conclure que c'est du code de qualité décente.
Ninestars Hors ligne Membre Points: 2448 Défis: 24 Message

Citer : Posté le 02/10/2018 21:42 | #


Yatis a écrit :
Juste à titre d'information, il est plus "lent" que l'ancien algo ?
Aucune idée, je ne l'ai pas fait J'ai commencé en adaptant mon algo de Windmill la semaine dernière, j'ai pas eu le temps de terminer :/
Yatis Hors ligne Membre Points: 564 Défis: 0 Message

Citer : Posté le 17/10/2018 11:21 | #


Lephenixnoir a écrit :
Je crois que tu t'es planté sur la gestion des octets individuels au début et à la fin de la zone : il n'y en a pas autant de chaque côté, au contraire plus il y en a d'un côté et moins il y en a de l'autre.

Laisse-moi te suggérer plus con :
- Tu écris 4 octets nuls au début de la zone.
- Tu écris 4 octets nuls à la fin de la zone.
- Tu écris 0x3fc octets par paquets de 4 sur une zone au milieu.

Effectivement je me suis planté sur la gestion des octets du début et fin de vram.
Du coup, j'ai repris de 0 et j'ai essayé de faire comme tu as dit et effectivement c'est plus rapide et moins chiant à mettre en place.
Cependant, j'ai un légé problème d'alignement de mémoire, je l'ai réglé avec une bete soustraction mais je ne suis pas sure pour la fiabilité du truc du coup....

_asm_clear_vram:    ! r4 = address vram
    mov.w 1f, r6    ! 1020 because we will clear 4 first and last octet
    extu.w r6, r6    ! clean r6
    add r4, r6    ! r6 = address vram + 1020
    mov #0, r7    ! r7 = 0
    mov #4, r5    ! r5 = 4
    mov #3, r1    ! r1 = 3
    extu.b r5, r5    ! clear r5
    extu.b r7, r7    ! clear r7
    extu.b r1, r1    ! clear r1
    and r4, r1    ! r1 = r5 & 3
    sub r1, r5
    add #-3, r5 ! BUG FIX (?)

    mov.b r7, @r6
    add #1, r6
    mov.b r7, @r6
    add #1, r6
    mov.b r7, @r6
    add #1, r6
    mov.b r7, @r6

    mov.b r7, @r4
    add #1, r4
    mov.b r7, @r4
    add #1, r4
    mov.b r7, @r4
    add #1, r4
    mov.b r7, @r4

    mov #255, r2
    mov r4, r3
    add r5, r3
    extu.b r2, r2
    loop_long:

        mov.l r7, @r3
        dt r2
        bf.s loop_long
        add #4, r3

    rts
    nop
1:    .word 0x03fc

grosso modo pour m'aligner en mémoire je fais: vram + (4 - (vram&3)) mais je me retrouve un octet trop "loin" et mal aligné donc je sais pas trop ou je me suis planté...

Au passage je donne des nouvelles de warning Forever: Il n'est pas abandonné, seulement j'aimerait pouvoir comprendre le fonctionnement des timers et des interruptions avant de continuer donc il n'y aura pas d'update avant pas mal de temps (de plus l'école me mange pas mal de mon temps).
Lephenixnoir Hors ligne Administrateur Points: 21343 Défis: 149 Message

Citer : Posté le 17/10/2018 22:22 | #


Quand tu fais mov #i, rn, la valeur est automatiquement mise sur 32-bits donc tu n'as pas besoin de faire un ext derrière. Tu n'as besoin de faire un ext que si tu as utilisé mov.b ou mov.w.

Ensuite, si tu utilises r0 alors tu peux utiliser l'instruction raccourcie and #3, r0 sans avoir à charger 3 dans un registre.

Ton calcul est assez bizarre. Je te laisse te convaincre que tu peux faire comme ça :

1. Entre vram et vram + 4 (donc 4 address vram, vram + 1, vram + 2, vram + 3) : mettre les octets à zéro (pas de problème d'alignment)
2. Écrire 1020 octets par groupes de 4 en partant de (vram + 4) & ~3
3. Entre vram + 1020 et vram + 1024 : écrire 4 octets à zéro

N'hésite pas à tester tous les cas (vram = 4n, 4n+1, 4n+2, 4n+3) pour t'en persuader. Jusque-là tu as des -3, et des petits trucs bizarres qui montrent que tu connais les notions mais que tu n'as pas prouvé que ça marche. Si tu as des doutes je peux te faire un cas (genre vram = 4n+1).

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2022 | Il y a 32 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd