Amiga in modalità HAM: gioia per gli occhi, ma per pochi giochi

Di recente è tornato alla ribalta l’utilizzo della modalità HAM (acronimo di Hold-And-Modify) dell’Amiga, che consente di visualizzare fino a 4096 colori sullo schermo col suo particolare modo di manipolari (maggiori dettagli nel link), grazie a un nuovo gioco sviluppato da un appassionato e che effettivamente si mostra come un’autentica meraviglia (nonché perla di programmazione. A parte alcuni problemi di compatibilità con piattaforme diverse dall’originale Amiga, come sistemi con alcune schede acceleratrici): Hamulet.

Qui si trova la mappa del livello demo.

Ma ancora più impressionante è il video, dal qualche emergono anche effetti di luce delle “tessere” (le famigerate tile utilizzate nei videogiochi che costruiscono la mappa dello schermo partendo da un loro insieme. Utilizzo sempre il termine tile d’ora in avanti, perché è quello diffuso in quest’ambito), oltre al notevole numero di oggetti grafici (pare siano soltanto sprite) che riesce a muovere a schermo:

I difetti dell’HAM

La peculiarità di questo gioco è che fa utilizzo di scroll multidirezionale, cioè sia in orizzontale che in verticale. Passi quello verticale, che non causa eccessivi problemi se implementato in una certa maniera (ad esempio utilizzando un framebuffer di altezza doppia), ma è ben noto che quello orizzontale mal si sposi con questa particolare modalità grafica, poiché saltano fuori i cosiddetti problemi di fringing.

Si tratta dell’apparizione di artefatti grafici quando si deve passare (orizzontalmente) da un colore a un altro, che non è presente fra i 16 colori base disponibili in questa modalità, oppure richiede alcuni passaggi (fino a un massimo di 3) per poter cambiare, una alla volta, ogni componente cromatica (in un pixel se ne cambia soltanto una, lasciando invariate le altre due).

Un esempio tratto da Wikipedia mostra un caso abbastanza estremo (usando soltanto due colori base: il bianco e il nero) per enfatizzare l’effetto di transizione a un colore non presente in quelli base e che richiede cambiamenti significativi per arrivare a quello voluto:

Ovviamente negli esempi reali le immagini non sono strapiene di fringing, perché generalmente pixel vicini hanno componenti cromatiche molto simili, ma in casi di “note particolarmente stonate”, non si fa fatica a riconoscerle. Come capita, nello specifico, nei primi 2 pixel di ogni immagine, poiché il colore di partenza è quello dello sfondo (generalmente il nero), come si può vedere in alcune famose foto digitalizzate:

Nel caso di immagini di qualsiasi natura, come queste per l’appunto, l’effetto di fringing al bordo sinistro è sempre presente, perché rappresenta il caso estremo per eccellenza ed è ineliminabile, poiché i colori base rimangono sempre 16. Si potrebbero riprogrammare a ogni riga orizzontale (ricorrendo al Copper. Uno dei due coprocessori dell’Amiga), in modo da ottimizzarne l’uso riga per riga, ma il numero di pixel di una riga rimane in ogni caso sempre nettamente superiore a 16.

Attivando lo scroll orizzontale si presenta praticamente sempre, poiché il controllore video inizia a disegnare il primo pixel di una riga che si può trovare in mezzo a qualunque tipo di colore, ed è molto probabile, per quanto detto sopra, che non si tratti di un colore base.

Come Hamulet “risolve” queste seccature

Hamulet risolve in maniera elegante questo problema utilizzando una barra verticale a sinistra costituita da sprite (i quali hanno una loro tavolozza dei colori e vengono visualizzati esattamente allo stesso modo a video, a prescindere dalla modalità grafica utilizzata per lo schermo), che copre (almeno) le prime due colonne di pixel dello schermo visualizzato.

Rimane, però, il fringing generato dall’utilizzo delle summenzionate tile. A occhio risulta evidente che il gioco utilizzi tile di 16 x 16 pixel (le più comuni utilizzate con l’Amiga), per cui la mappa dello schermo è costruita mettendo assieme un certo numero di queste tile fino a comporre tutta l’area visibile (fatta eccezione per la barra verticale sinistra che, come spiegato, è realizzata facendo uso degli sprite).

La rogna, in questo caso, è rappresentata dal fatto che ogni tile è sostanzialmente un componente grafico a sé stante e, soprattutto, il cui colore di ogni primo pixel di ogni sua riga potrebbe essere, in linea teorica, uno qualunque. In pratica, e proprio a causa della modalità HAM, è sempre conveniente che sia, invece, uno dei 16 colori base, ma in questo modo salteranno in ogni caso fuori gli artefatti visivi generati dal fringing.

