mercoledì 27 aprile 2022

FREEDOM FIGHTER SMOOTH SCROLLING (ENG)



Finally, after making you wait too long, I am about to reveal how Freedom Fighter's smooth scrolling works.

Since I have to assume that the article will be read also by people who are not familiar with the MSX system (and, in this specific case, MSX1) I'll have to mention how the video memory (VRAM) of this system is organized (at least in the Graphic2 video mode, which is the one used in Freedom Fighter).

Let's start with the nametable. The nametable is the screen area, the one where in all systems (at least the ones I know) the characters that appear on the screen are "contained". The MSX screen has a resolution of 256x192 pixels. So it is made up of 24 lines. Each of them contains 32 characters (8x8 pixels). In total we therefore have 768 characters, so the nametable is 768 bytes long.
The particularity of the MSX, compared to other computers, concerns the use of these characters. In computers like the Commodore64 we have a set of 256 characters, which can be freely positioned anywhere on the screen. In the MSX system, on the other hand, in the Graphic2 mode the screen is divided into 3 zones of 8 lines each. Each of these zones has its own set of 256 characters (32x8 = 256) so the screen can be filled with 768 unique characters (very useful for bitmap graphics screens).
This means that to have the same characters in all of the 3 areas on the screen we will have to redefine them 3 times.
Much of the VRAM memory is used to memorize the shapes of the characters and their color attributes.
Each "block" of characters occupies 256x8 = 2048 Bytes. Therefore the definitions of all three character blocks use 6144 bytes of the 16384 available in the VRAM of the MSX1. The color attribute table has exactly the same length, because for each 8-pixel line of each character 2 colors can be specified (foreground and background): since the MSX1 has only 16 colors, with a single byte we can insert both (one in the high nibble and one in the low nibble). So even the color definitions occupy 6144 Bytes. In short, 12 KB are already gone for the definitions of our characters (the MSX community identifies them as "tiles").
Fortunately, once the shapes and colors have been defined, each character will have a unique code, so by recalling character 0 (for example) it will appear on the screen complete with its colors.
So as far as the characters are concerned, they occupy (including the nametable) about 13KB. The remaining 3KB contain the definitions of the 32 hardware sprites and their respective attributes (but I won't talk about it because it's not relevant to the scrolling technique I'm about to describe).

As many of you know, the MSX1 does not have any kind of hardware scrolling aid. Therefore, everything that scrolls on the screen is the result of software techniques: from block scrolling to those that in different ways have tried to bring fluidity to the shift of the screen on machines equipped with tms9918 (in its various incarnations) and compatible (therefore not only MSX but also Colecovision, Sega SG-1000 and TI99 / 4A, to name a few).

Before describing my personal technique, let's see which are the most commonly used to simulate vertical scrolling on MSX. We obviously assume that all three blocks of 256 characters are defined in the same way, because the characters that are in the first block will cross the whole screen and will then move on to the second and third blocks ...
The first technique is the simplest one. Obviously, this is block scrolling (characters), so with an 8 pixels movement at a time. As mentioned, the MSX screen consists of 24 lines of 32 characters each:



To move the content of the entire screen downwards, you need to move all the characters from the first line to the penultimate down and then draw the first line:



To speed up this operation, it's a good practice to have a copy of the nametable in a special buffer in RAM where you can quickly perform all the operations and then copy the contents to VRAM in one go. By doing this very quickly, scrolling can even seem fluid (see, for example, Konami's Road Fighter).

The second technique, commonly used to have a sufficiently fluid vertical scrolling on MSX is the 2 pixels scrolling. In practice, we have to keep stored in VRAM the various frames that make up the movement of one character to another. In this way, at each "step" of the scrolling we replace all the characters in the game area with their next frame (4 frames are needed to perform the complete scrolling of a character). After having "replaced" the characters 4 times, you return to the starting character and at the same time scroll the whole screen by 8 pixels.
Let's see an example with the Freedom Fighter graphics.



Let us consider the two highlighted characters. By performing a vertical scrolling downwards, the character of the water must slowly replace that of the shore. So the shore character will be "pushed" down 2 pixels at a time. In turn, the character immediately below (grass) will suffer the same fate due to the "shore" character and the character of the sea will also be supplanted by another character of the sea.

But maybe it is clearer with a visual example:



