di  -  venerdì 6 maggio 2011

Pubblichiamo un contributo di Antonio Barba, sviluppatore software specializzato nel ramo videogiochi.

Come accennato nell’articolo precedente, il Nitro Processor, il componente principale del Nintendo DS, contiene 3 distinti coprocessori grafici denominati:
⁃ 2D Graphics Engine A
⁃ 2D Graphics Engine B
⁃ 3D Graphics Engine

La grafica 2D
I due coprocessori 2D Graphics Engine A e B, come intuibile, si occupano di disegnare la grafica 2D su ciascuno dei due schermi del Nintendo DS. Sono quasi gemelli, fatta eccezione per alcuni particolari che rendono l’engine B leggermente meno flessibile dell’engine A. Il programmatore può decidere arbitrariamente di collegare ciascun engine 2D allo schermo superiore o a quello inferiore, e può modificare questa impostazione in qualunque momento durante la pausa del Vertical Blanking (è quel breve periodo di tempo che intercorre tra la fine di un frame video e l’inizio del successivo).

Il timing dei due schermi è perfettamente sincronizzato, questo per evitare problemi nel caso si vogliano scambiare frequentemente gli agganci tra engine e schermo.
Nonostante il Nintendo DS sia provvisto esclusivamente di schermi a cristalli liquidi, l’engine grafico simula la presenza di un segnale video analogico. Questo significa che dopo il disegno di una riga orizzontale ci sarà una pausa definita Horizontal Blanking, che nei display a tubo catodico serve per riportare il pennello elettronico all’inizio della riga successiva. Dopo la scansione delle 192 righe orizzontali del display, segue il Vertical Blanking, più lungo dell’H-Blank, che serve per riportare il pennello elettronico (simulato) all’inizio della prima riga dello schermo per disegnare il frame successivo.

La presenza di queste pause consente di “infilare” delle istruzioni tra il disegno di una riga e la successiva, oppure tra un frame e il successivo, in modo perfettamente sincronizzato con lo schermo. Questa caratteristica consente di scrivere i giochi esattamente come si faceva nelle vecchie console casalinghe e nei primi Home Computer, che erano sostanzialmente legati (nella temporizzazione) allo standard televisivo PAL o NTSC (a seconda del paese).
Ad esempio, è possibile modificare al volo i registri video durante la schermata, per simulare effetti grafici particolari come visualizzare migliaia di colori usando palette da soli 16 colori (basta usare una palette diversa per ogni riga). Tuttavia questa tecnica, pur essendo attuabile, non è necessaria sul DS, perchè è possibile visualizzare immagini fino a 15 bit di colore (cioè 32768 colori).
Composizione di una schermata tipica
I due engine 2D compongono la schermata utilizzando tipicamente 3 elementi:
⁃ BG
⁃ OBJ
⁃ Backdrop

BG sta per Background. Si tratta di grosse schermate in formato Bitmap o Text. Si usano prevalentemente per gli sfondi. Possiamo avere fino a 4 diversi BG sovrapposti.
OBJ sta per Objects, e si tratta dei famosi Sprites. Sono piccoli elementi grafici che possono muoversi in modo indipendente dallo sfondo. Anch’essi possono essere in formato Bitmap o Text.

Infine il Backdrop non è altro che “tutto il resto”, cioè un colore omogeneo che copre il fondo dello schermo. Tipicamente il colore di Backdrop coincide con il colore numero 0 della palette principale (c’è sempre una palette principale con una sua memoria dedicata, ma possono essere caricate delle palette estese sulla comune VRAM).

A seconda della modalità video selezionata, cambiano il tipo e la dimensione dei 4 BG presenti in ciascun engine, inoltre i due engine 2D vengono configurati in modo indipendente, e devono spartirsi di conseguenza i vari banchi di VRAM.
Si va dal Mode 0 che imposta tutti e 4 i BG in modalità Text, fino al Mode 5 che imposta i primi 2 come Text e gli altri 2 come Affine Extended. Il 2D Engine A, a differenza del B, può impostare il BG0 in modalità 3D il che consente di visualizzare le immagini generate dal 3D Engine come se fossero un BG, quindi facilmente mescolabili insieme alla grafica 2D.

