|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
A chacun son village Vingt tours de tatami et cinquante pompes, c'était la punition à laquelle j'avais droit tous les mercredis soir à cause de mes retards répétés à l'entraînement de judo. Et tout ça parce que je n'arrivais pas à me résoudre à partir de chez moi avant la fin de la série télé : Le Prisonnier. J'étais moi aussi prisonnier de cette envie irrésistible de vouloir savoir comment il allait pouvoir s'échapper. Si le doute était un pays, Patrick McGoohan, alias numéro 6, ne saurait sur une carte le pointer du doigt. Durant ce générique, l'allure déterminée et avec des flammes dans les yeux, il n'avait de cesse de progresser encore et encore, avec cette volonté de fer qui ne laissait planer aucun doute : tôt ou tard, il finirait par s'échapper de cette prison qu'on appelle le village. Une très vieille série télé mais tout de même, ce qui frappe c'est sa modernité, le choix des thèmes abordés sont plus que jamais d'actualité. Un rapport quelconque avec le sujet de notre article ? Aucun. Une simple digression, une de plus, qui a peut-être l'avantage de vous interroger sur votre détermination. Je ne doute pas qu'elle soit intacte. Présentation Dans notre précédent article, sur le Copper et les rasters, nous avions mis en place un effet qui ne nécessitait aucune donnée graphique (DMA plans de bits). En effet, BPLCON0 ($DFF100) contenait la valeur $0200, ce qui proscrit tout affichage d'un élément graphique quel qu'il soit, excepté la couleur de fond. Mais ça va changer car nous allons habiller la démo d'un élément graphique qui se situera dans la partie haute de l'écran, à savoir un logo. Cela nécessite de comprendre ce que sont les plans de bits et comment l'Amiga les utilise. La mise en place et la programmation d'un écran Amiga est réputée complexe. A raison. Si on la compare par exemple au Commodore 64, il suffit sur ce dernier d'initialiser trois octets pour avoir un écran prêt à l'emploi. Sur Amiga, le parcours est plus escarpé et tortueux, mais pas infranchissable. L'avantage par contre, est que les écrans Amiga sont relativement flexibles, que ce soit du point de vue du positionnement ou des modes graphiques. Comme à notre habitude, nous allons scinder l'article en deux parties. Deux publications distinctes. L'une théorique, tandis que la seconde, sera plus axée sur la programmation. De manière globale et dans la continuité des articles sur le Copper déjà publiés (partie 1, partie 2), nous allons pas à pas expliquer dans une série d'articles, les différentes parties de la programmation d'une démo Amiga. Et je l'espère, à terme arriver à faire tourner une démo, simple, mais une démo tout de même. Prérequis Mon esprit brouillon m'en avait dissuadé, mais c'est un point que j'aurais dû aborder dès le premier article sur le Copper. Si vous êtes débutant et que vous désirez par la suite voler de vos propres ailes, alors il est indispensable de partir sur de bonnes bases en assimilant les notions suivantes :
Les plans de bits On pourrait décrire la mémoire vidéo de l'Amiga comme continue et linéaire, située exclusivement en mémoire Chip. Juste, mais un peu court. C'est pourquoi nous allons dépeindre la manière dont l'Amiga l'utilise pour obtenir un affichage graphique. Le champ de jeu ("playfield" en anglais) est à la base de toute représentation graphique de l'Amiga. Exception faite des lutins qui ont en parallèle leur gestion d'affichage propre. Un champ de jeu est constitué en fait d'un nombre variable de plans de bits (0 à 6 sur un Amiga OCS/ECS) défini par le programmeur. L'Amiga "superpose" les plans de bits activés, un peu à la manière de feuilles de calques pour former l'image finale. Modes graphiques et couleurs Détermination de la couleur d'un point Les bits éteints ou allumés de chaque plan de bits qui seront situés à la même position sur l'écran forment une combinaison de bits. Cette combinaison, qui est en fait un nombre, déterminera la couleur du point qui apparaîtra sur le moniteur. Ce nombre correspondra à un index qui servira à retrouver la couleur dans le tableau des couleurs qu'on peut aussi appeler "palette". ![]() Figure 1 : couleur d'un point - La Bible De L'Amiga © Micro Application
La codification d'une couleur se fait sur 12 bits, une composante R(ouge), V(erte) ou B(leue) est codée sur 4 bits, ce qui implique qu'elle peut prendre une valeur comprise entre 0 et 15 ($0 à $F), soit un total de 16 possibilités. Sachant qu'une couleur est composée de trois composantes, nous avons un nombre de couleurs possibles de 16x16x16 = 4096. Chaque couleur de la table peut donc être choisie parmi 4096 couleurs. Par exemple, si l'envie nous prenait de modifier la couleur du fond en jaune nous procéderions de la manière suivante :
Les composantes rouge et verte sont à leur valeur maximale tandis que la bleue est nulle, on obtient un jaune neutre et vif. Nous sommes donc dans un modèle additif, contrairement au soustractif que l'on retrouve par exemple en peinture à l'huile. Une remarque à titre personnel. Je trouve dommage que les ingénieurs de Commodore n'aient pas pensé (ou voulu) à coder les composantes RVB sur 15 bits, à savoir 5 bits par composante, ce nombre rentre encore dans un mot, ce qui aurait porté le spectre de la palette à un peu plus de 32 000 nuances. Modes graphiques Les modes graphiques sont relativement nombreux. On peut les sélectionner en modifiant les valeurs dans le registre BPLCON0 ($DFF100). ![]() Figure 2 : registre bplcon0 - La Bible De L'Amiga © Micro Application
Le bit 2, quant à lui, active le mode entrelacé. C'est-à-dire que la résolution verticale est deux fois plus fine. Ce mode présente néanmoins un inconvénient, sur un moniteur qui possède une fréquence verticale de 50 ou 60 Hz, l'image scintille. Le bit 11 active le mode HAM. Le fameux. Il permet d'obtenir beaucoup de couleurs, jusqu'à 4096. Avec des artefacts d'affichage cependant. Le bit 10, quant à lui, est un peu spécial. Il active le mode double champ de jeu ("dual playfield" en anglais). Il permet de regrouper les plans de bits pairs et impairs en deux champs de jeu totalement indépendants. Cela peut être utile pour la programmation de jeux. Il permet sur Amiga OCS/ECS, d'avoir deux champs de jeu de 8 et 7 couleurs (au maximum) chacun, superposés mais totalement autonomes. Par exemple, on pourra avoir pour un jeu, les décors en arrière-plan et dessiner par-dessus dans le deuxième champ de jeu les BOB (objets graphiques dessinés au Blitter), sans altérer le décor. Cela facilite grandement les choses pour le programmeur car il n'a pas à rétablir le décor sous les BOB. Positionnement et taille de l'image Positionnement Nous allons aborder un des points de la mise en place de l'affichage les plus délicats et plus difficile à appréhender pour les débutants : le réglage du positionnement et la taille de notre écran visible. Le positionnement et la taille de l'image sont variables et peuvent donc être modifiés par le programmeur dans certaines limites. L'image Amiga est rectangulaire et ne prend généralement pas toute la surface du moniteur. Tout ce qui se trouve autour de la fenêtre d'affichage prend la couleur de fond (couleur numéro 0). Centrer l'image sur l'écran se fait par la détermination des coordonnées des coins supérieur gauche et inférieur droit de la zone affichable. Nous utilisons pour se faire les registres DIWSTRT et DIWSTOP. ![]() Figure 3 - La Bible De l'Amiga © Micro Application Pour parler d'une manière simple et imagée, il faut bien appréhender ces registres comme des paramètres d'un cadre opaque et rectangulaire autour de l'image qui viendrait rétrécir, agrandir ou déplacer la zone visible. DIWSTRT contient les coordonnées (ordonnée, abscisse) à partir desquelles on désire que l'image commence à être visible. DIWSTOP, quant à lui, contient les coordonnées (ordonnée, abscisse) qui active le cache pour rendre l'image invisible. Pour obtenir une image de 320x256 pixels à peu près centrée on renseignera les registres comme suit :
Ces chiffres sont adaptés à la norme PAL. Ce que nous indiquent ces valeurs, c'est que pour le coin supérieur gauche, on a une image qui commence à être visible à partir de l'ordonnée $2C (44 en décimal) et l'abscisse $81 (144 en décimal). Pour le coin inférieur droit, nous avons l'image qui n'est plus visible à partir de l'ordonnée $12C (300 en décimal) et l'abscisse $C1 (193 en décimal). L'ordonnée de DIWSTOP à son bit V8 automatiquement activé à 1, ce qui implique qu'il faut additionner $100 (256 en décimal) à l'ordonnée pour avoir la valeur correcte. On fait le calcul : $12C-$2C = 256, ce qui correspond bien à la hauteur de notre image visible. Ces valeurs sont néanmoins tributaires du moniteur que l'on utilise, il faudra donc veiller à les modifier légèrement pour obtenir un centrage optimum. Taille Contrairement à précédemment, nous n'aborderons ici non pas la notion de cache mais bel et bien celle des données graphiques en soi. Nous allons déterminer le départ horizontal à partir duquel l'Amiga déclenchera le rapatriement des DMA des plans des bits et la position horizontale de leur arrêt. Ou pour faire simple, on indique à la machine à partir d'où on commence horizontalement à dessiner l'image et où l'arrêter. Pour déterminer DDFSTRT et DDFSTOP on se sert des abscisses contenues dans DIWSTRT et DIWSTOP. On pourrait ne pas s'y référer pour le calcul, bien évidemment, mais au risque d'avoir un décalage entre le cache et la fenêtre affichée. Dans ce cas, on se retrouverait à soit utiliser des DMA superflus qui ralentiront inutilement la machine, soit de manquer de DMA pour remplir toute la zone visible, ce qui risque de faire apparaître des bandes verticales uniformes (remplies avec la couleur 0) sur les côtés. En basse résolution, la machine a besoin de 17 pixels (soit 8,5 cycles) d'avance sur le faisceau à électrons pour pouvoir rapatrier les données des plans de bits de la mémoire Chip et les afficher juste à temps. Sachant cela, si on se base sur l'abscisse contenue dans DIWSTRT on peut en déduire la valeur de DDFSTRT comme suit :
A partir de là on peut déterminer DFFSTOP :
Au final nous avons donc :
Paramétrage des plans de bits (PDB) Nous arrivons au bout de nos peines, ou presque. Dans cette partie, nous allons aborder les derniers registres à renseigner pour enfin boucler les informations dont la machine à besoin pour afficher notre écran correctement. Pour ce faire, nous allons aborder les points suivants :
Il faut indiquer à quelles adresses mémoires les plans de bits se trouvent. Inutile de le répéter (c'est pourtant ce que je suis en train de faire ?) mais les données des plans de bits doivent être en mémoire Chip et à une adresse paire. Nous avons six plans de bits, donc six pointeurs vidéo. Liste des pointeurs vidéo :
Idem mais en utilisant l'instruction MOVE du Copper :
A chaque fin de ligne et en début de la ligne suivante, les pointeurs sont automatiquement incrémentés. La valeur d'incrémentation dépend de ce que l'on a mis dans les registres DDFSTRT et DDFSTOP. Si l'écran fait par exemple 320 pixels, la largeur d'un écran est donc de 20 mots, soit 40 octets. C'est cette dernière valeur qui est ajoutée automatiquement aux pointeurs vidéo à chaque début de ligne. C'est pour cette raison qu'il faut à chaque nouvelle trame réinitialiser ces pointeurs aux adresses correspondant au coin supérieur gauche. Modulos Je parlais de l'incrémentation des pointeurs qui sont augmentés automatiquement de la valeur de la largeur d'écran visible et à chaque départ de ligne. Mais j'ai omis de vous informer que l'Amiga en profite aussi pour ajouter une autre valeur, et ce au même moment, à savoir à chaque nouvelle ligne. Nous abordons là, la notion de modulos. Mais à quoi peuvent-ils bien servir ? Imaginons que vous programmiez un jeu de football dont le terrain vu de dessus prendrait plusieurs écrans de large et de haut, disons deux fois plus large que la zone visible. On ne verrait qu'une partie du terrain à la fois. Là survient un problème, car si l'Amiga n'incrémentait à chaque nouvelle ligne, les pointeurs vidéo qu'avec uniquement une valeur qui vaudrait la largeur de l'écran visible, on aurait l'affichage de l'image qui deviendrait corrompu. Pour y palier, une autre valeur vient à notre rescousse. Elle est appelée "modulo". Elle est ajoutée en plus de l'auto-incrémentation normale des pointeurs vidéo à chaque ligne. Dans ce cas précis, on initialiserait la valeur modulo égale à la différence des largeurs entre l'image totale (en fait la largeur totale du plan de bits) et l'image visible. Au final, nous avons donc une largeur d'écran visible qui est auto-incrémentée, plus la valeur modulo qui vaut à une largeur d'écran visible, ce qui fait bien au total la largeur complète du terrain, soit le double de l'image affichée. L'affichage devient cohérent. Les valeurs modulos sont renseignées dans les deux registres suivants :
Ces deux registres sont exclusivement accessibles en écriture. BPL1MOD correspond au modulo des plans impairs et BPL2MOD pairs. A priori, sauf si vous désirez programmer un effet visuel spécifique ou si vous utilisez le mode double champ de jeu, on devrait toujours avoir les mêmes valeurs dans les deux registres. Remarque : BPLxMOD contiennent la largeur en octets des zones graphiques non visibles. Dans le cas particulier où les plans de bits ont la même largeur que la zone visible, les modulos sont de ce fait nuls. ![]() Figure 4 Pour illustrer la flexibilité de l'affichage sur Amiga, je voudrais aborder le cas particulier où les pointeurs vidéo sont initialisés à l'adresse mémoire correspondant à la dernière ligne de notre image. Si nous choisissions des modulos avec une valeur qui correspondrait à deux fois la valeur négative de la largeur de l'écran visible, nous obtiendrions une image retournée verticalement. En effet, si notre écran faisait 320 pixels de large, nous aurions pour obtenir cet effet de renversement, à remplir les registres modulos avec la valeur -80. Le détail du calcul est comme suit :
Ce qui implique que les pointeurs vidéo à chaque ligne sont décrémentés et non le contraire. La fatigue aidant, je ne sais plus trop si je l'ai déjà évoqué précédemment, mais le contenu des registres modulos doit toujours être pair (logique car ils sont ajoutés aux pointeurs vidéo). Je ne résiste pas à l'idée de vous évoquer un autre cas particulier de l'usage des modulos. Si vous injectez dans les registres modulos la même valeur que la largeur d'écran en octets mais en négatif, vous obtenez en lieu et place de l'image normale, la même première ligne répétée verticalement. Le retard Dans BPLCON1 ($DFF102), on trouve deux groupes de bits qui permettent de déplacer l'écran défini par DDFSTRT et DDFSTOP (et non la totalité des plans de bits, notion importante) vers la droite uniquement d'un nombre de pixels qui peut aller de 0 à 15. Grâce à lui l'Amiga peut effectuer des défilements d'écrans latéraux fluides. La raison pour laquelle on l'appelle registre retard ("delay" en anglais), c'est qu'à chaque début de ligne, l'Amiga applique une légère pause avant le rapatriement des DMA plans de bits. L'attente est de ½ cycle d'horloge pour être précis pour chaque pixel de retard. Ce qui nous fait donc un retard maximum de 7,5 cycles (soit 15 pixels).
Défilements On peut modifier les pointeurs vidéo à chaque nouvelle trame pour simuler un défilement, seulement voilà, les adresses contenues dans ces registres ne peuvent qu'être paires. Ce qui implique que le déplacement ne peut se faire que de mot à mot, soit une précision d'au mieux 16 pixels. C'est là qu'intervient le registre de retard. Il permet de déplacer vers la droite notre écran au pixel près. La combinaison entre le changement de pointeurs vidéo et le registre retard permet donc un défilement fluide et précis. Pour effectuer un défilement vertical d'une ligne vers le bas, il suffit de rajouter (ou soustraire si on veut monter) la largeur en octets d'un plan de bits. En l'occurrence, pour un écran de 320 pixels de large, il faudra altérer les pointeurs de 320/8=40 octets. Pour déplacer de plusieurs lignes, il faudra juste multiplier 40 par le nombre de lignes désirées. La modification des pointeurs vidéo et de BPLCON1 doit impérativement se faire durant le temps mort vertical. Si vous deviez passer outre cette précaution, vous prendriez le risque de voir apparaître à l'écran des effets disgracieux non désirés. Le bout du tunnel Enfin, en dernier lieu, il convient d'activer les DMA plan de bits, pour se faire on activera le drapeau BPLEN dans le registre DMACON ($DFF096). Il s'agit du bit numéro 8. Ce point dépassé, nous sommes enfin prêts pour un affichage graphique. Le mot de la fin Ma lenteur ne fait plus aucun doute, inutile de le cacher. Mes genoux devraient grincer, pliant sous le poids de la culpabilité, mais il n'en est rien, je reste droit comme un peuplier et je vous dis donc à bientôt pour la partie programmation. D'ici là, portez-vous bien.
|