Allegro 5

Programmation de jeux en C ou C++


précédentsommairesuivant

V. Images

V-A. Introduction

Toutes les images sont des bitmaps dans un programme Allegro. Nous commençons ainsi par présenter la bitmap en mémoire qui dans un programme permet de créer, de composer ou de modifier une image. Ensuite nous présentons les « images ». À la différence des bitmaps en mémoire, ce sont au départ des fichiers externes au programme que l'on peut charger dans le programme. Nous abordons comment afficher ces images, comment les modifier, éventuellement pixel par pixel et comment les sauvegarder ensuite.

V-B. Bitmap en mémoire

Une bitmap, littéralement plan ou surface de bits, sert au codage d'une image en mémoire. Le principe est celui d'un tableau d'octets à deux dimensions, un tableau d'unsigned char. Chaque position du tableau correspond à un pixel de l'image et sa valeur code sa couleur.

En 8 bits, dont l'utilisation est de plus en plus rare, la valeur correspond à un indice dans un tableau de 256 couleurs RGB appelé une palette (comme la palette du peintre). En 15, 16, 24 et 32 bits, la valeur du pixel est décomposée en trois sous-valeurs, une pour le rouge, une pour le vert, une pour le bleu. En 32 bits, il y a en plus une valeur de transparence. Chacune de ses sous-valeurs correspond à un nombre de bits. Par exemple, pour la couleur 16 bits dans l'ancienne version 4 d'Allegro, chaque couleur est codée sur un unsigned short (2 octets) décomposé en 6 bits pour le rouge, 5 bits pour le vert et 6 bits pour le bleu. Actuellement la couleur est pratiquement toujours codée en 32 bits avec un octet par composante de couleur et un octet pour la transparence.

Il y a deux grands types de bitmap en mémoire : les bitmaps qui utilisent la RAM désignées sous le terme de « bitmaps mémoire » et les bitmaps de mémoire vidéo qui utilisent la mémoire de la carte vidéo. En général, les opérations de dessin et tous les traitements directement en mémoire RAM sont plus rapides. Pour cette raison, il est souvent préférable de faire ses opérations graphiques avec des bitmaps mémoire et d'afficher ensuite ou au fur et à mesure les résultats à l'écran. L'écran utilise de la mémoire vidéo. Les traitements sur l'image y sont beaucoup plus lents, en revanche les opérations d'affichage bénéficient au contraire d'une accélération graphique.

Le module bitmap fait partie du tronc commun d'Allegro, ce n'est pas un greffon (ce n'est pas un addon) et l'utilisation des fonctions de bitmaps nécessite uniquement l'inclusion du module de base de la bibliothèque Allegro :

 
Sélectionnez
#include <allegro5/allegro.h>

V-B-1. Créer une bitmap

Sous Allegro, une bitmap est une structure du type ALLEGRO_BITMAP . Elles seront toujours manipulées via des pointeurs. Pour créer une bitmap, il faut déclarer un pointeur :

 
Sélectionnez
ALLEGRO_BITMAP* mabmp ;

Ensuite plusieurs options sont possibles : bitmap mémoire, bitmap vidéo… Chaque option est désignée par une valeur drapeau (flag en anglais). L'option choisie doit être activée avec un appel à la fonction :

 
Sélectionnez
void al_set_new_bitmap_flags(int flags)

La documentation présente dix options mais les trois options les plus courantes sont :

 
Sélectionnez
ALLEGRO_MEMORY_BITMAP

Spécifie la création d'une bitmap en mémoire RAM. Pas d'accélération graphique mais l'accès direct aux pixels est plus rapide qu'avec la mémoire vidéo.

 
Sélectionnez
ALLEGRO_VIDEO_BITMAP

Bitmap en mémoire sur la carte vidéo. Profite de l'accélération graphique. Toutes les bitmaps vidéo dépendent de l'affichage (display) courant. La création peut échouer s'il n'y a pas de display ou si les dimensions ne sont pas supportées.

 
Sélectionnez
ALLEGRO_CONVERT_BITMAP

C'est le réglage par défaut et il ne nécessite pas d'appel à la fonction al_set_new_bitmap_flags() . Le principe sous-jacent pour la création d'une bitmap est alors premièrement d'essayer d'avoir une bitmap vidéo optimisée pour la fenêtre d'affichage du display courant et en cas d'échec de créer une bitmap mémoire.

Une fois l'option sélectionnée, la bitmap finale est obtenue avec un appel à la fonction :

 
Sélectionnez
ALLEGRO_BITMAP *al_create_bitmap(int w, int h)

La fonction retourne un pointeur alloué selon les dimensions demandées en w pour la largeur et h pour la hauteur de la bitmap.

Typiquement pour avoir une bitmap mémoire, nous aurons la séquence :

 
Sélectionnez
ALLEGRO_BITMAP*bmp ;
(...)
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
bmp=al_create_bitmap(tx,ty);
if(!bmp)
    erreur("al_create_bitmap()");

Par ailleurs une fonction offre la possibilité de cloner une bitmap.

La fonction al_clone_bitmap :

 
Sélectionnez
ALLEGRO_BITMAP *al_clone_bitmap(ALLEGRO_BITMAP *source)

Clone une bitmap existante. Elle retourne une copie de la bitmap passée au paramètre source.

V-B-2. Dessiner dans une bitmap

Une fois la bitmap créée, pour que les opérations de dessin s'exécutent dedans elle doit au préalable être sélectionnée avec un appel à la fonction :

 
Sélectionnez
void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)

qui prend en paramètre la bitmap pour dessiner (target signifie cible en anglais). Tant que cette bitmap est sélectionnée, il n'est pas possible de dessiner ailleurs et toutes les opérations d'affichage et de dessin se feront dedans. Pour retourner à l'écran, il faut resélectionner l'écran. C'est le rôle de la fonction :

 
Sélectionnez
void al_set_target_backbuffer(ALLEGRO_DISPLAY *display)

qui prend en paramètre la fenêtre d'affichage display courant. Cela revient à sélectionner le double buffer de l'écran pour les opérations d'affichage. Nous pourrions aussi utiliser la fonction al_set_target_bitmap() de la façon suivante :

 
Sélectionnez
al_set_target_bitmap(al_get_backbuffer(display));

Sachant que l'appel de la fonction al_get_backbuffer(display) retourne le double buffer de la fenêtre display passée en paramètre.

Typiquement nous aurons une séquence :

 
Sélectionnez
// sélection de la bitmap
al_set_target_bitmap(bmp);
// dessins dedans, par exemple
al_clear_to_color(al_map_rgb(10,0,100));
al_draw_filled_rectangle(10,20,30,40,color) ;
// revenir à l'affichage display
al_set_target_backbuffer(display);

Pour afficher à l'écran l'image ainsi créée, il y a de nombreuses fonctions que nous étudierons plus loin mais voici la plus usitée :

 
Sélectionnez
void al_draw_bitmap(ALLEGRO_BITMAP *bmp, float x, float y, int flags)

