Obligement - L'Amiga au maximum

Mardi 03 juin 2025 - 20:41  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Programmation graphique système - 2e partie : allouer une palette de couleurs
(Article écrit par l'équipe de GuruMed et extrait de GuruMed.net - juillet 2002)


Nous avons vu dans le premier article de cette série comment ouvrir une fenêtre. Vous avez peut-être essayé d'utiliser quelques fonctions de la graphics.library pour écrire dedans... et remarqué que SetAPen() ne permet que de choisir un "pinceau" (pen) parmi la palette actuelle du Workbench. C'est très limitatif, puisqu'on ne maîtrise absolument pas cette palette ! Au mieux, on peut tabler sur du gris dans le pinceau 0, du noir en 1 et du blanc en 2...

Heureusement, AmigaOS 3.0 a apporté des fonctions supplémentaires pour modifier proprement la palette de tout écran public tel que le Workbench.

Allouer un pinceau de couleur

La fonction ObtainBestPen() de la graphics.library permet d'obtenir un pinceau, c'est-à-dire un emplacement dans la palette, de la couleur que l'on désire.

D'après les AutoDocs, ObtainBestPen() s'utilise de cette façon :

color = ObtainBestPen(cm,r,g,b,tags....);

Avec :
  • color : numéro de pinceau (entre 0 et 255) ou -1 si échec.
  • cm : pointeur sur une structure ColorMap.
  • r : quantité de rouge (fraction 32 bits justifiée à gauche).
  • g : quantité de vert (fraction 32 bits justifiée à gauche).
  • b : quantité de bleu (fraction 32 bits justifiée à gauche).
  • tags : balises spécifiant les réglages de la sélection du pinceau.
Le principe d'ObtainBestPen() est le suivant : si un pinceau de la palette actuelle contient déjà la couleur demandée (couleur plus ou moins approximative selon les réglages passés dans les balises), alors ce pinceau sera fourni en valeur de retour. Sinon, s'il reste de la place dans la palette, un nouveau pinceau de la couleur demandée sera créé. S'il ne reste pas de place, le pinceau de la couleur la plus approchante sera choisi.

Procédons par ordre. Il nous faut d'abord une structure ColorMap. Par chance, toute structure ViewPort contient justement un pointeur vers une ColorMap. Par miracle, tout écran Intuition contient une structure ViewPort ! Et comme on a vraiment beaucoup de veine, chaque fenêtre est également associée à un écran Intuition :-). Nous avons donc tout ce qu'il faut sous la main.

Dans intuition/intuition.h, struct Window, on peut lire :

   struct Screen *WScreen;             /* this Window's Screen */

Dans intuition/screens.h, struct Screen :

   struct ViewPort ViewPort;           /* describing the Screen's display */

Et enfin, dans graphics/view.h, struct ViewPort :

   struct  ColorMap *ColorMap;     /* table of colors for this viewport */

Ceci nous permet d'écrire les lignes suivantes :

   struct ColorMap *cm;

   cm = win->WScreen->ViewPort.ColorMap;

Ensuite, les valeurs de rouge, vert et bleu. Elles sont encodées chacune sur 32 bits, ce qui nous laisse une certaine marge puisque actuellement aucune carte graphique (grand public) ne gère plus de 8 bits par composante à ma connaissance.

Si vous voulez obtenir une couleur quelconque R,G,B (avec R, G et B compris chacun entre 0 et 255 inclus), voici comment calculer les valeurs de r, g et b à passer à ObtainBestPen() :

   ULONG r,g,b;

   r = ( R<<24 ) | ( R<<16 ) | ( R<<8 ) | R;

   g = ( G<<24 ) | ( G<<16 ) | ( G<<8 ) | G;

   b = ( B<<24 ) | ( B<<16 ) | ( B<<8 ) | B;

En dernier viennent les balises :
  • OBP_Precision détermine la précision souhaitée de la correspondance entre la couleur demandée et la couleur obtenue. Les valeurs possibles sont PRECISION_GUI, PRECISION_ICON, PRECISION_IMAGE et PRECISION_EXACT. PRECISION_GUI sert pour les dessins dont la couleur exacte n'a que peu d'importance, tandis que PRECISION_EXACT permet d'obtenir la couleur la plus proche que possible de la couleur demandée. La valeur par défaut est PRECISION_IMAGE.
  • OBP_FailIfBad, s'il est positionné sur "TRUE", demande à ce qu'ObtainBestPen() échoue s'il est impossible d'allouer une couleur dans la précision souhaitée, au lieu de retourner la couleur la plus proche. Vous n'en aurez probablement pas besoin.
Ces balises sont donc optionnelles, les valeurs par défaut convenant à la plupart des usages.

Tout est maintenant prêt pour tracer une jolie ligne rouge dans notre fenêtre. Reprenons le source du premier article en y intégrant le code nécessaire :

#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/graphics.h>      // pour ObtainBestPen(), ReleasePen(),
                                 // SetAPen(), Move() et Draw()
#include <proto/intuition.h>
#include <stdio.h>

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

int main(void)
{
   struct Window *win=NULL;
   LONG redPen;
   struct ColorMap *cm;
   ULONG r,g,b;

   IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", 36 );
   if( !IntuitionBase ) {
      puts( "Impossible d'ouvrir intuition.library v36." );
      return 20;
   }

   GfxBase = (struct GfxBase *) OpenLibrary( "graphics.library", 39 );
   if( !GfxBase ) {
      puts( "Impossible d'ouvrir graphics.library v39." );
      CloseLibrary( (struct Library *) IntuitionBase );
      return 20;
   }

   win = OpenWindowTags( NULL,
            WA_Title,       (ULONG)"Pouet",
            WA_InnerWidth,  320,
            WA_InnerHeight, 240,
            WA_DragBar,     TRUE,
            WA_CloseGadget, TRUE,
            WA_DepthGadget, TRUE,
            WA_IDCMP,       IDCMP_CLOSEWINDOW,
            TAG_END );

   if( !win ) {
      puts( "Impossible d'ouvrir la fenêtre." );
      CloseLibrary( (struct Library *) IntuitionBase );
      CloseLibrary( (struct Library *) GfxBase );
      return 10;
   }

   cm = win->WScreen->ViewPort.ColorMap;
   r = 255<<24 | 255<<16 | 255<<8 | 255;
   g =   0<<24 |   0<<16 |   0<<8 |   0;
   b =   0<<24 |   0<<16 |   0<<8 |   0;

   redPen = ObtainBestPen( cm, r, g, b, TAG_END );

   if( redPen == -1 ) {
      puts( "Impossible d'allouer un pinceau !" );
      CloseWindow( win );
      CloseLibrary( (struct Library *) IntuitionBase );
      CloseLibrary( (struct Library *) GfxBase );
      return 10;
   }

   SetAPen( win->RPort, redPen );
   Move( win->RPort, 0, 239 );
   Draw( win->RPort, 319, 0 );

   WaitPort( win->UserPort );

   ReleasePen( cm, redPen );
   CloseWindow( win );
   CloseLibrary( (struct Library *) IntuitionBase );
   CloseLibrary( (struct Library *) GfxBase );

   return 0;
}

Je ne vais pas rentrer dans les détails en ce qui concerne l'ouverture et la fermeture de la graphics.library, ainsi que la libération des ressources en cas d'échec, puisque le principe est exactement le même que dans le source précédent.

Ceci nous amène directement à la ligne :

redPen = ObtainBestPen( cm, r, g, b, TAG_END );

Rien de spécial puisque tout a déjà été expliqué plus haut. La seule chose à noter est qu'aucune balise n'a été spécifiée : seule TAG_END a donc été écrite à l'emplacement de la liste des balises.

Ensuite, on teste si l'allocation a réussi. Normalement, il devrait être impossible qu'elle échoue sur l'écran du Workbench, mais on ne sait jamais.

SetAPen( win->RPort, redPen );

Allouer un pinceau, c'est bien, mais il faut encore le sélectionner pour tracer avec ! C'est à ça que sert SetAPen(). On lui donne le RastPort de la fenêtre en premier argument, et le pinceau obtenu avec ObtainBestPen() en second. Par la suite, toutes les opérations de tracé (basiques) utiliseront cette couleur.

Move( win->RPort, 0, 239 );

Move() déplace le "curseur" de tracé vers la position spécifiée en 2e et 3e arguments. Les opérations de tracé suivantes commenceront donc en (0,239) (sachant que (0,0) est l'angle supérieur gauche de la fenêtre).

Draw( win->RPort, 319, 0 );

Draw() trace une ligne allant de la position du curseur jusqu'à celle passée en arguments. Ici, on trace donc une ligne rouge allant de (0,239) à (319,0).

ReleasePen( cm, redPen );

Une fois qu'on a fini d'utiliser le pinceau, il faut le libérer. C'est ce à quoi sert ReleasePen().

Voilà. Si vous essayez ce programme, vous vous apercevrez que le segment est tracé en partie sur la bordure de la fenêtre, et non pas bien comme il faut dans la zone à l'intérieur de la fenêtre. La raison est tout simplement que les coordonnées que l'on donne à Move(), Draw(), etc. sont relatives au bord supérieur gauche de la fenêtre, bordures incluses !

Il existe deux solutions pour remédier à cela :

1. Rajouter la taille des bordures de la fenêtre à toutes les coordonnées

La structure Window renferme quatre champs contenant la taille des bordures :

   BYTE BorderLeft, BorderTop, BorderRight, BorderBottom;

Il suffit donc de rajouter "BorderLeft" à toutes les coordonnées horizontales et "BorderTop" à toutes les coordonnées verticales :

   Move( win->RPort, win->BorderLeft+0, win->BorderTop+239 );

   Draw( win->RPort, win->BorderLeft+319, win->BorderTop+0 );

2. Utiliser la balise WA_GimmeZeroZero à l'ouverture de la fenêtre

Utiliser cette option signifie que l'on souhaite que les coordonnées soient relatives à l'intérieur de la fenêtre. De plus, les opérations de tracé seront coupées sur les bordures de la fenêtre ; il est donc impossible d'écrire sur la bordure d'une fenêtre GimmeZeroZero.

C'est en quelque sorte la solution de facilité, mais il semblerait que les performances soient moindres lorsqu'on utilise des fenêtres de ce type. En tout cas, c'est ce qu'on m'a dit :-) (NDHenes : oui, utiliser GimmeZeroZero, c'est mal, les députés prévoient une loi l'interdisant). De plus, cela consomme plus de mémoire (comme expliqué dans le fichier d'inclusion intuition/intuition.h juste avant les champs BorderLeft, BorderTop, etc.).

Vous connaissez maintenant l'essentiel pour dessiner en couleur dans une fenêtre du Workbench. La prochaine fois, nous verrons le tracé de graphiques au format chunky.


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]