La Graphics.Library du Système 2.0 de Spencer Shanson Les différences visibles entre la version 2.0 et les versions précédentes du système d'exploitation sautent aux yeux dès qu'on lance l'Amiga. Finie l'ancienne combinaison de couleurs bleue, orange, noire et blanche, et fini aussi le dessin plat; à leur place, on trouve des gris et des bleus rafraîchissants, des ombres en dégradé, des nouveaux gadgets et, d'une façon générale, un aspect plus professionnel. Sous le lifting d'Intuition et du Workbench se trouvent les différences plus excitantes - les modifications de la graphics.library, qui reçoit le programme qui permet d'avoir toutes ces couleurs, ces affichages, ces lignes et ces icônes, qui l'amène à l'écran et qui crée un autre écran 1/60ème de seconde après en avoir créé un premier. Bien que l'utilisateur moyen soit protégé, les programmeurs apprécieront le travail qui a été fait dans la graphics.library du 2.0. (Notez qu'à partir de maintenant, je ferai référence à la version 2.0 sous l'appellation V37, en relation avec la 1.3 sous l'appellation V35, etc.. La V36 représentait la version alpha et les toutes premières versions béta du 2.0. Quand on ouvrira une bibliothèque système, on devra utiliser la V36 si l'on sait que la caractéristique demandée est disponible dans la V36, autrement on devra utiliser la V37. Il y a très peu de caractéristiques de la V37 qui ne se trouvent pas dans la V36). Chips (but no fish) [NdT : jeu de mots intraduisible. En anglais 'chips' indiques les 'intégrés' et les 'pommes de terre frites'; 'fish', c'est le poisson]. Le but principal de la graphics.library 2.0 était de fournir un support au nouvel Ensemble Amélioré des Circuits de Commodore (ECS). Cet ensemble est constitué de la nouvelle version du circuit d'affichage (Denise) et de celle du circuit chargé du graphisme et du DMA (Agnus). Qu'est-ce qu'il offre de plus ce ECS par rapport aux anciens circuits intégrés ? Agnus peut maintenant fonctionner en mode PAL ou NTSC. Un cavalier sur l'A2000 ou une piste sur un A500 configurent la machine pour que celle-ci, par défaut, se mette en mode PAL ou NTSC, mais on peut passer outre ceci grâce à la partie logicielle de la V37. L'ECS offre aussi un nouveau mode d'affichage qui s'appelle SuperHires, qui donne une résolution double d'un écran en haute résolution (largeur standard 1280 pixels). Cependant, à cause des limitations des DMA, on ne peut lancer ce mode qu'avec deux plans de bits au maximum (quatre couleurs). Tout en fournissant la synchronisation pour les modes NTSC/PAL et SuperHires, le nouveau circuit Denise peut être aussi programmé avec des taux de faisceau variables, c'est-à-dire que Denise peut fournir un mode de type VGA (640x480, non entrelacé) qui s'appelle mode Productivity sur un moniteur multisynchrone. Ces taux de faisceau variables nécessitent aussi le nouveau circuit Agnus, ceci pour la synchronisation du DMA. En outre, le DMA limite le mode Productivity à deux plans de bits. Tout ceci est bien joli, mais le nouvel Agnus fait aussi un pas dans le bon sens en soulageant cette maladie habituelle de "n'avoir que 512Ko de mémoire chip", car il accepte un méga-octet de mémoire chip (ou deux sur un A3000). Maintenant, on peut avoir des dessins, des animations et des échantillons sonores de dimensions plus importantes dans cette précieuse mémoire chip. Pour utiliser la mémoire étendue, Agnus a augmenté la fourchette des opérations de blitting de 1008x1024 à 32000x32000 pixels ! Comme c'est logique, celui-ci élargit sa capacité à dessiner des lignes d'une longueur de 32000 pixels. Denise est responsable de la définition de la fenêtre d'affichage de votre moniteur. (La fenêtre d'affichage est cette partie de l'écran où ont lieu des actions.) Le travail de Denise consiste à prendre les données destinées à l'affichage en provenance d'Agnus, de les mélanger avec les données des lutins et des aires de jeu, de convertir les nombres en valeurs pour le Rouge, le Vert et le Bleu et d'amener le port RVB à votre moniteur. Si cela n'était pas suffisant, Denise s'occupe aussi du genlock. Sous le système 1.3 et antérieurs, Denise était limitée pour ce qui était des dimensions de la fenêtre d'affichage. Horizontalement, celle-ci devait commencer dans les 3/4 gauche de l'affichage et terminer dans le 1/4 à droite. Verticalement, l'affichage devait commencer dans les 2/3 de la partie supérieure et se terminer dans la moitié inférieure. Ces limitations étaient imposées car les Bits Les Plus Significatifs n'étaient pas programmables et qu'ils avaient été programmés une fois pour toutes dans le silicium. Avec l'ECS, on a ajouté un nouveau registre programmable pour remplacer les valeurs codées dans la partie matérielle - par conséquent, fi !, finies les restrictions ! Probablement, la caractéristique la plus intéressante du nouveau circuit Denise, tout particulièrement pour ce qui est du monde de la vidéo, est constituée par les nouveaux modes destinés aux genlocks. L'ancien circuit mettait à 1 une broche dans le port RVB, broche qui s'appelait ZD (Détection du Zéro) quand le circuit tombait sur un pixel mis à la couleur 0 (couleur de l'arrière-plan). Un genlock externe pouvait interroger cette broche et, quand celle-ci était valide, pouvait afficher un signal vidéo (en provenance d'un magnétoscope, d'une caméra vidéo ou d'ailleurs) à la place du signal de l'Amiga normal. C'est la manière dont fonctionne un genlock. Mais, pour certains, le fait de ne pouvoir genlocker que la couleur d'arrière-plan n'était toujours pas suffisant. Ceux-là voulaient avoir la possibilité de genlocker une couleur quelconque de l'écran (ce qu'on appelle le réglage des effets chromatiques) et certains genlocks plus chers incorporaient cette fonction. Le nouveau circuit Denise peut le faire aussi, en outre il pourvoit le recouvrement des plans de bits, de sorte que tout un plan de bits commande le genlocking (pour permettre des effets de type "trou de serrure") et le BorderBlanking crée une "image" transparente qui entoure la zone active. La base de données graphique "Ainsi", vous vous dites, "voici ce que fait la partie matérielle du nouvel ensemble de circuits. Comment vais-je pouvoir créer des logiciels d'application capables d'utiliser ces nouvelles fonctions ?". Comme avant, vous pouvez déterminer la quantité de mémoire chip disponible en faisant appel à AvailMem(MEMF_CHIP) Votre programme devrait être capable de gérer les nouvelles dimensions (possibles). Les dimensions d'un blit sont un problème différent. Selon la tradition des valeurs choisies implicitement ("les blits sont toujours de 1Kox1Ko"), nous pourrions facilement supposer que "si une machine possède un circuit Agnus de type ECS, nous pouvons faire des blits de 32Kx32K". Nous pourrions, mais nous ne devrons pas. Ce qui sera le cas si Commodore sort une autre version d'Agnus qui accepte des blits même plus importants. Devra-t-on supposer qu'il faudra utiliser une autre suite de valeurs codées par voie matérielle ? Pour diminuer l'importance de ce problème (et de beaucoup d'autres) la graphics.library V37 a une base de données graphique qui renferme des informations sur les dimensions, les moniteurs et l'affichage de chaque mode d'affichage connu. Avant la version V37, on mettait en place les modes d'affichage dans le champ Viewport->Modes, d'une largeur de 16 bits (un MOT). Ce champ perdait joliment ses moyens, tout particulièrement à cause des nécessités des nouveaux modes (SUPERHIRES) et de plusieurs type de moniteurs (PAL, NTSC, VGA). Par conséquent, chaque mode d'affichage de la version V37 possède une valeur 32 bits DisplayID associée (un MOT LONG). Le MOT le plus à gauche renferme le numéro du type du moniteur, tandis que le mot le plus à droite définit les différents modes du moniteur. Pour la compatibilité avec les logiciels existants, si le mot le plus à gauche du MOT LONG associé à DisplayID est égal à 0, alors on choisit implicitement le moniteur "par défaut" (NTSC ou PAL, selon la configuration de votre Amiga). Les valeurs pour le numéro des moniteurs et pour DisplayID sont définies dans un nouveau fichier en-tête, graphics/display.info.h. On peut trouver le DisplayID d'un Viewport en se servant de la nouvelle fonction graphique de la version V37 : ULONG GetVPModeID(struct ViewPort *vp). Pour rester compatible avec les révisions à venir du SE, à partir de maintenant, vous devriez employer cette fonction au lieu de Viewport->Modes. En outre, pour les erreurs, il faudra s'assurer de tester la valeur retournée avec INVALID_ID (dans graphics/display.info.h). Lorsque vous êtes en possession de cet ID, vous avez la possibilité de vous en servir pour lire des informations dans la base de données. Quatre types d'informations sont disponibles -Moniteur, Dimension, Nom et Affichage- et chacune d'elles renferme des informations similaires à celles de l'exemple suivant (qui est fait pour le mode NTSC en mode entrelacé) : *** Mode 0x00019004 *** Name : NTSC:Hires-Interlaced MonitorInfo { ViewPosition = (0x73, 0x2C) = (115, 44) ViewResolution = (0x2C, 0x34) = (44, 52) (battements par pixel) ViewPositionRange Rectangle (fixe, dépend du matériel) = (0x5D, 0x15) - (0x88, 0x3F) = (93,21) - (136,63) TotalRows = 0x106 = 262 TotalColorCycles = 0xE2 = 226 MinRow = 0x15 = 21 Compatibility = 0x0 = MCOMPAT_MIXED (peut partager l'affichage avec d'autres modes MCOMPAT_MIXED) } DimensionInfo { MaxDepth = 0x4 /* Nombre de plans de bits acceptés */ MinRasterWidth = 0x20 = 32 pixels MinRasterHeigth = 0x1 = 1 pixel MaxRasterWidth = 0x3FF0 = 16368 pixels /* déterminé par le type d'Agnus */ MaxRasterHeight = 0x4000 = 16384 pixels /* déterminé par le type d'Agnus */ NominalRectangle (Dimensions standard) = (0x0, 0x0) - (0x27F, 0x18F) = (0, 0) - (639, 399) MaxOScan Rectangle (fixe, dépend du matériel) = (0xFFFFFFD4, 0xFFFFFFD2) - (0x2A7, 0x1B3) = (-44, -46) - (679, 435) VideoOScan Rectangle (fixe, dépend du matériel) = (0xFFFFFFD4, 0xFFFFFFD2) - (0x2B3, 0x1B3) = (-44, -46) - (691, 435) TxtOScan Rectangle (on peut l'éditer par les Preferences) = (0x0, 0x0) - (0x2A7, 0x18F) = (0, 0) - (679, 399) StdOScan Rectangle (on peut l'éditer par les Preferences) = (0xFFFFFFF8, 0x0) - (0x2A7, 0x18F) = (-8, 0) - (679, 399) } DisplayInfo { NotAvalaible = 0x0 /* si différent de 0, on ne peut disposer * de ce mode, si, par exemple, ce mode * nécessite les circuits ECS et que l'Amiga * ne les a pas. On peut déterminer la * disponibilité d'un mode avec la fonction * ModeNotAvalaible() */ PropertyFlags = 0xBC1 LACE SPRITES GENLOCK WB DRAGGABLE BEAMSYNC Resolution = (0x16) - (22, 26) (battements par pixel) PixelSpeed = 0x46ns = 70ns NumStdSprites = 8 PaletteRange = 0x1000 = 4096 SpriteResolution = (0x2C, 0x34) = (44, 52) (battement du lutin par pixel) } Comme vous pouvez le voir, les informations concernant chacun des modes possibles sont assez considérables. (Note : maintenant, la version V37 pourvoit le support de l'overscan par le SE). On peut avoir accès à la base de données par un DisplayInfoHandle. D'abord, cherchons le pointeur : handle = FindDisplayInfo(ULONG DisplayID). Maintenant, passons le pointeur à ULONG GetDisplayInfoData(DisplayInfoHandle handle, UBYTE *buf, ULONG size, ULONG tagID, [ULONG id]). Cette fonction a besoin du pointeur, d'un pointeur sur un tampon, du nombre d'octets qui sont à copier de la base de données dans le tampon et d'un identificateur pour le type d'information demandée. Alternativement, on peut lui passer comme pointeur une valeur NULL avec une valeur pour DisplayID. Pour répéter l'opération dans toute la base de données des modes connus, utiliser : ULONG NextDisplay(ULONG DisplayID) A titre d'exemple, pour montrer comment tout ceci fonctionne, le programme ci-dessous affiche la profondeur maximale (les plans de bits) acceptée par chaque mode d'affichage connu : #include #include struct GfxBase *GfxBase; void main() { APTR buf; ULONG ID = INVALID_ID; if (GfxBase = OpenLibrary("graphics.library",36)) /* la version V36 est la première du KS2.0 */ { if(buf = AllocMem(MAX(sizeof(struct DimensionInfo), sizeof (struct NameInfo)), MEMF_CLEAR)) { while((ID = NextDisplayInfo(ID)) != INVALID_ID) { /* Répéter l'opération pour chaque ID connu */ printf("ID 0x%lx ",ID); if(GetDisplayInfodata(NULL,buf,sizeof(struct NameInfo), DTAG_NAME, ID)) { printf("Name - %s, ",((struct NameInfo *) buf->Name); } if(GetDisplayInfodata(NULL,buf,sizeof(struct DimensionInfo), DTAG_SIMS,ID)) { printf("MaxDepth = %ld\n", ((struct DimensionInfo *) buf)->MaxDepth); } } FreeMem(buf, MAX(sizeof(struct DimensionInfo), sizeof(struct NameInfo))); } CloseLibrary(GfxBase); } } Genlocks et effets trous de serrure Toutes les nouvelles informations concernant les genlocks sont entreposées dans une structure ColorMap et peuvent être commandées par l'intermédiaire de la nouvelle fonction VideoControl(). Etant donné que la ColorMap a augmenté et que les versions futures vont probablement augmenter aussi, il faudra vous emparer et libérer la structure ColorMap en faisant appel aux fonctions GetColorMap() et FreeColormap(). Ces fonctions graphiques connaissent exactement la taille de la structure ColorMap pour une numéro de version donnée du Kickstart. Une ColorMap est associée à un ViewPort, il vous est ainsi possible d'employer VideoControl() pour altérer le mode pour le genlock sur une base de ViewPort-après-Viewport. VideoControl() demande une structure Colormap, ainsi qu'un pointeur sur une TagList : ULONG VideoControl(struct ColorMap *cm, struct TagItem *ti); La TagList est une liste d'instructions pour VideoControl() à exécuter sur la ColorMap. Certaines de ces instructions ont besoin de données supplémentaires et certaines de celles-ci sont des valeurs booléennes. Après avoir reçu la TagList, VideoControl() a la possibilité de l'altérer. A titre de démonstration, la routine ci-dessous détermine si la spécification BorderBlank du genlock est validée pour la ColorMap courante et valide la ChromaKey pour la couleur 3. Tous les tags sont définis dans le fichier graphics/videocontrol.h. (Pour une discusion générale sur les tags, voyez "Digging Deep in the OS", p.8.) ULONG GenlockStuff(struct ColorMap *cm) { #define TAG_COUNT 3 /* # d'instructions à passer à VideoControl() */ struct tagItem *ti; ULONG result = 1; if (ti = (struct TagItem*)AllocMem((sizeof(struct TagItem) * TAG_COUNT), 0)) { ti[0].ti_Tag = VTAG_BORDERBLANK_GET;ti[0].ti_Data = NULL; ti[1].ti_Tag = VTAG_CHROMA_PEN_SET;ti[1].ti_Data = 3; ti[2].ti_Tag = VTAG_END_CM;ti[2].ti_Data = NULL; /* indique la fin de TagList */ /* maintenant la Taglist est en place, la passer à VideoControl(). * Une valeur en retour différente de NULL indique une erreur - soit * une ColorMap non valide (d'un type qui précède la version V36), * soit une liste tags non valide * * on changera ti[0].Tag soit en VTAG_BORDERBLANK_SET * soit en * VTAG_BORDERBLANK_CLR, en rapport avec le réglage. */ if(result = VideoControl(cm, ti)) == NULL) { printf("BorderBlank is %s\n", ti[0].ti_Tag == VTAG_BORDERBLANK_SET ? "Set:" : "Clear"); } else { printf("VideoControl() error\n"); } FreeMem(ti, sizeof(struct TagItem) * TAG_COUNT); } else { printf("Could not allocate memory\n"); } return(result); } On a aussi la possibilité de commander d'autres aspects de la ColorMap (et par conséquent du ViewPort) par l'intermédiaire de VideoControl(). Par exemple, comme tous ceux qui ont utilisé des UserCopperLists le savent, ces listes "s'échappent" dans les autres écrans si on déplace ces derniers vers le bas. A titre d'exemple, regardez le comportement de PhotonPaint : mettez ce dernier derrière tous les autres écrans, déplacez ensuite vers le bas l'un des écrans qui se trouvent à l'avant, pour pouvoir apercevoir la partie supérieure de l'écran de PhotonPaint. Avec VideoControl(), vous pouvez maintenant mettre en route le "découpage des UserCopperLists" et arrêter la fuite. L'overscan - l'effet vidéo de mur-à-mur Avec VideoControl(), on peut aussi mettre en place un DisplayClip des ViewPorts. Un DisplayClip est une partie de ViewPort d'un seul tenant qui a la capacité de définir des surfaces plus grandes que celles de la partie standard. L'effet de cette spécification est connu sous le nom d'overscan. Ce dernier est utilisé par plusieurs applications, tout particulièrement par les progiciels de dessin, pour augmenter la surface de travail. Il est aussi utile -si l'on envoie la sortie de l'Amiga sur un magnétoscope- pour réduire la surface de suppression d'affichage dans le View et créer un effet de mur-à-mur. Toutefois, avant la version V37, les applications ne permettaient l'overscan qu'en employant une grand nombre d'astuces peu pratiques car le SE ne fournissait aucun support direct. Certains de ces trucs fonctionnent encore avec la version V37, mais on n'aura pas d'excuse si on continue à les employer. Rendez le travail aisé pour vous et pour les autres programmeurs - appliquez les règles du jeu du système 2.0. Pour pouvoir employer le DisplayClip, on se devait d'étendre la structure ViewPort. Il n'y avait pas de grosse ficelle. Physiquement, il n'était pas possible d'agrandir le ViewPort car Intuition a un rappel de la structure ViewPort dans sa structure Screen - le fait d'agrandir la structure aurait entraîné le changement des offsets de plusieurs données dans la structure Screen et aurait rendu impossible l'utilisation de tous les logiciels édités jusqu'à maintenant pour l'Amiga ! Par conséquent, on a créé une structure ViewPortExtra qu'on a relié de façon "magique", par l'intermédiaire du SE, à sa structure ViewPort associée. Pour saisir une structure ViewPortExtra, appelez la fonction GfxNew() de la version V37 : struct ExtendedNodes *GfxNew(ULONG node_type); Par exemple : struct ViewPortExtra *vpe = (struct ViewPortExtra *) GfxNew (VIEWPORT_EXTRA_TYPE); La structure ViewPortExtra (comme ViewExtra) possède dans son en-tête une structure ExtendedNode, d'où la conversion de type. Ces types sont définis dans graphics/gfxnodes.h. Etant donné qu'à l'avenir on pourra étendre la structure ViewPortExtra, il vous faudra dès maintenant employer la fonction GfxNew() pour réserver l'une de ces structures et vous assurer ainsi que vos programmes soient compatibles avec les version futures du SE. Quand vous en aurez fini avec la structure, vous devrez rendre la mémoire au système par l'intermédiaire de la fonction GfxFree() : void GfxFree(struct ExtendedNodes *en); Ainsi, maintenant que vous avez une structure ViewPortExtra, vous pouvez définir un DisplayClip. Celui-ci est tout simplement un rectangle, défini par le coin supérieur gauche et le coin inférieur droit, en utilisant les unités du mode ViewPort. En d'autres termes, les unités sont en pixels LORES pour un ViewPort LORES et en pixels HIRES pour un ViewPort HIRES, et ainsi de suite. L'origine du rectangle est la position d'origine du View du graphisme. Si vous donnez un autre coup d'oeil aux spécifications de la base de données, vous verrez que DimensionInfo possède cinq types de rectangles définis : Nominal, MaxOScan, VideoOScan, TxtOScan et StdOScan. Nominal est le DisplayClip standard de ce mode, d'une dimension égale à 320x200 pour un ViewPort en LORES non entrelacé. MaxOScan est le plus grand DisplayClip pouvant être géré par voie logicielle, tandis que VideoOScan est le plus grand DisplayClip pouvant être géré par voie matérielle. TxtOScan est le DisplayClip dans lequel tous les textes dont on aura fait le rendu seront visibles. StdOScan est la partie qui s'étend à la portée de votre moniteur. Il est possible de modifier TxtOScan et StdOScan grâce à l'éditeur de préférences Overscan du Workbench 2.0. Si vous souhaitez que votre application s'ouvre avec un TxtOScan destiné à l'utilisateur avec un ViewPort en HIRES, interrogez d'abord la base de données. Copiez ensuite le rectangle TxtOScan qui a été copié dans le tampon que vous avez passé par la fonction GetDisplayInfoData() dans le rectangle de ViewPortExtra->DisplayClip. Après, associez ce ViewPortExtra à son ViewPort et répétez le processus en utilisant VideoControl() avec le tag VTAG_VIEWPORTEXTRA_SET. Notez qu'on n'est aucunement obligé de se servir d'un DisplayClip pré-défini; on a la possibilité d'en créer un de son choix, mais un DisplayClip plus grand que MaxOScan est dangereux ! Le Copper ? Je dirai que je le connais à peine Le Copper (co-processeur) est un simple processeur qui ne comprend que trois types d'instructions : MOVE, WAIT et SKIP. Il a la capacité d'attendre (WAIT) tant que le faisceau vidéo -qui balaie l'affichage- n'aura pas atteint au moins une certaine position, et ensuite de transférer (MOVE) des données dans les registres du circuit spécialisé qui font de l'Amiga un ordinateur différent de tous les autres, dans des registres tels que les pointeurs de plans de bits et ceux qui commandent le mode d'affichage. C'est ce processeur qui permet à l'Amiga d'afficher en même temps à l'écran des modes différents (quand vous faites glisser les écrans). Comme tous les autres processeurs, celui-ci exécute une liste d'instructions. Beaucoup de jeux utilisent leurs propres listes Copper pour afficher leurs choses, mais certains aiment "emprunter" et corrompre les listes Copper des graphismes. La plupart du temps, ces jeux s'en sortent avec cela, mais il y a certains jeux qui font des suppositions erronées sur les listes Copper des graphismes. Les auteurs de ces programmes sont partis du principe qu'étant donné que le format des listes Copper n'avait pas changé dans les premières versions du SE les listes ne changeraient pas à l'avenir. Ils avaient tort ! Le format des listes Copper a considérablement changé entre la version V35 et la V37. Les logiciels qui s'attendent à ce que certaines instructions Copper se trouvent toujours à certains offsets au début de la liste se bloquent avec la version V37. D'autres programmes partent du principe que les listes Copper chargent toujours certains registres des circuits avec des données de même valeur et, par conséquent, finissent par ne jamais charger ces registres. Ces programmes aussi se bloquent. Avec les listes Copper, il ne faut partir d'aucun principe implicite. Ces listes ont changé dans le passé et sont sujettes à changer à l'avenir. Notez bien le commentaire présent dans graphics/copper.h : /* private graphics data structure */ [NdT : /* structure de données graphiques privée */] Si vous avez besoin d'utiliser les listes Copper du système, mettez en place vos propres UserCopperLists, en vous servant des macros de la graphics.library -CINIT, CMOVE, CWAIT et CEND- qui sont définies dans graphics/gfxmacros.h. Des exemples d'utilisation sont des trucs tels que SlicedHAM (SHAM) et DynamicHiRes qui permettent d'avoir plus de couleurs à l'écran simultanément en modifiant la palette de couleurs à chaque ligne. Texte (très approprié !) On a ajouté quelques nouvelles fonctions dans le module Text de la graphics.library pour aider à ajuster un texte dans une zone bien définie. Gardez en mémoire que, dans la version V37, la fonte par défaut peut avoir une taille quelconque (comme celle mise en place avec les préférences texte); il n'est pas possible de choisir implicitement quoique ce soit sur la fonte dont l'application fera le rendu tant qu'on n'aura pas indiqué une fonte bien déterminée dans le programme. Le problème avec l'ancienne fonction TextLength() était que la valeur qu'on recevait en retour n'indiquait pas le nombre de pixels avec lesquels on faisait le rendu de la fonte, mais la valeur qu'on ajoutait à celle de RastPort->cp_x. Si, par exemple, vous faisiez le rendu du texte "Salut" dans un rastport et qu'ensuite vous vouliez l'effacer, vous auriez pu utiliser TextLength() pour déterminer le nombre de pixels de la chaîne de caractères et effacer le texte en employant le résultat. Toutefois, si l'on avait fait le rendu du texte en italique, la valeur retournée par TextLength() (qui est la valeur ajoutée à RastPort->cp_x) aurait dû être inférieure au nombre réel de pixels utilisés pour faire le rendu de la chaîne. La nouvelle fonction TextExtent() de la version V37 cherche le "cadre qui entoure" une chaîne de texte, si on lui fournit la taille de la fonte et les attributs du texte (gras, italique, souligné et ainsi de suite) : void TextExtent(struct Rastport *rp, STRPTR string, WORD count, struct TextExtent *te); Cette fonction a besoin du RastPort, d'un pointeur sur une chaîne, du nombre de caractères de la chaîne elle-même et d'un pointeur sur une structure TextExtent, qui sera remplie par la fonction pour donner le résultat. La nouvelle structure TextExtent est définie dans graphics/text.h et contient ce qui suit (d'après les AutoDocs de Commodore) : te_Width - Identique au résultat de TextLength() : la progression rp_cp_x que le rendu du texte devrait provoquer. te_Height - Identique à tf_YSize. Hauteur de la fonte. te_Extent.MinX - Offset par rapport au coin gauche du rectangle où se fera le rendu du texte. Souvent 0. te_Extent.MinY - Identique à -tf_Baseline. Offset de la ligne de base à la partie supérieure du rectangle où se fera le rendu. te_Extent.MaxX - Offset par rapport au coin droit du rectangle où se fera le rendu du texte. Souvent identique à te_Width-1. te_Extent.MaxY - Identique à tf_YSize-tf_Baseline-1. Offset de la ligne de base à la partie inférieure du rectangle où se fera le rendu. Une autre caractéristique qui manque dans les précédentes versions du SE est une fonction qui permette de déterminer combien de caractères d'une chaîne s'ajusteraient à l'intérieur d'une surface déterminée. La routine TextFit() pallie à ce problème dans la version V37. Cette fonction aussi remplit une structure TextExtent : ULONG TextFit(struct RastPort *rp, STRPTR string, UWORD strlength, struct TextExtent *te, struct TextExtent *constraining_te, WORD strdirection, UWORD constraining_BitWidth, UWORD constraining_BitHeight); Constraining_te est l'étendue du texte que le texte doit ajuster. Si celle-ci est NULL, alors constraining_BitWidth/Height définit l'étendue du texte à sa place. Strdirection peut être égale à 1 ou à -1. Si la valeur est égale à 1, la chaîne est ancrée dans la partie gauche du cadre. Si la valeur est égale à -1, la chaîne est ancrée dans la partie droite du cadre et le pointeur sur cette chaîne devrait pointer sur le dernier caractère de la chaîne. Le fragment de programme brut ci-dessous affiche les n premières lettres de l'alphabet qui s'ajusteront dans un cadre d'une largeur de 200 pixels et d'une hauteur de 100, pour une fonte et un style donnés du rasport. Notez qu'aucun caractère ne s'ajustera dans le cadre, si la fonte a une hauteur supérieure à 100 pixels. void alphabet(struct RastPort *rp) { #define STRING "abcdefghijklmnopqtstuvwxyz" #define LENGTH strlen(STRING) #define WIDTH 200 #define HEIGHT 100 struct TextExtent *te; ULONG count; if(te=AllocMem(sizeof(struct TextExtent), MEMF_CLEAR)) { count = TextFit(rp, STRING, LENGTH, te, NULL, 1, WIDTH, HEIGTH); if (count) { Move(rp,0,HEIGHT); Text(rp,STRING,count); } FreeMem(te,sizeof(struct TextEXtent)); } } Fontes Avant la version V37, si l'on essayait d'ouvrir une fonte et que la taille voulue n'était pas disponible, alors l'ouverture échouait. Avec la version V37, la taille de la fonte indiquée sera créée (réduite) à partir de la taille définie la plus proche possible. Par conséquent, votre application devra être prête à gérer des fontes de toutes sortes. La routine qui réalise la réduction effective s'appelle BitMapScale() et peut être employée par vos applications. Pour la description de la structure utilisée par cette routine, regardez dans graphics/scale.h. Pour un exemple d'utilisation et des précisions sur les bogues et les limitations connues, regardez dans le tiroir Shanson de la disquette. Pour finir, dans la version V37, la structure TextFont avait besoin d'être étendue. Etant donné que beaucoup d'applications utilisent des structures TextFont imbriquées dans leur programme, telles que struct TextFont myTextFont la structure ne pouvait être interrompue sans rendre inutilisables beaucoup de logiciels existant. Ainsi, à chaque fois qu'on appelle OpenFont(), le système crée une nouvelle TextFontExtension et la relie de façon magique à la structure TextFont qu'il a retournée. La structure TextFontExtension est supprimée lors de l'appel à CloseFont(). Certaines applications, toutefois, utilisent leurs propres fontes programmées de manière physique qu'on n'ouvre jamais par OpenFont(); dans ce cas aussi le système crée une structure TextFontExtension lorsqu'on appelle SetFont pour cette fonte. Ceci crée un problème. La système a réservé la mémoire pour la nouvelle structure mais n'a aucune possibilité de savoir quand il devra rendre cette mémoire car la fonte n'est jamais fermée. Par conséquent, tous les anciens logiciels, ayant leurs propres fontes imbriquées, codées à volonté, font perdre 24 octets au système à chaque fois qu'ils sont lancés. Il existe une fonction, StripFont(), qui supprime la TextFontExtension mais naturellement les anciens logiciels ne l'emploient pas. Moralité de l'histoire : ne définissez pas des répliques des structures graphiques du système dans vos programmes. Si une fonction existe pour créer une structure, comme GfxNew() ou GetColorMap(), alors employez-la; autrement servez-vous d'AllocMem(). A l'avenir, cela rendra notre vie plus facile chez Commodore. Vous avez la console Nous espérons que vous aimez le résultat final du 2.0. Avec ses nouvelles caractéristiques et sa stabilité, la bibliothèque graphique a été fortement améliorée. En réalité, tout le Kickstart est maintenant beaucoup plus stable par rapport aux versions précédentes. Il existe un tas de spécificités graphiques nouvelles pour rendre plus aisée l'écriture d'un programme et le rendre plus attirant. Servez-vous de la base de données et prenez bien note de tout ce qui est marqué privé !