Allegro 5

Programmation de jeux en C ou C++


précédentsommairesuivant

IV. Texte, police, couleur, dessin

IV-A. Introduction

Ce chapitre expose comment sélectionner une police TTF et afficher du texte. Il explore les fonctions de gestion de la couleur ainsi que l'ensemble des primitives de dessin fourni avec Allegro 5. Les possibilités de dessin y sont particulièrement développées et intéressantes.

IV-B. Texte et polices

Le module de traitement allegro_font regroupe tout ce qui concerne le texte, à savoir la gestion des polices et les fonctions d'affichage. Pour les polices, il y a deux catégories : les polices obtenues à partir d'images bitmap et les polices TTF (True Type Font) en général utilisées dans tous les traitements de texte. C'est l'utilisation de polices TTF que nous allons voir maintenant.

IV-B-1. Sélectionner une police

Pour avoir une police TTF ou une police bitmap, inclure le module font :

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

Pour avoir une police TTF, inclure en plus le module ttf.

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

Ensuite dans le main() l'initialisation du module font ne nécessite pas de vérification du code de retour :

 
Sélectionnez
al_init_font_addon(); // la fonction ne retourne rien

En revanche la fonction d'initialisation de la partie ttf est contrôlable. Elle retourne vrai ou faux selon que l'opération a réussi ou non :

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

Dans un programme Allegro, une police sera toujours manipulée via un pointeur de type ALLEGRO_FONT* , il faut

en déclarer un par police utilisée :

 
Sélectionnez
ALLEGRO_FONT* arial72 ;

La récupération de la police se fait avec un appel à la fonction :

 
Sélectionnez
ALLEGRO_FONT *al_load_font(char const *filename, int size, int flags)

ou à la fonction :

 
Sélectionnez
ALLEGRO_FONT *al_load_ttf_font(char const *filename, int size, int flags)

Dans les deux cas, filename correspond au nom du fichier de la police avec son extension .ttf, size donne la taille de la police et flag permet de sélectionner des options particulières.

Pour changer la taille de la police, il faut recharger la police pour chaque taille en spécifiant à chaque fois la taille voulue. Pour avoir plusieurs polices et/ou de tailles différentes simultanément, le mieux est de préparer un pointeur par taille. Dans notre exemple nous avons nommé notre pointeur arial72 , afin de faciliter la lecture du code en rappelant police et taille choisies :

 
Sélectionnez
arial72 = al_load_font("arial.ttf",72,0);
if(!arial72)
    erreur("al_load_font()");

Il est vivement conseillé de faire un contrôle d'erreur. Autant éviter un dysfonctionnement du programme uniquement parce que le fichier TTF n'est pas à la bonne place dans le dossier de l'exécutable par exemple.

IV-B-1-a. Expérimentation

Ce qui suit correspond à la première partie de notre programme d'expérimentation et s'arrête juste avant la boucle d'événements :

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

#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>

#define NOIR al_map_rgb(0,0,0)
#define BLANC al_map_rgb(255,255,255)

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_FONT*arial72; // pour la police dans le programme
    int tmps = 0; // pour le temps qui passe

    int screenx = 800;
    int screeny = 600;
    bool fin = 0;

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

    display = al_create_display(screenx, screeny);
    if (!display)
        erreur("al_create_display()");

    // UTILISATION DE POLICES / TEXTE

    // initialisation du module polices (sans retour d'erreur)
    al_init_font_addon();

    // initialisation du module de polices ttf
    if (!al_init_ttf_addon())
        erreur("al_init_ttf_addon()");

    // récupération de la police voulue
    arial72 = al_load_font("arial.ttf", 72, 0);
    if (!arial72)
        erreur("al_load_font()");

    // (...)

Dans la boucle du programme, nous affichons le texte.

IV-B-2. Afficher du texte

Allegro dans le module police (Font addons) fournit les fonctions suivantes pour l'affichage du texte :

La fonction al_draw_text :

 
Sélectionnez
void al_draw_text(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, char const *text)

Écrit la chaîne text dans la bitmap courante à la position x , y , selon la police font et de la couleur color . Le paramètre flag peut prendre les valeurs :

ALLEGRO_ALIGN_LEFT : valeur 0, l'alignement est à gauche à partir de la position x, y donnée.

ALLEGRO_ALIGN_CENTRE : centrage du texte autour de la position x, y donnée.

ALLEGRO_ALIGN_RIGHT : alignement à droite sur la position x, y donnée.

La fonction al_draw_justified_text :

 
Sélectionnez
void al_draw_justified_text(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, const char *text)

Même fonction que al_draw_text mais écrit la chaîne text dans la zone délimitée par x1 , x2 . Le paramètre diff donne le maximum d'espace autorisé entre deux mots. Si la justification de la chaîne nécessite de dépasser la valeur diff ou si la chaîne contient moins de deux mots, alors la chaîne est alignée à gauche.

