Home   Archives    Hardware   Programmation   Challenges   Forum   Le Mag    Faq   La Communauté   L'Equipe
 
L'équipe progG de Ti-Fr

Voici les nicks de vos serviteurs ;-)

chickensaver_john
Kevin Kofler
Thibaut
janjan2
TiMad
Iceman89
fréka
Zewoo
Squale92
Verstand
ZdRUbAl
UtOpIaH

et nEUrOne ...

Une idée ?
Une idée pour améliorez cette partie? ou tout simplement vous souhaitez participer à l'élaborations des tutos.
Mailez-nous ici

Les raccourcis
 

Chapitre XIX


    J'ai reçu, pendant pas mal de temps, un grand nombre de questions concernant la manipulation d'images, auxquelles je n'ai généralement pas su répondre. Étant donné que ce nombre allait en s'accroissant, que Juan ne connaissait pas non plus les solutions, et que des questions à ce sujet étaient aussi posées sur le forum de TI-Fr, je me suis un peu penché sur la question, et, résultat, voici un nouveau chapitre pour ce tutorial : le 19ème, celui-ci !

    Ce chapitre suppose que vous savez déjà comment utiliser les fonctions graphiques de base, qui permettent d'afficher des lignes, et autres multiples figures à l'écran, ainsi que, éventuellement, des sprites.

Nous allons, pour plus de simplicité, partager ce chapitre en plusieurs parties :

 

I:\ Mémorisation d'images, par la fonction BitmapGet :

    Parfois, dans un programme, vous êtes amené à dessiner quelque chose à l'écran, plusieurs fois pendant l'exécution du programme. La solution la plus rapide pour faire ceci est d'utiliser les sprites, mais, malheureusement, TIGCC ne permet pas de définir des sprites de plus de 32x32 pixels. Dans ce cas, il est possible de dessiner ce que vous souhaitez à l'écran en utilisant des fonctions graphiques "simples" (lignes, cercles, points, triangles, ...). Cependant, puisque les fonctions de dessin du TIOS sont lentes, refaire le dessin à chaque fois entraînerait un fort ralentissement du programme. Donc, ce que l'on peut dans de tels cas être tenté de faire, c'est une copie de l'écran après le premier dessin, que l'on restaurera à chaque fois par la suite.

    Pour effectuer cette mémorisation de l'écran, il faut utiliser la fonction BitmapGet, qui est capable de mémoriser l'écran entier, ou, plus généralement, une partie de l'écran. (En fait, cette fonction est l'équivalent C de la fonction TI-BASIC StoPic).

    Cette fonction admet la syntaxe suivante :
        BitmapGet( partie_de_l'écran, nom_de_la_mémoire);
    Elle prend en argument une variable partie_de_l'écran de type SCR_RECT, qui correspond au cadre qui sera mémorisé dans la variable nom_de_la_mémoire, qui correspond à une variable de type char. (Attention, cette variable doit être de taille suffisante pour pouvoir accueillir toute la partie d'écran donnée !)

    Par exemple, pour mémoriser le contenu d'un cadre dont le coin supérieur gauche a pour coordonnées (10;10), et le coin inférieur droit a pour coordonnée (90;90), il conviendra d'utiliser la portion de code suivante :
        SCR_RECT a_sauver = {{10, 10, 90, 90}};
       
char buffer_mem[BITMAP_HDR_SIZE + 80*80/8];
       
BitmapGet(&a_sauver, buffer_mem);
   A présent, la portion d'écran que vous souhaitiez mémoriser l'est, dans la variable buffer_mem.

    Lors de la déclaration de la variable qui servira à accueillir la portion d'écran, il convient de mettre la taille de celui-ci. Ainsi, on a, de façon plus générale :
        char buffer_mem[BITMAP_HDR_SIZE + largeur_de_l'image*longeur_de_l'image/8];
    Il est possible de toujours utiliser une variable de la taille de l'écran entier pour effectuer ceci, ce qui simplifie considérablement les calculs, mais cela prend beaucoup d'espace mémoire...

Remarque : Il est possible d'allouer l'espace mémoire nécessaire à cette variable de façon dynamique, en utilisant malloc, ce qui, dans la plupart des cas, permettra d'obtenir un programme prenant moins de place sur la TI. (Nous verrons ceci dans un prochain chapitre...)

 

