Page 1 of 12

[Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 11:02
by Levak
Bonjour à tous !
Depuis bientôt 2 semaines, un vénérable membre de UTI nous a donné la voie pour commencer à programmer en C++ compilé pour le faire fonctionner avec l'émulateur de Goplat :
http://www.unitedti.org/forum/index.php ... stp=139981

Sur cette belle occasion, et histoire de mettre à l'épreuve ma logique, j'ai essayé de programmer une fonction pour afficher un pixel.

A première vue, ça parait simple, x et y, et clic clac pouf paf, on déplace le pointeur et on met la couleur... AAAAA, pas si vite petit ! Car quand on se penche dessus de plus près, on remarque que les pixels sont codés deux par deux dans un même octet... Je dois reprendre depuis le début, vous m'avez laché ?

Rappel :
Un octet est une séquence de 8 bits, en binaire cela donne : 0b00000000 ou encore 0b11111111, ou encore 0b01110110
puis en hexa : 0x00 ou encore 0xFF ou encore 76
en décimal : 0 ou encore 255 ou encore 118

De plus, on sait que l'écran de la nspire est codé entre les adresses mémoire 0xA4000100 et 0xA40096FF (cf Hackspire)
Or si l'on fait le calcul, en sachant que l'écran comporte 240*320 pixels, soit 76800 pixels, en hexa 12C00. Or 12C00 + 100 = 12D00 octets de décallage, ce qui est beaucoup trop par rapport à la limite 96FF de l'écran !!
En fait, chaque octet code deux pixels, c'est à dire que les bits de poids fort (les 4 premiers) vont coder le pixel de gauche, et les pixels de poids faible (les 4 derniers) le pixel de droite.
En effet : (240*(320/2)) = 38400, en hexa = 9600, et 9600 + 100 = 9700. Comme on commence à 0 et pas à 1 dans l'adressage mémoire, cela donne 96FF, ce qui convient.
Cette méthode était dure à gérer en C, on ne peux pas couper un octet en deux, il faut obligatoirement gérer les deux pixels en même temps, soit en les valorisant deux par deux, soit en utilisant un peu de logique (et tellement de logique que je suis assez fier de mon exploit, même si d'autres l'ont déjà fait avant :p).


Enfin, une subtilité qui m'a fait bien des soucis est la couleur. En effet, il y a 16 niveaux de gris (0 à 15, puisque de 0b0000 à 0b1111 puisque de 0x0 à 0xF). Mais, logiquement, il y a un problème en termes d'algorithme. Comme on ne peut pas exploiter un demi octet seulement (ou alors je sais pas faire et je me suis compliqué la vie pour rien), on doit utiliser les opération AND/OR/XOR/NOT. J'utiliserais ce que j'appelle des masques. De plus, pour effacer l'écran on utilise une boucle qui va donner la valeur FF à chaque octet (dual-pixel si vous voulez) et là pas besoin de masque, puisque c'est partout pareil.

exemples :
# pour noir, - pour blanc
[tableborder=1]pixels....................-.-.-.##-.##[/table]
[tableborder=1]valeur des octets...255240.15...0................................FF..F0..0F..00.[/table]

Alors maintenant, imaginez que vous voulez afficher UN et UN seul pixel ? Comment ça "facile" ?
Oh que non, car une autre contrainte est que vous devez conserver la valeur du précédent octet, tout en assignant au bon endroit notre demi octet.
Vous comprenez ? non ? Allez... imaginons un unique octet pour notre écran :
[tableborder=1]pixels....................-.-.[/table]
[tableborder=1]valeur des octets...255..............................FF.[/table]

Et là on veut assigner le deuxième pixel à # (noir), donc cela revient à valoriser l'octet à 240 :
[tableborder=1]pixels....................-.#[/table]
[tableborder=1]valeur des octets...240..............................F0.[/table]

Maintenant, on veut allumer le 1er pixel, mais on ne sait pas si le deuxième pixel est allumé, on donne la valeur 15 à l'octet :
[tableborder=1]pixels....................#-.[/table]
[tableborder=1]valeur des octets...15..............................0F.[/table]

Et là... catastrophe ! Il aurait fallut assigner la valeur 0 !
[tableborder=1]pixels....................##[/table]
[tableborder=1]valeur des octets.....0................................00.[/table]

C'est donc là que l'opération AND rentre en jeux, mais avec d'autres opérandes, comme le décalage de bit et le masque pour éviter la perte de valeur, étant donné que le 1 est universel (il n'influence pas sur la valeur) pour cette opérande.

Allez, trêve de bavardage, voilà la solution, qui affiche un magnifique dégradé :
http://pastebin.com/f435c1bbb
 