Le paramètre flag peut prendre la valeur 0 ou ALLEGRO_ALIGN_INTEGER qui signifie un alignement des positions de mot en valeurs entières de pixels (en effet sous Allegro 5 les positions en pixels des fonctions de dessin et d'affichage sont en valeur flottantes (float).

La fonction al_draw_textf :

 
Sélectionnez
void al_draw_textf(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, const char *format, ...)

Version avec texte formaté de al_draw_text() . La chaîne texte est une chaîne formatée comme sous printf() .

La fonction al_draw_justified_textf :

 
Sélectionnez
void al_draw_justified_textf(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, const char *format, ...)

Version avec texte formaté de al_draw_justified_text() . La chaîne texte est une chaîne formatée comme sous printf() .

IV-B-2-a. Expérimentation

Reprenons notre exemple de code. À chaque tour de boucle, une variable est incrémentée de 1 et sa valeur est affichée avec la fonction al_draw_textf() . Notons l'utilisation de la fonction al_rest() :

 
Sélectionnez
void al_rest(double seconds)

Cette fonction bloque le déroulement du programme pendant le temps indiqué en secondes au paramètre seconds .

Dans notre exemple, l'appel :

 
Sélectionnez
al_rest(0.5);

provoque un affichage de la variable tmps toutes les demi-secondes :

Afficher du texte avec une police TTF
Sélectionnez
    // (...)

    while (!fin){
        
        al_get_keyboard_state(&key);
        if (al_key_down(&key, ALLEGRO_KEY_ESCAPE))
            fin = 1;

        // efface la fenêtre
        al_clear_to_color(NOIR);

        // tester les accents
        al_draw_textf(arial72, BLANC, 10, 10,
            ALLEGRO_ALIGN_LEFT, "accents : àâäéèêëôöù");

        // affiche les 1/10 de seconde
        tmps++;
        al_draw_textf(arial72, BLANC, screenx / 2, screeny / 2,
            ALLEGRO_ALIGN_CENTRE, "temps : %i", tmps);
        al_flip_display();

        al_rest(0.5);
    }

    al_destroy_display(display);
    al_destroy_font(arial72);
    return 0;
}

En principe l'affichage des accents ne pose pas de problème mais il arrive sous Visual Studio qu'un paramétrage pour l'encodage du fichier source en UTF-8 soit nécessaire. Pour ce faire :

Assurez­vous que c'est bien la page de code qui est sélectionnée dans Visual Studio et non l'explorateur de solutions (la sélection courante peut influer sur le contenu de certains menus). Ensuite dans le menu Fichier sélectionnez Options d'enregistrement avancées (cet item n'apparaît pas si l'explorateur de solutions est sélectionné).

La fenêtre suivante s'ouvre :

Image non disponible

Par défaut à l'ouverture, la première liste indique :

Alphabet occidental (Windows) - Page de codes 1252

Sélectionnez la valeur :

Unicode (UTF-8 sans signature) - Page de codes 65001

Puis cliquez sur OK et recompilez le programme.

IV-B-3. Obtenir les dimensions d'une police

Des fonctions en rapport avec la taille du texte peuvent être bien utiles. Le module police d'Allegro (allegro_font) en fournit quelques-unes. La taille d'une police bitmap (une bitmap est une image) c'est la taille des bitmaps nécessaires pour la police. Mais dans le cas d'une police TTF, les différentes dimensions se répartissent de la façon suivante :

Image non disponible

La hauteur totale est partagée entre une partie haute ascent et une partie basse descent la taille de la lettre seule se trouvant dans la partie haute, la partie basse assurant une distance minimum entre chaque ligne. La hauteur totale, ascent plus descent , est donnée avec height . Les trois fonctions suivantes permettent de retrouver ces longueurs :

La fonction al_get_font_line_height :

 
Sélectionnez
int al_get_font_line_height(const ALLEGRO_FONT *f)

Donne la hauteur totale height d'une police en pixels.

La fonction al_get_font_ascent :

 
Sélectionnez
int al_get_font_ascent(const ALLEGRO_FONT *f)

Retourne la hauteur ascent des lettres dans une police de type TTF.

La fonction al_get_font_descent :

 
Sélectionnez
int al_get_font_descent(const ALLEGRO_FONT *f)

Retourne l'intervalle minimum descent prévu entre deux lignes dans une police de type TTF.

La fonction al_get_text_width :

 
Sélectionnez
int al_get_text_width(const ALLEGRO_FONT *f, const char *str)

Retourne la longueur en pixels de la chaîne str selon la police passée en f.

La fonction al_get_text_dimensions :

 
Sélectionnez
void al_get_text_dimensions(const ALLEGRO_FONT *f, char const *text, int *x, int *y, int *w, int *h)

Permet de récupérer l'encadrement en pixels de la chaîne text compte tenu de la police f avec : x , y un éventuel décalage pour le coin haut gauche et w , h la longueur et la hauteur (quatre passages par référence).

La fonction al_load_ttf_font_stretch :

 
Sélectionnez
ALLEGRO_FONT *al_load_ttf_font_stretch(char const *filename, int w, int h, int flags)

Cette fonction est similaire à la fonction al_load_ttf_font() mais elle contraint la taille de la police en largeur avec w et en hauteur avec h , ce qui permet de faire des effets, comme l'aplatissement, la dilatation, etc.

Avec des valeurs positives, la dimension est donnée dans la mesure standard des polices (la norme « units per EM »). Avec des valeurs négatives, la mesure est donnée en pixels. C'est pourquoi hauteur h et largeur w doivent impérativement être de même signe, les deux en positifs ou les deux en négatifs. Le résultat est indéfini sinon.

IV-C. Couleurs, transparence

Le module graphique Allegro met à disposition huit fonctions pour la création de couleurs :

La fonction al_map_rgb :

 
Sélectionnez
ALLEGRO_COLOR al_map_rgb( unsigned char r, unsigned char g, unsigned char b)