Cette fonction affiche la bitmap bmp dans la bitmap actuellement sélectionnée pour l'affichage (écran ou une autre bitmap) à la position x, y , selon le paramétrage donné par flags . Il y a trois possibilités :

0 : l'image est affichée sans changement.

ALLEGRO_FLIP_HORIZONTAL : renversement horizontal selon l'axe des y.

ALLEGRO_FLIP_VERTICAL : renversement vertical selon l'axe des x.

La bitmap à afficher et la bitmap de destination ne peuvent pas être la même bitmap. Pour une opération sur la même bitmap il faut passer par des copies sur des bitmaps intermédiaires.

Dernière chose, la libération de la mémoire allouée pour une bitmap se fait avec la fonction :

 
Sélectionnez
void al_destroy_bitmap(ALLEGRO_BITMAP *bitmap)

Elle prend en paramètre la bitmap à libérer de la mémoire.

V-B-2-a. Expérimentation

Voici un exemple complet, création d'une bitmap, dessin, mouvement et affichage à l'écran :

Manipuler une bitmap
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>
#include <time.h>

#define COLORALEA al_map_rgb(rand()%256,rand()%256,rand()%256);

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int is_key_pressed(ALLEGRO_KEYBOARD_STATE*key, int touche, int repeat)
{
    //le tableau conserve ses valeurs d'un appel à l'autre (static)
    static int press[ALLEGRO_KEY_MAX] = { 0 };
    int res = 0;

    if (al_key_down(key, touche) && press[touche] < repeat){
        press[touche]++;
        res = 1;
    }
    else if (!al_key_down(key, touche))
        press[touche] = 0;
    return res;

}
/*****************************************************************
*****************************************************************/

int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;

    ALLEGRO_BITMAP*bmp;
    ALLEGRO_COLOR color;
    int x, y, tx, ty, dx, dy, i;
    int screenx, screeny;

    srand(time(NULL));
    if (!al_init())
        erreur("al_init()");
    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    if (!al_init_primitives_addon())
        erreur("al_init_primitives_addon()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");
    screenx = al_get_display_width(display);
    screeny = al_get_display_height(display);

    // dimension pour la bitmap
    tx = 10 + rand() % (screenx / 2);
    ty = 10 + rand() % (screeny / 2);

    // création d'une bitmap mémoire
    al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
    bmp = al_create_bitmap(tx, ty);
    if (!bmp)
        erreur("al_create_bitmap()");

    // dessiner dans la bitmap en mémoire
    al_set_target_bitmap(bmp);

    // bombardement de pixel de couleurs aléatoires
    al_clear_to_color(al_map_rgb(10, 0, 100));
    for (i = 0; i<10000; i++){
        color = COLORALEA;
        al_put_pixel(rand() % tx, rand() % ty, color);
    }

    // revenir à l'affichage display
    al_set_target_backbuffer(display);


    // position de départ
    x = rand() % (screenx - tx);
    y = rand() % (screeny - ty);

    // déplacement
    dx = rand() % 20 - 10;
    dy = rand() % 20 - 10;
    do{
        al_get_keyboard_state(&key);

        // bouger
        x += dx;
        if (x<0 || x + tx>screenx)
            dx *= -1;

        y += dy;
        if (y<0 || y + ty> screeny)
            dy *= -1;

        // effacement Double Buffer
        al_clear_to_color(al_map_rgb(0, 0, 0));
        // affichage DB de l'imae aux coordonnées x,y
        al_draw_bitmap(bmp, x, y, 0);
        // DB copié à l'écran
        al_flip_display();

        al_rest(1.0 / 30.0);

    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    al_destroy_bitmap(bmp);
    return 0;
}
/*****************************************************************
*****************************************************************/

V-C. Image

L'image est toujours une bitmap dans le programme mais elle provient au départ d'un fichier sur le disque dur. Les formats reconnus avec certitude sont BMP, PCX, TGA, JPEG et PNG.

V-C-1. Charger une image (load)

Le chargement d'images ainsi que la sauvegarde des images nécessitent l'utilisation du module image, soit l'inclusion de allegro_image.h :

 
Sélectionnez
#include <allegro5/allegro_image.h>

et l'initialisation du module image avec un appel à :

 
Sélectionnez
bool al_init_image_addon(void)

La fonction retourne true si succès et false sinon. Typiquement nous écrirons :

 
Sélectionnez
if(!al_init_image_addon())
    erreur("al_init_image_addon()");

Ensuite pour charger une image dans le programme c'est un appel à la fonction :

 
Sélectionnez
ALLEGRO_BITMAP *al_load_bitmap(const char *filename)

Cette fonction prend en paramètre le chemin d'accès au fichier image extension comprise et retourne un pointeur sur la bitmap qui est une copie de l'image ou NULL en cas d'échec.

Tous les formats d'image ne sont pas reconnus, mais les principaux formats BMP, PCX, TGA, JPEG et PNG le sont. Exemple d'utilisation, le programme charge une image de type bitmap (.bmp) nommée « image.bmp » qui se trouve dans le dossier « images » lui-même dans le répertoire du programme :

Charger une image
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_BITMAP*image;        // l'image

    if (!al_init())
        erreur("al_init()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");

    //nécessaire pour laod et save bitmap
    if (!al_init_image_addon())
        erreur("al_init_image_addon()");

    // charger une image dans le programme
    image = al_load_bitmap("./images/image.bmp");
    if (!image)
        erreur("al_load_bitmap()");

    // l'afficher
    al_draw_bitmap(image, 0, 0, 0);
    al_flip_display();

    al_rest(3.0);
    al_destroy_display(display);
    al_destroy_bitmap(image);
    return 0;
}
/*****************************************************************
*****************************************************************/

V-C-2. Afficher une image

Allegro fournit de nombreuses fonctions pour l'affichage des images.

La fonction al_draw_bitmap :

 
Sélectionnez
void al_draw_bitmap(ALLEGRO_BITMAP *source, float x, float y, int flags)

Affiche la bitmap source dans la bitmap cible actuellement sélectionnée à la position x , y et selon la valeur flags qui peut être :

0 : l'image est affichée sans changement.

ALLEGRO_FLIP_HORIZONTAL : renversement horizontal selon l'axe des y.

ALLEGRO_FLIP_VERTICAL : renversement vertical selon l'axe des x.

La bitmap à afficher et la bitmap cible ne peuvent pas être la même bitmap. Pour une opération sur la même bitmap, il faut passer par des copies sur des bitmaps intermédiaires.

La fonction al_draw_bitmap_region :

 
Sélectionnez
void al_draw_bitmap_region(ALLEGRO_BITMAP *source, float sx, float sy, float sw, float sh, float dx, float dy, int flags)