Show/Hide spoilerAfficher/Masquer le spoiler
En version non colorée et non commentée
Code: Select all
asm ("mov sp,#0x12000000");
void main(void)
{
   unsigned char ligne = 0xA0;
   unsigned char *ptr;
   unsigned int ini = 0xa4000100;
   unsigned int x = 0;
   unsigned int y = 0;
   unsigned char color, colorf = 0;
   unsigned int xf;

   ptr = (unsigned char *) ini;
   
   while (ptr  (unsigned char *) (ini+240*ligne)) {
      *ptr++= 0xFF;
    }
   
   while (y  240){   
      while (x  320){   
         while (color = 15){
            xf = x1;
            if (xf1==x){colorf = (color4)+0b1111;} 
            else {colorf = color+0b11110000;}     
            ptr = (unsigned char*) (ini+(xf+ligne*y));
            *ptr = *ptrcolorf;           
            color++;
            x++;
         }
         color = 0;
      }
      x = 0;
      y++;   
   }
   b:
   goto b;
}

et le résultat :
Image

@+ !

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 13:11
by critor
Levak, je suis heureux de voir que tu as suivi mes conseils, notamment en terme de masques et de logique (ce qui n'empêche pas que l'ensemble du travail te revient).


Superbe exposé, nous te remercions tous. :#top#:

J'ai tout suivi de A à Z, ou plutôt de A à F devrais-je dire :#langue#:


Maintenant, ce serait bien que tu programmes un convertisseur d'images.
Il prendrait une image (BMP, GIF, TIFF... je vais pas te demander de gérer du JPEG :;): ) et afficherait sur la calculatrice une image en niveaux de gris.

Ce serait vraiment génial comme programme.

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 16:20
by Adriweb
Super cool :D

Sisi ,franchement :D

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 17:18
by Levak
critor2000 wrote:Levak, je suis heureux de voir que tu as suivi mes conseils, notamment en terme de masques et de logique (ce qui n'empêche pas que l'ensemble du travail te revient).


Superbe exposé, nous te remercions tous. :#top#:

J'ai tout suivi de A à Z, ou plutôt de A à F devrais-je dire :#langue#:


Oups ! J'ai oublié de te citer Critor ! Effectivement, n'ayant pas de maitrise complète en C/C++ (je n'avais fait auparavant que sur les traitements de donnés et échanges d'informations avec des PIC16F et 18F = Robots) j'ai demandé pleins de choses et pleins de conseils il m'a donné ! Merci Critor !


Maintenant, ce serait bien que tu programmes un convertisseur d'images.
Il prendrait une image (BMP, GIF, TIFF... je vais pas te demander de gérer du JPEG :;): ) et afficherait sur la calculatrice une image en niveaux de gris.

Ce serait vraiment génial comme programme.


Aaaah je l'avais oublié celui-là :#langue#:
J'essaierais, mais plein de questions encore te demander je ferais ^^

Adri merci ^^

@+ !

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 17:31
by Ciwtron
Levak wrote:
critor2000 wrote:Maintenant, ce serait bien que tu programmes un convertisseur d'images.
Il prendrait une image (BMP, GIF, TIFF... je vais pas te demander de gérer du JPEG :;): ) et afficherait sur la calculatrice une image en niveaux de gris.

Ce serait vraiment génial comme programme.


Aaaah je l'avais oublié celui-là :#langue#:
J'essaierais, mais plein de questions encore demander je ferais ^^


Si tu as quelques questions sur le bmp, je pourrais peut-être y répondre.

Sinon, bravo pour ce que tu as fait!

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 17:56
by Levak
critor2000 wrote:Maintenant, ce serait bien que tu programmes un convertisseur d'images.
Il prendrait une image (BMP, GIF, TIFF... je vais pas te demander de gérer du JPEG :;): ) et afficherait sur la calculatrice une image en niveaux de gris.
Ce serait vraiment génial comme programme.


Je me suis concerté à moi-même et je me suis rappelé d'une chose. Ce code en C est le code pour la calculatrice. en gros, si je dois faire un code qui soit capable de transposer une image en affichant les pixels, il faudra qu'il interprète une image on-calc... vous voyez ce que je veux dire ? En gros ce code est transposé en code machine (compilation), mais les actions restent à faire, elles ne sont pas déjà machées. Si il doit y avoir échange de données, il faut que ce soit la calculette (ici l'émulateur) qui doit gérer cet échange. Or en l'absence d'OS, ça risque d'être plus couteux en temps de réflexion...
De plus, ce code marche car c'est une boucle simple, si vous regardez bien, il n'utilise aucune fonction, que des variables et un pointeur. Or j'ai déjà tenté de créer une fonction "affpix" mais où que je la mette, avant le main(), après avec déclaration *.h ou dedans, il y a toujours une chose qui ne lui plait pas (je parle de l'émulateur, le compilateur ne vois aucune erreur et compile). C'est souvent l'erreur "Bad adress".
Quelqu'un a-t-il une idée là dessus ?

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 19:30
by JayTe
Pas mal Levak! :#top#:
Mais perso j'aurai écrit ça comme ça (ça fait exactement la même chose):
Code: Select all
asm("mov sp,#0x12000000");