Cette fonction retourne une couleur selon les valeurs de rouge r, vert g et bleu b passées en paramètre. Ces valeurs sont dans la fourchette 0-255 compris.

La fonction al_map_rgb_f :

 
Sélectionnez
ALLEGRO_COLOR al_map_rgb_f(float r, float g, float b)

Même fonction que al_map_rgb() mais les valeurs sont établies en float dans la fourchette de 0.0 à 1.0.

La fonction al_map_rgba :

 
Sélectionnez
ALLEGRO_COLOR al_map_rgba(unsigned char r, unsigned char g, unsigned char b, unsigned char a)

Fonction comme al_map_rgb() mais qui ajoute le canal alpha de la transparence. La transparence est réglée de la même façon avec une valeur dans la fourchette 0-255 (0 pas de transparence).

La fonction al_map_rgba_f :

 
Sélectionnez
ALLEGRO_COLOR al_map_rgba_f(float r, float g, float b, float a)

Identique à al_map_rgba() mais les valeurs sont passées en float entre 0.0 et 1.0.

La fonction al_unmap_rgb :

 
Sélectionnez
void al_unmap_rgb(ALLEGRO_COLOR color, unsigned char *r, unsigned char *g, unsigned char *b)

Fonction qui permet de récupérer les valeurs des composantes de rouge, vert et bleu de la couleur color . Les paramètres de sortie sont des variables passées par référence.

La fonction al_unmap_rgb_f :

 
Sélectionnez
void al_unmap_rgb_f(ALLEGRO_COLOR color, float *r, float *g, float *b)

Même fonction que al_unmap_rgb() mais les valeurs sont des valeurs flottantes comprises entre 0.0 et 1.0.

La fonction al_unmap_rgba :

 
Sélectionnez
void al_unmap_rgba(ALLEGRO_COLOR color,unsigned char *r, unsigned char *g, unsigned char *b, unsigned char*a)

Fonction qui récupère les composantes de rouge, vert, bleu et de transparence de la couleur color . Les paramètres de sortie sont des variables passées par référence.

La fonction al_unmap_rgba_f :

 
Sélectionnez
void al_unmap_rgba_f(ALLEGRO_COLOR color, float *r, float *g, float *b, float *a)

Même fonction mais les résultats sont fournis en valeurs flottantes comprises entre 0.0 et 1.0.

Par ailleurs Allegro 5 fournit un greffon color addon qui ajoute une vingtaine de fonctions pour la couleur. Ces fonctions permettent d'aborder la couleur autrement qu'en RGB. Ces fonctions nécessitent l'inclusion de l'en-tête :

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

Nous trouvons notamment :

  • La couleur selon un mélange CMYK (cyan, magenta, yellow, black).
  • La couleur selon le principe HSV (hue, saturation, lightness pour teinte, saturation, luminosité).
  • La couleur en hexadécimal sur le modèle du HTML, par exemple #00AFC4 ou #FF0000 / rouge.
  • Les couleurs par leur nom (ce sont les couleurs de la norme W3C pour le CSS).
  • La couleur selon le principe YUV. C'est un modèle qui définit un espace colorimétrique composé de Y pour la luminance et de U et V pour la chrominance. Ce modèle a à voir avec la diffusion télévisuelle.
  • Pour chaque domaine, des possibilités de conversion vers le mode RGB ou à partir du mode RGB.

IV-D. Primitives de dessin

Il s'agit du module Primitives addon qui concerne toutes les opérations de dessin. Nous trouvons les tracés de points, de rectangles, de cercles, de triangles, de polygones, d'arcs, d'ellipses, de rubans et de courbes de Bézier (splines en anglais).

IV-D-1. Mise en place du module de dessin

L'utilisation de ce module dans le programme nécessite l'inclusion de l'en­tête :

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

Ensuite l'appel de la fonction d'initialisation :

 
Sélectionnez
bool al_init_primitives_addon(void)

Cette fonction retourne true sur succès et false sur erreur. Il est recommandé de faire un test :

 
Sélectionnez
if( !al_init_primitives_addon())
    erreur("al_primitives_addon()") ;

IV-D-2. Lignes, triangles, rectangles, cercles

Les principales fonctions de tracés des formes de base sont les suivantes :

La fonction al_draw_line :

 
Sélectionnez
void al_draw_line(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)

Trace une ligne depuis la position x1 ,y1 jusque x2 ,y2 de la couleur color et de l'épaisseur en pixels thickness . Pour l'épaisseur, toute valeur inférieure ou égale à 1 donne une épaisseur de 1 (épaisseur minimum).

La fonction al_draw_triangle :

 
Sélectionnez
void al_draw_triangle(float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color, float thickness)

Trace un triangle à partir des trois sommets x ,y de la couleur color et de l'épaisseur en pixels thickness . Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_triangle :

 
Sélectionnez
void al_draw_filled_triangle(float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color)

Dessine un triangle plein à partir des trois sommets x ,y de la couleur color .

La fonction al_draw_rectangle :

 
Sélectionnez
void al_draw_rectangle(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)

Trace un rectangle à partir des deux coins x ,y de la couleur color et de l'épaisseur thickness . Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_rectangle :

 
Sélectionnez
void al_draw_filled_rectangle(float x1, float y1, float x2, float y2,ALLEGRO_COLOR color)

Dessine un rectangle plein à partir des deux coins x ,y de la couleur color .

