Résumé des fonctions, structures, constantes et variables Allegro utilisées par les programmes vus en cours


Systématiques pour les programmes allegro

#include <allegro.h>
Inclusion du fichier en-tête de la librairie qui contient les diverses déclarations.
En fait contient des listes de #include sur d'autres fichiers .h d'allegro
Les curieux peuvent consulter le dossier include dans le dossier CodeBlocks/MinGW

int allegro_init();
Lance les services de la librairie mais n'ouvre pas de mode graphique.
Impératif au début du main (juste après les déclarations des variables)

END_OF_MAIN();
Truc technique qui permet de compiler le même source sur windows/linux/OSX
Doit impérativement être présent juste après l'accolade fermante du main

Initialisation graphique

int desktop_color_depth();
void set_color_depth(int depth);
desktop_color_depth retourne la "profondeur couleur" effective de l'affichage système
"profondeur couleur" = nombre de bits utilisés pour stocker un pixel  (8 / 15 / 16 / 24 / 32)
Sur les systèmes récents le résultat est souvent de 32 bits (4 octets pour chaque pixel)
Pour garantir un fonctionnement optimal sur la machine, on indiquera à allegro cette profondeur :
    set_color_depth(desktop_color_depth());
juste avant l'ouverture du mode graphique

int set_gfx_mode(int card, int w, int h, int v_w, int v_h);
GFX_AUTODETECT_WINDOWED
GFX_AUTODETECT_FULLSCREEN
Ouvre un affichage en mode graphique en précisant le type card
    - soit sur une fenêtre en utilisant GFX_AUTODETECT_WINDOWED
    - soit en plein écran en utilisant GFX_AUTODETECT_FULLSCREEN
w et h indiquent la largeur et la hauteur souhaitées (640x480 800x600 1024x768 ...)
Nous n'utiliserons pas v_w et v_h : mettre à 0 pour ignorer
Retourne une valeur non nulle en cas de problème (à tester...)

Divers, messages, problèmes

void allegro_message(const char *text_format, ...);
Affiche une popup avec un message.
Peut s'utiliser avec des %d %f %c %s ... comme un printf :
    allegro_message("valeur de variables x et y : %d %d",x,y);

void allegro_exit();
Sortie forcée d'allegro en cas de problème.
N'a pas à être appelé à la fin du main (Allegro termine automatiquement)

Affichage ecran

screen  :  extern BITMAP *screen;
C'est l'identifiant de l'écran réel :
A utiliser à chaque fois qu'on veut dessiner ou écrire sur la sortie graphique
Convient pour toutes les fonctions prenant un BITMAP * en paramètre :
directement utiliser screen comme 1er paramètre des fonctions de dessin

SCREEN_W
SCREEN_H
Largeur (Width) et Hauteur (Height) de la sortie graphique.
Permet de retrouver les valeurs w et h utilisées lors du set_gfx_mode
Ne peuvent être modifiés pour changer la taille de la sortie graphique
(pour changer la taille il faut relancer le mode graphique)

void clear_bitmap(BITMAP *bitmap);
Efface (en noir) l'image en paramètre.
Exemple pour effacer l'écran :
    clear_bitmap(screen);

void clear_to_color(BITMAP *bitmap, int color);
Efface avec une couleur l'image en paramètre.
Exemple pour effacer l'écran avec un fond blanc :
    clear_to_color(screen,makecol(255,255,255));

Couleurs

Une couleur est déterminée par trois composantes rouge/vert/bleu
"Couleur" ne veut pas forcément dire coloré :
            0/0/0 -> Noir    128/128/128 -> Gris    255/255/255 -> Blanc