As you can see, the character at the top (water) in each frame is replaced with another in which the image is shifted down by 2 pixels and its first two lines contain the same data as the two lower lines of the character that is immediately above (in this case water, again)
In the same way, the character at the bottom (shore) at each frame is replaced with its image shifted by 2 pixels downwards and the first two lines contain the data of the last two of the uppermost character.
After 4 frames the classic block scrolling is carried out, whereby the character of the bank is completely replaced by that of water and that of water (in this case) by another character of water.
Let's do some calculations: 4 frames are needed for each character that must scroll, obviously related to the other characters that can be placed on it (scrolling starts in fact between 2 characters so it must be taken into account).
For which 256/4 = 64 total characters with which to build the graphics. As long as we don't need numbers and letters ... And we usually need them! Then we remove the digits 0-9. 64-10 = 54 characters. Then we remove the letters 54-26 = 28 characters with which to build the graphic. We can arrange and keep only the characters that make up the word SCORE, for example and maybe also HI so we can also have HISCORE so 54-7 = 47 characters.
From these characters we will have to organize the "pairs" of characters to scroll between them ... it follows that the graphics cannot be very varied, but for a fluid scrolling some sacrifices can also be made.
Now imagine that you want to achieve a fluid one pixel scrolling. 8 frames for each character? Forget it, come on!

Or maybe not.

 Here's how I approached the challenge for my Freedom Fighter.

The first step was obviously to decide the pairs of characters with which I would build the map (we said that scrolling always happens between two characters, right?). Let's start by saying that I have chosen to keep all the letters of the alphabet available (in addition to numbers and punctuation). Then I selected 30 pairs of characters, obtained by mixing 14 unique characters. Few to have a sufficient result. So at a certain point of the level the tileset (MSXists use the term tile to refer to the "tiles" that make up the graphics) is changed with another of 30 pairs of characters, some of which are in common, to facilitate the transition. from one tileset to another.
These are the two tilesets (3 rows of "pairs" for each tileset):



It is no coincidence that it shows you characters in pairs. It is from these pairs that the fluid scrolling of Freedom Fighter originates. Starting from these pairs, in fact, I constantly redefine the characters in order to "simulate" a scrolling. And I do it like this. The starting tile for scrolling is, between the two, the character below (the one that will be "interpenetrated" by the character above). The work that is performed, for each shift of a pixel (and for each pair of characters) is this:



These pairs of tiles are stored in the ROM of the cartridge (but in the very first version of the scrolling routine they were stored in RAM) one after the other, first the character definitions and then the color attributes. So from each pair of tiles I "extract" (pointing to the right memory location with an offset) the 8 bytes of the character definition and write them in VRAM, in all three character blocks. Then I repeat the operation for the color attributes: I extract the corresponding 8 bytes of the 30 characters and write them in VRAM in all three blocks.




Doing a quick calculation, to move the screen by one pixel I write in VRAM 8x30x3x2 = 1440 bytes. This leads to some problems: our MSX, in fact, cannot write all that data in VRAM during a single frame. The very first version of this routine, in fact, although fluid, presented several flickers and flashes. This is because often the raster beam reaches some characters while they are redefined and thus the modification of the characters and/or colors is visible.
To overcome this drawback it was necessary to implement a double buffer: in practice it was a matter of redefining characters NOT displayed on the screen and then swapping them once the process was finished. My solution was to use characters 128-157. So the "primary" characters are 0-29 and the "secondary" ones are 128-157.
The level map is unpacked in RAM (occupying just over 9 K) before the start of the level and the characters that form it are all belonging to the range 0-29.
Each time the character redefinition process is completed, a flag is updated to let us know which characters need to be redefined and which ones to show. So if we have to show the secondary characters, each value of the portion of the map displayed on the screen is read and an "xor 128" is made for each one (but it could also have been a simple sum) to point to the corresponding secondary character, before sending it to the screen.
Once the 7 pixel scrolling has been carried out, the offset of characters and colors are reset and a scrolling of one character is performed. Also in this case, having the whole map in RAM, it is sufficient to move the offset of the area to be copied to the nametable by 32 bytes back (the map is stored as seen on the screen).