La fonction al_draw_rounded_rectangle :

 
Sélectionnez
void al_draw_rounded_rectangle(float x1, float y1, float x2, float y2,float rx, float ry, ALLEGRO_COLOR color, float thickness)

Trace un rectangle à partir des deux coins x ,y de la couleur color et de l'épaisseur thickness . Ce rectangle est arrondi à ses angles selon les rayons rx ,ry . Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_rounded_rectangle :

 
Sélectionnez
void al_draw_filled_rounded_rectangle(float x1, float y1, float x2, float y2,float rx, float ry, ALLEGRO_COLOR color)

Dessine un rectangle plein à partir des deux coins x ,y arrondi à ses angles selon les rayons rx , ry de la couleur color .

La fonction al_draw_pieslice :

 
Sélectionnez
void al_draw_pieslice(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness)

Trace une portion de cercle (« part de gâteau » ou « camembert ») à partir du centre cx , cy , du rayon r , de l'angle de départ (par rapport à l'horizontal) start_theta , selon l'angle delta_theta , de la couleur color avec l'épaisseur thickness . Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_pieslice :

 
Sélectionnez
void al_draw_filled_pieslice(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color)

Dessine une portion de cercle pleine à partir du centre cx , cy , du rayon r , de l'angle de départ (par rapport à l'horizontale) start_theta , selon l'angle delta_theta , de la couleur color .

La fonction al_draw_ellipse :

void al_draw_ellipse(float cx, float cy, float rx, float ry, ALLEGRO_COLOR color, float thickness)

Trace une ellipse à partir du centre cx , cy des rayons rx , ry , de la couleur color et de l'épaisseur thickness .

Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_ellipse :

 
Sélectionnez
void al_draw_filled_ellipse(float cx, float cy, float rx, loat ry, ALLEGRO_COLOR color)

Dessine une ellipse pleine à partir du centre cx , cy , des rayons rx , ry et de la couleur color .

La fonction al_draw_circle :

 
Sélectionnez
void al_draw_circle(float cx, float cy, float r, ALLEGRO_COLOR color,float thickness)

Trace un cercle de centre cx , cy de rayon r, de couleur color et d'épaisseur thickness . Une épaisseur inférieure ou égale à 1 donne une épaisseur de 1.

La fonction al_draw_filled_circle :

 
Sélectionnez
void al_draw_filled_circle(float cx, float cy, float r, ALLEGRO_COLOR color)

Dessine un cercle plein de centre cx , cy de rayon r , de couleur color .

IV-D-2-a. Expérimentation des fonctions de tracé

Notre programme d'expérimentation ci-dessous consiste à appeler chacune des fonctions de dessin en appuyant sur les touches :

  • [F1] pour les lignes,
  • [F2] pour les triangles,
  • [F3] pour les rectangles,
  • [F4] pour les ellipses,
  • [F5] pour les cercles,
  • [Entrée] pour effacer l'écran,
  • [Echap] pour quitter.
Expérimenter les fonctions de tracés
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.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_DISPLAY_MODE mode;
    ALLEGRO_KEYBOARD_STATE key;

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

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

    // plein écran dans la résolution optimale
    al_get_display_mode(al_get_num_display_modes() - 1, &mode);
    al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW);
    display = al_create_display(mode.width, mode.height);
    if (!display)
        erreur("al_create_display()");

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

    if (!al_init_primitives_addon())
        erreur("al_init_primitives_addon()");

    do{
        al_get_keyboard_state(&key);

        int x1 = rand() % screenx;
        int y1 = rand() % screeny;
        int x2 = rand() % screenx;
        int y2 = rand() % screeny;
        int x3 = rand() % screenx;
        int y3 = rand() % screeny;
        int cx = rand() % screenx;
        int cy = rand() % screeny;
        int rx = rand() % (screenx / 2);
        int ry = rand() % (screeny / 2);
        int r = rand() % (screeny / 2);

        ALLEGRO_COLOR color = al_map_rgba(rand() % 256, rand() % 256,
            rand() % 256, rand() % 256);
        int thickness = rand() % 30 - 5;

        // LIGNE
        if (al_key_down(&key, ALLEGRO_KEY_F1)){
            al_draw_line(x1, y1, x2, y2, color, thickness);
        }

        // TRIANGLES
        else if (al_key_down(&key, ALLEGRO_KEY_F2)){
            if (rand() % 2) // pile ou face
                al_draw_triangle(x1, y1, x2, y2, x3, y3, color, thickness);
            else
                al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, color);
        }

        // RECTANGLES
        else if (al_key_down(&key, ALLEGRO_KEY_F3)){
            switch (rand() % 4){
            case 0:
                al_draw_rectangle(x1, y1, x2, y2, color, thickness);
                break;
            case 1:
                al_draw_filled_rectangle(x1, y1, x2, y2, color);
                break;
            case 2:
                al_draw_rounded_rectangle(x1, y1, x2, y2, rx, ry,
                    color, thickness);
                break;
            case 3:
                al_draw_filled_rounded_rectangle(x1, y1, x2, y2,
                    rx, ry, color);
                break;
            }
        }

        // ELLIPSES
        else if (al_key_down(&key, ALLEGRO_KEY_F4)){
            if (rand() % 2)
                al_draw_ellipse(cx, cy, rx, ry, color, thickness);
            else
                al_draw_filled_ellipse(cx, cy, rx, ry, color);

        }
        // CERCLES
        else if (al_key_down(&key, ALLEGRO_KEY_F5)){
            if (rand() % 2)
                al_draw_circle(cx, cy, r, color, thickness);
            else
                al_draw_filled_circle(cx, cy, r, color);
        }

        // EFFACER
        else 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);
    return 0;
}
/*****************************************************************
*****************************************************************/

