article
Les scrollers d'antan
Making of « Logon’s run - 3D meets the aging bits » (sortie à la Revision 2017) par Overflow / Logon System
Article écrit et conçu par Overflow / Logon System en février 2017 - Publié par NoRecess en avril 2017. Cliquez ICI pour la demo sur Pouet.
Introduction
Tricher a toujours fait partie du demomaking. Une animation fluide ? pensez au hardware-scroller : tout peut être pré-rendu en VRAM, puis l’affichage à l’écran est judicieusement réglé à chaque frame en changeant le pointeur vers la VRAM. Je crois que j’en suis obsédé depuis le tout début ! Au fil des années, j’ai utilisé les HW-scrollers de différentes façons pour obtenir des animations qui n’ont cessé de s’améliorer. Jusqu’à la sortie aujourd’hui de « Logon’s run - 3D meets the aging bits ». En bonus ou en making-of : voici toute l’histoire. Beaucoup à regarder, quelques DSK à télécharger, mais pas tant que ça à lire.
64KB de VRAM pré-rendue = 4096 caractères = 60 (largeur) * 68 (hauteur) + 16 | affichage à l’écran = fenêtres de scrolling de 48*34

« Gagacubiz » [2014 | sortie en 2017 dans « Logon’s run - 3D meets the aging bits »] Pouet!
1991-1992 LES PREMIÈRES ANNÉES
En 1991 : cacher 12 caractères dans la bordure, en dehors de l’écran affiché.

« S&KOH » [1991] Pouet!
Animation en 4 étapes | scrolling de 4 caractères vers la droite

Scroller fluide | 4 flippings + scrolling de 1 caractère vers la droite

Est venue une amélioration : une ligne de caractères sans restriction de longueur, pour cacher bien plus sur une seule ligne de caractères. Normalement, il ne devrait pas y avoir plus de 64 caractères sur une seule scanline. En splittant l’écran à chaque ligne de caractères : la restriction disparaît.

« Shadow of the Beast - demo menu » [1992 | preview 1994] Pouet!
Scroller fluide | scrolling de N caractères vers la droite + décalage de 1 pixel

Encore de la triche : générer lentement des données d’écran en basic puis sauvegarder 16KB de VRAM ; plus tard : les charger et faire du HW-scroll.
16KB de VRAM pré-rendue = 900 caractères | scrolling de N caractères vers la droite - largeur du tile = ~6c.

« Waves » [1992 | preview 1994]
2002-2004 DEULIGNES
« Deulignes » signifie « 2 lignes de basic ». PhenixInformatique a organisé plusieurs compétitions amicales autour des « deulignes » en 2002, 2004 et 2008. Ma méthode a été : l’essentiel du code source pour calculer l’écran (sans doute 15-30 min. de rendu ! vu que le basic est si lent), puis un HW-scroller pour faire boucler l’animation. Plus tard, CPCrulez les a repackées : 16KB de vram chargés d’un coup. Téléchargement sur CPC-power.
4KB de VRAM pré-rendue | scrolling de 2 caractères vers la droite

« Worms » [2002 | repack 2010 par cpcrulez]
4KB de VRAM pré-rendue | scrolling de 4 caractères vers la droite

« Plasmegg » [2002 | repack 2010 par cpcrulez]
16KB de VRAM pré-rendue = 1024 caractères = 40 (largeur) * 25 (hauteur) +24 | scrolling de 2 caractères vers le haut

« Barfive » [2004 | repack 2010 par cpcrulez]
2004-2011 LES ROUAGES INTERNES
Enfin une animation générique à tiles carrés !
16KB de VRAM pré-rendue = 1024 caractères = 64 * tiles | tile carré = 4 (largeur) * 4 (hauteur)

« 0%-cpu animation » [2004 inédite - preview+gfx 2010 par cpcrulez] Téléchargement sur CPC-power.
Passer de 16KB à 64KB (pour multiplier par 4 le nombre de frames d’animation) aurait été une tâche facile. Mais… regardez cet écran : des tiles carrés statiques ? en n’utilisant que des entiers ? Cela m’a fait me demander comment on pouvait améliorer ça. J’y ai réfléchi quelques jours jusqu’à trouver des principes qui me travaillaient : un nombre de layers virtuellement illimité ? des tiles de taille non entière avec du scrolling sub-pixel ??? Il fallait que je teste l’idée ! C’était en 2006.
64KB de VRAM pré-rendue | 6 layers | uniquement du plot et du tracé de lignes

[2006 inédite - preview discrète à la Croco Chanel party 2007]
Calculs et chiffres