II:\ Affichage d'images mémorisées dans la partie précédente :

    Après avoir mémorisé l'écran, ou, du moins, une partie de l'écran, vous allez pouvoir modifier celui-ci, en dessinant de nouvelles choses, affichant ce que vous voulez...

    Ensuite, si vous souhaitez restaurer la partie d'écran que vous aviez sauvegardé dans la partie précédente, il vous faudra utiliser la fonction suivante :
        BitmapPut(x, y, buffer_mem, zone_clip, attribut);
    Cette fonction prend en argument la position en X et en Y où vous souhaitez réafficher l'image précédemment enregistrée. Le troisième argument correspond au nom de la variable où la portion d'écran a été enregistrée (voir la partie précédente). Le dernier argument correspond à l'attribut avec lequel l'image sera affichée à l'écran. 7 attributs différents sont disponibles pour cette instruction :

A_REPLACE Remplace la région où l'image apparaît par celle-ci.
A_REVERSE Remplace la région où l'image apparaîtra par l'inverse de celle-ci. (Affiche l'inverse de l'image).
A_NORMAL Affiche l'image sans modifier ce qui était précédemment à l'écran
A_XOR Affiche l'image en XOR (ou exclusif) sur l'écran.
A_OR Affiche l'image en OR par rapport à ce qui était affiché auparavant.
A_AND Affiche l'image en AND par rapport à ce qui était affiché auparavant.
A_SHADED Heu.... là, j'ai pas tout suivi, désolé...

    Enfin, le quatrième argument correspond à la zone de l'écran dans laquelle on peut afficher quelque chose : tout ce qui est en dehors de cette zone ne devrait pas apparaître à l'écran. Cette variable est de type SCR_RECT (pour un exemple de définition de ce type de variable, voir la partie précédente.). Le plus simple est d'utiliser une zone couvrant l'écran entier...

    Comme exemple, nous allons réafficher l'image mémorisée dans la partie précédente, au point de coordonnées (5;5). On supposera que, entre la première partie et la seconde, l'écran a été effacé, et qu'il ne s'agit ici que d'en restaurer une partie.
        SCR_RECT zone_clip = {{0, 0, 160, 100}};  // Sur TI-89.
       
SCR_RECT zone_clip = {{0, 0, 240, 128}};  // Sur TI-92plus.
       
BitmapPut(5, 5, buffer_mem, &zone_clip, A_NORMAL);  // Affiche l'image.

 