Première remarque : comme nous ne contrôlons pas le clavier, lorsque l'on appuie sur une touche même rapidement, la boucle est exécutée de nombreuses fois. Vous pouvez utiliser la fonction is_key_pressed présentée dans la section Compter les répétitions clavierCompter les répétitions clavier du chapitre Premiers pas avec Allegro 5.

Deuxième remarque : si vous testez le programme en ALLEGRO_FULLSCREEN plutôt qu'en ALLEGRO_FULLSCREEN_WINDOW vous obtiendrez une sorte de vibration à l'écran, des rayures, bref un problème d'affichage. Nous verrons dans la section Bitmap en mémoire du chapitre Images, comment résoudre ce problème.

IV-D-3. Arcs

Allegro propose deux fonctions pour tracer des arcs.

La fonction al_draw_arc :

 
Sélectionnez
void al_draw_arc(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness)

Trace un arc de cercle de centre cx , cy , de rayon r , à partir de l'angle de départ start_theta selon la plage angulaire delta_theta , de la couleur color et de l'épaisseur thickness . Les angles sont notés 0 pour horizontal, tournent en positif dans le sens des aiguilles d'une montre et dans le sens inverse en négatif. Les angles sont considérés en radians (cercle total = 2 PI radians).

La fonction al_draw_elliptical_arc :

 
Sélectionnez
void al_draw_elliptical_arc(float cx, float cy, float rx, float ry, float start_theta,float delta_theta, ALLEGRO_COLOR color, float thickness)

Trace un arc elliptique de centre cx , cy , de rayon rx et ry , à partir de l'angle de départ start_theta , selon la plage angulaire delta_theta , de la couleur color et de l'épaisseur thickness . Les angles sont notés 0 pour horizontal, tournent en positif dans le sens des aiguilles d'une montre et dans le sens inverse en négatif. Les angles sont considérés en radians (cercle total = 2 PI radians).

IV-D-3-a. Expérimentation : tracer des arcs

Tracer des arcs
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 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;

    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()");

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

    do{
        al_get_keyboard_state(&key);
        int rien = false;

        int r = 100; //rand()%(screeny/2) +1 ;
        int rx = rand() % (screeny / 2) + 1;
        int ry = rand() % (screeny / 2) + 1;
        int cx = screenx / 2; //rand()%screenx;
        int cy = screeny / 2; //rand()%screeny;
        float start_theta = 1 + rand() % 6; //rand()%1000;
        float delta_theta = 1 + rand() % 6000; //rand()%1000;
        ALLEGRO_COLOR color = al_map_rgba(rand() % 256, rand() % 256,
            rand() % 256, rand() % 256);
        float thickness = 2; //((float)rand()/RAND_MAX) * 30;

        if (is_key_pressed(&key, ALLEGRO_KEY_F1, 1)){
            al_draw_arc(cx, cy, r, start_theta, delta_theta, color,
                thickness);
            printf("cx=%d, cy=%d, r=%d, start_theta=%.2f, "
                "delta_theta=%.2f, thickness=%.2f\n",
                cx, cy, r, start_theta, delta_theta, thickness);
        }

        else if (is_key_pressed(&key, ALLEGRO_KEY_F2, 1)){
            al_draw_elliptical_arc(cx, cy, rx, ry, start_theta,
                delta_theta, color, thickness);
            printf("cx=%d, cy=%d, rx=%d, ry=%dstart_theta=%.2f, "
                "delta_theta=%.2f, thickness=%.2f\n",
                cx, cy, rx, ry, start_theta, delta_theta, thickness);
        }

        else if (is_key_pressed(&key, ALLEGRO_KEY_ENTER, 1))
            al_clear_to_color(al_map_rgb(0, 0, 0));

        else
            rien = true;

        // si quelque chose dessiné, le basculer à l'écran
        if (!rien)
            al_flip_display();

        // efface double buffer
        //al_clear_to_color(al_map_rgb(0, 0, 0));

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


    return 0;
}
/*****************************************************************
*****************************************************************/

Si aucune touche n'est appuyée, le booléen rien est à true et le double buffer n'est pas copié à l'écran (al_flip_display() n'est pas appelée). En revanche si une touche a été appuyée, un dessin a eu lieu, le booléen rien est à false et le double buffer qui contient le dessin est copié à l'écran. Mais quelle que soit la valeur de rien, à chaque tour le double buffer est effacé pour éviter l'accumulation des dessins les uns sur les autres à l'écran.

Si vous mettez en commentaire l'effacement du double buffer, vous obtenez :

  1. Quelle que soit la valeur aléatoire supérieure ou égale à 1 de start_theta , le résultat est toujours un arc qui se déplace sur le périmètre du cercle.
  2. Si la valeur aléatoire de delta_theta dépasse 6,5 les arcs se superposent régulièrement autour du cercle et des figures assez intéressantes apparaissent :
Image non disponible

Il reste une autre fonction à propos des arcs qui permet de récupérer un ensemble de points constitutifs de l'arc tracé. Cet ensemble ne comprend pas nécessairement tous les points mais un échantillonnage de points prélevés de façon régulière et homogène.

