lundi 22 janvier 2018

Chapitre 15 : dessiner des figures avec le FrameBuffer



Nous allons continuer à utiliser le framebuffer pour dessiner diverses figures. En fait il s’agit d’utiliser la zone mémoire résultant du mapping pour renseigner les octets nécessaires avec la couleur désirée, le reste restant inchangée par rapport aux programmes précédents. Mais nous n’utiliserons que la résolution en 32 bits (soit 4 octets soit un registre) pour l’affichage.
Donc dans ce programme, nous modifierons la routine dessin pour afficher les différentes figures.  Mais tout d’abord nous préparons deux sous routines : la première  codeRGB pour concaténer les 3 couleurs rouge, vert et bleu dans le même registre de 32 bits, le 4ième octet sera ici mis toujours à zéro. La deuxième  aff_pixel_codeRGB32 placera le code couleur calculé par la précédente sur les 4 octets de la mémoire du mapping à la position X,Y correspondante de l’écran. Il faut donc multiplier la position y par le nombre de pixels contenus dans la largeur de l’écran et ajouter le nombre de pixel X puis multiplier le tour par 4 pour obtenir la correspondance en mémoire. En fait pour cette dernière opération il suffit d’utiliser l’instruction str r3,[r9,r0,lsl #2]. Vous remarquerez que je ne respecte pas de norme dans l’utilisation des registres puisqu’ici j’utilise le registre r9 dans toutes les sous procédures pour véhiculer l’adresse de début du mapping. Mais cela n’a pas beaucoup d’importance puisque toutes ces routines sont internes au programme.
Ensuite, nous écrivons toutes les routines de dessin en essayant de passer les mêmes données dans les mêmes registres (r0, r1 pour la position x,y, r2 pour la largeur de l’écran (mais que j’ai appelé malencontreusement longueur de la ligne), r3 pour le code couleur).
Voyons une des plus simples : traçage d’une ligne horizontale : traceDroiteH. En argument, nous passons les positions X de début et de fin de la droite  puis la longueur de la ligne (largeur de l’écran) la couleur et la position Y. Dans la routine, nous vérifions que la position X de fin est supérieure à la position de début puis nous effectuons une boucle qui va faire varier la position x du début à la fin et appeler la fonction d’affichage du pixel  précédente. Nous faisons la même chose pour tracer une ligne verticale sauf que nous faisons varier la position y du début à la fin.
Pour tracer une ligne quelconque, j’ai adapté et converti un algorithme de Bresenham trouvé sur internet. Vous trouverez sur Wikipédia, l’analyse complète de cet algorithme.
Pour tracer un polygone, nous créons en mémoire une série de positions X,Y de chaque sommet  et dans la routine, il nous suffira de tracer les droites qui relient ces points sans oublier de fermer le polygone. Pour le remplir, j’ai écrit une procédure au plus vite qui n’est certainement pas la bonne solution. En effet elle utilise une zone mémoire équivalent à la taille de la zone du mapping pour détecter les points se trouvant au même niveau horizontal sur les bords du polygone puis tracer des droites horizontales pour relier ces 2 points. Hélas elle fonctionne très mal pour un polygone convexe (voir le résultat du polygone vert) que l’on peut rattraper en remplissant des triangles (voir le résultat en bleu).
Pour tracer un cercle, j’ai aussi adapté et converti un algorithme trouvé sur internet. Celui çi calcule et trace les positions X,Y d’un octant (1/8 de cercle) puis par symétrie, affiche toutes les autres positions. Ces 2 derniers algorithmes minimisent les opérations arithmétiques couteuses mais je n’ai pas optimisé ces routines en assembleur ARM (pistes : meilleure utilisation des registres, réduction des push et pop, etc).
Je vais me pencher sur l’écriture d’une petite animation pour voir si ces routines sont efficaces.    
En écrivant ce post et en balayant ce programme, je me suis rendu compte que j’avais codé de nombreuses incohérences : fatigue des fêtes !!! Ce code sera certainement à reprendre pour amélioration !!!  

Aucun commentaire:

Enregistrer un commentaire