|
|||||||||||||||||||||||||||||||||||||||||||||
|
Comme il en a été question dans un long article sur la petite histoire de la programmation de Scoopex "TWO", Scoopex "ONE" était restée dans les cartons. En effet, au moment de la diffusion de Scoopex "TWO" sur Amiga 500, il s'était avéré que cette cracktro, et celle qui devait la précéder sur Amiga 1200, ne tournaient dans la trame que du fait d'une erreur de configuration de WinUAE. L'émulation n'était pas fidèle, le matériel ne volant pas autant de cycles au MC68000 que dans la réalité. Dans Scoopex "TWO", le problème fut résolu via une réduction de la taille ("downsizing"). Restait à trouver une solution pour Scoopex "ONE". C'est à l'occasion de la programmation d'une BBS-intro à venir pour le groupe Desire qu'elle fut trouvée. Voici donc le détail de la petite histoire de la programmation de Scoopex "ONE", une cracktro pour Amiga 1200. Cette cracktro exploite quelques possibilités offertes par le jeu de composants AGA (Advanced Graphics Architecture) : l'affichage en 256 couleurs, et le mode rafale ("burst") permettant au matériel de lire les données des plans de bits par paquets de 64 bits. En tant que telle, cette cracktro constitue une bonne introduction à la programmation du matériel de l'Amiga 1200, pour ceux qui souhaitent renouer avec le passé de la plus glorieuse gamme de micro-ordinateurs. Cette cracktro n'a toujours pas été utilisée par Scoopex, mais j'ai jugé qu'après des mois d'attente, il était nécessaire... de ne plus attendre. A priori, elle devrait être utilisée pour la publication d'une version AGA de Hired Guns. On verra bien... A écouter en lisant l'article : The Nightwalker par Marion. Cliquez ici pour télécharger l'intégralité du code et des données de la cracktro. Cette archive contient les fichiers suivants :
L'apparition du logo Le logo est une image de 320x64 pixels, en seize couleurs, soit quatre plans de bits. Il est progressivement découvert par des carrés qui vibrent indépendamment les uns des autres. En effet, non seulement ils ne commencent pas à vibrer simultanément, mais lorsqu'ils commencent à vibrer, ils ne sont pas en phase. La vibration est une animation cyclique où le côté d'un carré de 8x8 diminue de deux pixels à chaque étape, jusqu'à atteindre 0 et s'accroître de deux pixels à nouveau jusqu'à atteindre sa dimension initiale (spSquareBitmaps) : Le scénario de révélation d'un carré du logo a fait l'objet d'un certain nombre de tests avant de trouver celui qui ne choque pas l'oeil :
Le résultat produit est ainsi le suivant : ![]() Apparition du logo dans Scoopex "ONE" Le système de particules Le principal effet dans la cracktro est un système de particules : ![]() Le système de particules de Scoopex "ONE" Une particule est créée par un générateur, représenté à l'écran comme une particule qui n'est pas animée - un disque de huit pixels de diamètre. Il y a PARTICLE_SEEDS générateurs, répartis à intervalles réguliers le long d'une trajectoire précalculée de PATH_LENGTH positions. Cette trajectoire est de type système d'équations paramétriques comme une courbe de Lissajous. Un générateur crée une particule toutes les PARTICLE_DELAY trames. La particule apparaît à la position qu'occupe alors le générateur. Elle se déplace selon un vecteur directeur dont les coordonnées sont simplement la différence entre les coordonnées de la position du générateur et sa position précédente. Pour éviter que des particules générées à haute fréquence n'adoptent des trajectoires trop similaires, ces coordonnées sont légèrement brouillées par l'ajout aléatoire d'un constante empiriquement déterminée (2), en fonction des positions horizontale et verticale du raster au moment de la génération. Par la suite, ces coordonnées ne changent que lorsque la particule atteint un bord, la particule rebondissant sur ce dernier. La vitesse de la particule est initialement PARTICLE_SPEED. Comment calculer la nouvelle position d'une particule à chaque trame ? Le MC68020 est certainement plus rapide que le MC68000 pour effectuer des multiplications et des divisions, Toutefois, dans la lignée du travail accompli sur Amiga 500, il n'était pas question de recourir à de telles opérations ici. La position de la particule est calculée en s'appuyant sur un algorithme très simple, qui permet de diviser deux valeurs entières à l'aide de seules additions et soustractions, en procédant comme s'il s'agissait de tracer une droite à base de pixels. Cet algorithme est le même que celui évoqué dans l'article sur Scoopex "TWO" - présenté alors comme l'algorithme de Lucas, mais cet algorithme est si peu documenté sur le Web, et il partage tant avec celui de Bresenham, que je ne suis plus certain de pouvoir l'identifier ainsi... Il est clair que le vecteur directeur de la particule est une approximation - parfois très grossière - de celui de la tangente à la trajectoire du générateur à la position qu'occupe le générateur, et il est tout aussi clair que le déplacement de la particule de PARTICLE_SPEED pixels le long de la plus grande dimension de ce vecteur à chaque trame est une approximation - elle aussi, parfois très grossière - d'une vitesse de PARTICLE_SPEED pixels le long de ce vecteur. Toutefois, cela passe bien à l'écran. Une particule a une durée de vie limitée, fixée à PARTICLE_TTL trames. Tandis qu'elle vieillit, son image dans l'animation progresse et sa vitesse est ralentie, si bien qu'elle est représentée par un disque toujours plus petit qui se déplace toujours plus lentement. In fine, la particule disparaît et sa vitesse atteint 0 au moment où elle expire. Comme lors du calcul de la position, un algorithme permet de procéder à l'interpolation linéaire de l'indice de l'image de la particule, et à l'interpolation linéaire de sa vitesse, sur toute la durée de vie de la particule, à l'aide de seules additions et soustractions. Le nombre de particules en vie est limité à NB_PARTICLES. Pour parvenir à afficher un tel nombre de particules, PARTICLE_TTL doit donc être fixé à NB_PARTICLES*PARTICLE_DELAY/PARTICLE_SEEDS. La liste des particules en vie est maintenue sous la forme d'une liste de structures composées des champs suivants :
![]()
Cette liste des structures des particules est prévue pour comprendre jusqu'à NB_PARTICLES entrées. C'est ce qu'on appelle un barillet, c'est-à-dire une liste gérée comme si elle était circulaire, la première entrée étant considérée comme venant après la dernière. Son début est référencé par ptParticlesStart, sa fin par ptParticlesEnd. L'entrée de la première particule en vie est référencée par ptFirstParticle, et celle qui vient après celle de la dernière particule en vie, par ptNextParticle. Lorsqu'une particule est créée, sa structure est ajoutée à l'entrée référencée par ptNextParticle, et ce pointeur est incrémenté en le faisant reboucler sur ptParticlesStart si jamais il atteint ptParticlesEnd. Ainsi, par construction, les structures des particules sont triées de la plus vieille à la plus jeune à partir de l'entrée référencée par ptFirstParticle. La liste des particules est visitée à chaque trame pour éliminer les structures des particules dont la durée de vie a expiré. La liste étant triée comme on vient le dire, la manoeuvre consiste simplement à incrémenter ptFirstParticle en le faisant reboucler sur ptParticlesStart si jamais il atteint ptParticlesEnd. La démultiplication des particules Comme on s'en doute, le nombre de particules visibles à l'écran est de loin supérieur à NB_PARTICULES. En fait, ce nombre est tout simplement quadruplé en recourant à deux techniques : la rémanence et le renversement. En plus de permettre de démultiplier les particules, elles permettent d'en enrichir la palette, qui se limiterait autrement à deux couleurs, dont une pour le fond. Comme il est possible de le constater, le résultat serait alors assez plat : ![]() Le plan de bits 1 de particules Il en résulte que les particules ne sont plus affichées en une, mais trois couleurs. Une recherche montre qu'utiliser une couleur vive là où les particules des trames T et T+1 se superposent produit un résultat intéressant : ![]() Les plans de bits 1 et 3 de particules, le 3 étant le précédent 1 Il en résulte que les particules ne sont plus affichées en trois, mais quinze couleurs. Toutefois, ce nombre est théorique. Une recherche montre que pour donner l'illusion d'une démultiplication des particules, il ne faut pas aider le spectateur à distinguer des particules des plans de bits 2 et 4 de celles des plans de bits 1 et 3, et donc plutôt généraliser la palette de trois couleurs de ces derniers plans de bits : ![]() Les plans de bits 1, 3, 2 et 4 de particules, les 2 et 4 étant les 1 et 3 renversés Au final, l'organisation des plans de bits est la suivante : yable plan de bits Usage 1 Particules à l'instant T 2 plan de bits 1 inversé 3 Particules à l'instant T-1 4 plan de bits 3 inversé 5 plan de bits 1 du logo, plan de bits du texte 6 plan de bits 2 du logo, plan de bits du crâne 7 plan de bits 3 du logo 8 plan de bits 4 du logo Pour qu'il soit lisible, le texte est affiché au premier plan, masquant tout ce qui se trouve derrière. Par contre, le crâne laisse entrevoir en semi-transparence les particules lorsqu'elles passent derrière. Ces effets sont réalisés en jouant sur certaines couleurs de la palette, éventuellement à partir d'une certaine hauteur dans l'écran, pour réutiliser des couleurs. Par exemple, sous le logo, toutes les couleurs dont le bit 5 est positionné (32, 33, etc.) sont passées à TEXT_COLOR pour afficher le texte, du fait qu'elles ne sont plus utilisées pour afficher le logo qui partage ce plan de bits avec le texte. Comme expliqué ici, le raster a le temps de se déplacer de huit pixels en basse résolution tandis que le Copper exécute un MOVE. En conséquence, il faut laisser à ce coprocesseur le temps d'exécuter les MOVE qui modifient les couleurs, avant que le raster ne commence à tracer la ligne où ces couleurs doivent être utilisées. Ici, c'est à partir de la ligne DISPLAY_Y+HALFBRIGHT_Y-2, qui correspond à l'avant-dernière ligne avant celle du séparateur blanc - et non la dernière avant celle du séparateur -, que l'opération doit débuter. Le printer Tout à déjà été dit ici sur le printer. En fait, le printer de Scoopex "ONE" est une version antérieure du printer de Scoopex "TWO". Les transitions Les transitions sont aussi nécessaires que pénibles à programmer dans une cracktro, et celle-ci, qui fut la première de la série entamée récemment, fut pour moi l'occasion de me le rappeler. Pourquoi ?
Mode rafale et triple tampon mémoire pour doper les performances La cracktro exploite huit plans de bits. Quand on sait que sur Amiga 500, passé quatre plans de bits, rajouter des plans de bits conduit à voler des cycles DMA pairs au processeur, on peut se douter qu'une telle profondeur va pénaliser les performances sur Amiga 1200, rétrocomptabilité oblige, conduisant à limiter grandement le nombre de particules. De fait, c'est ce qui s'avère, à moins d'exploiter une fonctionnalité du matériel vidéo qui consiste à lire les données des plans de bits non pas par paquets de 16 pixels, mais par paquets de 64 pixels - une sorte de mode rafale, on dira. A priori, il faudrait que les adresses des plans de bits soient alors alignées sur 64 bits. Du moins, c'est ce qui est requis pour afficher des sprites des 64 pixels de large propres à l'AGA, comme il est possible de le tester à l'aide du code proposé au téléchargement dans cet article - noter le présence de directives CNOP 0,8. Toutefois, en l'espèce, il n'est pas apparu nécessaire de forcer un tel alignement. L'adresse renvoyée par AllocMem() lors de l'allocation en mémoire des plans de bits est utilisée directement sans que cela pose de problème. Rétrocomptabilité oblige, la lecture par paquets de 64 pixels n'est pas activée par défaut. Pour cela, il faut positionner certains bits dans le registre FMODE propre à l'AGA. Par ailleurs, il faut adapter les valeurs des registres DDFSTRT et DDFSTOP qui spécifient à quel moment le matériel doit commencer à lire et achever de lire les octets des plans de bits correspondant aux pixels d'une ligne, ainsi que celle des registres des modulos BPL1MOD et BPL2MOD qui spécifient combien d'octets le matériel doit rajouter aux pointeurs sur les plans de bits à la fin de l'affichage d'une ligne. Ainsi, on retrouve dans la liste Copper de la cracktro :
Pour l'anecdote, la référence au désassemblage de la liste Copper AGA pour déterminer les valeurs de DFFSTRT et de DDFSTOP est un témoignage de la profonde opacité de ces registres... Certes, l'Amiga Hardware Reference Manual contient bien des explications sur la manière de calculer ces valeurs, mais qui rentre dans le détail réalise bien vite que le raisonnement semble relever d'une abstraction plus que d'une réalité, ce qui le rend difficilement transposable au cas présent. Pour déterminer ces valeurs, j'ai donc désassemblé la liste Copper du Workbench après avoir ajusté la résolution à celle de la cracktro : ![]() Désassemblage de la liste Copper du Workbench
La petite histoire L'histoire de cette cracktro remonte à l'été 2017. Parti sur l'idée de produire une démo, je programme plusieurs effets pour Amiga 500, dont une première version du système de particules présenté plus tôt : ![]() Le système de particules initial
Chose faite, je fais parvenir à la cracktro à Galahad, qui me remercie tout en m'indiquant qu'aucune publication de jeu AGA n'est pour l'heure prévue. Par contre, il s'apprête à sortir le portage d'un jeu Atari ST sur Amiga 500. Si donc le coeur m'en dit, une cracktro pour OCS est bienvenue. C'est l'histoire de Scoopex "TWO", précédemment narrée ici. Comme rapporté dans ce récit, au moment de la diffusion de Scoopex "TWO", je constate que du fait d'une erreur de configuration de WinUAE, cette cracktro ne tourne pas dans la trame. L'émulation n'est pas fidèle, le matériel ne volant pas autant de cycles au MC68000 que dans la réalité. Tout se passe comme si j'avais surestimé les capacités de calcul de l'Amiga. Comme j'ai programmé Scoopex "ONE" avant, je réalise que le problème affecte aussi cette cracktro. Une fois WinUAE correctement configuré, le nombre maximum de particules qu'il est possible d'afficher dans la trame chute vertigineusement de plus de 500 à guère plus de 70. Dans ces conditions, l'effet n'a plus rien d'impressionnant, et Scoopex "TWO" ne peut donc être distribuée sans risquer la honte. Une chance qu'à l'époque, Galahad n'a pas eu de jeu AGA en attente de cracktro, car il avait visiblement commis la même erreur d'appréciation que moi... Il faut trouver une solution ou enterrer le code. Toutefois, je suis déjà engagé sur la programmation d'autres petites choses - notamment "Scoopex THREE", un menu de triches pour StingRay. Je laisse donc filer, en me disant que j'y reviendrai un jour... ou jamais ! Car sur le moment, je dois bien avouer que je ne vois pas très bien comment faire mieux. Longtemps après, je dois me frotter à l'AGA pour expliquer comment afficher des sprites de 64 pixels de large en 256 couleurs dans le cadre de la rédaction d'un article sur ces hobbits du matériel vidéo. C'est alors que je me souviens - ce qui est un comble, car j'étais quand l'un de ceux qui avaient commencé à le documenter à l'époque - que l'AGA peut afficher de tels sprites en utilisant une lecture accélérée des données en mémoire vidéo. L'exploration de la documentation officieuse de l'AGA - comme je l'ai expliqué, Commodore n'a jamais documenté officiellement ce matériel - me renseigne sur le fait qu'il en va de même pour les plans de bits. Je fais le pari raisonnable que cela peut libérer des cycles pour le processeur, et donc me permettre d'accroître le nombre de particules. Je teste, et il s'avère que c'est bien le cas. Le gain est là, mais il reste limité au regard du nombre de particules d'où je suis parti. Pour l'accroître plus encore, je décide dans la foulée de mobiliser la technique du triple tampon mémoire que j'avais à l'époque écartée, par flemme. Cela me contraint de réécrire une petite partie du code. Rien de bien de grave quand je peux constater qu'au final, cette technique jointe à l'autre me permet d'atteindre un nombre de particules beaucoup plus conséquent, et de produire un effet à l'écran proche de celui auquel j'étais tout d'abord parvenu. La cracktro est sauvée. Elle pourra être jouée sur les écrans de petits et grands. Ouf ! Et voilà ! Nul doute qu'il est possible de faire mieux en assembleur avec le jeu de composants AGA. Toutefois, le système de particules est assez sympathique - même s'il serait possible d'en démontrer la puissance autrement qu'en faisant simplement circuler les générateurs le long d'une trajectoire précalculée. Et finalement, les magnifiques graphismes et l'excellente musique rehaussent l'ensemble, pour en faire quelque chose qui se tient. Pas de cracktro digne de ce nom sans crédits et salutations. Pour les premiers :
|