La fonction al_calculate_arc :

 
Sélectionnez
void al_calculate_arc(float* dest, int stride, float cx, float cy,float rx, float ry, float start_theta, float delta_theta, float thickness, int num_segments)

p1 : cette fonction retourne un ensemble de points dans le tableau dynamique préalablement alloué et passé en dest . Un point sera défini par une structure ayant pour premier et second champs la position x et y du point.

p2 : le paramètre stride donne la taille de cette structure.

p3, 4 : les paramètres cx et cy correspondent au centre du cercle ou de l'ellipse.

p5, 6 : les paramètres rx et ry donnent les rayons pour l'horizontale et la verticale.

p7 : le paramètre start_theta spécifie l'angle de départ (0 pour l'horizontal puis progression en radians dans le sens des aiguilles d'une montre).

p8 : le paramètre delta_theta donne l'angle qui définit l'arc.

p9 : le paramètre thickness définit l'épaisseur de l'arc. Si thickness est inférieur ou égal à 0, il faut un point par position dans l'arc. Si thickness est supérieur à 0, il faut deux points par position dans l'arc.

p10 : le paramètre num_segments donne le nombre de positions que l'on souhaite prendre sur l'arc. Ainsi le nombre total de points pour allouer le tableau est num_segments si thickness est inférieur ou égal à 0 et num_segments *2 si thickness est supérieur à 0.

IV-D-3-b. Expérimentation : récupérer les points d'un arc

Le programme ci-dessous récupère tous les points d'un arc sur la base de dix segments et d'une épaisseur de dix pixels et les affiche sous forme de petits ronds de cinq pixels de rayon.

Récupérer les points d'un arc
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>

// le type des points d'un arc
typedef struct{
    float x, y; // obligatoirement au début de la structure
    int data;
}t_point;


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;
    int i;

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

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

    if (!al_init_primitives_addon())
        erreur("allegro init primitives addon");

    // les points constitutifs de l'arc
    int screenx = al_get_display_width(display);
    int screeny = al_get_display_height(display);
    float cx = screenx / 2;
    float cy = screeny / 2;
    float rx = 100;
    float ry = 100;
    float start_theta = 0;
    float delta_theta = 3.5; // radian

    float thickness = 10;
    int num_segment = 10;
    int nbpoint = (thickness <= 0) ? num_segment : num_segment * 2;
    t_point*dest = (t_point*)calloc(nbpoint, sizeof(t_point));

    al_calculate_arc((float*)dest,
        sizeof(t_point),
        cx, cy,
        rx, ry,
        start_theta,
        delta_theta,
        thickness,
        num_segment);

    for (i = 0; i<nbpoint; i++){
        al_draw_filled_circle(dest[i].x, dest[i].y, 5,
            al_map_rgb_f(1, 0.5, 0));
        al_flip_display();
        al_rest(0.5);
    }
    al_rest(5.0);
    al_destroy_display(display);
    free(dest);
    return 0;
}
/*****************************************************************
*****************************************************************/

IV-D-4. Courbe de Bézier (spline)

Allegro fournit une fonction qui permet de tracer des courbes de Bézier. Ces courbes sont des lignes arrondies calculées en partant d'une ligne brisée constituée de trois segments.

La fonction al_draw_spline :

 
Sélectionnez
void al_draw_spline(float points[8], ALLEGRO_COLOR color, float thickness)

Les coordonnées des quatre points de départ sont passées dans le tableau points et la courbe résultante est tracée de la couleur color et de l'épaisseur thickness . Dans le tableau les points sont rangés dans l'ordre x1,y1 indices 0,1, x2,y2 indices 2,3, etc.

IV-D-4-a. Expérimentation : tracer une courbe de Bézier

Le programme propose un tracé animé de la courbe. Pour ce faire, les quatre points constitutifs se déplacent dans l'écran et une nouvelle courbe est à chaque fois tracée. Le tableau pour les coordonnées des points est doublé par un tableau pour le déplacement des points :

Tracer une courbe de Bézier
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>
#include <time.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_DISPLAY_MODE mode;
    ALLEGRO_KEYBOARD_STATE key;
    // les tracés avec une animation
    float ptxy[8]; // les points de la courbe
    float dxdy[8]; // les déplacements de chaque point
    ALLEGRO_COLOR color;
    int screenx, screeny;
    int i;

    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()");

    // création plein écran sans fenêtre de la taille maximum
    al_get_display_mode(al_get_num_display_modes() - 1, &mode);
    al_set_new_display_flags(ALLEGRO_FULLSCREEN);
    display = al_create_display(mode.width, mode.height);
    if (!display)
        erreur("al_create_display()");

    // taille écran
    screenx = al_get_display_width(display);
    screeny = al_get_display_height(display);

    // initialiser les position de chaque point, 
    // les valeur de déplacement et la couleur
    for (i = 0; i<8; i += 2){
        ptxy[i] = rand() % screenx;
        ptxy[i + 1] = rand() % screeny;
        dxdy[i] = (1 + rand() % 10) * (rand() % 2 * 2 - 1);
        dxdy[i + 1] = (1 + rand() % 10)* (rand() % 2 * 2 - 1);
    }
    color = al_map_rgba(rand() % 255, 64, rand() % 255, 128);

    do{
        al_get_keyboard_state(&key);

        // bouger
        for (i = 0; i<8; i += 2){
            ptxy[i] += dxdy[i];
            if (ptxy[i]<0 || ptxy[i]>screenx)
                dxdy[i] *= -1;

            ptxy[i + 1] += dxdy[i + 1];
            if (ptxy[i + 1]<0 || ptxy[i + 1]>screeny)
                dxdy[i + 1] *= -1;
        }
        // afficher
        al_draw_spline(ptxy, color, 20);
        al_flip_display();
        al_clear_to_color(al_map_rgb(0, 0, 0));

        al_rest(1 / 30.0);

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


    return 0;
}
/*****************************************************************
*****************************************************************/