La dimensione di un BG va da un minimo di 128×128 (utile per rappresentare grossi oggetti che non entrano in uno Sprite) fino ad un massimo di 1024×1024 (utile per fare lo scrolling di grosse mappe). Il numero di colori va da un minimo di 16 fino ad un massimo di 32768. La combinazione di dimensioni, colori e formato influiscono sulla quantità di VRAM occupata, e di questo il programmatore deve tener conto quando progetta la composizione di una schermata di gioco.

Gli OBJ hanno dimensioni che variano da 8×8 fino a 64×64 pixel, possono avere forma rettangolare purchè le dimensioni siano sempre potenze di 2 (ad esempio 32×16 è una dimensione valida, mentre 40×20 non lo è). Si possono utilizzare fino a 128 OBJ contemporaneamente, e possono stare tutti e 128 contemporaneamente sulla stessa riga (il Graphics Engine del GameBoy Advance e tutte le precedenti console avevano dei limiti per quanto riguarda il numero massimo di sprite su una linea).

Come per i BG, anche gli OBJ possono avere da 16 a 32768 colori.
Characters, Bitmap e trasformazioni affini
Sia i BG (sfondi) che gli OBJ (sprite), possono essere rappresentati in memoria in due diversi formati.

Il formato Character è quello più utilizzato per i BG, perchè consente di disegnare grandi aree usando poca memoria. L’immagine viene scomposta sostanzialmente in caselle quadrate da 8×8 pixel, e a ciascuna casella è assegnato un numero, è la cosiddetta Screen Map. Il 2D Graphics Engine legge questo numero e lo usa come “indice” per andare a pescare la corrispondente casella 8×8 all’interno della Character Map.

Sembra complicato come meccanismo, ma basta guardare la grafica un vecchio gioco per capire subito come funziona. Ad esempio nella classica schermata di un gioco di tipo RPG possiamo vedere che il tipico cespuglietto d’erba è sempre identico ovunque si trovi. L’immagine di questo cespuglietto sarà rappresentato, ad esempio, dalla casellina numero 5 della Character Map. Se vogliamo disegnare una fila di 4 cespugli sullo schermo, basterà scrivere una file di byte nella Screen Map contenente i valori 5555.

È chiaro che l’uso intelligente di questa tecnica consente di risparmiare moltissima memoria video.

La Character Map, a sua volta, rappresenta i pixel delle caselline utilizzando una Palette di colori per risparmiare ulteriore memoria. In questo modo, anziché usare 16 bit per ogni singolo pixel, si usano solo 4 bit (16 colori) oppure 8 bit (256 colori) per pixel. Il numero rappresentato dai 4-8 bit è considerato come un indice per andare a pescare il vero colore, contenuto nella Palette, che è formato da 15 bit (5 per il Rosso, 5 per il Verde e 5 per il Blu), il sedicesimo bit in alcuni casi viene usato per indicare che il colore è trasparente, ma spesso è semplicemente ignorato.

Ricapitolando, per ogni pixel del BG il 2D Graphics Engine legge il valore della ScreenMap corrispondente, usa il numero come indice per pescare una casellina 8×8 dalla CharacterMap, poi prende il numero corrispondente al pixel da disegnare, e lo usa come indice per pescare dalla Palette il vero colore in formato RGB. Tutte queste operazioni sono eseguite dall’hardware dedicato del 2D Graphics Engine, quindi il risparmio di memoria è ottenuto senza nessun tipo di sacrificio della potenza di calcolo della CPU.

Il formato Bitmap è più semplice. Ciascun pixel contiene un valore a 4,8 o 16 bit che rappresenta direttamente il colore. Se i bit sono 4-8, questi vengono usati come indice per pescare il colore RGB da una Palette. Se i bit sono 16 vengono usati i primi 15 come canali RGB (5 bit per canale) e il sedicesimo bit se è impostato a 1 significa che il pixel corrente è un pixel normale, se viene impostato a 0 significa che quel pixel non deve venire disegnato, e al suo posto si vedrà lo sfondo. Possiamo considerarlo un sorta di canale Alpha ad un solo bit (completamente opaco o completamente trasparente).

Le Trasformazioni Affini sono degli effetti che possono venire applicati agli OBJ ed ai BG (solo nelle modalità Affine e Affine Extended, che a loro volta possono essere sia di tipo Character che Bitmap). Tale nome è preso in prestito dalla geometria e, in sostanza, si riferisce alla possibilità di applicare 3 effetti di base: scala, rotazione, traslazione.
Combinando queste tre trasformazioni si possono creare effetti di scrolling, rotazione e zoom con una fluidità perfetta, perchè tutti i calcoli necessari sono effettuati da hardware dedicato.
Effetti grafici