Fourni sans le moindre commentaire (essayez de comprendre par vous-même ce qui se passe !) :
Ce Proof-Of-Concept était sympa mais absolument pas prêt pour une sortie : l’idée principale était de ploter (puis : de tracer une ligne) dans chaque frame depuis un layer d’animation. C’était tellement lent… L’amélioration à laquelle j’ai pensé était : dessiner une forme pleine d’un seul coup. C’est donc ce que j’ai codé.
64KB de VRAM pré-rendue | 4 layers | dessin d’une forme pleine

[2008 inédite]
Encore une belle déception ! Il semblait que la 3D était le seul moyen d’obtenir une vraie sensation de layers. Il semblait aussi que le dithering était une autre condition pour tricher avec la restriction des 4 couleurs. Bon sang ! cela voulait-il dire que je devais me faire mon propre moteur 3D ? Une sacrée affaire ! vu que je me voyais plutôt comme un hardware-coder que comme un software coder. Eh bien ! il m’a fallu quelques années pour atteindre l’objectif : moteur 3D prêt ! prêt à être mélangé au HW-scroll… quelques années plus tard.

Hommage Face Hugger [2011 inédite]
2014-2016 LE TRAVAIL CACHÉ SUR « Logon’s run »
En fait, j’ai réussi à obtenir les 3 FX principaux assez vite : quelques mois en 2014. Cela signifiait : pouvoir dessiner des objets 3D et les placer comme sprite n’importe où dans les 64KB de VRAM. Les petits objets pouvaient même être générés à l’écran en une seule frame, ce qui permet de les faire apparaître pendant le scrolling de l’écran.

« Doyousea » [2014 | sortie en 2017 dans « Logon’s run - 3D meets the aging bits »]

« Dragonfly » [2014 | sortie en 2017 dans « Logon’s run - 3D meets the aging bits »]
Des FX impressionnants à l’écran. Mais… il faut un temps fou pour dessiner autant d’objets 3D sur plusieurs layers dans 64KB de VRAM ! L’idée de base à l’époque était : bon, faisons une sorte de gfx procédural, montrons partiellement ce qui est mis à l’écran.
Preview précoce : rendu directement à l’écran. La honte !


Titre de travail « Crafted » [2014 | preview à la Reset party 2015]
J’ai donc décidé de cacher les gfx en cours de génération. Je l’ai fait par 3 moyens. Tout d’abord : quand c’est possible, cacher des bitplanes pour ne montrer qu’un fond ou des FX en 1 couleur. Ensuite ? retour à des animations bien plus simples en 16KB ! oublier la 3D, n’utiliser que des sprites : cela se génère vite et laisse plus de temps pour les FX lourds. Enfin, et ce n’est pas le moindre : utiliser une tâche de fond pour générer l’animation, pendant qu’on affiche autre chose au premier plan (par exemple : le gfx procédural d’un logo).
« BITPLANE » CACHÉ
Mode 1 = 4 couleurs = 2 bits nécessaires. Le CPC n’a pas de bit-planes. Cela dit : un usage habile des « inks » permet de cacher 1 bit sur 2. Cela permet de calculer un gfx en 1 couleur pendant qu’un autre gfx est affiché à l’écran via l’autre bit.
Note : les captures suivantes (celles de gauche) sont tirées de ce DSK :
Rendu de cubes de taille moyenne… mais on ne les voit pas

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Rendu de cubes de taille XL… mais on ne les voit pas

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Rendu du fond de « Doyousea » (gris - en bas)… mais on ne le voit pas

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
ANIMATION EN 16KB
16KB de VRAM | fx uniquement avec des sprites | pendant le rendu de « Dragonfly » 1/2

16KB de VRAM | fx uniquement avec des sprites | pendant le rendu de « Dragonfly » 2/2

Le même fond pour 3 animations | 1) hauteur du tile = 2 caractères

Le même fond pour 3 animations | 2) hauteur du tile = 4 caractères - scrolling de 2*4 caractères

Le même fond pour 3 animations | 3) hauteur du tile = 6 caractères

TÂCHE DE FOND
Afficher « quelque chose » pendant que les données (principalement 64KB/16KB de VRAM) sont générées.
Rendu de « Doyousea » en tâche de fond, pendant que l’affichage au premier plan est : le gfx procédural du logo « Logon System »

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Rendu de « Dragonfly » en tâche de fond, pendant que l’affichage au premier plan est : des sprites fantômes

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Rendu de « Gears » en tâche de fond, pendant que l’affichage au premier plan est : « Dragonfly » puis les plateformes de « Donkey Kong »

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Rendu de « Rubberbar » en tâche de fond, pendant que l’affichage au premier plan est : « Mario »

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Génération des 64KB de données « Gameboy » en tâche de fond, pendant que l’affichage au premier plan est : « Rubberbar »

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
BONUS : SPLITRASTERS !
Changer le pointeur vers la VRAM : cela ne coûte vraiment pas beaucoup de cpu ! Alors ? assez de temps pour ajouter quelques « split-rasters » (c’est-à-dire changer une seule « ink » jusqu’à 12 fois sur une seule scanline).
La méthode facile : un gros sprite chunky - ou plus tard : du texte


