|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Cet article est le second, et donc le dernier, d'une série consacrée au développement d'une cracktro sur Amiga. Dans le premier article, nous avons vu comment mettre en place un environnement de développement en assembleur 68000 dans le contexte d'un émulateur Amiga, et nous sommes rentrés dans une présentation d'un des deux coprocesseurs graphique, le Blitter, exemple à l'appui. Ici, nous présenterons pareillement le Copper et nous conclurons sur l'intérêt de revisiter ce passé. ![]() Cracktro sur Amiga Les bases de l'affichage Comme chacun sait, une image affichée à l'écran est composée de pixels, chaque pixel étant codé en mémoire par une valeur qui permet de déterminer la couleur dans laquelle il doit être affiché. De nos jours, cette valeur est généralement un "quad", les composantes rouge, verte et bleue de la couleur du pixel étant codées chacune sur un octet (le quatrième octet étant réservé au degré de transparence, ou alpha). Sur Amiga, la solution est très différente. Exception faite du mode "Hold-And-Modify" (HAM) exceptionnellement utilisé, l'affichage sur Amiga fonctionne sur le principe suivant. Pour afficher en N couleurs, N étant une puissance de 2, il faut N plans de bits, ou "bitplanes", dont les dimensions correspondent à celles de la surface affichée - par exemple, 320x256 pixels. Le premier plan de bits fournit les bits 0 des pixels, le deuxième fournit les bits 1 des pixels, etc. ![]() Un plan de bits L'Amiga peut afficher en basse ou haute résolution, ce qui joue sur le nombre de couleurs :
Ces possibilités ont été étendues au fil des évolutions du matériel, mais on se limitera ici à évoquer l'Amiga 500, donc l'Original Chip Set (OCS) et non les suivants - Ehanced Chip Set (ECS) pour l'Amiga 500+ et Advanced Graphics Architecture (AGA) pour l'Amiga 1200. Parler de basse ou haute résolution en évoquant un nombre de pixels affichés horizontalement est un abus de langage. En fait, il faut entendre que le faisceau d'électrons met un certain temps à balayer une ligne de l'écran, et qu'il est possible de lui demander de tracer plus ou moins longtemps, donc sur une certaine longueur, un pixel : 140 nanosecondes en basse résolution, 70 en haute résolution. C'est pourquoi indépendamment de la résolution, il faut distinguer la surface d'affichage et les données affichées. La surface correspond à la partie de la région balayée par le faisceau d'électrons effectivement utilisée. Elle doit être spécifiée via les registres DIWSTART et DIWSTOP. D'autres registres, DDFSTART et DDFSTOP, permettent de spécifier les positions horizontales du faisceau d'électrons entre lesquelles les données doivent être lues et affichées au rythme imposé par la résolution adoptée. Les données doivent être lues un peu avant leur affichage pour laisser le temps au matériel de jouer sur le faisceau d'électrons. Jouer la "playlist" vidéo Le Copper est un des coprocesseurs de l'Amiga, essentiellement utilisé pour contrôler l'affichage en écrivant dans des registres tels que ceux déjà cités pour spécifier des paramètres de ce dernier. Avant d'aller plus loin, il faut clarifier deux points :
Dans la liste Copper, une instruction est fournie sous la forme de deux mots. Autrement dit, le Copper se programme directement en codes opération ("opcodes"), généralement écrits en hexadécimal. Le Copper détecte de quelle instruction il s'agit en se basant sur la combinaison des deux bits 0 des mots d'une instruction. Le Copper comprend simplement trois instructions :
Autant l'intérêt de MOVE et de WAIT est évident, autant celui de SKIP ne l'est pas. SKIP est utile dans le contexte d'usages (très) avancés, tout particulièrement :
Dans la cracktro, la liste Copper permet d'organiser l'affichage de la manière suivante, la transition entre la première et la seconde partie s'effectuant à l'aide d'un WAIT :
Il serait trop long de restituer ici le code de la liste Copper de la cracktro. Réécrite à l'occasion de la rédaction de cet article en s'en inspirant, voici une liste Copper basique. Elle commande l'affichage d'un écran en 320x256 en deux couleurs (un unique plan de bits) en changeant la couleur de fond à mi-hauteur : ![]() Exécution de la liste Copper de base
Au passage, un effet très couru consiste à enchaîner les MOVE pour changer la couleur de fond sur le nombre de pixels que le faisceau d'électrons parcourt le temps que cette instruction soit exécutée, soit le temps d'afficher huit pixels en basse résolution. En répétant une séquence de couleurs formant un dégradé cyclique sur une ligne, et en répétant cette opération sur plusieurs lignes en commençant à chaque ligne dans la séquence à un indice qui varie de ligne en ligne selon une fonction telle qu'un sinus, on produit un effet "plasma" qui peut être animé, comme dans la très belle partie Plasmaworld de la Megademo du groupe Humanoids : ![]() Superbe effet plasma dans la Megademo de Humanoids Or, les faces opposées d'un cube sont mutuellement exclusives. Par exemple, quand la face avant est visible, la face arrière est nécessairement cachée - pour déterminer si une face est visible, l'orientation de sa normale est testée. Dès lors, l'astuce consiste à afficher des faces opposées de sorte que leurs pixels référencent la même couleur dans la palette, couleur qui leur est réservée. Quand une face est visible, sa couleur est modifiée en écrivant dans la liste Copper pour écraser la valeur que cette dernière écrit dans le registre correspondant. Par exemple, sans que cela corresponde nécessairement à ce qui se retrouve dans la cracktro :
Chaque face étant affichée dans une couleur qui lui est propre, le cube semble affiché en sept couleurs alors qu'il n'est affiché que sur deux plans de bits. Sprites, double champ de jeu et défilement... matériels ! Le matériel de l'Amiga ne permet pas que d'afficher des plans de bits. Il permet aussi d'afficher des sprites, de découpler l'affichage des plans de bits sur deux plans (double champ de jeu ou "dual playfield"), de faire défiler un plan des plans de bits : autant de fonctionnalités qu'il encore une fois possible de contrôler au processeur ou au Copper en écrivant dans certains registres. La cracktro n'utilise aucune de ces fonctionnalités, mais il serait malheureux de ne pas profiter de l'occasion pour les évoquer car elles permettent de réaliser des effets graphiques qu'on retrouve dans nombre de démos et autres cracktros. Les sprites. Chacun sait ce qu'est un sprite : une image qui doit être affichée par-dessus un décor dans lequel elle se déplace en évitant de recouvrir les pixels qui, dans le sprite, sont censés être transparents - une couleur ou un masque permet de les identifier. Normalement, l'affichage des sprites est effectué au processeur, ce qui implique d'écrire le code requis pour non seulement afficher mais aussi effacer le sprite en restaurant la partie du décor qu'il recouvrait dans sa position antérieure. Sur Amiga, ces sprites logiciels sont souvent affichés au Blitter car ce dernier permet de combiner logiquement lors d'une seule copie les pixels du sprite, de son masque et du décor - raison pour laquelle ces sprites sont désignés comme des "BOB", pour "Blitter objects". Aussi le terme de sprite est-il réservé pour désigner les sprites matériels du Copper. Le matériel peut afficher huit sprites de 16 pixels de large en quatre couleurs dont une couleur transparente, sur une hauteur illimitée. Les sprites sont couplés (le 0 avec le 1, le 2 avec le 3, etc.). Dans un couple, les sprites partagent la même palette (0 et 1 utilisent les couleurs 16 à 19, 2 et 3 utilisent les couleurs 20 à 23, etc.), et ils peuvent de plus être combinés. Deux sprites combinés forment un sprite toujours de 16 pixels de large et de hauteur illimitée, mais en 16 couleurs dont une couleur transparente. Enfin, un système de priorités permet de gérer finement quel sprite est affiché devant ou derrière quel champ de jeu (Cf. ci-après). Un sprite se contrôle très simplement. En effet, ses données se présentent sous la forme d'une liste de mots. Les deux premiers permettent de spécifier l'abscisse, l'ordonnée, et la hauteur du sprite. Suivent deux mots par ligne du sprite : le premier donne les bits de poids faible et le second les bits de poids fort permettant de déterminer l'indice de la couleur des pixels correspondant du sprite. Un couple de mots nuls marque la fin des données du sprite. Par exemple, un sprite formant un petit damier cases de 4x4 pixels dans ses quatre différentes couleurs affiché en (23, 23) dans un repère classique commençant en ($81, $2C) : ![]() Un sprite de 16 pixels en quatre couleurs affiché sur un plan de bits
D'ingénieux codeurs maîtrisant parfaitement le matériel ont élaboré des techniques très élaborées pour enrichir l'affichage en jouant avec le Copper, notamment avec les sprites. Le site Codetapper permet de constater tout ce que l'analyse de la liste Copper de différents jeux à succès révèle... Passionnant ! Le double champ de jeu ("dual playfield"). En positionnant simplement un bit dans un registre, les six plans de bits qu'il est possible d'utiliser peuvent être regroupés : les pairs, d'une part, les impairs, d'autre part. Chaque ensemble constitue alors un champ de jeu, c'est-à-dire un décor à part entière doté d'une palette de huit couleurs, dont une couleur transparente. Le double champ de jeu ("dual playfield") permet d'afficher les deux décors avec effet de transparence, l'un laissant entrevoir l'autre dans ses zones de pixels de couleur transparente, sans avoir à faire intervenir le processeur. Comme par ailleurs, le défilement de chaque champ de jeu peut être géré indépendamment de l'autre tant verticalement qu'horizontalement (Cf. ci-après), le double champ de jeu permet de réaliser un effet de parallaxe où un décor se déplace derrière l'autre à une vitesse différente, comme s'il se trouvait à une certaine distance de l'autre le long d'un axe qui, partant de l'observateur, s'éloigne vers le fond de l'écran. Le défilement ("scrolling"). Pour afficher un plan de bits, il faut en fournir l'adresse au matériel dans une paire de registres : BPL1PTH et BPL1PTL pour le plan de bits 1, BPL2PTH et BPL2PTL pour le plan de bits 2, etc. Or, que ce soit pour le groupe des plans de bits pairs, d'une part, ou celui des plans de bits impairs, d'autre part, il est possible de contrôler deux paramètres du matériel lorsqu'il lit les données d'un groupe de plans de bits pour afficher une ligne de pixels :
C'est ce mécanisme qui peut être utilisé pour produire l'effet de parallaxe dont il a été question plus tôt. Pour être complet dans cet inventaire des fonctionnalités vidéo du matériel, il faut mentionner la détection de collisions à la précision du pixel. Toutefois, c'est une fonctionnalité plus utile aux jeux qu'aux démos et autres cracktros. Quoique... ? Que retenir de tout cela pour aujourd'hui ? Comme expliqué dans l'introduction du premier article de cette série, le propos de cette présentation illustrée de la programmation des deux coprocesseurs graphiques de l'Amiga en assembleur n'était certainement pas d'inciter à programmer sur cette machine de nos jours, même si cela peut être des plus instructifs. Le propos était plutôt d'enrichir la culture générale de ceux qui n'ont jamais eu l'occasion de s'adonner à une telle programmation en leur montrant brièvement en quoi elle pouvait consister. Au passage, il s'agissait aussi montrer à tous comment l'affichage d'une image à l'écran peut, à bas niveau, fonctionner - un mécanisme qu'il est d'autant plus essentiel de connaître que son principe n'a, somme toute, guère évolué. Rappelons qu'il subsiste un petit monde de créateurs de démos qui produisent des exercices de style fascinants mêlant graphismes, musiques et code, désormais bien plus sophistiqués que la simple cracktro présentée - qui, même si elle n'était pas mal, était loin d'être un chef-d'oeuvre de l'époque dans son genre. On ne saurait trop conseiller aux jeunes de rejoindre cette "scène". Même s'ils ne feront pas de la programmation de routines graphiques leur métier, ils acquerront une connaissance du matériel et du logiciel qui leur servira dans bien d'autres circonstances par la suite. Ah ! Peut-être un conseil pour tous pour terminer... Comme déjà mentionné, c'est l'Amiga Hardware Reference Manual rédigé par les ingénieurs de Commodore qui a servi de référence pour élaborer cette série d'articles. Autrement dit, l'information à la source. Or, c'est toujours à la source qu'il faut s'alimenter pour découvrir une technologie : même si elle paraît indigeste parce que très technique, privilégiez la documentation de référence sur la documentation dérivée. Par exemple, si vous souhaitez faire du JavaScript, commencez par lire la spécification ECMAScript. A défaut, vous risquez de penser que JavaScript est un langage orienté objet à base de classes et, commettant cette erreur, vous passerez à côté d'aspects fondamentaux du langage.
|