Dans allegro une couleur est stockée dans un int.
C'est le type attendu au niveau d'un paramètre de dessin color
Pour passer de rouge/vert/bleu vers une couleur utiliser makecol
Pour passer d'une couleur vers rouge/vert/bleu utiliser getr, getg, getb
Pour poser un pixel de couleur (sur screen ou sur une BITMAP) utiliser putpixel
Pour lire la couleur d'un pixel (sur screen ou sur une BITMAP) utiliser getpixel
Couleur spéciale pour transparence : voir Sprites et bitmaps avec transparences

int makecol(int r, int g, int b);
Pour fabriquer l'entier représentant une couleur à partir de Red/Green/Blue
Chaque composante est donnée entre 0 (minimum) et 255 (maximum)
Exemple pour fabriquer du rose on met rouge à 100% et vert et bleu à 50%
    int couleur;
    ...
    couleur=makecol(255,127,127);
    rectfill(screen,0,0,800,100,couleur);
Ou directement (sans passer par une variable)
    rectfill(screen,0,0,800,100,makecol(255,127,127));

int getr(int c);
int getg(int c);
int getb(int c);
Permet d'accéder aux 3 composantes rouge vert et bleu d'une couleur.
Chaque composante est entre 0 (minimum) et 255 (maximum)
Exemple pour récupérer les composantes couleur du pixel en x y sur l'écran :
    int couleur,rouge,vert,bleu;
    ...
    c = getpixel(screen,x,y);
    rouge=getr(c);  vert=getg(c);  bleu=getb(c);
 
void putpixel(BITMAP *bmp, int x, int y, int color);
int getpixel(BITMAP *bmp, int x, int y);
Poser ou lire un seul pixel d'une BITMAP ou de l'écran
voir ci-dessous dans "Affichage graphique"

Affichage graphique : dessiner

Drawing primitives

Fonctions de dessin géométrique et de changements de couleurs des images
Lien ci-dessus pour accéder à la liste de toutes les primitives de dessin
En général le premier paramètre attend un BITMAP *
Pour dessiner à l'écran directement on met  screen  à ce niveau
Rappel : l'origine (0,0) est en haut à gauche de la fenêtre graphique
L'axe des x est orienté de gauche à droite
L'axe des y est orienté de haut en bas