Copie une région de la bitmap source définie par sx, sy, sw, sh à la position dx, dy dans la bitmap cible actuellement sélectionnée. Le paramètre flags peut être : 0 , ALLEGRO_FLIP_HORIZONTAL,

ALLEGRO_FLIP_VERTICAL.

La fonction al_draw_scaled_bitmap :

 
Sélectionnez
void al_draw_scaled_bitmap(ALLEGRO_BITMAP *source ,float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags)

Copie en étirée ou en réduction (scale, stretch) de la région définie par sx , sy , sw , sh dans la bitmap source vers la région définie par dx , dy , dw , dh dans la bitmap cible (target) actuellement sélectionnée. Le paramètre flags peut être : 0 , ALLEGRO_FLIP_HORIZONTAL , ALLEGRO_FLIP_VERTICAL .

La fonction al_draw_rotated_bitmap :

 
Sélectionnez
void al_draw_rotated_bitmap(ALLEGRO_BITMAP *source, float cx, float cy, float dx, float dy, float angle, int flags)

Copie la bitmap source dans la bitmap cible sélectionnée en effectuant une rotation. Les paramètres cx et cy fournissent un point dans l'image source autour duquel s'effectue la rotation. Les paramètres dx et dy fournissent la correspondance dans l'image de destination. L'angle est donné en radians avec angle . Le paramètre flags indique si une permutation horizontale ou verticale doit être effectuée.

La fonction al_draw_scaled_rotated_bitmap :

 
Sélectionnez
void al_draw_scaled_rotated_bitmap(ALLEGRO_BITMAP *source, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)

Copie la bitmap source dans la bitmap cible (target) sélectionnée en effectuant un étirement ou une réduction (scale, stretch) et une rotation (se reporter aux deux fonctions précédentes pour le détail des paramètres).

La fonction al_draw_tinted_bitmap :

 
Sélectionnez
void al_draw_tinted_bitmap(ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float dx, float dy, int flags)

Identique à al_draw_bitmap() mais en plus le paramètre tint permet un filtrage des couleurs de l'image. Le filtre est une couleur. Chaque composante rouge, vert, bleu, alpha de la couleur du filtre multiplie les composantes correspondantes de la couleur de chaque pixel de l'image. Par exemple :

 
Sélectionnez
ALLEGRO_COLOR tint=al_map_rgba_f(0.5, 0.5, 0.5, 0.5);
al_draw_tinted_bitmap(bitmap, tint, x, y, 0);

Cet appel divise par deux l'affichage de la valeur de couleur de chaque composante des couleurs de l'image source ce qui l'assombrit.

 
Sélectionnez
ALLEGRO_COLOR tint=al_map_rgba_f(1, 0, 0, 2);
al_draw_tinted_bitmap(bitmap, tint, x, y, 0);

Cet appel laisse le rouge inchangé, met à 0 le vert et le bleu puis multiplie par deux la transparence.

La fonction al_draw_tinted_bitmap_region :

 
Sélectionnez
void al_draw_tinted_bitmap_region(ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, int flags)

Fonction identique à al_draw_bitmap_region() mais ajoute le paramètre tint pour le filtrage des couleurs (voir al_draw_tinted_bitmap() pour le fonctionnement de ce paramètre).

La fonction al_draw_tinted_scaled_bitmap :

 
Sélectionnez
void al_draw_tinted_scaled_bitmap(ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags)

Fonction identique à al_draw_scaled_bitmap() mais ajoute le paramètre tint pour le filtrage des couleurs (voir al_draw_tinted_bitmap() pour le fonctionnement de ce paramètre).

La fonction al_draw_tinted_rotated_bitmap :

 
Sélectionnez
void al_draw_tinted_rotated_bitmap(ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float angle, int flags)

Fonction identique à al_draw_rotated_bitmap() mais ajoute le paramètre tint pour le filtrage des couleurs (voir al_draw_tinted_bitmap() pour le fonctionnement de ce paramètre).

La fonction al_draw_tinted_scaled_rotated_bitmap :

 
Sélectionnez
void al_draw_tinted_scaled_rotated_bitmap(ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)

Fonction identique à al_draw_scaled_rotated_bitmap_region() mais ajoute le paramètre tint pour le filtrage des couleurs (voir al_draw_tinted_bitmap() pour le fonctionnement de ce paramètre).

La fonction al_draw_tinted_scaled_rotated_bitmap_region :

 
Sélectionnez
void al_draw_tinted_scaled_rotated_bitmap_region(ALLEGRO_BITMAP *bmp, float sx, float sy, float sw, float sh, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)

Fonction identique à al_draw_scaled_rotated_bitmap_region() mais ajoute le paramètre tint pour le filtrage des couleurs (voir al_draw_tinted_bitmap() pour le fonctionnement de ce paramètre).

V-C-3. Expérimenter les fonctions d'affichage

Très honnêtement les affichages valent la peine d'être tous expérimentés. Ils sont vraiment très réussis. Une chose est de comprendre ce que fait la fonction, une autre de voir le résultat. Le programme ci-dessous suppose une image bitmap (.bmp) positionnée dans le répertoire du programme et nommée « image.bmp ». Toutes les fonctions d'affichage sont testées à partir des touches [F1] à [F11]. La touche [Entrée] efface l'écran.

Nous profitons volontairement dans ce programme de la répétition de touche due à la méthode de capture du clavier dans une structure ALLEGRO_KEYBOARD_STATE par la fonction al_get_keyboard_state() .

