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 :
#include <allegro5/allegro_font.h>
Pour avoir une police TTF, inclure en plus le module ttf.
#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 :
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 :
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 :
ALLEGRO_FONT*
arial72 ;
La récupération de la police se fait avec un appel à la fonction :
ALLEGRO_FONT *
al_load_font
(
char
const
*
filename, int
size, int
flags)
ou à la fonction :
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 :
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 :
#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 :
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 :
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 :
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 :
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() :
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 :
al_rest
(
0
.5
);
provoque un affichage de la variable tmps toutes les demi-secondes :
// (...)
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 :
Assurezvous 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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
#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'entête :
#include <allegro5/allegro_primitives.h>
Ensuite l'appel de la fonction d'initialisation :
bool al_init_primitives_addon
(
void
)
Cette fonction retourne true sur succès et false sur erreur. Il est recommandé de faire un test :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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.
#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 :
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 :
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▲
#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 :
- 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.
- 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 :
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 :
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.
#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 :
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 :
#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 :
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 :
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 :
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 :
int
nbpoint =
5
*
2
;
Le tableau de points est ensuite alloué dynamiquement en fonction du nombre de points décidé :
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 :
// 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 :
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 :
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 :
#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 :
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▲
#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 :
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▲
#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▲
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. |