Flammes |
L'idée originale
de ce programme est de Shawn Hargreaves. Elle est donnée dans l'exemples
exflame.c de la librairie Allegro. Mais pour simple qu'elle ait pu paraître
à son auteur elle n'est pas si triviale que ça et elle mérite
d'être regardée en détail. |
![]() |
TELECHARGER aaaTexte des explications, aaaExecutable (Windows), aaaSource (utilise la librairie Allegro)
|
![]() |
EXPLICATIONS 1. Principe L’idée de feu s’appuie d’abord sur la création d’une palette de couleur : un dégradé du noir au rouge puis au blanc en passant par l’orange et le jaune. Les flammes ont une allure de dessin d’enfant, montent du bas de l’écran vers le haut, du jaune le plus clair vers le plus foncé, le rouge sombre et finalement disparaissent dans l’obscurité. Pour ce faire il y a trois principales étapes. La première est la définition de la première ligne de feu, c’est-à-dire, puisque les flammes montent, la dernière ligne en bas de l’écran. Sur cette ligne des segments sont définis à partir de points pris au hasard comme centres des segments. La couleur des segments est un dégradé qui, de gauche à droite, part du rouge le plus sombre et rejoint à nouveau le rouge le plus sombre en passant par le blanc. Eventuellement les segments peuvent se superposer ce qui ajoute un peu de relief à la régularité du dégradé. En second lieu il s’agit de faire monter les flammes. La ligne du bas va être recopiée sur la ligne au-dessus avec au passage un léger assombrissement de la couleur. Ce principe de recopie ligne à ligne en partant du haut et en descendant vers le bas avec assombrissement progressif de la couleur fait l’objet d‘une boucle jusqu’à ce qu’il n’y ait plus de couleur sur la ligne tout en haut de la flamme à une certaine hauteur de l’écran. Tel
quel l’algorithme donne un dégradé vers le haut des
couleurs de la palette à partir des centres des segments de la
ligne initiale et il n’y a pas de mouvement. Pour qu’il y
ait un mouvement il faut modifier légèrement et au hasard
la ligne initiale du bas, c’est l’objet de la troisième
étape. Les segments sont définis par un point sur une ligne
: une distance est retranchée à gauche et ajoutée
à droite du point, ce qui donne le segment par rapport au point.
Il suffit de modifier légèrement la position du point pour
créer le décalage, base de l’animation de la flamme.
La figure ci-dessous récapitule le principe de cette représentation.
Créer
la palette (1)aaaaPALETTE pal ; (2)aaaavoid
couleurs_flammes(void) (3)aaaaaaafor
(i=0; i<64; i++) {
(2) La fonction « couleurs_flammes » ne renvoie aucune valeur et n’a pas de paramètre en argument. (3) Le rouge augmente de 0 à 63 alors que vert et bleu restent à 0 (progression du rouge de plus en plus vif). (4) Le rouge reste à 63 et le bleu à 0, le vert augmente progressivement de 0 à 63 ( les orangers d’abord et jaunes ensuite de plus en plus vifs). (5) Rouge et vert restent à 63, le bleu augmente progressivement de 0 à 63 ( du jaune au blanc). La formulation est intéressante, plutôt que d’écrire « i-128 » c’est « i-192 », disons par coquetterie littéraire du domaine. Pour comprendre l’expression il ne faut pas oublier que seuls les six premiers bits comptent pour le codage de la couleur et également que 192 correspond à 1100 0000 en binaire. La soustraction 128-192 en binaire donne sur un octet non signé la valeur 192, la soustraction suivante 129-192 donne la valeur 193 soit en binaire 1100 0001, ce qui fait 1 pour les six premiers bits du codage de la couleur etc. (6) Rouge, vert et bleu restent à 63, couleur blanche des indices 192 à 255 de la palette. (7) Activation de la palette. Initialiser
les variables aaaaa#define
NB_BRAISES 48 L’initialisation de ce
tableau est pour chacune de ses positions un nombre pris au hasard entre
0 et la taille de la ligne qui est la taille horizontale de l’écran
définie par la macro ECRAN_X.
aaaaaBITMAP*
page ; (1)aaaaaint
initialisations(void) (3)aaaaaaafor
(i=0; i<NB_BRAISES; i++) (4)aaaaaaareturn
1; (1) La fonction « initialisations » n’a pas de paramètre et renvoie un entier. (2) Création de la bitmap « page » à la dimension de l’écran. Ensuite allocation de mémoire pour l’équivalent d’une ligne de l’écran codé en 8 bits (ECRAN_X fois la taille d’un caractère non signé). Au cas où un problème de mémoire surviendrait, test pour vérifier le bon fonctionnement des deux opérations. Si un problème est survenu un message d’erreur est envoyé via l’appel d’une fonction spécialisée « allegro_message » et ensuite la valeur de retour 0 provoque la sortie de la fonction. S’il n’y a pas eu de problème toutes les positions de la bitmap « page » sont mises à 0 avec l’appel de la fonction « clear ». (3) Le tableau « braise » est un tableau d’entiers qui correspondent à des points sélectionnés au hasard sur une ligne. Pour avoir une position horizontale de chacun il suffit de tirer un nombre pseudo-aléatoire avec la fonction « rand » puis exercer un modulo avec la taille maximum de la ligne ECRAN_X. Ensuite affecter ce nombre à l’entier de la i-ème position du tableau « braise ». (4) Tout a bien fonctionné
et la fonction renvoie à la fonction appelante la valeur 1. 3. Processus générateur Programme
complet, boucle du processus aaaaaint
main(void) (2) Boucle « tant que » du processus. Le test est l’appel d’une fonction qui renvoie simplement si oui ( valeur 1 ) ou non (valeur 0 ) une touche du clavier a été pressée. Si oui, le test est faux et la boucle prend fin. Si non le test est vrai et la boucle continue. (3) Appel à la fonction « ligne_initiale_de_feu ». Le rôle de cette fonction est de modifier la ligne de base à partir de laquelle les flammes sont constituées. Le détail de cette fonction est donné plus bas. (4) Appel de la fonction « monte_flammes ». A partir du haut jusqu’en bas de l’écran, c’est la recopie de la ligne immédiate du bas à la lignes courante supérieures avec décrémentation progressive de la couleur. Détail de la fonction « ligne initiale de feu » Fonction pour établir et modifier la ligne de base sur laquelle s’appuie l’édifice des flammes (1)aaaaavoid
ligne_initiale_de_feu(void) (2)aaaaaaaafor
( i=0; i<ECRAN_X; i++ ) (3)aaaaaaaafor
( i=0; i<NB_BRAISES; i++ ) { (5)aaaaaaaaaaaaaaif
((dx >= 0) && (dx < ECRAN_X)) (6)aaaaaaaaaaaaaabraise[
i ] += (rand() & 7) - 3; (1) « ligne_initiale_de_feu » ne renvoie rien et ne prend pas d’argument. (2) Toutes les positions désignées par le pointeur tmp sont mises à 0. (3) et (4) Boucles for imbriquées.
Tout d’abord en (3) chaque position du tableau « braise »
va être convoquée via l’incrémentation de la
variable i. Pour chaque indice i, braise[ i ] contient une valeur de position
en x sur une ligne. Pour faire un segment il suffit de lui retrancher
une valeur à gauche et de l’ajouter à droite. La taille
du segment est fixée à 40 pixels. (5) Si la valeur de dx fait que dx est toujours dans la ligne et ne sort pas de l’écran, la position courante dans le segment va être affectée d’une valeur pour la couleur du pixel. La formule pour obtenir cette valeur utilise la macro « MIN » qui donne la valeur minimum entre deux valeurs : MIN( a, b) donne a si a<b et b sinon. Le
deuxième argument de MIN est 192, le premier se décompose
en trois parties : aaaaa1) donne la distance de dx au centre du segment braise[ i ] en positif à gauche et négatif à droite, mais restitué en valeur absolue. aaaaa2) Comme 20 est la distance maximum d’une extrémité au centre, en soustrayant la valeur absolue de la distance de dx au centre, aaaaaplus dx est près des bords plus le résultat est petit et plus dx est près du centre plus le résultat est grand. Le résultat va de 0 à 20 aaaaaet de 20 à 0. aaaaa3) Uniquement pour le premier segment toutes les positions de tmp sont à 0. Mais ensuite des segments peuvent se superposer aaaaacomme nous l’avons indiqué plus haut. La valeur de chaque position de tmp est additionnée ce qui surélève d’autant les valeurs aaaaacalculées en 2), et crée un effet de superposition, comme des collines à partir du mouvement de crescendo et decrescendo. aaaaaC’est-à-dire que l’augmentation de l’intensité de la couleur dépend du rapport entre le nombre de « braises » et la taille horizontale aaaaade l’écran. Le rapport est ici prévu à l’origine pour un écran tout petit de 320 pixels sur 200 pixels. aaaaaSi le résultat final de ce calcul est inférieur à 192, il est affecté à la position dx de tmp, sinon tmp prend une valeur maximum de aaaaa192 (6) Ensuite la position du centre de segment braise[ i ] est légèrement modifiée au hasard dans la fourchette de – 3 à 3 pixels, afin de faire bouger la ligne et de créer l’animation souhaitée. (7) L’écran est considéré comme circulaire, c’est-à-dire que si braise[ i ] dépasse à gauche de l’écran il est renvoyé à droite et inversement s’il dépasse à droite il est renvoyé à gauche de l’écran. (8) La dernière instruction est la recopie de cette nouvelle ligne de base, en bas de l’écran, sur la bitmap intermédiaire « page ». Pour ce faire la fonction « memcpy », qui fait partie de la librairie standard du C <string.h>, est employée. Cette fonction copie à l’adresse du premier argument la taille de mémoire passée en troisième argument et à partir de l’adresse passée en deuxième argument. En l’occurrence la ligne tmp est recopiée toute entière à l’adresse de la dernière ligne de la bitmap « page ». Détail de la fonction « monte_flammes » Après création de la ligne de base il reste à faire monter la flamme. C’est le rôle de la fonction « monte_flammes » (1)aaaaavoid
monte_flammes ( void ) (2)aaaaaa
afor ( y = 192; y < ECRAN_Y – 1; y++ ) (1) « monte_flammes » ne prend pas de paramètre et ne renvoie rien. (2) Boucles for imbriquées. La première examine les lignes, la seconde les pixels de chaque ligne. (3) Le principe est de partir à la hauteur maximum des flammes et de descendre ligne par ligne. A chaque ligne, il s’agit de copier la ligne de dessous ( y+1 ) sur la ligne courante y. Pour ce faire la valeur de couleur de chaque pixel de la ligne de dessous est récupérée dans la variable c. Si elle est supérieure à 0 elle est décrémentée de 1. La valeur c obtenue est affectée à la même position horizontale sur la ligne courante y. C’est ainsi que le dégradé vers le haut des flammes est obtenu. C’est également ce qui donne la hauteur maximum des flammes. La valeur de couleur est 192 au maximum et elle décroît à chaque ligne copiée de un en un jusqu’à 0. Maintenant il est possible de faire traverser
des flammes à un bonhomme, voire de le faire courir dans une boite
enflammée ou au contraire de le faire s’enfuir à la
vue des flammes, d’être poursuivi par des flammes. Les flammes
peuvent aussi perdre leur caractère de flammes ordinaires et changer
de couleur ce qui est assez amusant et puis il y a à voir l’étude
de flammes sur une surface circulaire etc. |
![]() |