Tester les fonctions d'affichage
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;
    ALLEGRO_BITMAP*image;
    int tx, ty, screenx, screeny;

    if (!al_init())
        erreur("al_init()");
    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    if (!al_init_image_addon())
        erreur("al_init_image_addon()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");

    screenx = al_get_display_width(display);
    screeny = al_get_display_height(display);

    image = al_load_bitmap("image.bmp");
    if (!image)
        erreur("al_load_bitmap()");

    tx = al_get_bitmap_width(image);
    ty = al_get_bitmap_height(image);



    do{
        al_get_keyboard_state(&key);

        int flags = 0; // pas de permutation
        // autres possibilités :
        // flags=ALLEGRO_FLIP_HORIZONTAL
        // flags=ALLEGRO_FLIP_VERTICAL
        // flags=ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL

        if (al_key_down(&key, ALLEGRO_KEY_F1))
            al_draw_bitmap(image, // l'image source
            0, 0,                 // position
            flags);                 // permutation

        // pour les régions
        int sx = rand() % tx;
        int sy = rand() % ty;
        int sw = rand() % (tx - sx);
        int sh = rand() % (ty - sy);
        int dx = rand() % (screenx - sw);
        int dy = rand() % (screeny - sh);

        if (al_key_down(&key, ALLEGRO_KEY_F2)){
            al_draw_bitmap_region(
                image,
                sx, sy, // hg source
                sw, sh, // taille dans source
                dx, dy, // hg destination
                flags); //permutation
        }

        // taille destination pour déformation
        float dw = ((float)rand() / RAND_MAX)*screenx;
        float dh = ((float)rand() / RAND_MAX)*screeny;
        if (al_key_down(&key, ALLEGRO_KEY_F3))
            al_draw_scaled_bitmap(
            image,        // image source
            0, 0,        // coin haut gauche
            tx, ty,        // taille source
            0, 0,        // coin haut gauche destination
            dw,            // taille destination
            dh,
            flags);        // permutation

        if (al_key_down(&key, ALLEGRO_KEY_F4))
            al_draw_rotated_bitmap(
            image,            // image source
            tx / 2, ty / 2,    //pivot source
            screenx / 2,    //pivot destination
            screeny / 2,
            rand() % 360,    // angle en radian
            flags);            // permutation

        // proportion pour déformation
        float xscale = ((float)rand() / RAND_MAX) * 2;
        float yscale = ((float)rand() / RAND_MAX) * 2;
        float angle = ((float)rand() / RAND_MAX)* (2 * 3.14);
        if (al_key_down(&key, ALLEGRO_KEY_F5)){
            al_draw_scaled_rotated_bitmap(
                image,
                tx / 2, ty / 2,    //pivot source
                screenx / 2,    //pivot destination
                screeny / 2,
                xscale, yscale, // le rapport,
                angle,            // angle en radian
                flags);            // permutation
        }

        // pour les affichages teintés
        // la couleur originale de chaque pixel est modifiée
        // par multiplication. Par exemple un filtre de
        // al_map_rgba_f(0.5, 0.5,0.5,0.5)
        // signifie que rouge,vert, bleu et transparence de
        // l'image seront divisés par deux
        // un filtre de al_map_rgba_f(1, 0,0,2) signifie
        // que le rouge reste identique, vert et bleu sont
        // supprimés et transparence multipliée par deux.
        float r = ((float)rand() / RAND_MAX) * 2;
        float g = ((float)rand() / RAND_MAX) * 2;
        float b = ((float)rand() / RAND_MAX) * 2;
        float a = ((float)rand() / RAND_MAX) * 2;
        ALLEGRO_COLOR filtre = al_map_rgba_f(r, g, b, a);

        if (al_key_down(&key, ALLEGRO_KEY_F6))
            al_draw_tinted_bitmap(
            image,
            filtre, // transformation couleur
            0, 0, // position destination
            flags); // permutation


        if (al_key_down(&key, ALLEGRO_KEY_F7))
            al_draw_tinted_bitmap_region(
            image,
            filtre,
            sx, sy, //coin hg source
            sw, sh, // taille source
            dx, dy, // position destination
            flags);// permutations


        if (al_key_down(&key, ALLEGRO_KEY_F8))
            al_draw_tinted_scaled_bitmap(
            image,
            filtre,
            sx, sy,// coin h-g source
            sw, sh,// taille source
            dx, dy,// coin h-g destination
            dw, dh,// taille destination
            flags); // permutation

        if (al_key_down(&key, ALLEGRO_KEY_F9))
            al_draw_tinted_rotated_bitmap(
            image,
            filtre,
            tx / 2, ty / 2, // pivot source
            dx, dy, // pivot destination
            angle,
            flags);

        if (al_key_down(&key, ALLEGRO_KEY_F10))
            al_draw_tinted_scaled_rotated_bitmap(
            image,
            filtre,
            tx / 2, ty / 2,//pivot source
            dx, dy, // pivot destination
            xscale, yscale,// rapport taille
            angle,
            flags);

        if (al_key_down(&key, ALLEGRO_KEY_F11))
            al_draw_tinted_scaled_rotated_bitmap_region(
            image,
            sx, sy,// source h-g
            sw, sh,// source taille
            filtre,
            tx / 2, ty / 2,// pivot source
            dx, dy,// pivot destination
            xscale, yscale, // rapport taille
            angle,
            flags);

        if (al_key_down(&key, ALLEGRO_KEY_ENTER))
            al_clear_to_color(al_map_rgb(0, 0, 0));
        

        al_flip_display();
    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    al_destroy_bitmap(image);
    return 0;
}
/*****************************************************************
*****************************************************************/

V-C-4. Sélectionner une image pour la modifier

Dans un programme Allegro, une image est une copie en bitmap d'un fichier sur le disque dur. Nous avons vu que pour pouvoir dessiner ou afficher dans une bitmap, la bitmap cible doit au préalable être sélectionnée. Voici un rappel des principales fonctions pour cette opération et aussi le moyen de connaître celle réservée pour l'affichage à un moment dans le programme.

La fonction al_set_target_bitmap :

 
Sélectionnez
void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)

Cette fonction permet de sélectionner la bitmap dans laquelle dessiner ou afficher.

La fonction al_get_target_bitmap :

 
Sélectionnez
ALLEGRO_BITMAP *al_get_target_bitmap(void)

Cette fonction retourne l'adresse de la bitmap actuellement sélectionnée pour les opérations de dessin et d'affichage.

La fonction al_set_target_backbuffer :

 
Sélectionnez
void al_set_target_backbuffer(ALLEGRO_DISPLAY *display)

Cette fonction sélectionne le double buffer de la fenêtre display passée en paramètre pour les opérations de dessin et d'affichage.

La fonction al_get_current_display :

 
Sélectionnez
ALLEGRO_DISPLAY *al_get_current_display(void)

Cette fonction récupère la fenêtre display actuellement sélectionnée pour les opérations d'affichage.

La fonction al_get_backbuffer :

 
Sélectionnez
ALLEGRO_BITMAP *al_get_backbuffer(ALLEGRO_DISPLAY *display)

Cette fonction retourne l'adresse de la bitmap double buffer de la fenêtre display passée en paramètre.

V-C-5. Obtenir les propriétés de l'image

Allegro fournit également des fonctions pour connaître la longueur, la hauteur et la profondeur, c'est-à-dire le format de couleur des pixels (8, 15, 16, 24, 32 bits), d'une bitmap.

Les fonctions al_get_bitmap_width et al_get_bitmap_height :

 
Sélectionnez
int al_get_bitmap_width(ALLEGRO_BITMAP *bmp)
int al_get_bitmap_height(ALLEGRO_BITMAP *bmp)

Ces deux fonctions permettent de récupérer respectivement la longueur et la hauteur de la bitmap bmp.

La fonction al_get_bitmap_format :

 
Sélectionnez
int al_get_bitmap_format(ALLEGRO_BITMAP *bmp)

Donne le format de pixel de la bitmap bmp, c'est-à-dire la taille en mémoire du pixel avec la configuration des bits pour la couleur. Tous les formats sont définis au sein d'Allegro 5 par un enum :

 
Sélectionnez
typedef enum ALLEGRO_PIXEL_FORMAT