When it is necessary to change tilesets, to add variety, we simply change the initial offsets pointing to the area of the ROM where the secondary tileset is stored.
I hope that this article hasn't bored you to death, but instead that it is an incentive to create your own technique or, why not, to improve this!
Soon (01/06/2022) I will declare Freedom Fighter as freeware and publish the code on Github. Be good when you look at it, I learned how to program in assembly by creating it!

martedì 26 aprile 2022

FREEDOM FIGHTER SMOOTH SCROLLING (ITA)





Finalmente, dopo aver rinviato troppo a lungo, mi accingo a rivelare come funziona lo smooth scrolling di Freedom Fighter.

Poiché devo presumere che l'articolo verrà letto anche da persone che non conoscono bene il sistema MSX (e in questo caso specifico MSX1) dovrò ovviamente accennare anche a come è organizzata la memoria video (VRAM) di questo sistema (almeno nel modo video Graphic2 che è quello usato in Freedom Fighter).


Comiciamo con la nametable. La nametable è l'area dello schermo, quella in cui in tutti i sistemi (almeno quelli che conosco) sono “contenuti” i caratteri che appaiono sullo schermo. Lo schermo dell'MSX ha una risoluzione di 256x192 pixels. Per cui è formato da 24 righe, ognuna delle quali contiene 32 caratteri 8x8 pixel. In totale abbiamo quindi 768 caratteri, per cui la nametable è lunga 768 bytes.
La particolarità dell'MSX, rispetto ad altri computer, riguarda proprio l'uso di questi caratteri. In computer come il Commodore64 abbiamo un character set di 256 caratteri, liberamente posizionabili in qualsiasi punto dello schermo. Nel sistema MSX, invece, nel modo Graphic2 lo schermo viene diviso in 3 zone da 8 righe ciascuna. Ognuna di queste zone ha un proprio charater set di 256 caratteri (32x8=256) per cui lo schermo può essere riempito con 768 caratteri tutti diversi uno dall'altro (questo è particolarmente utile per le schermate in grafica bitmap).
Questo significa che per avere gli stessi caratteri in tutte e 3 le zone dello schermo dovremo ridefinirli 3 volte.
Gran parte della memoria VRAM è utilizzata proprio per memorizzare le forme dei caratteri e i loro attributi colore.
Ogni “blocco” di caratteri occupa 256x8=2048 Bytes. Quindi le definizioni di tutti e tre i blocchi di caratteri usano 6144 Bytes dei 16384 disponibili nella VRAM dell'MSX1. La tabella degli attributi colori ha esattamente la stessa lunghezza, perchè per ogni linea di 8 pixel di ogni carattere possono essere specificati 2 colori (primo piano e sfondo): poiché l'MSX1 ha solo 16 colori, con un singolo byte possiamo inserire entrambi (uno del nibble alto e uno nel nibble basso). Quindi anche le definizioni dei colori occupano 6144 Bytes. Insomma, 12 KB se ne sono già andati per le definizioni dei nostri caratteri (la comunità MSX li identifica come “tiles”).
Fortunatamente, una volta definite forme e colori ogni carattere avrà un codice univoco, per cui richiamando il carattere 0 (ad esempio) esso comparirà a schermo completo dei suoi colori.
Quindi per quanto concerne i caratteri, essi occupano (compresa la nametable) circa 13KB. I rimanenti 3KB contengono le definizioni dei 32 sprites hardware e i loro rispettivi attributi (ma non ne parlerò perché non è rilevante per la tecnica dello scrolling di cui sto per parlare).


Come molti di voi sapranno, l'MSX1 non possiede nessun tipo di ausilio hardware allo scrolling. Per cui, tutto quello che scorre sullo schermo è frutto di tecniche software: dagli scrolling a blocchi a quelli che in diversi modi hanno cercato di portare fluidità nello shift degli schermi delle macchine dotate di tms9918 (nelle sue varie incarnazioni) e compatibili (quindi non solo MSX ma anche Colecovision, Sega SG-1000 e TI99/4A, per dirne alcuni).


Prima di descrivere la mia tecnica personale vediamo quale siano quelle più comunemente utilizzata per simulare uno scrolling verticale su MSX. Diamo ovviamente per scontato che tutti e tre i blocchi da 256 caratteri siano definiti allo stesso modo, perchè i caratteri che sono nel primo blocco attraverseranno tutto lo schermo e passeranno quindi al secondo e terzo blocco...
La prima tecnica è quella più semplice. Si tratta ovviamente dello scrolling a blocchi (caratteri), quindi con lo spostamento di 8 pixel per volta. Come detto, lo schermo MSX è formato da 24 righe da 32 caratteri ciascuna:



Per spostare verso il basso il contenuto di tutto lo schermo bisogna spostare tutti i caratteri dalla prima riga alla penultima verso il basso e poi disegnare la prima riga:



Per velocizzare questa operazione è buona norma avere una copia della nametable in un buffer apposito in RAM dove compiere velocemente tutte le operazioni per poi copiarne il contenuto in VRAM in una volta sola. Eseguendo questa operazione molto velocemente lo scrolling può addirittura sembrare fluido (cito ad esempio Road Fighter della Konami).


La seconda tecnica, comunemente usata per avere uno scrolling verticale sufficientemente fluido su MSX è quella dello scrolling a passi di 2 pixel. In pratica, dobbiamo tenere memorizzati in VRAM i vari fotogrammi che compongono lo spostamento di un carattere verso un altro. In questo modo, ad ogni “passo” dello scrolling sostituiamo tutti i caratteri presenti nell'area di gioco con il loro fotogramma successivo (per eseguire lo scrolling completo di un carattere servono 4 fotogrammi). Dopo aver “sostituito” i caratteri 4 volte si ritorna al carattere di partenza e allo stesso tempo si effettua uno scrolling di 8 pixel.
Vediamo un esempio con la grafica di Freedom Fighter.


Prendiamo in esame i due caratteri evidenziati. Eseguendo uno scrolling verticale verso il basso, il carattere dell'acqua deve lentamente sostituire quello della riva. Per cui il carattere della riva verrà “spinto” verso il basso 2 pixel alla volta. A sua volta anche il carattere subito sotto (erba) subirà la stessa sorte ad opera del carattere “riva” e anche il carattere del mare verrà soppiantato da un altro carattere del mare.

Ma forse è più chiaro con un esempio visivo:


Come vedete, il carattere in alto (acqua) ad ogni frame viene sostituito con un altro in cui l'immagine è spostata verso il basso di 2 pixel e le sue prime due righe contengono gli stessi dati delle due righe più basse del carattere che si trova subito sopra (in questo caso altra acqua)
Allo stesso modo il carattere in basso (sponda) ad ogni frame è sostituito con la sua immagine spostata di 2 pixel verso il basso e le prime due linee contengono i dati delle ultime due del carattere più in alto.
Dopo 4 frames viene effettuato il classico scrolling a blocchi, per cui il carattere della sponda è completamente sostituito da quello dell'acqua e quello dell'acqua (in questo caso) da un altro carattere dell'acqua.
Facciamo un po' di calcoli: servono 4 frames per ogni carattere che deve scrollare, ovviamente correlati agli altri caratteri che gli possono essere posti sopra (lo scrolling avviane infatti tra 2 caratteri per cui se ne deve tenere conto).
Per cui 256/4=64 caratteri totali con cui costruire la grafica. Sempre che non ci servano numeri e lettere... E di solito ci servono! Quindi togliamo le cifre da 0 a 9. 64-10=54 caratteri. Poi togliamo le lettere 54-26=28 caratteri con cui costruire la grafica. Ci si può arrangiare e tenere solo i caratteri che compongono la parola SCORE, ad esempio e magari anche HI così possiamo avere anche HISCORE quindi 54-7=47 caratteri.
Da questi caratteri dovremo organizzare le “coppie” dei caratteri da scrollare fra loro... ne consegue che la grafica non potrà essere molto varia, ma per uno scrolling fluido qualche sacrificio lo si può anche fare.
Immaginate ora di voler realizzare uno scrolling fluido “al pixel”. 8 frames per ogni carattere? Lasciamo perdere, dai!


Oppure no. 

Ecco come ho affrontato la sfida per il mio Freedom Fighter.