Allegro 5 fournit une autre fonction qui permet de récupérer sans les afficher des points sur une courbe de Bézier.

Le nombre des points est un échantillonnage qui correspond à un découpage de la courbe en segments.

La fonction al_calculate_spline :

 
Sélectionnez
void al_calculate_spline(float* dest, int stride, float points[8], float thickness, int num_segments)

p1 : les points récupérés sont stockés dans un tableau dynamique préalablement alloué : dest.

p2 : le paramètre stride donne la taille d'un élément du tableau passé en p1. En effet, le tableau peut contenir des éléments de n'importe quel type, et donc de n'importe quelle taille. Le type est ensuite converti en float* grâce à l'opérateur de conversion (cast).

p3 : le paramètre points contient les quatre points pour le calcul de la courbe de Bézier.

p4 : le paramètre thickness donne l'épaisseur voulue pour la courbe. Si thickness est inférieur ou égal à 0, il y aura un seul point par position dans la courbe. Si thickness est supérieur à 0, il y aura deux points par position dans la courbe.

p5 : le paramètre num_segments donne le nombre de points dans le tableau, à savoir le nombre d'échantillons, donc de segments, pris dans la courbe. Si thickness est inférieur ou égal à 0, c'est exactement la taille du tableau dest avec un point par position. Si thickness est supérieur à 0, il y a deux points par position et num_segment correspond alors à la moitié du tableau dest.

IV-D-4-b. Expérimentation : récupérer les points d'une courbe de Bézier

Un point est une structure qui contient ses coordonnées et qui peut aussi contenir d'autres données :

 
Sélectionnez
typedef struct {
    float x, y; // position
    int autres_donnees;
}t_point;

L'important est que les deux premiers champs soient bien des floats qui correspondent à la position du point. La taille d'un élément du tableau sera donnée avec l'opérateur sizeof, par l'expression :

 
Sélectionnez
sizeof(t_point)

Le nombre de positions que l'on souhaite récupérer sur la courbe est arbitraire, choisi par le programmeur, mais c'est obligatoirement un nombre pair, par exemple :

 
Sélectionnez
int nbpoint = 5*2;

Le tableau de points est ensuite alloué dynamiquement en fonction du nombre de points décidé :

 
Sélectionnez
t_point*recpoint ;
recpoint = (t_point*)calloc(nbpoint,sizeof(t_point));

L'épaisseur de la courbe influe sur le nombre des positions récupérées. Si l'épaisseur est inférieure ou égale à 0, il y a un point par position et donc le nombre total des positions récupérées est la taille nbpoint du tableau de points. Si l'épaisseur est supérieure à 0, il faut deux points par position et par conséquent le nombre total de positions est nbpoint/2, ce que nous obtiendrons ainsi :

 
Sélectionnez
// le nombre de positions c'est :
int nbpos= (thickness<=0) ? nbpoint : nbpoint/2 ;

Bien entendu pour le tracé de la courbe nous avons aussi besoin d'un tableau à quatre points, comme pour la fonction de tracés de courbe de Bézier, par exemple :

 
Sélectionnez
float beziers_4_pos[8] =
{
    400, 100, // position 1
    500, 200, // 2 ...
    300, 400,
    400, 500
};

Maintenant nous avons tous les éléments pour appeler la fonction, ce qui donne :

 
Sélectionnez
al_calculate_spline((float*)recpoint,    // tableau de t_points,
                                         // le cast est obligatoire
                    sizeof(t_point),     // taille un élément
                    beziers_4_pos,       // position pour le calcul
                    thickness,           // épaisseur
                    nbpos);              // nombre total de positions
                                         // en sortie

Voici la démonstration complète :

Récupérer les points d'une courbe de Bézier
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>

// le type point pour la courbe : la position doit obligatoirement
// être les deux premiers champs de la structure;
typedef struct {
    float x, y; // position
    int autres_donnees;
}t_point;

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;
    int i;

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

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

    if (!al_init_primitives_addon())
        erreur("allegro init primitives addon");

    // les quatre nécessaires au tracé d'une courbe de Bézier
    float beziers_4_pos[8] =
    {
        400, 100,
        500, 200,
        300, 400,
        400, 500
    };
    // le nombre maximum de points pour la récupération (pair)
    int nbpoint = 5 * 2;

    // tableau dynamique pour la récupération
    t_point*recpoint = (t_point*)calloc(nbpoint, sizeof(t_point));

    // l'épaisseur qui détermine s'il y a un ou deux points par
    // position :
    // si épaisseur <=0 : 1 seul point
    // si épaisseur >0 : 2 points par position qui sont espacés
    // de épaisseur (thickness)
    int thickness = 30;

    // le nombre de position
    int nbpos = (thickness <= 0) ? nbpoint : nbpoint / 2;

    al_calculate_spline((float*)recpoint,
        sizeof(t_point),
        beziers_4_pos,
        thickness,

        nbpos);


    for (i = 0; i < nbpoint; i++){
        al_draw_filled_circle(recpoint[i].x, recpoint[i].y, 5,
            al_map_rgb_f(0.5, 1, 0));
        al_rest(0.5);
        al_flip_display();
    }

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