Ce sont donc des valeurs entières. C'est pourquoi la fonction retourne un int. Chaque valeur code un type de format, en voici quelques-uns à titre indicatif :

ALLEGRO_PIXEL_FORMAT_ARGB_8888 - 32 bit

ALLEGRO_PIXEL_FORMAT_RGBA_8888 - 32 bit

ALLEGRO_PIXEL_FORMAT_ARGB_4444 - 16 bit

ALLEGRO_PIXEL_FORMAT_RGB_888 - 24 bit

ALLEGRO_PIXEL_FORMAT_RGB_565 - 16 bit

ALLEGRO_PIXEL_FORMAT_RGB_555 - 15 bit

Ceci permet éventuellement d'accéder directement à chaque composante de couleur en utilisant les opérateurs bit à bit plutôt que les fonctions prévues. Par exemple soit le format 32 bits ALLEGRO_PIXEL_FORMAT_ARGB_8888 , l'expression :

 
Sélectionnez
(pixel & 0x00FF0000) >> 16

donne la valeur de la composante de rouge (chaque colonne correspond à 4 bits). Le masque 0x00FF0000 isole les 8 bits qui correspondent à la valeur du rouge et le décalage à droite ramène cette valeur pour donner le résultat.

Toutefois il est peut-être plus simple d'utiliser les fonctions dédiées à la couleur. Notamment pour récupérer ses composantes il y a la série de fonctions al_unmap_(...) présentées dans le chapitre Texte, polices, couleur, dessin, section Couleurs, transparenceCouleurs, transparence.

V-C-6. Sauvegarder une image

Pour sauvegarder une image, le greffon (addon) « image » est nécessaire et il doit être inclus :

 
Sélectionnez
#include <allegro5/allegro_image.h>

Il faut également veiller à son initialisation ensuite avec la fonction al_init_image_addon() qui retourne true sur succès et false sur erreur :

 
Sélectionnez
if(!al_init_image_addon())
    erreur("al_init_image_addon()");

Ensuite dans le programme la sauvegarde d'une bitmap s'effectue avec :

 
Sélectionnez
bool al_save_bitmap(const char *filename, ALLEGRO_BITMAP *source)

Cette fonction crée un fichier en copie de la bitmap source. Le nom du fichier est passé en filename, il se termine obligatoirement par une extension : .bmp, .png, .jpg, .pcx, .tga, qui détermine quel est le type de l'image.

V-C-6-a. Expérimentation

Nous reprenons une partie du programme précédent de chargement d'une image et de son affichage avec la fonction al_draw_tinted_scaled_rotated_bitmap_region() qui donne de très beaux résultats. Au départ appuyer sur [F1] pour obtenir un affichage. Ensuite chaque appui sur la touche S déclenche une sauvegarde de l'image affichée dans la fenêtre courante display de l'application ou une capture d'écran si le programme est en plein écran.

Pour éviter des sauvegardes multiples avec un seul appui sur la touche S, la fonction is_key_pressed() , présentée dans le chapitre Premiers pas avec Allegro 5, section Compter les répétitions clavierCompter les répétitions clavier, est utilisée.

Sauvegarder une image
Sélectionnez
// ceci sous Visual Studio uniquement afin de
// lever l'interdiction d'utiliser des fonctions 
// jugées unsafe par microsoft.
#define _CRT_SECURE_NO_WARNINGS

#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>
#include <stdio.h>

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int is_key_pressed(ALLEGRO_KEYBOARD_STATE*key, int touche,
    int repeat)
{
    //le tableau conserve ses valeurs d'un appel à l'autre (static)
    static int press[ALLEGRO_KEY_MAX] = { 0 };
    int res = 0;

    if (al_key_down(key, touche) && press[touche] < repeat){
        press[touche]++;
        res = 1;
    }
    else if (!al_key_down(key, touche))
        press[touche] = 0;
    return res;

}
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;
    ALLEGRO_BITMAP*image;
    int tx, ty, screenx, screeny;

    if (!al_init())
        erreur("al_init()");
    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    if (!al_init_image_addon())
        erreur("al_init_image_addon()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");

    screenx = al_get_display_width(display);
    screeny = al_get_display_height(display);

    image = al_load_bitmap("image.bmp");
    if (!image)
        erreur("al_load_bitmap()");

    tx = al_get_bitmap_width(image);
    ty = al_get_bitmap_height(image);

    do{
        al_get_keyboard_state(&key);

        // pour les régions
        int sx = rand() % tx;
        int sy = rand() % ty;
        int sw = rand() % (tx - sx);
        int sh = rand() % (ty - sy);

        // pivot destination (pivot source centré)
        int dx = rand() % (screenx - sw);
        int dy = rand() % (screeny - sh);

        // filtre
        float r = ((float)rand() / RAND_MAX) * 2;
        float g = ((float)rand() / RAND_MAX) * 2;
        float b = ((float)rand() / RAND_MAX) * 2;
        float a = ((float)rand() / RAND_MAX) * 2;
        ALLEGRO_COLOR filtre = al_map_rgba_f(r, g, b, a);

        // proportion pour déformation
        float xscale = ((float)rand() / RAND_MAX) * 2;
        float yscale = ((float)rand() / RAND_MAX) * 2;
        float angle = ((float)rand() / RAND_MAX)* (2 * 3.14);

        if (is_key_pressed(&key, ALLEGRO_KEY_F1, 100))
            al_draw_tinted_scaled_rotated_bitmap_region(
            image,
            sx, sy,// source h-g
            sw, sh,// source taille
            filtre,
            tx / 2, ty / 2,// pivot source
            dx, dy,// pivot destination
            xscale, yscale, // rapport taille
            angle,
            0);// pas de permutation

        // faire une photo d'écran
        if (is_key_pressed(&key, ALLEGRO_KEY_S, 1)){
            static int cmpt = 1;
            char nom[80];
            ALLEGRO_BITMAP*save;

            // nom du fichier (save+numéro+extension)
            sprintf(nom, "save%d.png", cmpt);
            cmpt++;

            // l'image bitmap, deux solutions pour obtenir écran :
            save = al_get_backbuffer(display); // écran
            //save=al_get_target_bitmap();// image cible actuelle

            // sauvegarde
            al_save_bitmap(nom, save);

        }

        if (al_key_down(&key, ALLEGRO_KEY_ENTER))
            al_clear_to_color(al_map_rgb(0, 0, 0));

        al_flip_display();

    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    al_destroy_bitmap(image);
    return 0;
}
/*****************************************************************
*****************************************************************/

V-D. L'image pixel par pixel

Il est possible d'accéder à chaque pixel d'une image soit pour connaître sa couleur avec la fonction al_get_pixel() , soit pour la modifier avec la fonction al_put_pixel() . Ces accès sont lents surtout en mémoire vidéo, mais ils peuvent être accélérés avec l'utilisation de fonctions de verrouillage quels que soient les types de bitmap.

