Dessin de rosaces en C sur Apple II

Cette page est la suite de l’article programmation graphique haute résolution en C sur Apple II. Il est vivement conseillé de lire le premier article avant de continuer sur cette page.

Nous allons voir comment programmer en C le dessins rosaces en mode haute résolution, en reprenant le programme de tracé de rosaces en Applesoft BASIC présenté dans cet article. Il s’agit d’un exemple qui permet d’aborder deux aspects intéressants de la programmation graphique avec cc65 et qui sont liés aux limitations suivantes :

  • cc65 ne supporte pas les type float ni double et il est impossible de faire des calculs sur des nombres à virgule flottante comme en BASIC Applesoft ou en C standard.
  • cc65 ne dispose pas de la bibliothèque mathématique <math.h> ce qui rend difficile l’utilisation de fonctions mathématiques avancées, notamment des fonctions trigonométriques.

Nous allons voir comment contourner ces limitations.

Calculs en virgule fixe

Il est possible d’encoder un nombre décimal possédant un nombre fixe de chiffres après la virgule dans une variable de type entier. Par exemple, le nombre 1,32 peut être mémorisé sous la forme du nombre entier 132, il y a alors un coefficient de 100 entre les deux. Dans cet exemple, la précision obtenue est de deux chiffres après la virgule.

Pour une implémentation en langage C il est préférable d’utiliser un coefficient de 2n car la multiplication par 2n revient à faire un décalage de n bits sur la gauche, opération qui est effectuée très rapidement par le processeur. Ceci revient à réserver les n bits de poids faible à la partie décimale (chiffres à droite de la virgule), les m bits de poids fort restants sont utilisés pour la partie entière (chiffres à gauche de la virgule) et l’éventuel bit de signe.

Par exemple, si le nombre à virgules fixes est mémorisé dans une variable de type int (entier signé) sur 16 bits, il est possible d’utiliser les 8 bits de poids fort pour la partie entière et le bit de signe, les 8 bits de poids faible servant aux chiffres après la virgule. Le format est dénommé « virgule fixe 8.8 signé« .

Plus généralement, le format m.n peut être utilisé à condition que m+n soit égal au nombre de bits de la variable utilisée pour mémoriser le nombre. Si la variable de type int utilise 2 octets (16 bits), il faut que m+n=16. Il est également possible d’utiliser des entiers non signés ce qui permet de gagner le bit de signe.

fixed point number
Codage d’un nombre décimal x en virgule fixe m.n

Il est ensuite possible de faire des calculs sur ces nombres représentés en virgule fixe, à condition d’avoir une représentation avec le même format m.n et de contrôler qu’il n’y a pas de débordement.

  • Addition en virgule fixe : z = x + y

si x et y sont au format m.n, z sera au format m.n. Il faut simplement vérifier que l’addition ne conduit pas à avoir un débordement.

  • Multiplication : z = x * y

Si x et y sont au format m.n (et occupent ainsi chacun m+n bits en mémoire), le résultat de la multiplication occupera 2(m+n) bits. Pour revenir ensuite au format m.n il faut diviser le précédent résultat par 2n, ce qui équivaut à décaler de n bits vers la droite.

Ceci impose une contrainte sur le type de variable qui mémorise le résultat de la multiplication, qui doit avoir suffisamment d’espace mémoire. Par exemple, si x et y sont de type int sur 16 bits, le résultat de la multiplication doit être mémorisé dans un long int sur 32 bits.

Vous noterez la perte de précision liée au nombre de bits utilisés pour encoder les chiffres après la virgule.

Trigonométrie sans math.h

cc65 dispose des fonctions trigonométriques suivantes :

int _sin(unsigned x);
int _cos(unsigned x);

ces deux fonctions disponibles dans <cc65.h> renvoient respectivement le sinus et le cosinus de l’angle x exprimé en degré (valeurs comprises entre 0 et 360). La valeur renvoyée est exprimée en virgule fixe au format 8.8 signé ; la valeur $100 (256 en base 10) correspond à 1,0 et la valeur $FF00 (-256 en base 10) correspond à -1,0.

Il est ainsi possible de faire des calculs trigonométriques.

Application au tracé de rosaces

Le tracé de rosaces nécessite les calculs mathématiques suivants, qu’il faudra effectuer avec un encodage de variables en virgule fixe :

Encodage des variables :

  • La variable b est encodée en virgule fixe au format 8.8 non signé dans une variable de type unsigned int (16 bits)
  • n est encodée au format 8.8 signé car n peut être négatif.
  • La variable a est encodée au format 9.7 non signée car elle est multipliée par une nombre compris entre 0 et 360 qui nécessite 9 bits en mémoire.
  • La variable theta est mémorisée sous la forme d’un entier non signée et contient l’angle en degré.
  • x et y sont mémorisées sous la forme d’entiers.

Voici l’archive contenant le code source C rosaces.c, le makefile et l’image de la disquette au format DOS3.3 ROSACES.DSK.

La procédure d’installation et de fabrication de l’exécutable est la suivante :

Ceci fabrique l’exécutable ROS et le copie sur la disquette ROSACES.DSK.

Il suffit ensuite de démarrer sur cette « disquette » (en utilisant AppleWin par exemple) puis, dans l’environnement Apple II, de lancer l’exécutable :

Le programme demande alors la saisies des paramètres de la rosace puis l’affiche soit en mode point (touche P) soit en mode trait (touche T).

Voici un exemple d’exécution :

Saisie des paramètre de la rosace : A=3,5 ; B=0,3 ; PE = 2 et PAS = 1 degré
Le tracés obtenu en mode HGR

Les paramètres A et B sont affectés d’un coefficient de mise à l’échelle de respectivement 100 et 10, afin de pouvoir saisir des chiffres après la virgule.

Conclusion

Cet article a permis d’aborder le calcul en virgule fixe et un exemple de programmation en langage C. Il permet également d’appréhender les contraintes et les limites ; taille maximum de la partie entière, perte de précision. Le calcul en virgule reste un outil puissant permettant de palier l’absence de virgule flottant d’un compilateur et reste une solution efficace en temps de calcul.