void main()
{
    static unsigned char *ptr = (unsigned char*) 0xa4000100;
    unsigned int x, y, color;

    for(x = 0; x  240*160; x ++)
    ptr[x] = 0xFF;

    for(y = 0; y  240; y ++)
        for(x = 0; x  320; x ++)
        {
            color = x % 15;
            ptr[y*160+x/2]=x%2?ptr[y*160+x/2]0xF0+color:ptr[y*160+x/2]0x0F+(color 4);
        }
    while(1);
}


(plus court :#langue#: mais aussi plus réutilisable (il n'y a qu'une ligne interessante, et on peut la copier où on veut des qu'on a besoin d'afficher un pixel))

Quand on on met color =x*y%15 au lieu de x % 15 ça donne ça: (jolie illusion d'optique au passge :): )
Image

a+
JayTe

ps: Levak je viens de voir ton nouveau message et j'ai le meme prob que toi (j'ai ausi essayé de créer la fonction setpixel :): ), mais dès que j'essaie d'utiliser une fonction (même si elle ne fait rien) l'émulateur plante en sortant une Bad Address (emu ver 0.21).
même ce code plante:
Code: Select all
asm("mov sp,#0x12000000");
void foo(){}
void main(){foo();while(1);}

difficile de faire plus simple et pourtant...
Quelqu'un a une idée?

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 19:34
by Levak
Des semi-fractales ! bien joué !

JayTe wrote:ps: Levak je viens de voir ton nouveau message et j'ai le meme prob que toi (j'ai ausi essayé de créer la fonction setpixel :): ), mais dès que j'essaie d'utiliser une fonction (même si elle ne fait rien) l'émulateur plante en sortant une Bad Address (emu ver 0.21).
même ce code plante:
Code: Select all
asm("mov sp,#0x12000000");
void foo(){}
void main(){foo();while(1);}

difficile de faire plus simple et pourtant...
Quelqu'un a une idée?

Oui, je pense que c'est à cause de la ligne : " asm("mov sp,#0x12000000"); "
J'ai beau chercher comment l'exploiter, je ne vois aucune piste, a part qu'il s'agit du stack pointer (sp) = pile = souvent un label

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 19:57
by JayTe
j'ai trouvé une demi-solution :): :
Code: Select all
asm("mov sp,#0x12000000");

void main()
{
   static unsigned char *ptr = (unsigned char*) 0xa4000100;
    unsigned int x = 0, y = 0, color = 0;
   
   void setpixel(unsigned int x, unsigned int y, unsigned int color)
   {
      ptr[y * 160 + x / 2] = x % 2 ? ptr[y * 160 + x / 2]  0xF0 + color : ptr[y * 160 + x / 2]  0x0F + (color  4);
   }
   
   for(x = 0; x  240*160; x ++)
      ptr[x] = 0xFF;
      
    for(y = 0; y  240; y ++)
        for(x = 0; x  320; x ++)
      {
          color = (x * y) % 15;
            setpixel(x, y, color);
      }
   while(1);
}

il faut définir les fonctions dans le main
mais c'est pas génial parce qu'il faut que les variables que la fonction prend comme arguments soient déjà définies au moment où on appelle la fonction, et a priori la fonction s'execute une fois au moment où on la définit :s: (et puis bon on perd un peu l'avantage des fonctions qui est de pouvoir séparer le code en plusieurs fichiers)

Re: [Programme C] Algorithme de traçage de pixel

Unread postPosted: 04 Feb 2010, 19:59
by Levak
JayTe wrote:j'ai trouvé une demi-solution :): :

il faut définir les fonctions dans le main
mais c'est pas génial parce qu'il faut que les variables que la fonction prend comme arguments soient déjà définies au moment où on appelle la fonction, et a priori la fonction s'execute une fois au moment où on la définit :s: (et puis bon on perd un peu l'avantage des fonctions qui est de pouvoir séparer le code en plusieurs fichiers)

Raté, essaye d'appeler la fonction deux fois, tu verras l'embrouille ^^

edit: pardon, j'avais mal lu ta phrase, tu l'avais aussi vu ^^