V-D-1. Accès aux pixels

La partie graphique du module de base de la bibliothèque Allegro (inclusion de allegro.h) met à disposition les fonctions suivantes pour l'accès pixel par pixel.

La fonction al_get_pixel :

 
Sélectionnez
ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *source, int x, int y)

Cette fonction retourne la couleur du pixel à la position x , y dans la bitmap source.

La couleur retournée peut ensuite être décomposée avec les fonctions spécifiques al_unmap_rgb() , al_unmap_rgb_f() etc. présentées au chapitre Texte, polices, couleur, dessin, section Couleurs, transparenceCouleurs, transparence.

Si la fonction doit être appelée souvent lors d'un traitement sur une même bitmap, il est conseillé de « verrouiller » cette bitmap afin de faciliter les opérations de lecture-écriture. Le verrouillage s'effectue avec la fonction al_lock_bitmap() expliquée plus loin. Une fois les opérations d'accès aux pixels effectuées, le déverrouillage s'effectue avec la fonction al_unlock_bitmap() . Verrouillage et déverrouillage ne concernent que des opérations pixel par pixel.

Cette opération est absolument nécessaire dans le cas d'une bitmap de mémoire vidéo. La mémoire vidéo est en effet destinée à l'affichage et se révèle extrêmement lente pour des traitements internes spécifiques pixel par pixel. Rappelons que la création d'une bitmap avec la fonction al_create_bitmap() ou le chargement d'une bitmap avec al_load_bitmap() retournent par défaut une bitmap vidéo optimisée pour l'affichage dans la fenêtre display courante.

La fonction al_put_pixel

 
Sélectionnez
void al_put_pixel(int x, int y, ALLEGRO_COLOR color)

Cette fonction colore un pixel à la position x , y avec la couleur color . C'est relativement lent avec une bitmap mémoire et très lent avec une bitmap vidéo. Si les appels sont répétés et fréquents, il est nécessaire de verrouiller la bitmap au début des opérations et de la déverrouiller à la fin (voir al_lock_bitmap() ).

La fonction al_get_bitmap_format

 
Sélectionnez
int al_get_bitmap_format(ALLEGRO_BITMAP *bmp)

Retourne le format de la bitmap bmp. Chaque format est identifié par une valeur entière (cf. chapitre Images - Obtenir les propriétés de l'imageObtenir les propriétés de l'image où la fonction a déjà été présentée avec le détail des formats).

La fonction al_get_pixel_format_bits :

 
Sélectionnez
int al_get_pixel_format_bits(int format)

Retourne le nombre de bits d'un pixel selon le format format .

La fonction al_lock_bitmap :

 
Sélectionnez
ALLEGRO_LOCKED_REGION *al_lock_bitmap(ALLEGRO_BITMAP *bitmap, int format, int flags)

La fonction verrouille toute la bitmap pour accélérer l'accès en écriture et en lecture et retourne une structure ALLEGRO_LOCKED_REGION qui correspond ici à toute la bitmap. L'appel fonctionne avec n'importe quel type de bitmap, vidéo aussi bien que mémoire. Cette structure est la suivante :

 
Sélectionnez
typedef struct ALLEGRO_LOCKED_REGION {
    void *data;
    int format;
    int pitch;
    int pixel_size;
} ALLEGRO_LOCKED_REGION;

Le champ data permet d'accéder à chaque pixel de la partie de l'image verrouillée, le format donne le format de la bitmap. Le champ pixel_size donne la taille en octet d'un pixel et le champ pitch donne la taille en octets d'une ligne (largeur de la région * pixel_size).

Le format de la bitmap passé au paramètre format peut être obtenu avec la fonction al_get_bitmap_format() . Pour le drapeau flags il y a trois valeurs possibles :

ALLEGRO_LOCK_READONLY : lecture uniquement.

ALLEGRO_LOCK_WRITEONLY : écriture uniquement. Attention il est impératif d'écrire sur absolument tous les pixels avant de déverrouiller.

ALLEGRO_LOCK_READWRITE : lecture et écriture sont possibles. Cette valeur est à utiliser pour des besoins en écriture seule lorsque tous les pixels ne sont pas à prendre en compte.

La fonction al_lock_bitmap_region :

Éventuellement il peut être utile de ne verrouiller qu'une partie de l'image avec la fonction :

 
Sélectionnez
ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags)

La région est alors verrouillée à partir de x sur la longueur width et à partir de y sur la hauteur height pour le format obtenu avec la fonction al_get_bitmap_format() et selon la valeur passée en flags pour lecture, écriture ou lecture-écriture.

La fonction al_unlock_bitmap :

 
Sélectionnez
void al_unlock_bitmap(ALLEGRO_BITMAP *bitmap)

Déverrouille la bitmap ou région de bitmap préalablement verrouillée.

La fonction al_is_bitmap_locked :

 
Sélectionnez
bool al_is_bitmap_locked(ALLEGRO_BITMAP *bitmap)

Retourne true si la bitmap est verrouillée et false sinon.

Attention : le verrouillage-déverrouillage ne concerne que les opérations pixel par pixel. Les autres opérations de dessin et d'affichage ne sont pas possibles pendant que la bitmap est verrouillée.

V-D-2. Expérimentations verrouillage, al_get_pixel(), al_put_pixel()

Au départ, on charge une image. C'est une bitmap nommée « image.bmp » qui se trouve dans le répertoire du programme. Ensuite si la touche [F1] est appuyée, la bitmap image est sélectionnée pour affichage, elle est verrouillée, puis chaque pixel est récupéré et modifié, la bitmap est déverrouillée, la sélection est redonnée au double buffer du display , l'image modifiée y est copiée, le double buffer est affiché. Ce qui donne :

Verrouiller une bitmap en lecture-écriture
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int is_key_pressed(ALLEGRO_KEYBOARD_STATE*key, int touche, int repeat)
{
    //le tableau conserve ses valeurs d'un appel à l'autre (static)
    static int press[ALLEGRO_KEY_MAX] = { 0 };
    int res = 0;

    if (al_key_down(key, touche) && press[touche] < repeat){
        press[touche]++;
        res = 1;
    }
    else if (!al_key_down(key, touche))
        press[touche] = 0;
    return res;

}
/*****************************************************************
*****************************************************************/