Il programmatore del gioco ha dichiarato che le tile sarebbe state realizzate in modo da eliminare il fringing, e direi che non è affatto difficile crederlo andando a guardare più attentamente la schermata all’inizio o soffermandosi su qualche fotogramma del video. Si noterebbe, infatti, la costante presenza di colonne di pixel rigorosamente in grigio, ogni 16 pixel, anche quando la specifica tile abbia tutt’altro colore:

La seconda colonna (quella a seguire di quella grigia) è, in genere, affetta da qualche artefatto dovuto alla transizione, ma dipende dalla specifica tile (se le tile sono progettate appositamente tenendone conto, come in questo caso, l’impatto è nullo o minimo). Anche la terza colonna può essere affetta, ma in maniera ancora più limitata (e vale sempre il discorso della realizzazione delle tile).

La scelta del grigio è essenziale, poiché è il colore che ha lo stesso valore per tutte e tre le componenti cromatiche, e il cui effetto di transizione cambiando una sola componente alla volta risulta, quindi, molto più ridotto: più “soffice” e gradevole alla vista.

Le animazioni in Hamulet

Come per lo scroll, anche l’animazione della grafica del gioco non può che essere una perenne fonte di fringing, dovuta sempre al problema di far collimare i colori dei pixel che si muovono con quelli che sono fermi, cercando di eliminare o ridurne gli effetti.

Si tratta di una grossa gatta da pelare che il programmatore ha scelto di risolvere in maniera radicale: senza modificare la grafica dello schermo, ma facendo amplissimo ricorso ai summenzionati sprite che, come già precedentemente riportato, sono sempre visualizzati allo stesso modo, a prescindere dalla modalità grafica utilizzata.

Esistono, però, due problemi con gli sprite. Il primo è che la loro tavolozza cromatica è limitata a soli 15 colori in totale (che, fortunatamente, sono indipendenti dai 16 base utilizzati dall’HAM). In questo caso il motore grafico del gioco riesce a mitigare il problema riprogrammando, per ogni singola riga, fino a 12 colori di questa tavolozza.

Il secondo problema è dovuto al fatto che gli sprite a disposizione nell’Amiga sono soltanto otto e dotati di soli 3 colori (il primo viene usato per “bucarne” la grafica per visualizzare quella dello schermo). Oppure fino a quattro da 15 colori “appaiandone” due alla volta. Anche qui il motore grafico si adopera nella cosiddetta tecnica di multiplexing degli sprite, provvedendo manualmente a riprogrammarne la posizione orizzontale e/o la grafica (usando sempre il Copper), in modo da simulare più sprite a schermo.

Il multiplexing è possibile perché il Copper consente di cambiare i valori dei registri (sempre a 16 bit) degli sprite, ma con uno schermo HAM (che utilizza ben 6 bitplane per prelevare i dati della grafica) ha davvero poco margine per poter effettuare quest’operazione (una MOVE). Infatti l’istruzione del Copper occupa 32 bit, ossia due word (16-bit. Una per selezionare il registro del chipset da cambiare e un’altra per il valore da scrivergli) che devono prima essere lette in memoria (l’unica accessibile dal chipset: quella “Chip”), effettuando quindi due accessi per prelevarle.

Casualmente il controllore video utilizza 6 “slot” (accessi alla memoria. Vedi alcuni vecchi articoli in merito: Divide et impera: i color clock nelle righe di raster dell’Amiga e I bitplane e le righe di raster: l’Amiga visualizza la grafica dello schermo) per prelevare il contenuto dei 16 pixel da visualizzare per ciascuno dei 6 bitplane dello schermo HAM, dunque rimangono due slot inutilizzati che il Copper può sfruttare per leggere le due word per una sua istruzione.

Questo perché il controllore video lavora sempre a gruppi di 8 slot nel caso in cui debba visualizzare la grafica dello schermo, per poi ricominciare di nuovo le stesse, identiche, operazioni nel gruppo successivo. Quindi ogni 8 slot in cui c’è grafica da visualizzare, 6 vengono effettivamente utilizzati quando lo schermo è in modalità HAM, mentre due sono sempre liberi.

Il problema è che due slot liberi significa dare la possibilità di poter eseguire soltanto un’istruzione del Copper (che ne richiede sempre due, per l’appunto), limitando pesantemente quello che si può fare ogni 16 pixel visualizzati (i gruppi di 8 slot di cui sopra riguardano sempre 16 pixel alla volta da visualizzare).