III:\ Affichage d'images définies dans le programme :

    Nous avons vu au Chapitre XII comment faire pour définir "Manuellement" un sprite. Eh bien, il est possible d'utiliser exactement la même technique pour définir des images. Ainsi, il ne sera pas nécessaire de les afficher une première fois à l'écran pour pouvoir les enregistrer, car elles seront déjà définies dans le programme.

    Je tiens à remercier Kevin Kofler ( http://ti89prog.kevinkofler.cjb.net/ ) pour l'aide qu'il m'a apporté concernant l'utilisation de cette fonction pour les cas qui sont concernés par cette partie du Chapitre.

    Cette fonction permet d'afficher à l'écran des dessins dont la taille peut être égale à celle de l'écran, ou moins. Ici, nous étudierons deux exemples pour l'utilisation de cette fonction. Il vous faut cependant savoir que si le dessin que vous souhaitez afficher à une taille inférieure à 32x32 pixels, il est conseillé d'utiliser les fonctions d'affichage de sprites, car celles-ci sont beaucoup plus rapides que BitmapPut... (La différence se fait largement sentir dans les jeux, par exemple !)

    A: Le fonctionnement général :

    Pour utiliser cette fonction, il faut que vous sachiez comment lui passer le dessin en lui-même. Celui-ci doit être une structure de type BITMAP, qui comporte trois variables :

  • La hauteur de l'image.
  • La largeur de l'image.
  • La définition de l'image.

    Comme nous l'avons dit, l'image est codée un peu comme un sprite. En fait, ce n'est pas tout à fait aussi simple... Celle-ci doit être codée par une suite d'octets (qui comportent donc 8 bits, soit le code de 8 pixels.). Pour cela, la largeur de l'image dans la définition sera toujours un multiple de 8, même si ce n'est pas sa vraie taille (celle que vous lui avez donné auparavant). Donc, pour arriver à un multiple de 8, il suffit de "combler les trous" avec des 0, qui signifient "pixel éteint".

    Pour vous donner une idée de ce qu'il convient vraiment de faire, nous allons utiliser l'exemple suivant, qui est celui que Kevin à utilisé dans ses explications :
        BitmapPut(10, 10,             // Permet de positionner le dessin.
       
(BITMAP *)&(unsigned char[])  // Déclaration de la structure du dessin.
       
{0,5,0,5,                     // Permet de dire que le dessin est un rectangle de 5x5 pixels.
       
0b10001000,
       
0b01010000,                   // Le dessin en lui-même. Comme vous pouvez le voir, il s'agit
       
0b00100000,                   // d'une croix, ou plutôt, d'un X...
       
0b01010000, 
        0b10001000}, 
        &(SCR_RECT){{0,0,239,127}},  // Permet de définir la partie d'affichage (celle-ci correspond à une TI-92plus)
       
A_REPLACE);                   // Donne l'attribut avec lequel sera affichée l'image.

Remarque 1 : Comme vous pouvez le remarquer, la "ligne" de code qui correspond à cette instruction a ici été découpée en plusieurs lignes de texte, pour des raisons évidentes de simplicité de compréhension. Il est possible d'utiliser exactement la même technique sous TIGCC, qui permettra ainsi de mieux repérer le dessin
Remarque 2 : De même, vous pouvez voir que, ici, nous avons noté les codes correspondant au dessin sous forme binaire. Ceci n'est autorisé que depuis la version 0.91 de TIGCC. Par souci de compatibilité avec les versions précédentes de TIGCC, je vous conseille fortement de convertir ces valeurs en langage hexadécimal comme vous le faisiez auparavant, en particulier si vous souhaitez distribuer vos sources... Ici, au lieu de "0b10001000, 0b01010000, 0b00100000, 0b01010000, 0b10001000", on obtiendrai "0x88, 0x50, 0x20, 0x50, 0x88". Cette conversion est rapide, et elle ne fait pas de mal !
                            Dans la suite de ce chapitre, nous continuerons généralement d'utiliser la forme binaire associée à la forme hexadécimale, pour plus de simplicité de compréhension des dessins...

    B: Une erreur à éviter :

Nous allons partir d'un simple exemple, en fait, de deux codes presque similaires, mais qui donnent un résultat totalement différent :

Voici le premier :
        BitmapPut(10,10,(BITMAP *)&(unsigned char[]){0,5,0,13,
       
0b10001000,0b10001000,        /* 0x88, 0x88 */
       
0b01010000,0b01010000,        /* 0x50, 0x50 */
       
0b00100000,0b00100000,        /* 0x20, 0x20 */
       
0b01010000,0b01010000,        /* 0x50, 0x50 */
       
0b10001000,0b10001000},       /* 0x88, 0x88 */
       
&(SCR_RECT){{0,0,239,127}},A_REPLACE);

Et voici le second :
        BitmapPut(10,10,(BITMAP *)&(unsigned char[]){0,10,0,5,
       
0b10001000,0b10001000,        /* 0x88, 0x88 */
       
0b01010000,0b01010000,        /* 0x50, 0x50 */
       
0b00100000,0b00100000,        /* 0x20, 0x20 */
       
0b01010000,0b01010000,        /* 0x50, 0x50 */
       
0b10001000,0b10001000},       /* 0x88, 0x88 */
       
&(SCR_RECT){{0,0,239,127}},A_REPLACE);

   Comme vous pourrez le remarquer si vous essayez de compiler ces deux codes, le premier donne deux croix côtes à côtes, tandis que le second ne donne qu'une grande croix verticale... Et pourtant, les deux codes donnent l'air d'être identiques... Donc, faites bien attention aux valeurs de hauteur et de largeur de l'image, qui, si elles sont incorrectes, suffisent à donner un résultat tout à fait différent de celui attendu...

    C: Un dernier exemple, où il n'est pas possible d'utiliser un sprite :

    J'ai pas trop d'imagination sur le point de vue graphique, alors j'ai fait simple, mais, là,  vous pouvez voir un exemple pour lequel il ne serait pas possible d'utiliser un sprite, puisque le dessin fait plus que 32x32 pixels...

BitmapPut(10,10,(BITMAP *)&(unsigned char[]){0,16,0,49,
0b10000011, 0b11100011, 0b11000111, 0b01000101, 0b11100011, 0b11101111, 0b10000000, 
0b10000010, 0b00000100, 0b00001000, 0b01000101, 0b00010000, 0b10000010, 0b00000000, 
0b10000010, 0b00000100, 0b00001000, 0b01000101, 0b00010000, 0b10000010, 0b00000000, 
0b10000011, 0b10000100, 0b00000110, 0b01000101, 0b11100000, 0b10000010, 0b00000000, 
0b10000010, 0b00000100, 0b00000001, 0b01000101, 0b01000000, 0b10000010, 0b00000000, 
0b10000010, 0b00000100, 0b00000001, 0b01000101, 0b00100000, 0b10000010, 0b00000000, 
0b11111011, 0b11100011, 0b11001110, 0b00111001, 0b00010000, 0b10001111, 0b10000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 
0b00000000, 0b00000000, 0b11111001, 0b11110111, 0b11000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100011, 0b11100001, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100011, 0b00000001, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100011, 0b00000001, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100011, 0b00000001, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100011, 0b11100001, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00100001, 0b11110111, 0b11000000, 0b00000000, 0b00000000},
&(
SCR_RECT){{0,0,239,127}},A_REPLACE);   // Pensez à changer les valeurs pour TI-89...

    Je me suis "bien amusé :-)" en écrivant cet exemple, mais je ne penses pas le traduire en hexadécimal... En effet, il est là juste pour vous montrer ce que cette fonction permet de faire... Pour la traduction, si vous n'utilisez pas la version 0.91SP1 de TIGCC, faite comme indiqué au Chapitre XII...

 

IV:\ Affichage d'images de type TI-BASIC :

    Cette fonction n'est pas de moi, elle est donnée dans la FAQ de TIGCC, mais comme j'ai plusieurs fois reçu des mails me demandant comment on pouvais afficher des images de type PIC (correspondant au TI-BASIC), je la remet ici, en espérant que vous lirez ce Chapitre mieux que certains ne lisent la FAQ...
        short show_picvar(char *SymName, short x, short y, short Attr)
        {
         
SYM_ENTRY *sym_entry = SymFindPtr(SymName, 0);
         
if (!sym_entry) return FALSE;
         
if (peek(HToESI (sym_entry->handle)) != PIC_TAG) return FALSE;
         
BitmapPut(x, y, HeapDeref (sym_entry->handle) + 2, ScrRect, Attr);
         
return TRUE;
        }

    Pour lancer cette fonction, il faut utiliser :
        show_picvar ($(testpic), 30, 30, A_NORMAL);
    En supposant que testpic est le nom de l'image PIC à afficher.
    Cette fonction renvoie TRUE si l'image a été affichée sans difficultés, et FALSE si elle ne l'a pas été (par exemple, si la variable testpic n'existe pas, ou alors si ce n'est pas une image de type PIC).

 

V:\ Un cas où il n'est pas nécessaire d'utiliser ces instructions :

    Il existe un cas où il n'est pas nécessaire d'utiliser ce type d'instructions pour sauvegarder une image, et le réafficher ensuite : quand l'image à sauvegarder/réafficher représente l'écran entier de la TI.
    Dans ce cas là, il faut utiliser les instructions suivantes :
        LCD_BUFFER buffer_mem;  // Déclare la variable qui servira à mémoriser l'écran.
        LCD_save(buffer_mem);        // Sauvegarde l'écran entier dans la variable déclarée précédemment.
        /*...
        ...  Diverses instructions qui modifient l'écran.
        ...*/

        LCD_restore(buffer_mem);    // Rappelle l'écran mémorisé auparavant.

 

Voilà, j'espère que vous avez compris comment fonctionne ces diverses instructions.

Retour au menu général

Chapitre XX


 


Copyright © Ti-Fr v2.0 1999-2002