void putpixel(BITMAP *bmp, int x, int y, int color);
Poser un seul pixel de couleur sur une BITMAP ou sur l'écran (screen) en x y
La couleur précédente du pixel est écrasée.
Avec la fonction putpixel on peut en principe dessiner toutes les formes possibles
(puisque toute forme est composée d'ensembles de pixels de couleurs particulières)
Exemple pour dessiner une fonction mathématique ( ici une sinusoïde  ->  #include <math.h> )
    for (x=0;x<800;x++)
        putpixel( screen, x,  300-100.0*sin(0.01*x) , makecol(255,255,255) );
Si on veut remplir toute une zone rectangulaire on fera une double boucle imbriquée
Exemple pour faire un dégradé à l'écran avec rouge croissant horizontalement et vert verticalement
    for (y=0;y<256;y++)
        for (x=0;x<256;x++)
            putpixel(screen,x,y,makecol(x,y,128));
   
int getpixel(BITMAP *bmp, int x, int y);
Lire la couleur du pixel de la BITMAP ou de l'écran (screen) en x y
La valeur récupérée est un int, équivalent à une couleur obtenue avec un makecol
Exemple pour tester si le pixel à l'écran en x y est du rouge pur :
    if ( getpixel(screen,x,y) = = makecol(255,0,0) )
      ...
Souvent pour pouvoir traiter la couleur de manière spécifique il faudra décomposer en rgb
Voir getr/getg/getb rubrique Couleurs ci dessus

void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
Trace un segment de droite de (x1,y1) à (x2,y2)

void rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
void rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
Rectangle contour et Rectangle plein
(x1,y1) : coordonnées du coin supérieur gauche
(x2,y2) : coordonnées du coin inférieur droit

void circle(BITMAP *bmp, int x, int y, int radius, int color);
void circlefill(BITMAP *bmp, int x, int y, int radius, int color);
Cercle et Cercle plein (disque)
(x,y) : coordonnées du centre
radius : rayon

void ellipse(BITMAP *bmp, int x, int y, int rx, int ry, int color);
void ellipsefill(BITMAP *bmp, int x, int y, int rx, int ry, int color);
Ellipse et Ellipse pleine (disque vu de coté)
Les axes de l'ellipse sont nécessairement orientés sur le repère
( ne permet pas de dessiner une ellipse oblique à l'écran )
(x,y) : coordonnées du centre
rx et ry : rayon horizontal et rayon vertical

Images mémoires  - BITMAP -  et copies de zones  - blit -

Bitmap objects

Une BITMAP est une structure qui contient les données d'une image
A part "screen" qui est une BITMAP particulière (écran réel, visible)
les BITMAPs correspondent à des images en mémoire (invisibles)
Pour rendre visible l'image d'une BITMAP on utilisera la fonction blit
de la BITMAP contenant l'image vers la BITMAP screen :   blit(image,screen,...);
Le buffer "page" (pour un affichage double buffer) est une BITMAP créée
à la taille de l'écran et qui sert à construire la prochaine image d'une animation,
une fois cette image construite sur le buffer "page" on le blit à l'écran (screen)

typedef struct BITMAP ...
La structure qui contient les images allegro (chargées depuis fichiers ou dessinées par programme)
Les BITMAPs seront toujours déclarées et utilisées comme pointeurs :
    // Declaration d'une BITMAP "bmp"
    BITMAP *bmp;
    // Attention sur les déclarations multiples de mettre l'étoile à chaque fois
    BITMAP *image1, *image2;

Comme on déclare un "pointeur sur quelque chose" on est dans le cadre de l'allocation dynamique.
Pour allouer une BITMAP on ne fera pas un malloc mais on utilisera des fonctions allegro :
- create_bitmap (pour une image vierge, à dessiner) 
- load_bitmap (pour une image venant d'un fichier .bmp)

Pour accéder à la largeur et à la hauteur d'une BITMAP (après création ou chargement)
    bmp->w   // largeur (width)           bmp->h   // hauteur (height)

BITMAP *create_bitmap(int width, int height);
Allouer et initialiser une BITMAP "vide" de taille width(largeur) x height(hauteur) pour dessiner dessus.
En fait la mémoire de l'image est réservée mais pas nettoyée : pour avoir une image vierge il faut effacer.
On peut réutiliser plusieurs fois la même BITMAP : effacer/redessiner effacer/redessiner ...
Dans ce cas on ne refait pas create_bitmap à chaque  fois !
Par contre si on a terminé d'utiliser une BITMAP et qu'on est sûr de ne plus jamais l'utiliser
alors il faut la libérer (destroy_bitmap). Ceci est facultatif si le programme se termine juste après.
Exemple : déclarer, créer, effacer une BITMAP, dessiner des diagonales dessus et afficher à l'écran
    BITMAP *bmp;
    ... (initialisation du mode graphique allegro...)
    bmp=create_bitmap(200,100);
    clear_bitmap(bmp);
    ...
    line(bmp,0,0,199,99,makecol(255,255,255));
    line(bmp,0,99,199,0,makecol(255,255,255));
    blit(bmp,screen,0,0,SCREEN_W/2-100,SCREEN_H/2-50,200,100);

BITMAP *load_bitmap(const char *filename, RGB *pal);
Charge l'image d'un fichier .bmp (ou .tga ou .pcx) dans une BITMAP créée sur mesure.
Retourne le pointeur sur la BITMAP en cas de succès, NULL en cas d'échec (à tester)
Nous n'utilisons pas les palettes : on indiquera NULL dans le paramètre pal.
Le fichier doit se trouver à la racine du projet (avec main.c ...)
pendant le développement avec codeblocks.
Plus tard (version "release") il faudra mettre les images au niveau du .exe
On peut créer un sous répertoire pour regrouper toutes les images,
dans ce cas le nom de fichier ressemblera à  "mes_images/mickey.bmp" ...
Une BITMAP créée avec load_bitmap a un contenu initial qui correspond à l'image du fichier,
mais elle se comporte comme une BITMAP usuelle : on peut l'effacer, dessiner dessus...
(dans ce cas bien sûr le contenu graphique initial est altéré ou perdu)
Comme pour create_bitmap, quand on a terminé de l'utiliser il faut la libérer (destroy_bitmap)
Il faut éviter de recharger sans arrêt le même fichier image (load_bitmap dans la boucle de jeu)
Si on veut afficher plusieurs fois, on charge le fichier image une fois pour toute dans une BITMAP
(avant d'entrer dans la boucle de jeu, phase de chargement du jeu) puis on blit cette BITMAP
chaque fois que c'est nécessaire.
Exemple pour charger "mon_image.bmp" et afficher au milieu de l'écran (voir prog3_0 cours2) :
    BITMAP *image;
    ... (initialisation du mode graphique allegro...)
    image=load_bitmap("mon_image.bmp",NULL);
    if (!image)
        ... (problème)
    ...
    blit(image,screen,0,0, (SCREEN_W-image->w)/2, (SCREEN_H-image->h)/2, image->w, image->h);

int save_bitmap(const char *filename, BITMAP *bmp, const RGB *pal);
Sauve l'image d'une BITMAP dans un fichier .bmp (ou .tga ou .pcx)
Retourne un entier différent de 0 en cas d'échec (à tester si nécessaire)
Nous n'utilisons pas les palettes : on indiquera NULL dans le paramètre pal.
L'image se retrouve à la racine du projet (codeblocks) ou à coté du .exe (release)
Exemple pour sauver "ma_bitmap.bmp" (voir prog2_0 cours2) :
    BITMAP *img;
    ... (initialisation du mode graphique allegro...)
    img=create_bitmap(400,200);
    ... effacer, dessiner dans img
    save_bitmap("ma_bitmap.bmp",img,NULL);

void blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);

Copie une zone rectangulaire de la BITMAP source vers la BITMAP destination.
La source est inchangée, la zone destination est écrasée, tout contenu préalable est perdu.
Source et/ou dest sont des pointeurs sur BITMAP ( images créées ou chargées, ou screen )



Il est fréquent de vouloir afficher la totalité d'une BITMAP image en x y sur une BITMAP plus grande :
    blit(image, grande, 0, 0, x, y, image->w, image->h);



Dans ce cas la BITMAP "grande" peut être l'écran (screen) ou le buffer (page)
Noter que les coordonnées se réfèrent toujours au coin supérieur gauche des rectangles concernés.

Enfin dans la technique du double buffer, pour afficher le buffer "page" à l'écran :
    BITMAP *page;
    ...
    page=create_bitmap(SCREEN_W, SCREEN_H);
    ...
        ... dans la boucle de jeu : effacer, dessiner sur le buffer puis actualiser l'écran réel :
        blit(page, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);

void stretch_blit(BITMAP *source, BITMAP *dest, int source_x, source_y, source_width, source_height, int dest_x, dest_y, dest_width, dest_height);
Copie une zone rectangulaire de la BITMAP source vers la BITMAP destination en étirant
ou en comprimant l'image dans le rectangle source de telle sorte qu'il rentre dans la taille de destination.
Cette fonction peut permettre d'utiliser par exemple une image de fond qui n'a pas la bonne taille
pour remplir l'écran, mais attention si le rapport largeur/hauteur est différent l'aspect sera anamorphosé
D'autre part cette fonction est plus lente qu'un simple blit et le résultat est de moins bonne qualité
que si on utilise une image à la bonne taille (préalablement recadrée ou ré-échantillonnée avec paint...)
Exemple pour afficher un fond de taille arbitraire en plein écran (sur le buffer) :
    stretch_blit(decor, page, 0, 0, decor->w, decor->h, 0, 0, SCREEN_W, SCREEN_H);


Sprites et bitmaps avec transparences, fonctions draw_sprite et masked_blit

Blitting and sprites

Lors de l'affichage avec une fonction de type draw_sprite (toutes les fonctions avec sprite dans leur nom)
ou avec masked_blit, les pixels qui ont exactement la couleur spéciale magenta ne sont pas dessinés.
A ces emplacements sur la bitmap destination (le plus souvent il s'agit du buffer) les pixels ne sont pas modifiés.
L'effet obtenu est donc une "transparence" : les zones marquées avec la couleur spéciale restent invisibles,
le fond ou tout ce qui a été affiché avant sur la page (dans la chronologie de la boucle de jeu)  n'est pas écrasé.
On appellera généralement "sprite" ces images d'éléments graphiques posés sur un fond magenta.
La transparence n'est pas obligatoirement autour du graphisme, on peut aussi faire des "fenêtres".

             
            image sur fond blanc (ou autre)                    image sur fond transparent


                                résultats après avoir fait un draw_sprite sur un fond déjà en place

Techniquement la couleur reconnue comme transparente est   rouge 255   vert 0   bleu 255.
Avec votre logiciel d'édition d'image il faut bien s'assurer d'obtenir exactement cette couleur.
Le problème se pose rarement mais si vous souhaitez avoir un sprite avec du magenta qui ne soit pas
invisible il suffit d'utiliser un couleur proche mais non identique : rouge 254   vert 0   bleu 254.
Vous pouvez aussi dessiner avec la couleur transparente à l'intérieur du programme directement sur une bitmap,
ce qui permet par exemple de faire des "trous" sur un sprite : utilisez une primitive graphique et makecol(255,0,255)

Voir la documentation Blitting and sprites pour une liste complète des options d'affichage des sprites (échelles, rotations...)

void draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y);
Dessine la totalité de l'image sprite sur la bitmap bmp,
en évitant de dessiner là où les pixels du sprites sont transparents.
Attention par rapport à un blit, ici la destination est indiquée avant la source.
Les coordonnées x y seront celles du coin supérieur gauche du rectangle de l'image source
dans le repère de la bitmap destination.

Ceci est équivalent à l'appel  masked_blit(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h);
On utilisera plutôt draw_sprite quand on dessine de petits éléments mobiles (acteurs)
et plutôt masked_blit quand on dessine de grandes images avec transparences (avant-plans)
ou quand on souhaite avoir un contrôle fin de la géométrie (plus de paramètre)

void draw_sprite_h_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
void draw_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
void draw_sprite_vh_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
Dessine des versions symétriques horizontalement/verticalement du sprite de départ.

void masked_blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
Très proche de draw_sprite mais disposant de plus de paramètres de réglages
et plutôt utilisé pour des grandes images (avant-plans)
Les paramètres et l'utilisation sont les mêmes que pour blit la seule différence étant
que les pixels de couleur transparente ne sont pas affichés : la transparence est prise en compte.

Affichage texte

Text output
Fonctions d'écriture de texte sur des images (par exemple l'écran screen)
Lien ci-dessus pour accéder à la liste de toutes les primitives de texte

font  :  extern FONT *font;
Police de caractère par défaut d'allegro
Pas très jolie mais nécessaire pour afficher simplement des textes

void textprintf_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...);
Equivalent au printf mais affiche le texte où on veut quand on veut sur une image
bmp : image destination (par exemple  screen  )
f : utiliser   font  à ce niveau
(x,y) : coordonnées du coin supérieur gauche du bloc de texte
color : couleur du texte (makecol...)
bg : couleur du fond (makecol ...) ou -1 pour un fond transparent
fmt,... : une chaine formatée comme pour un printf
Exemple pour afficher un score (int score;) en (100,10) rouge fond transparent à l'écran
    textprint_ex(screen, font, 100, 10, makecol(255,0,0), -1, "SCORE=%d", score);
Ne connait pas \n : pour un retour ligne faire un autre affichage avec y croissant

Gestion clavier


int install_keyboard();
A appeler une fois après init_allegro pour signaler que le programme utilise le clavier

key  :  extern volatile char key[KEY_MAX];
Tableau de booléens (Vrai/Faux) indiquant si "là tout de suite maintenant" une touche est enfoncée
Voir le lien ci-dessus pour une liste des noms correspondant aux différentes touches
Exemple pour tester si la touche espace est enfoncée (alors effacer écran)
    if (key[KEY_SPACE])
       clear_bitmap(screen);
Exemple pour faire une boucle qui tourne tant que Echap n'est PAS appuyé
    while (!key[KEY_ESC])
    {
       ...
       ...
    }

int keypressed();
Version allegro équivalente de kbhit()
Booléen : est-ce qu'une touche a été appuyée ?
Si oui retourne Vrai
Si non retourne Faux (n'attend pas qu'un caractère soit entré)

int readkey();
Version allegro équivalente de getch()
Retourne un code correspondant a une touche effectivement appuyée
Si aucune touche n'a été appuyée alors attend qu'une touche le soit :
ceci peut être pratique pour faire un test en pausant l'exécution.
Caster le code retourné en char pour avoir le caractère ascii correspondant à la touche
Faire un décalage binaire à droite de 8 bits pour obtenir le scancode (KEY_SPACE KEY_ESC ...)
Voir exemples 6_0 et 6_1 du cours 1 pour un exemple d'usage en situation

void set_keyboard_rate(int delay, int repeat);
Modifie les caractéristiques de l'auto-répétition du clavier.
Ne concerne PAS l'approche "instantanée" par scancodes (key[KEY_SPACE] ...)
Ne concerne que l'approche buffer : keypressed et readkey
delay : au bout de combien de ms une touche reste appuyée pour lancer la répétition
repeat : temps en ms entre deux répétitions une fois que la répétition est lancée
Passer 0,0 pour désactiver toute répétition automatique

Gestion souris

int install_mouse();
A appeler une fois après init_allegro pour signaler que le programme utilise la souris

void show_mouse(BITMAP *bmp);
S'utilise le plus souvent directement sur l'écran : show_mouse(screen);
A appeler une fois APRES l'ouverture du mode graphique pour montrer le curseur de souris
Si la souris n'a pas été installée (pas d'appel à install_mouse) alors la souris du bureau
est quand même visible sur l'écran graphique mais n'est pas utilisable dans le programme
Si la souris à été installée mais qu'il n'y a pas d'appel à show_mouse alors la souris
est utilisable dans le programme (mouse_b/mouse_x/mouse_y) mais le pointeur reste invisible.
Utiliser une souris visible en mode plein écran ( GFX_AUTODETECT_FULLSCREEN )
nécessite des précautions supplémentaires (lire attentivement la doc technique)

mouse_b  :  extern volatile int mouse_b;
Contient l'état instantané des boutons de la souris.
mouse_b&1 : Booléen vrai si le bouton gauche est enfoncé, faux sinon
mouse_b&2 : Booléen vrai si le bouton droit est enfoncé, faux sinon
Attention si votre test est dans une boucle de gestion d'événements
il y a toutes les chances pour qu'il soit validé plusieurs fois de suite
alors que l'utilisateur n'a cliqué qu'une seule fois
(car le bouton est resté enfoncé pendant plusieurs tours de boucle)
Ceci n'est pas forcément souhaitable... (mérite réflexion)

mouse_x  :  extern volatile int mouse_x;
mouse_y  :  extern volatile int mouse_y;
Coordonnées instantanées de la souris (bout du pointeur)
Accessible même si la souris est invisible (pas de show_mouse)
à condition d'avoir fait install_mouse