Nello specifico, con una sola istruzione del Copper si può, ad esempio, cambiare la posizione iniziale in cui visualizzare uno sprite (che era già stato precedente visualizzato o con la sua grafica già caricata. Mi riferisco a esattamente gli stessi 16 pixel che erano stati visualizzati o caricati), ma non anche quella finale (quando il controllore deve smettere di visualizzarne il contenuto).

Cambiare quella finale, comunque, non è un problema insormontabile: siccome serve, appunto, a bloccarne la visualizzazione, si può istruire il controllore anche alla fine della visualizzazione della riga dello schermo, quando subentra il cosiddetto intervallo di rinfresco orizzontale (horizontal blanking) e tutti gli slot a disposizione possono essere utilizzati (ma non sono tanti, comunque).

Sono necessarie due istruzioni del Copper se, invece, si vuole cambiare la grafica di uno sprite, poiché per visualizzare 4 colori servono due bitplane e, quindi, due word (sempre a 16-bit) devono essere lette dalla memoria Chip.

Infine, se lo sprite utilizza 16 colori e non 4, quanto scritto sopra va raddoppiato, in quanto vengono combinati due sprite da 4 colori per formarne uno a 16 colori (per cui i registri dei rispettivi sprite devono essere opportunamente caricati).

Ricapitolando, se si vuole:

  • riutilizzare uno sprite (quindi con la stessa grafica già caricata) a 4 colori è necessaria un’istruzione del Copper / due slot liberi;
  • riutilizzare uno sprite a 4 colori cambiandone l’altezza sono necessarie due istruzioni del Copper / quattro slot liberi;
  • modificare la grafica di uno sprite a 4 colori sono necessarie due istruzioni del Copper / quattro slot liberi;
  • combinare una delle prime due con la terza sono necessarie tre o quattro istruzioni del Copper / sei o otto slot liberi;
  • una delle precedenti, ma con sprite a 16 colori, bisogna raddoppiare il tutto.

Da puntualizzare, in conclusione, che gli sprite sono larghi sempre e soltanto 16 pixel. Cioè esattamente la larghezza massima che si può osservare nei vari oggetti che si muovono a schermo (incluso il protagonista). Oltre al fatto che la quasi totalità degli sprite risultano allineati a passi di 16 pixel; probabilmente per le limitazioni relative agli slot, come discusso prima.

Motore grafico esemplare, ma estremamente limitato (“ad hoc“)

Con questi accorgimenti il motore grafico riesce a deliziare la vista con l’ampia gamma cromatica in mostra, nonché le numerose animazioni (complessive. Per ogni riga risultano limitate per quanto scritto nella precedente sezione), e il tutto girando alla velocità massima possibile (60 fotogrammi al secondo per le macchine NTSC e 50 per quelle PAL).

Anche se più che di accorgimenti si dovrebbe parlare propriamente di compromessi: pesanti compromessi. Sono, infatti, diversi quelli che il programmatore ha adottato pur di ottenere l’obiettivo di realizzare un gioco che sfrutti la modalità HAM senza ricadere vistosamente negli artefatti generati dal fringing, che si sarebbero potuti rivelare un pugno nell’occhio.

Non credo di sbagliare, pertanto, se affermo che è stato realizzato proprio attorno alla e per la modalità HAM: un motore grafico scritto ad hoc, che ne sfrutta i vantaggi riducendo al minimo le problematiche. Non è un caso, infatti, che non siano stati utilizzati i BOB (Blitter Object: oggetti grafici realizzati utilizzando il Blitter) per i personaggi o le animazioni, affidandosi interamente agli sprite (che sono del tutto “immuni” agli artefatti visivi, poiché sono totalmente indipendenti dalla modalità utilizzata per visualizzare lo schermo).

Questo è anche il motivo per cui vengono pesantemente utilizzati con la tecnica del multiplexing, per riutilizzarli il più possibile orizzontalmente (normalmente il controllore video può visualizzare al massimo 4 sprite a 16 colori), oltre che per cambiarne alcuni colori al volo (massimo 12 per riga video, come dichiarato dallo sviluppatore): è l’unico mezzo a disposizione per la grafica animata e per variare l’altrimenti povera tavolozza dei colori degli sprite.

Per far questo il motore grafico cerca di sfruttare come meglio può e in maniera sapiente i pochi slot che il controllore video lascia a disposizione quando visualizza la grafica. HAM, come pure l’Extra Half-Brite, utilizza ben 6 bitplane, per cui soltanto il 25% degli slot (accessi alla memoria) sono liberamente utilizzabili quando il pennello elettronico è al lavoro, ed è il motivo per cui sono pochissimi (rispetto alla vastissima libreria per la nostra amata piattaforma) i titoli che ne hanno fatto uso.