Sui BG e sugli OBJ, in base al loro tipo ed alla modalità video scelta, possono essere applicati alcuni effetti grafici, come alpha blending a 5 bit (32 livelli trasparenza), effetto Mosaico (per vedere l’immagine “a quadrettoni”, effetto molto utilizzato nei vecchi giochi come transizione tra una scena e l’altra), flip orizzontale e verticale (utile per avere immagini invertite ad effetto specchio, si usa spessissimo nella modalità Character per evitare di memorizzare le varianti speculari di ogni casellina risparmiando ulteriore memoria).
Conclusione

In questo articolo abbiamo visto a grandi linee quali sono le funzioni dei 2D Graphics Engine. Nel prossimo prenderemo in esame il 3D Graphics Engine e vedremo come questo si integri con il già citato BG0 del 2D Graphics Engine A, per dar vita ad un interessante quanto utile mix tra scene poligonali ed elementi 2D.

9 Commenti »

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.

  • # 1
    Mirco Tracolli
     scrive: 

    Ancora una volta non vedo l’ora di leggere il prossimo… :D

    Volevo però chiedere una cosa: la simulazione del video analogico è proprio gestita a livello hardware oppure è il software che è stato scritto per essere eseguito in un certo modo (con una precisa esecuzione temporale)?

  • # 2
    Fabio FLX
     scrive: 

    Sono diversi mesi che mi diletto a programmare sulla DSi.
    I framework disponibili permettono di sfruttare con estrema facilità le funzioni principali della consolle, e in brevissimo tempo si riesce ad ottenere un buon risultato, mentre con l’esperienza si arrivano a sfruttare le peculiarità più specifiche di ogni componente hardware.
    Peccato che la Nintendo non supporti i giochi indie fornendo licenze a basso costo (che poi è il motivo del successo di Angry Birds su iPhone, tanto per dirne una), e si debba ricorrere a stratagemmi formalmente illegali per potersi godere i propri stessi giochi. Sigh.

  • # 3
    Antonio Barba (TheKaneB)
     scrive: 

    è gestita via hardware e, a differenza delle vecchie console, non è più necessario contare “a mano” i cicli di clock per “indovinare” se siamo in fase di retrace oppure no.

    Il Nitro Processor, tramite hardware dedicato, genera 2 diversi interrupt all’inizio della fase di Vertical Blank e all’inizio di ciascun Horizontal Blank.

    L’interrupt così generato viene servito da una routine la quale, a sua volta, esegue una call ad una funzione specificata dal programmatore.

    Quindi, se devi eseguire del codice durante i periodi di blanking, puoi scrivere tale codice in apposite funzioni e memorizzare i puntatore a queste funzioni nella locazione di memoria designata.

    Questa cosa è utile ad esempio per fare calcoli e/o streaming di dati durante i periodi di Blanking in modo da non creare tearing ed artefatti sulla schermata ed avere animazioni sempre perfette.

  • # 4
    [D]
     scrive: 

    Supponiamo uno volesse far apparire dei testi davanti tutto come nei sistemi arcade si usa per i tipici insert coin, high score e level N, se non esiste un livello “text”, un overlay, deve mettere su una serie di sprite ?

  • # 5
    iva
     scrive: 

    Pessimo articolo… mi ha fatto ritornare una voglia di smanettare con i giochi in 2D ma non ho assolutamente tempo!! (e’ una battuta naturalmente, complimenti per il bel pezzo).

    Domanda adesso:
    in effetti anche a me erano venuti dubbi quando ho letto “simulazione del segnale analogico”.
    Concordo che non ci sia un pennello elettronico che si deve muovere sullo schermo, ma se l’update tra la VRAM e la memoria vera e propria degli schermi LCD avviene negli intervalli di blank questi sono necessari comunque per evitare sfarfallii, no?

  • # 6
    Antonio Barba (TheKaneB)
     scrive: 

    [D] Per fare il display del testo puoi usare uno dei 4 livelli BG, tipicamente il BG1 per svariati motivi (il BG0 può contenere anche grafica 3D e quindi meglio conservarlo per altro). Si mette una bella mappa con il font scelto nella Character Map (se il font è più grande di 8×8 pixel, si possono associare 2 o più caselle per ogni lettera del font), e si scrive il testo nella Screen Map come se fosse una comunissima mappa di gioco. Se la Character Map è costruita in modo intelligente, la funzione per outputtare il testo sul BG1 diventa banale quasi come scrivere caratteri ASCII direttamente in VRAM :-)
    In alternativa, se proprio hai già tutti i BG occupati, puoi sempre usare dei grossi sprite da 64×16 pixel per contenere intere parole, usando sempre la stessa tecnica delle Character Maps (anche gli sprite OBJ possono essere in formato Character).
    Altra cosa, nel gergo il formato “text” esiste e corrisponde ad un formato Character in cui può essere effettuato scrolling, ma non zoom nè rotazione. Quindi spesso si usano i termini “Text” e “Character Map” quasi come sinonimi.

    @iva: non esiste alcun pennello elettronico, ma l’aggiornamento dei pixel avviene una riga dopo l’altra con la stessa tempistica che avrebbe se lo schermo fosse un CRT. Di conseguenza puoi a tutti gli effetti ragionare in termini di scanline e tutto il resto, esattamente come nelle console vecchie con output su Televisore. Questo, ovviamente, comporta la necessità di aggiornare la schermata durante il VBlank per evitare il tearing. Comunque, se vuoi, puoi benissimo disegnare durante la riga di raster, utile se vuoi ottenere qualche effetto speciale sfruttando proprio gli artefatti di aggiornamento a tuo vantaggio :-)
    Mi viene in mente ad esempio il cambio di matrice di rototraslazione durante l’HBlank, effetto usato una volta per simulare la prospettiva (http://en.wikipedia.org/wiki/Mode_7 ).
    In realtà sul DS ciò non è più necessario (ma volendo, ancora perfettamente fattibile) perchè puoi usare il 3D vero e proprio per questi effetti.
    Comunque si, se smanetti con i timing di aggiornamento dello schermo e i tempi di retrace, noterai esattamente lo stesso comportamento che avrebbe un comune display CRT, proprio per consentire l’uso di vecchie tecniche di programmazione a cui molti siamo affezionati :-D

    PS: Il captcha oggi ce l’ha con me! http://imageshack.us/photo/my-images/839/captchaimpossibile.png/

  • # 7
    [D]
     scrive: 

    Ma i BG non dovrebbero stare tutti “dietro” agli sprite e poi doverli sprecare per scrivere un testo, non dovrebbe limitare in qualche modo quanto si può ottenere con il resto ?

  • # 8
    Antonio Barba (TheKaneB)
     scrive: 

    @[D]: i BG, e anche gli OBJ, hanno un attributo di “priority” che serve a decidere l’ordine di profondità.
    Il programmatore può scegliere arbitrariamente a che livello posizionare i singoli BG e gli OBJ (Sprite) :-)
    Puoi “sprecare” un BG per scrivere il testo e ne avresti comunque altri 3 (di cui uno, il BG0, a sua volta può contenere un rendering 3D, quindi potenzialmente altri sfondi sottoforma di grossi poligoni texturizzati).
    Tuttavia il vero limite consiste nel fatto che questo metodo prevede soltanto caratteri di larghezza fissa a multipli di 8 pixel.
    Se vuoi avere del testo con caratteri proporzionali devi passare al software rendering, cioè tramite del codice setti singolarmente il colore di ciascun pixel all’interno di una bitmap, dopodichè imposti questa bitmap come un BG a tua scelta (oppure su una texture per l’hardware 3D) e in questo modo ottieni il testo proporzionale, similmente a quanto accade nei PC. Ovviamente questo metodo va a consumre parecchi cicli di CPU, quindi bisogna calcolare se il trade-off sia accettabile o meno (varia da caso a caso e bisogna valutarlo con l’aiuto di un profiler per misurare le prestazioni del codice).

  • # 9
    Z80Fan
     scrive: 

    Aspettavo questo articolo ;)

    Queste console sono veramente interessanti, una volta mi ero messo a programmare il Game Boy Color :D

    Sopratutto mi interessa come il DS gestisce il 3D; quindi, al prossimo articolo!

Scrivi un commento!

Aggiungi il commento, oppure trackback dal tuo sito.

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.