Changer le nombre de points nbpoint et changer l'épaisseur thickness permet de bien comprendre le fonctionnement de la fonction.

IV-D-5. Ruban

Allegro 5 fournit une fonction originale qui permet de tracer une succession de segments, c'est-à-dire un ruban.

La fonction al_draw_ribbon :

 
Sélectionnez
void al_draw_ribbon(const float *points, int points_stride, ALLEGRO_COLOR color,float thickness, int num_segments)

Cette fonction trace une ligne brisée en plusieurs segments à partir du tableau de points passé au paramètre points . Bien que le tableau dynamique points soit un float*, il peut contenir des structures. Il est utilisé en réalité comme un tableau d'octets qui offre en outre la possibilité de contenir des floats. Ainsi chaque point doit être une structure contenant au moins une position x et y comme premier et second champ. Cette structure points peut contenir d'autres informations dans les champs suivants. Le paramètre stride donne la taille en octets de chaque élément du tableau. Le ruban est tracé de la couleur color et selon l'épaisseur thickness . Le nombre maximum de points est donné en num_segments (segment en anglais signifiant secteur et segmenter, c'est ce que font les points). Ce nombre ne doit pas excéder la taille du tableau de points passé au paramètre p1 points .

IV-D-5-a. Expérimentation : tracer un ruban

Tracer un ruban
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>

typedef struct{
    float x, y; // obligatoirement au début de la structure
    int data;
}t_point;

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;

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

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

    if (!al_init_primitives_addon())
        erreur("allegro init primitives addon");

    // tracer des rubans
    const int nbmax = 5;
    t_point tabpoint[] =
    {
        { 100, 100, 0 },
        { 100, 150, 0 },
        { 200, 200, 0 },
        { 200, 300, 0 },
        { 100, 500, 0 }
    };

    al_draw_ribbon((float*)tabpoint, // le tableau de points
        sizeof(t_point), // la taille d'une structure
        al_map_rgb_f(1, 0, 0.5),// couleur
        10, // épaisseur du trait
        nbmax); // nombre max de points


    al_flip_display();
    al_rest(4.0);
    al_destroy_display(display);
    return 0;
}
/*****************************************************************
*****************************************************************/

Comme pour les courbes de Bézier (spline) une autre fonction permet de récupérer des points constitutifs d'un ruban selon un échantillonnage donné en paramètre.

La fonction al_calculate_ribbon :

 
Sélectionnez
void al_calculate_ribbon(float* dest, int dest_stride, const float *points,int points_stride, float thickness, int num_segments)

p1 : les points constitutifs du ruban sont récupérés dans le tableau dynamique dest .

p2 : la taille d'un élément point de ce tableau en sortie est passée en octets au paramètre stride , en effet une structure points peut contenir plus d'informations que la seule position x,y mais la position x,y doit toujours constituer les deux premiers champs de la structure.

p3 : le paramètre points est le tableau de points initial en entrée pour le tracé du ruban.

p4 : le paramètre points_stride donne la taille d'un élément point en entrée. Les points pour chacun des tableaux en entrée et en sortie peuvent être de types différents et donc correspondre à des tailles différentes en mémoire.

p5 : le paramètre thickness spécifie l'épaisseur. Si l'épaisseur est supérieure à 0 il faut deux points par position. Ils seront écartés de la valeur en pixels de cette épaisseur.

p6 : le paramètre num_segment donne le nombre de positions qui découpe le ruban. Si l'épaisseur demandée est inférieure ou égale à 0 le paramètre num_segment correspond au nombre de points du tableau de points en entrée. Si l'épaisseur est supérieure à 0, num_segment correspond alors à la moitié du nombre d'éléments du tableau de points en entrée.

IV-D-5-b. Expérimentation : récupérer les points d'un ruban

Récupérer les points d'un ruban
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>

// les points d'un ruban
typedef struct
{
    float x, y; // obligatoirement au début de la structure
    int data;
}t_point;


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;
    int i;

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

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

    if (!al_init_primitives_addon())
        erreur("allegro init primitives addon");

    // les points constitutifs du ruban
    const int nbpos = 5;
    t_point tabpos[] =
    {
        { 100, 100, 0 },
        { 100, 150, 0 },
        { 200, 200, 0 },
        { 200, 300, 0 },
        { 100, 500, 0 }
    };

    int thickness = 10;
    //
    int nbpoint = (thickness <= 0) ? nbpos : nbpos * 2;
    t_point*recpoint = (t_point*)calloc(nbpoint, sizeof(t_point));

    al_calculate_ribbon((float*)recpoint, // sortie 
        sizeof(t_point),// taille point en sortie
        (float*)tabpos,//les positions du ruban
        sizeof(t_point),//taille point en entrée              
        thickness,// si >0 alors 2 points par position et séparés de thickness. 
                // Si <=0 un seul point par position 

        nbpos); // le nombre de positions 


    for (i = 0; i<nbpoint; i++){
        al_draw_filled_circle(recpoint[i].x, recpoint[i].y, 5,
            al_map_rgb_f(1, 0.5, 0));
        al_flip_display();
        al_rest(0.5);
    }
    al_rest(5.0);
    al_destroy_display(display);
    free(recpoint);
    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.