Molto probabilmente il motore grafico si occupa di fare praticamente solo questo nel momento in cui vengono visualizzate le righe in cui è presente la grafica del gioco, mentre nelle altre righe (che appartengono al cosiddetto intervallo di rinfresco verticale: vertical refresh) si elabora la “business logic” (mi spiace per i puristi della lingua italiana, ma l’equivalente italiano suona decisamente male per essere utilizzato in questo contesto), che si occupa anche di costruire la lista di istruzioni del Copper (chiamata Copper List, in gergo amighista. Il termine generico in computer grafica è Display List) che verrà poi eseguita durante l’elaborazione del fotogramma successivo, e la quale si occupa proprio di tutto quanto riportato in precedenza (multiplexing degli sprite, cambio colori della tavolozza).

Niente di generico e liberamente utilizzabile

Va da sé che tutto ciò porta all’ovvia (ma non tanto, per chi non è esperto in materia e sogna ad occhi aperti) conclusione che questo motore grafico non si possa né si sarebbe potuto utilizzare (se fosse stato disponibile all’epoca della nostra gloriosa macchina) per implementare qualunque videogioco: soffre di troppe, pesanti, limitazioni ed è stato realizzato appositamente per Hamulet e la sua particolare meccanica di gioco.

E’ chiaro che altri giochi con meccaniche simili si possano realizzare, ma sfruttando proprio quello che il programmatore ha messo a disposizione oppure rifacendo sostanzialmente le stesse scelte.

Perché non v’è né può esserci piena libertà per i programmatori, che non possono usare il Blitter per muovere oggetti sullo schermo con o al posto degli sprite, in quanto si manifesterebbero immediatamente gli artefatti grafici generati dal fringing e che non si possono eliminare nemmeno circondando tali oggetti da un bordo facente uso dei colori base (si “salverebbe” soltanto una parte della grafica del personaggio / oggetto grafico, ma salterebbero fuori gli artefatti finita tale grafica e dovendo visualizzare quella dello schermo).

Conseguenza di ciò è che non ci sarebbe libertà nemmeno per gli artisti, perché contornare qualunque oggetto di un bordo avrebbe delle ripercussioni dal punto di vista estetico, producendo risultati diversi da quelli voluti. Oltre al fatto che, come detto, il fringing apparirebbe comunque non appena superato tale bordo, quando la grafica dello schermo dovrebbe essere visualizzata. Dulcis in fundo, la sovrapposizione di BOB comporterebbe la relativa sovrapposizione dei relativi bordi, con risultati che potrebbero essere anche peggiori…

Sia chiaro che programmatori e grafici non è che abbiano libertà assoluta e possano fare quello che vogliono quando lavorano allo sviluppo di qualche progetto videoludico: i vincoli dettati dall’hardware e dallo specifico gioco ci sono sempre, che pongono sempre un limite a ciò che sia fattibile. Ma nel caso della modalità HAM, e di questo particolare gioco, è evidente che ci siano di gran lunga più restrizioni e impedimenti rispetto a quanto si verifichi con giochi diversi che facciano uso di una delle altre modalità grafiche.

Si potrebbero fare facilmente degli esempi in merito, prendendo alcune vecchie glorie del passato di qualche categoria e “pensandole” realizzate in HAM. Intanto si tagliano subito tutti i giochi che facciano uso della modalità Dual Playfield, perché con l’HAM c’è un solo schermo (scrollabile in maniera indipendente) a disposizione.

Passando ai giochi con un solo schermo, andiamo subito al sodo con un picchiaduro: Mortal Kombat, che già nell’originale da sala faceva uso grafica digitalizzata e che, quindi, si presterebbe decisamente bene con l’HAM (che per ovvi motivi, infatti, è stato ampiamente utilizzato dalle applicazioni di visualizzazione di immagini particolarmente ricche di colori).

Ci sono personaggi che si estendono anche per più di mezzo schermo, e che è impossible rendere a video sfruttando gli sprite, perché ce ne sono soltanto 4 larghi 16 pixel e non ci sono abbastanza slot liberi per poterli riprogrammare (tra l’altro le posizioni sullo schermo sono arbitrarie e non a multipli di 16 pixel orizzontalmente). Oltre al fatto che i colori sono limitati a 15 in totale e anche cambiandone fino a 12 per ogni riga visualizzata non potrebbero in ogni caso riuscire a coprire tutta la gamma cromatica.