La méthode inhabituelle : cacher des cubes en bas et les faire tomber depuis le haut

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
La méthode difficile : appliquer de nombreuses couleurs sur une forme 3D d’une seule couleur

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
…MAIS QUE SE PASSE-T-IL AVEC LA GAMEBOY ?
La scène Gameboy, c’est une autre histoire. Elle n’est pas non plus faite en hardware-scroll et n’a pas sa place ici en tant qu’Elder’s scroller. Cela dit, cet article ressemble à un making-of, non ? C’est peut-être le bon endroit pour plus de texte et moins de GIF animés.
Batman m’a tué. La scène Gameboy tire son inspiration de ce Batlogo qui tue. Elle utilise le même algorithme de base. Évident : l’animation est packée. Pour chaque frame packée, les données stockées sont : de la scanline #n à la scanline #(n+1), quels octets doivent être changés. Autrement dit : du delta-packing en considérant que l’écran n’utilise qu’une seule scanline répétée, mise à jour en suivant le balayage. À partir de là, la scène Gameboy introduit quelques autres fonctionnalités.
Deux scanlines sont répétées. Un glitch peut apparaître s’il y a trop d’octets à mettre à jour sur une seule scanline. Si un octet est mis à jour trop tard, c’est-à-dire une fois que le balayage est passé sur cet octet : l’octet est affiché dans son état précédent. Pour éviter cela : ne pas utiliser une seule scanline mais deux. La scanline paire est mise à jour pendant l’affichage de la scanline impaire ; et vice-versa.

À gauche : les deux scanlines répétées sont mises à jour pendant la frame, à chaque fois par très peu d’octets, à droite
Dithering. Puisque deux scanlines sont utilisées, ajouter du dithering a été facile.
d’octets mis à jour pour une scanline. Dans cette animation Gameboy : jusqu’à 14 octets sont mis à jour sur une seule scanline. Le temps cpu nécessaire est de 14*6 = 84μs. Ce qui est plus que 64μs = la largeur de la scanline telle que la voit le balayage. Cela entraînerait des glitches (voir le point a) avec un framework à une seule scanline. Cela n’a aucune importance avec un framework à double scanline. +20μs de plus sont nécessaires pour une scanline donnée ? pas de souci : les scanlines suivantes, avec moins d’octets, permettront de compenser ce retard.
Fond. Quelques carrés sont affichés en fond. C’est obtenu par des rasters (c’est-à-dire des changements de couleur) appliqués sur (3) colonnes.
de couleurs. 7 sont affichées au lieu de 4. Voir le point précédent pour les changements de couleur sur le fond. Il y a aussi un autre changement de couleur (pas toujours au même y) sur la Gameboy elle-même : l’écran et les boutons partagent la même ink.
Des carrés en fond et plus de couleurs grâce au changement d’ink en suivant le balayage.

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]
Scrolling vers le bas sur l’axe y. Cela nécessite d’arrêter la routine de depacking avant la fin des données de la frame courante.
Scrolling vers le haut sur l’axe y. Cela nécessite qu’une routine de pré-depacking tourne avant la boucle-principale-qui-suit-le-balayage.
Pas d’écran vide avant/après. Le fx bascule depuis/vers un framework d’écran standard où la Gameboy a été pré-rendue en utilisant les mêmes données que le fx.
Pas de chargement de données. Mais : 25 secondes de tâche de fond pour calculer et packer 64KB de données.
Fond/premier plan. Les colonnes de carrés semblent passer devant l’objet en rotation. C’est obtenu en modifiant les données générées auparavant.
SCÈNE FINALE
Scène facile qui n’a pas coûté beaucoup de temps à coder.
À chaque frame, ne changer que les très rares octets qui ont changé (effacer en haut des cœurs, poser des pixels en bas).
Ensuite, en utilisant une table de masque inverse : quand on pose les pixels des cœurs, les pixels du fond ont la priorité.
Pour chaque cœur qui scrolle : effacer 7 octets, poser 7 nouveaux octets rouges.

[« Logon’s run - 3D meets the aging bits » - build spécial « hidden work »]

[« Logon’s run - 3D meets the aging bits » - build final]