int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;
    ALLEGRO_BITMAP*image;
    int tx, ty;

    if (!al_init())
        erreur("al_init()");
    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    if (!al_init_image_addon())
        erreur("al_init_primitives_addon()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");

    image = al_load_bitmap("image.bmp");
    if (!image)
        erreur("al_load_bitmap()");
    tx = al_get_bitmap_width(image);
    ty = al_get_bitmap_height(image);

    do{
        al_get_keyboard_state(&key);

        if (is_key_pressed(&key, ALLEGRO_KEY_F1, 10)){
            al_set_target_bitmap(image);
            if (al_lock_bitmap(image,
                al_get_bitmap_format(image),
                ALLEGRO_LOCK_READWRITE) != NULL){
                int x, y;
                for (y = 0; y<ty; y++){
                    for (x = 0; x<tx; x++){
                        unsigned char r, g, b;
                        ALLEGRO_COLOR color;
                        color = al_get_pixel(image, x, y);
                        al_unmap_rgb(color, &r, &g, &b);

                        r = (r<246) ? r + rand() % 10 : 0;
                        g = (g>10) ? g - rand() % 10 : 255;
                        b = (b<251) ? b + rand() % 5 : 0;

                        al_put_pixel(x, y, al_map_rgb(r, g, b));
                    }
                }
                al_unlock_bitmap(image);
                al_set_target_backbuffer(display);
            }
        }
        al_draw_bitmap(image, 0, 0, 0);
        al_flip_display();

    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    return 0;
}
/*****************************************************************
*****************************************************************/

Lors d'un appui sur [F1], dix tours se produisent. Si vous mettez en commentaire le verrouillage, vous constaterez que la lenteur est phénoménale au point de penser que ça ne marche pas. En revanche c'est instantané avec le verrouillage.

V-D-3. Mélanges de couleurs (blending)

Une autre fonction pixel par pixel nous amène à considérer des opérations de mélange entre couleurs.

La fonction al_put_blended_pixel :

 
Sélectionnez
void al_put_blended_pixel(int x, int y, ALLEGRO_COLOR color)

Elle fonctionne comme al_put_pixel() mais au lieu qu'une couleur source remplace la couleur d'un pixel dans la bitmap cible, les deux couleurs sont mélangées. La couleur color est mélangée avec la couleur du pixel en x , y de l'image concernée (l'image cible actuellement sélectionnée avec la fonction al_set_target_bitmap() ).

Différentes options de mélange sont prévues. L'option choisie doit au préalable être sélectionnée par un appel à la fonction al_set_blender .

La fonction al_set_blender :

 
Sélectionnez
void al_set_blender(int mel, int src, int dst)

Le paramètre mel indique un type prédéfini de mélange. En fonction de ce type, la valeur de src est retenue dans une opération pour la couleur source et la valeur dest est retenue dans une opération pour la couleur de destination. Ces valeurs ne sont pas libres et les valeurs valides sont prédéfinies.

Les formules proposées qui définissent les types de mélange sont les suivantes : soit sr , sg , sb , sa pour des valeurs de rouge, vert, bleu, alpha de la couleur source et dr , dg , db , da pour des valeurs de rouge, vert, bleu, alpha de la couleur de destination. Nous avons donc :

 
Sélectionnez
ALLEGRO_ADD
r = dr * dst + sr * src
g = dg * dst + sg * src
b = db * dst + sb * src
a = da * dst + sa * src
ALLEGRO_DEST_MINUS_SRC
r = dr * dst - sr * src
g = dg * dst - sg * src
b = db * dst - sb * src
a = da * dst - sa * src
ALLEGRO_SRC_MINUS_DEST
r = sr * src - dr * dst
g = sg * src - dg * dst
b = sb * src - db * dst
a = sa * src - da * dst

Les valeurs valides pour src et dest sont les suivantes :

 
Sélectionnez
ALLEGRO_ZERO
src = 0
dst = 0
ALLEGRO_ONE
src = 1
dst = 1
ALLEGRO_ALPHA
src = sa
dst = sa
ALLEGRO_INVERSE_ALPHA
src = 1 - sa
dst = 1 - sa
ALLEGRO_SRC_COLOR
f = s.r, s.g, s.b, s.a
ALLEGRO_DEST_COLOR
f = d.r, d.g, d.b, d.a
ALLEGRO_INVERSE_SRC_COLOR
f = 1 - s.r, 1 - s.g, 1 - s.b, 1 - s.a
ALLEGRO_INVERSE_DEST_COLOR
f = 1 - d.r, 1 - d.g, 1 - d.b, 1 - d.a

Voici quelques exemples d'appel :

Mode par défaut :

 
Sélectionnez
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA)

Action transparence :

 
Sélectionnez
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA)

Addition :

 
Sélectionnez
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE)

Copier la source dans la destination :

 
Sélectionnez
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO)

Multiplier la source et la destination :

 
Sélectionnez
al_set_blender(ALLEGRO_ADD, ALLEGRO_DEST_COLOR, ALLEGRO_ZERO)

V-D-3-a. Expérimentation : al_put_blended_pixel()

Le test est un peu rudimentaire mais il permet de se faire rapidement une idée. Au départ, nous avons une couleur qui va être mélangée à chaque pixel de l'image (une bitmap nommée image.bmp et qui se trouve dans le répertoire du programme). Cette couleur peut être changée en tapant la touche C. Le blender par défaut (éclaircissant) est en [F2], il peut être changé pour un blender assombrissant en [F1]. Taper [Entrée] réinitialise l'image.

Après sélection d'une opération [F1][F2] pour exécuter la transformation, il faut taper la touche [Espace].

Mélange de couleurs (blending)
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>

// remarque signe \ pour aller à la ligne dans une macro :
#define COLORALEA al_map_rgba(rand()%256,rand()%256,\
    rand() % 256, rand() % 256);

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "Erreur", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int is_key_pressed(ALLEGRO_KEYBOARD_STATE*key, int touche,
    int repeat)
{
    //le tableau conserve ses valeurs d'un appel à l'autre (static)
    static int press[ALLEGRO_KEY_MAX] = { 0 };
    int res = 0;

    if (al_key_down(key, touche) && press[touche] < repeat){
        press[touche]++;
        res = 1;
    }
    else if (!al_key_down(key, touche))
        press[touche] = 0;
    return res;
}
/*****************************************************************
*****************************************************************/