Si dovrebbe, quindi, ricorrere al Blitter sfruttando i summenzionati BOB, ma a questo punto salterebbero fuori parecchi artefatti grafici con tutta quella grafica in movimento e i personaggi che si sovrappongono. A cui si aggiunge il fatto che la grafica in modalità HAM “costa” in termini sia di spazio (6 bitplane da utilizzare e senza i trucchetti possibili come con la modalità EHB) sia di banda di memoria, per cui si dovrebbe necessariamente ridurre lo spazio per le animazioni e anche la fluidità della visualizzazione.

Prendiamo un altro gioco in cui la grafica non ha personaggi / oggetti così grandi, ma sono molto piccoli, con la maggior parte (soldati, uccelli, ecc.) come quelli di Hamulet: Cannon Fodder.

Qui sorgono tre problemi. Il primo è che almeno i soldati si muovono in maniera abbastanza libera e possono sovrapporsi, e avendone un numero elevato molto vicino si potrebbe eccedere il massimo di 4 larghi 16 pixel che il chipset dell’Amiga concede per ogni riga visualizzata. Anche perché lo sprite del mouse si muove anch’esso liberamente, essendo sotto il controllo dell’utente, e potrebbe sovrapporsi al mucchio di soldati. Il motore del gioco dovrebbe stare molto attento a questi casi, e potrebbe sacrificare la visualizzazione di qualche sprite quando c’è eccessiva sovrapposizione, generando artefatti visivi (apparizioni / sparizioni di oggetti).

Il secondo problema è rappresentato dalle animazioni della grafica del fondale, come ad esempio quando viene fatta saltare in aria una baracca. Il grafico dovrebbe fare un notevole sforzo per preparare queste animazioni in modo da evitare il più possibile il fringing. Lo stesso vale per i soldati che vengono uccisi o feriti in determinate aree della mappa, e che richiederebbero apposita grafica per le loro animazioni, per farle incastrare in maniera naturale e senza fringing dove si trovano.

Sarebbe necessario un lavoro enorme per il programmatore e per il grafico, tra l’altro sfruttando anche il Blitter per le animazioni. Infatti una baracca è troppo grande per poter essere animata facendo uso dei soli sprite, anche perché potrebbero esserci dei personaggi / oggetti proprio sulla sua area (quindi sovrapposti a essa), e non sarebbe possibile utilizzare altri sprite. Quindi col rischio di non riuscire a visualizzare la grafica a 60 (NTSC) o 50 (PAL) fotogrammi al secondo, dovendo ricorrere a tecniche di double buffering e, quindi, consumando ulteriore memoria nonché banda.

Dulcis in fundo (e terzo problema), Cannon Fodder utilizza le tile per generare la mappa dello schermo. Abbiamo visto come quelle di Hamulet siano realizzate in maniera particolare per ridurre al minimo il fringing, ma ciò comporta enormi limitazioni a livello artistico, per cui ci si dovrebbe scordare la grafica per come la conosciamo noi (mi riferisco alla ricchezza dei dettagli che offre questo gioco, fino al singolo pixel).

Conclusioni

Questo giochetto si potrebbe fare prendendo un qualunque altro gioco pubblicato per Amiga e analizzandone il funzionamento per vedere se si riesca in qualche modo a inquadrare nei limiti del motore grafico di Hamulet, ma mi fermo qui perché il concetto che ho voluto esprimere dovrebbe essere piuttosto chiaro ormai: la modalità HAM presenta troppe limitazioni che mal si sposano con la gran varietà di giochi che sono stati realizzati (e che si possono realizzare).

Qualcuno ha sdoganato l’idea di utilizzarla, ad esempio, per il Workbench, in modo da poter avere immagini con tanti colori utilizzate per gli sfondi delle finestre. A parte il fatto che, almeno coi chipset OCS o ECS, funzionerebbe soltanto in bassa risoluzione (320×200 o 320×256 pixel, a seconda se NTSC o PAL) mentre il Workbench funziona (a buon motivo) ad alta risoluzione (640×200 o 640×256), bisogna prepararsi a un’esplosione di artefatti causati sempre dal fringing, che alla fine farebbe saltare i nervi.

Se qualcuno volesse provare personalmente gli effetti del fringing potrebbe far utilizzare un programma di grafica per Amiga che supporti l’HAM (ad esempio Deluxe Paint o Personal Paint), caricare un’immagine HAM e poi caricarne un’altra qualunque da utilizzare come pennello (brush, in gergo): spostandosi col mouse si sposterebbe in tempo reale anche il pennello con la nuova immagine, con un fioccare di fringing nei contorni del pennello.

Parafrasando una nota pubblicità italiana, HAM: per pochi e non per tutti…

Press ESC to close