lib et documentation rédigée par Julien P. (Orwell).
gxLib permet de faire apparaitre 5 couleurs (noir, blanc et 3 gris) à l’écran d’une calculatrice Graph100/AFX en fournissant toutes les fonctions utiles pour faire apparaître un point, une ligne, un sprite ou encore pour remplir l’écran avec une certaine couleur.
La technique utilisée ici permet de générer les 5 couleurs à partir de 3 buffers (au lieu de 2 pour les 3 couleurs du mode DB classique, et de 4 pour les fonctions proposées par tonton1664 pour un autre mode 5 couleurs). Ces trois buffers permettant 8 combinaisons de bits possibles pour chaque pixel, les 3 combinaisons superflues sont utilisées pour éliminer les clignotements des différents tons de gris.
La lib fournit des fonctions d’affichage de sprites basées sur les mêmes méthodes que la librairie Drawlib 1.4b pour le mode DB; reportez-vous à son fichier “lisez-moi” pour plus d’infos sur leur utilisation. gxLib reprend tous les avantages de Drawlib: compression du masque dans les couches, tailles de sprites quelconques, pointeurs far, cadre de clipping paramétrable...
L’utilisateur peut choisir les fonctions qu’il souhaite utiliser dans son programme, pour ne pas avoir à augmenter la taille de son executable avec du code inutilisé. La compilation peut se faire indifferemment avec TurboC ou Digital Mars (Open watcom n’est pas encore supporté).
Toutes les fonctions dessinent uniquement dans un buffer, et jamais directement à l’écran; il faut donc appeler une fonction de raffraichissement pour actualiser l’écran une fois que l’image a été entièrement dessinée en buffers.
Le mode 5 couleurs se contrôle grâce à la fonction gxSetMode(), à laquelle il suffit de passer la valeur “true” (ou 1) pour activer le mode et “false” (ou 0) pour le désactiver. Cette fonction definit le contraste par defaut pour le mode 5 couleurs (paramétrable dans gxlib10.h), ou restaure l’ancien contraste lorsqu’on souhaite le quitter. Il ne faut donc pas se soucier de sauvegarder le contraste au début d’un programme pour le restaurer à la fin.
Attention, ceci est très important: TOUTES les fonctions d’affichage de cette lib ne font QUE du double buffering. C’est-à-dire que toutes les fonctions agiront de manière “invisible” car elles dessinent en dehors de la zone de l’écran: la seule fonction capable de fare apparaitre quelque chose est la fonction gxRefresh() dont le rôle est précisément d’afficher en une seule fois à l’écran tout ce qui a pu être dessiné progressivement en buffers. Ne vous étonnez donc pas si votre écran reste désespérément blanc alors que le mode a bien été activé et que vous appelez des fonctions d’affichage de cette lib: il se peut que vous ayez tout simplement oublié d’appeler gxRefresh() en dernier lieu pour que tout soit copié vers l’écran. ;) Un ordre “classique” d’affichage est donc:
gxClearBuff(); // efface le contenu des buffers gxDrawBmp( monBmp ); // affichage de l'arrière-plan gxSpr_M_C( 20, 10, monSprite ); // affichage d'un sprite ... gxRefresh(); // le sprite et son décor apparaissent a l'écran
Comme leur noms l’indiquent, ces fonctions permettent d’afficher respectivement un point, une ligne horizontale ou verticale, ou de remplir l’écran avec l’une des 5 couleurs ou par inversion des couleurs. Chaque fonction possède une version différente par couleur: pour afficher un pixel par exemple les fonctions gxPixB() (noir), gxPixDG() (gris foncé), gxPixMG() (gris moyen), gxPixLG() (gris clair), gxPixW() (blanc) et gxPixInv() (inversion) sont utilisables, et on peut également appeler gxPixel() en spécifiant la couleur d’affichage grâce aux macros définies dans gxlib10.h (par exemple GX_DARKGRAY pour le gris foncé).
Pensez à consulter la liste des fonctions dans le fichier gxlib10.h!
Il est également possible d’afficher (toujours en buffers) une image 5 couleurs converties avec Sprite Maker, simplement en la passant à la fonction gxDrawBmp().
Les sprites peuvent être facilement dessinés et encodés avec le logiciel « Sprite Maker 2.3 » (reportez-vous au fichier readme de ce prog ;)).
Les 4 fonctions gxSpr_M_C(), gxSpr_M_noC(), gxSpr_noM_C(), gxSpr_noM_noC() permettent de choisir le mode d’affichage d’un sprite, selon que l’on veuille afficher le masque, tenir compte du clipping ou les ignorer l’un ou l’autre.
La fonction gxSprite() peut recevoir le mode d’affichage en paramètres grâce à des macros (comme GX_SPR_MASK_NOCLIP par exemple pour afficher un sprite en appliquant son masque mais sans se soucier du clipping).
Le fichier gxlib10.h possède un ensemble de macros correspondant à chacune des fonctions qu’elle contient:
#define FUNC_GX_REFRESH #define FUNC_GX_DRAWBMP ... #define FUNC_GX_PIXEL ... #define FUNC_GX_SPR_NOM_C #define FUNC_GX_SPR_M_NOC #define FUNC_GX_SPR_NOM_NOC
Chacune de ces lignes correpond à une des fonctions de la lib. Si vous ne souhaitez pas utiliser une de ces fonctions, mettez simplement la ligne correspondante en commentaire (ne la supprimez jamais!!!) et la fonction ne sera pas visible par le compilateur. Si vous souhaitez réutiliser la fonction, il suffit de retirer les commentaires de la ligne.
Notez que les fonctions comme gxPixel() ou gxSprite() qui peuvent recevoir un mode d’affichage en paramètre font en fait simplement un appel vers la fonction correspondant au mode choisi, il faut donc par exemple que la fonction gxPixDG() soit compilée également si on appelle gxPixel() avec GX_DARKGRAY comme paramètre dans le programme.
Mais d’où viennent ces couleurs??
Par défaut, la calculatrice fonctionne en noir et blanc, et la couleur de chaque pixel est représentée par un bit dans la mémoire dont la valeur vaut 1 pour le noir et 0 pour le blanc.
Le mode DB a permis de faire apparaitre une nouvelle couleur en utilisant un deuxième bit, et les combinaisons possibles dont devenues 00 pour le blanc, 11 pour le noir et et 01-10 pour le gris. Malheureusement, ces deux dernières combinaisons donnent la même couleur car le “poids” de chaque bit est identique, donc il n’y en a aucun qui prime sur l’autre pour influencer l’intensité de la couleur du pixel correspondant.
Pour augmenter le nombre de couleurs, il faut donc soit jouer sur le nombre de bits, soit modifier leurs poids respectifs. Comme il est très difficile d’influencer les poids sans générer du clignotement, on cherche plus généralement à augmenter le nombre de bits et donc le nombre de combinaisons possibles. Le problème qui se pose alors est qu’on a du coup plus de données à écrire dans la mémoire pour obtenir une certaine couleur, ce qui peut ralentir fortement toutes les fonctions d’affichage.
Une gamme de 5 couleurs avait déjà été obtenue par tonton1664 en utilisant 4 bits par pixels, ce qui en faisait un mode relativement lent (mais parfois utile pour des images fixes). Le but de cette lib est d’obtenir le même résultat, mais avec 3 bits seulement.
Segments utilisés
gxLib utilise donc 3 segments pour l’écran, et 3 autres segments pour son buffer. Ces segments sont fixes et ne peuvent jamais être modifiés (mais cela ne devrait normalement pas s’avérer nécessaire).
Les segments utilisés sont:
0x1A20 -> 0x1A60 : 1ere couche de l'écran 0x1A60 -> 0x1AA0 : 1ere couche du buffer 0x1AA0 -> 0x1AE0 : 2nde couche de l'écran 0x1A60 -> 0x1B20 : 2nde couche du buffer 0x1B20 -> 0x1B60 : 3eme couche de l'écran 0x1B60 -> 0x1BE0 : 3eme couche du buffer
Superposition des couches
gxLib se base sur le mode DB (qui utilise par défaut les segments 0x1A20 et 0x1AA0 pour l’écran) et le force à alterner régulièrement entre ces deux segments et un troisième, en l’occurence avec 0x1B20. En fait puisque le mode DB fonctionne par paires de segments, on doit ici créer deux paires qu’il faudra alterner, et en l’occurrence on aura (0x1A20,0x1AA0) et (0x1AA0,0x1B20).
On voit donc que le segment 0x1AA0 possèdera un poids double par rapport aux autres puisqu’il apparait deux fois plus souvent (en fait il est affiché en continu tandis que les deux autres apparaissent “une fois sur deux”). C’est sur cette modification du poids des bits que l’on va jouer, mais celle-ci n’est pas gratuite et en l’occurence des clignotements vont apparaître lors du passage d’une paire à l’autre si on ne prend pas certaines mesures.
Si on examine les 8 combinaisons possibles avec nos 3 bits par pixel, et qu’on attribue les poids correspondants à chacun des bits, on peut obtenir le resultat suivant:
couche 1 : 1 1 0 0 1 1 0 0 (*1) couche 2 : 1 1 1 1 0 0 0 0 (*2) couche 3 : 1 0 1 0 1 0 1 0 (*1) ----------------------------------- intensite : 4 3 3 2 2 1 1 0
On voit donc que chaque combinaison de 3 bits donne l’intensité du pixel correspondant sur une échelle de 0 à 4, ce qui nous donne 5 valeurs possibles (et pas 8 comme on aurait pu le penser au départ: pour obtenir une echelle de 0 à 7, les poids auraient du être (1,2,4) et pas (1,2,1) comme nous avons ici).
On peut alors constater les 5 différentes couleurs à l’écran selon les combinaisons que l’on écrit sur les buffers, et remarquer par exemple que les deux combinaisons 110 et 011 donnent bien la même couleur. On peut également voir un certain effet de clignotement, et s’apercevoir justement que ces deux combinaisons “ne clignotent pas de la même facon”.
Si on décompose l’affichage des pixels par la succession des deux paires de bits, on voit qu’on a en fait
110 : 11 (noir) -> 10 (gris) -> 11 (noir) -> 10 (gris) ->... => gris foncé 011 : 01 (gris) -> 11 (noir) -> 01 (gris) -> 11 (noir)-> ... => même gris foncé
par exemple pour deux autres types de combinaisons on a
001 : 00 (blanc) -> 01 (gris) -> 00 (blanc) -> ... => gris clair 000 : 00 (blanc) -> 00 (blanc) -> 00 (blanc) -> ... => blanc
On remarque que pour 110 et 011 la succession des couleurs est la même, mais que lorsque l’une affiche du noir (avec sa paire 11), l’autre affiche du gris (avec sa paire 10 ou 01) et inversément. Ces deux combinaisons sont donc parfaitement complémentaires.
Cette complémentarité va pouvoir être utilisée pour annuler les clignotements d’une couleur: il suffit en fait de mélanger les deux combinaisons pour qu’on ne puisse plus remarquer les passages d’une paire à l’autre. Plutot que d’afficher un rectangle gris clair avec toutes des combinaisons 001 par exemple, on préférera donner à un pixel sur deux la combinaison 001 et à l’autre la combinaison 100. Ceci est bien entendu plus compliqué à mettre en oeuvre, mais donne de très bons résultats. De toute façon, cette lib est là pour faire en sorte que toutes ces combinaisons soient correctement choisies en fonction de ce qu’on veut afficher comme couleur, vous n’aurez donc pas à vous soucier de ça ;)
Intégration du masque dans le code des sprites
Puisque les 8 combinaisons sont utilisées pour afficher les couleurs, il a fallu en sacrifier une pour qu’elle joue le rôle de masque pour les sprites qui en nécéssitent un. Le choix s’est porté sur la combinaison 100 principalement à cause de sa faible intensité. Il est donc possible d’observer un très léger clignotement du gris clair pour les sprites affichés avec leur masque (puisqu’il n’est plus possible d’alterner les combinaisons un pixel sur deux), mais je pense qu’il est réellement insignifiant...
#include "utils.h" #include "gxlib10.h" extern uchar img0[], img1[], img2[]; uchar* images[] = { img0, img1, img2 }; void main() { uchar num=0; bool key=false; inter(0); // desactive l'APO et le clavier gxSetMode(true); // passe en mode 5 couleurs while( !testkey(K_ESC) ) { if(testkey(K_SHIFT)) { if(!key) { num = (num+1)%3; key = true; } } else if(testkey(K_PLUS)) { if(!key) { contplus(); key = true; } } else if(testkey(K_MOINS)) { if(!key) { contmoins(); key = true; } } else key=false; gxClearBuff(); gxDrawBmp( images[num] ); gxRefresh(); } gxSetMode(false); inter(1); } /////////////////////////////////////////////////////////////////////////////////////// uchar img0[] = { 170,62,32,0,42,42,42,42,42,42,42,42,42,42,42,42, 212,55,84,0,85,85,85,85,85,85,85,85,85,85,85,85, 248,34,34,0,42,42,42,42,42,42,42,42,42,42,42,42, 84,81,16,0,85,85,85,85,85,85,85,85,85,85,85,85, 170,168,32,0,42,42,42,42,42,42,42,42,42,42,42,42, 255,93,0,0,85,85,85,85,85,85,85,85,85, ….}
Lib implémenté par Medivh
Les fonctions de cette librairie sont conçues uniquement pour GxLib.
Les lettres sont en majuscule.
Les chiffres affichés sont des entiers signés.
Pour integrer la librairie a votre programme mettez les deux fichiers y correspondant dans le même répertoire que le « main.c », rajouter le fichier « GxString.c » au projet et incluez le fichier « GxString.h ».
void write(int x, int y, char string[]);
Fonction qui écrit une chaîne de caractère à l’aide des sprites de Alphabet[]
void writevalue(int x,int y,int value);
fonction qui affiche une valeur numérique décimale
void gxFillrect(int Ax, int Ay, int Bx, int By, char color);
Efface du texte sans effacer tout le buffer
gxClearBuff (); write(25, 28, "AFFICHAGE DE TEXT"); writevalue(15,18,123); //affichage de 123 gxRefresh (); getch();