int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;
    ALLEGRO_BITMAP*image, *save;
    int tx, ty, scrx, scry;
    ALLEGRO_COLOR color;

    if (!al_init())
        erreur("al_init()");
    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    if (!al_init_image_addon())
        erreur("al_init_primitives_addon()");

    display = al_create_display(800, 600);
    if (!display)
        erreur("al_create_display()");
    scrx = al_get_display_width(display);
    scry = al_get_display_height(display);

    image = al_load_bitmap("image.bmp");
    if (!image)
        erreur("al_load_bitmap()");
    save = al_clone_bitmap(image);

    tx = al_get_bitmap_width(image);
    ty = al_get_bitmap_height(image);

    color = al_map_rgba(128, 8, 32, 2);

    do{
        al_get_keyboard_state(&key);

        // modification de l'image
        if (is_key_pressed(&key, ALLEGRO_KEY_SPACE, 5)){
            al_set_target_bitmap(image);
            if (al_lock_bitmap(image,
                al_get_bitmap_format(image),
                ALLEGRO_LOCK_READWRITE) != NULL){
                int x, y;
                for (y = 0; y<ty; y++){
                    for (x = 0; x<tx; x++)
                        al_put_blended_pixel(x, y, color);
                } 
                al_unlock_bitmap(image);
                al_set_target_backbuffer(display);
            } 
        }
        // changer la couleur à ajouter
        if (is_key_pressed(&key, ALLEGRO_KEY_C, 1))
            color = COLORALEA;

        // SELECTION TYPE MELANGE (BLENDER)
        // assombrissant
        if (is_key_pressed(&key, ALLEGRO_KEY_F1, 1))
            al_set_blender(ALLEGRO_ADD,
            ALLEGRO_ALPHA,
            ALLEGRO_INVERSE_ALPHA);

        // éclaircissant, mode par défaut
        if (is_key_pressed(&key, ALLEGRO_KEY_F2, 1))
            al_set_blender(ALLEGRO_ADD,
            ALLEGRO_ONE,
            ALLEGRO_INVERSE_ALPHA);

        // efface l'écran, recopie l'image de départ
        if (is_key_pressed(&key, ALLEGRO_KEY_ENTER, 1)){
            al_clear_to_color(al_map_rgba(0, 0, 0, 0));
            al_destroy_bitmap(image);
            image = al_clone_bitmap(save);
        }

        // affichage écran à chaque tour
        al_draw_bitmap(image, (scrx - tx) / 2, (scry - ty) / 2, 0);
        al_flip_display();

    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_bitmap(image);
    al_destroy_bitmap(save);
    al_destroy_display(display);
    return 0;
}
/*****************************************************************
*****************************************************************/

C'est une technique qui peut être utilisée pour opérer des transitions d'une image à une autre. Par exemple prendre chaque pixel d'une image source et le mélanger à chaque pixel correspondant dans l'image de destination, les deux images étant de même dimension. On peut aussi agir juste sur une partie d'une image source ou d'une image cible.

V-E. Paramétrage des options

Dans les deux programmes précédents, la couleur est toujours traitée dans un mode 32 bits choisi par Allegro. Allegro est multiplateforme et il y a en effet plusieurs modes 32 bits (ils se différencient par la position des composantes et l'existence ou non du canal alpha de transparence). Après expérimentation sur notre machine, c'est le mode identifié par la constante ALLEGRO_PIXEL_FORMAT_XRGB_8888 , qui correspond au mode par défaut. Mais, le cas échéant, il peut être utile de choisir un autre format de couleur 15, 16 ou 24 bits. Pour ce faire, il faut utiliser la fonction al_set_new_display_option .

La fonction al_set_new_display_option :

 
Sélectionnez
void al_set_new_display_option(int option,int value,int importance)

Cette fonction permet de paramétrer un certain nombre d'options qui concernent l'affichage et le son pour une fenêtre display . Parmi ces options, nous nous intéressons ici uniquement à la possibilité de modifier le format de couleur. Le type d'option à modifier est indiqué en paramètre p1. Chaque option est définie par une constante. La valeur à donner à l'option est donnée en paramètre p2. En paramètre p3 est spécifié le degré de priorité voulu pour la requête. Pour modifier plusieurs options, il faut donc plusieurs appels, un par option. L'option qui nous intéresse pour la couleur est :

 
Sélectionnez
ALLEGRO_COLOR_SIZE

Il y a trois degrés, chacun défini par une macro constante :

ALLEGRO_REQUIRE : en principe la fenêtre display ne sera pas créée si le paramétrage n'est pas possible. Toutefois, dans notre test ci-dessous, le programme prend la valeur par défaut.

ALLEGRO_SUGGEST : si le paramétrage n'est pas possible, la fenêtre display sera créée de toute façon avec une valeur acceptable la plus proche de ce qui est demandé.

ALLEGRO_DONTCARE : avec ce degré, Allegro ne tient pas compte des éventuels paramétrages réalisés préalablement avec les deux degrés précédents. En cas d'échec, il écrase les valeurs obtenues précédemment et prend des valeurs par défaut.

V-E-1. Expérimentation

Le programme ci-dessous permet de voir ce qui se passe si l'on demande un double buffer en 16 bits. Il affiche le choix fait par la machine entre les différentes possibilités de 16 bits.

En modifiant le paramètre deux pour le nombre de bits et trois pour la priorité, on constate qu'il y a peu de différence entre ALLEGRO_REQUIRE et ALLEGRO_SUGGEST , en général si la demande ne passe pas c'est la valeur par défaut ALLEGRO_PIXEL_FORMAT_XRGB_8888 qui est sélectionnée de sorte que AUTRE du case default ne sort jamais.

Paramétrer des options
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>
#include <stdio.h>

void erreur(const char*txt)
{
    ALLEGRO_DISPLAY*d;
    d = al_is_system_installed() ? al_get_current_display() : NULL;
    al_show_native_message_box(d, "ERREUR", txt, NULL, NULL, 0);
    exit(EXIT_FAILURE);
}
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;
    ALLEGRO_BITMAP*db;

    int screenx = 800;
    int screeny = 600;

    if (!al_init())
        erreur("al_init()");

    if (!al_install_keyboard())
        erreur("al_install_keyboard()");
    
    // peu de différence ici entre ALLEGRO_REQUIRE et ALLEGRO_SUGGEST
    al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, ALLEGRO_SUGGEST);
    display = al_create_display(screenx, screeny);
    if (!display)
        erreur("al_create_display()");

    db = al_get_backbuffer(display);
    int format = al_get_bitmap_format(db);
    switch (format){
        
        case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA:
            printf("ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA:
            printf("ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_ARGB_4444:
            printf("ALLEGRO_PIXEL_FORMAT_ARGB_4444\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_RGB_565:
            printf("ALLEGRO_PIXEL_FORMAT_RGB_565\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_RGBA_5551:
            printf("ALLEGRO_PIXEL_FORMAT_RGBA_5551\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_ARGB_1555:
            printf("ALLEGRO_PIXEL_FORMAT_ARGB_1555\n");
            break;
        case ALLEGRO_PIXEL_FORMAT_BGR_565:
            printf("ALLEGRO_PIXEL_FORMAT_BGR_565\n");
            break;
            //Mode par défaut sur notre machine 
        case ALLEGRO_PIXEL_FORMAT_XRGB_8888 : 
            printf("ALLEGRO_PIXEL_FORMAT_XRGB_8888\n");
            break;

        default:
            printf("AUTRE\n");
            break;
    }
    printf("valeur : %d\n", format);

    do{ 
        al_get_keyboard_state(&key);
    
    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    return 0;
}

Obtenir ce livre

Image non disponible

Ce document est une retranscription autorisée du livre Allegro 5 - Programmation de jeux en C et C++ écrit par Frédéric DROUILLON. Initialement publié aux éditions ENI, vous pouvez commander le livre sur le site de l'éditeur.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Frédéric DROUILLON. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.