Il primo passo è stato ovviamente decidere le coppie di caratteri con i quali avrei costruito la mappa (abbiamo detto che lo scrolling avviene sempre tra due caratteri, no?). Cominciamo col dire che ho scelto di tenere disponibili tutte le lettere dell'alfabeto (oltre ai numeri e alla punteggiatura). Dopodiché ho selezionato 30 coppie di caratteri, ottenute mescolando 14 caratteri unici. Pochi per avere un risultato sufficiente. Per cui ad un certo punto del livello il tileset (gli MSXisti usano il termine tile per riferirsi alle “mattonelle” che compongono la grafica) viene cambiato con un altro di 30 coppie di caratteri, alcuni dei quali sono in comune, per facilitare la transizione da un tileset all'altro.
Questi sono i due tileset del primo livello (3 righe di “coppie” per ogni tileset):



Non è un caso che vi mostri i caratteri in coppie. E' proprio da queste coppie che ha origine lo scrolling fluido di Freedom Fighter. Partendo da queste coppie, infatti, ridefinisco costantemente i caratteri in modo da “simulare” uno scrolling. E lo faccio in questo modo.

Il tile di partenza per lo scrolling è, tra i due, il carattere che sta sotto (quello che verrà “compenetrato” dal carattere sovrastante). Il lavoro che viene eseguito, per ogni scorrimento di un pixel (e per ogni coppia di caratteri) è questo:


Queste coppie di tiles sono memorizzate nella ROM della cartuccia (ma nella primissima versione della routine di scrolling erano memorizzate in RAM) una di seguito all'altra, prima le definizioni dei caratteri e di seguito gli attributi colore. Quindi da ogni coppia di tiles “estraggo” (puntando alla giusta locazione di memoria con un offset) gli 8 bytes della definizione del carattere e li scrivo in VRAM, in tutti e tre i blocchi caratteri (è infatti necessario che i caratteri siano gli stessi in tutti e tre i blocchi). Subito dopo ripeto l'operazione per gli attributi colore: estraggo gli 8 bytes corrispondenti dei 30 caratteri e li scrivo in VRAM in tutti e tre i blocchi.



Facendo un rapido calcolo, per spostare di un pixel lo schermo scrivo in VRAM 8x30x3x2=1440 bytes. Questo comporta qualche problema: il nostro MSX, infatti, non riesce a scrivere tutti quei dati in VRAM durante un solo frame. La primissima versione di questa routine, infatti, seppur fluida presentava diversi sfarfallamenti e lampeggi. Questo perché la ridefinizione dei caratteri non era ancora completata durante il passaggio del pennello elettronico, per cui in alcuni punti dello schermo era possibile vedere il “lavoro” di ridefinizione.

Per ovviare a questo inconveniente si è reso necessario implementare un double buffer: in pratica si trattava di ridefinire caratteri NON visualizzati sullo schermo per poi scambiarli una volta terminato il processo. La mia soluzione è stata utilizzare i caratteri dal 128 al 157. Quindi i caratteri “primari” sono 0-29 e i “secondari” 128-157.
La mappa del livello viene scompattata in RAM (occupando poco più di 9 K) prima dell'inizio del livello e i caratteri che la formano sono tutti appartenenti al range 0-29.
Ogni volta che il processo di ridefinizione dei caratteri viene completato, un flag viene aggiornato per farci sapere quali caratteri devono essere ridefiniti e quali mostrati. Per cui se dobbiamo mostrare i caratteri secondari ogni valore della porzione di mappa visualizzata sullo schermo viene letto e per ognuno viene effettuato un “xor 128” (ma avrebbe potuto anche essere una semplice somma) per puntare al carattere secondario corrispondente, prima di inviarlo allo schermo.
Una volta effettuato lo scrolling di 7 pixel gli offset di caratteri e colori vengono resettati e viene effettuato uno scrolling di un carattere. Anche in questo caso, avendo tutta la mappa in RAM, è sufficiente spostare l'offset dell'area da copiare nella nametable di 32 bytes indietro (la mappa è memorizzata così come si vede a schermo).



Quando è necessario cambiare tileset, per aggiungere varietà, si cambiano semplicemente gli offset iniziali puntando alla zona della ROM in cui è memorizzato il tileset secondario.
Spero che l'articolo non vi abbia annoiato a morte, ma vi sia invece di stimolo a creare una vostra tecnica personale o, perché no, a migliorare questa!
A breve (01/06/2022) dichiarerò Freedom Fighter come freeware e ne pubblicherò il codice su Github. Siate buoni quando lo esaminerete, ho imparato a programmare in assembly creandolo!