Variable Width Font

Aperto da Gemini, Maggio 27, 2006, 21:54:22

Discussione precedente - Discussione successiva

Gemini

Wow, da quanto tempo che non apro più un topic. >_> Oggi voglio cimentarmi con una mini-guida che dovrebbe rendere un tantino meno oscuro il concetto di vwf, che ormai sembra essere sulla bocca di tutti, almeno su Romhacking.net. :B Avrei voluto scriverla già più di un anno fa, quando iniziai a fare i primi esperimenti di hacking asm su snes, ma ho lasciato stare per un po' di tempo l'idea in quanto il mio codice conteneva dei bug assurdi. :X Ora che ne ho scritti due totalmente funzionani, sono pronto a rivelarvi questo mistero. *_*

Quanti di voi sanno cosa sia un vwf? Per i meno esperti, si tratta di font con spaziatura variabile da carattere a carattere, detto anche Variable Width Font. Un esempio pratico? Ignorate le scritte di sopra e guardate solo la lista degli oggetti:

L'utilità di tutto ciò? Come potrete constatare, si risparmia moltissimo spazio a video impiegando questo sistema di visualizzazione dei caratteri.

Ma cosa c'è esattamente dietro un vwf? Finché si parla di console che lavorano a poligoni, si tratta di semplici sprite posizionati incrementando la spaziatura orizzontale in modo variabile, ma quando si va sulle console che lavorano a tile (NES, SNES, GB, GBA, Master System, MegaDrive, etc...) il concetto cambia quasi radicalmente. In questi casi si tratta di un processo che disegna in tempo reale la parola su tile e poi passa tutto alla VRAM per la visualizzazione. Questo piccolo tutorial parla esattamente di questo processo per il disegno della stringa.

Conoscenze necessarie:
1) Concetto degli operatori And, Shift e Or;
2) Formato grafico del vostro font.
Livello di difficoltà: medio/avanzato.

Per questo esempio utilizzerò un font 8x8 in formato GBA, ovvero grafica 4 bit per pixel lineare invertita (come quella della lista degli oggetti di FFVI).

1) Lunghezze e variabili: Scrivete una tabella con TUTTE le lunghezze in pixel dei caratteri e trovate delle locazioni di memoria libere in cui salvare le seguenti variabili: un contatore della spaziatura orizzontare e un altro contatore per il numero di tile completamente disegnati.
2) Shift e Or: Tutto ciò che rende possibile un vwf sono queste due semplici operazioni. Shift sarà vitale per spostare i pixel contenuti nel nostro tile, mentre Or servirà per sovrapporre il risultato su un tile esistente. Prendiamo il nostro bel pezzettone di grafica iniziale:

Ci troviamo all'inizio del rendering della stringa, per cui il nostro contatore di posizione sarà 0. Nulla da spostare sul nostro vwf, quindi una semplice copia della grafica su un tile pulito. La nostra grafica utilizza 32 bit per 8 pixel (una linea orizzontale), quindi utilizziamo un ciclo da 8 ripetizioni per leggere e scrivere 4 byte alla volta.
3) Incrementare la larghezza: Carichiamo la larghezza del tile appena letto e aggiungiamolo alla nostra variabile per il conteggio della posizione X. 'J' ha come valore di larghezza 4, quindi siamo ancora all'interno del primo tile.
4) Shift in azione e Or pronto a disegnare: L'operazione è come quella del passo 2, con una differenza, ovvero stavolta il tile caricato andrà spostato a destra di 4 pixel, cieè la larghezza X che prima è stata salvata. Sapendo che ogni pixel della linea pesa 4 bit, dovremo moltiplicare X per tale valore, ottenendo così il numero di bit dello shift a sinistra (notare bene che qui è a sinistra, ma se la grafica non fosse stata con ordine di bit invertiti avremmo avuto bisogno di uno shift a destra). Questo sarà l'aspetto del tile una volta finito il ciclo degli 8 shift, uno per ogni linea di pixel:

Adesso però abbiamo necessità di sovrapporre questo tile a quello precedente, in modo da ottenere l'effetto vwf. È qui che entra in gioco l'operatore Or, utilizzato proprio per questo scopo. Ripetiamo la stessa operazione, leggendo però il tile precedente e quello attuale con lo shift appena eseguito ed aggiungiamo un'operazione di Or con i dati precedenti. Questo è il risultato di tale processo:

Come noterete quasi subito, parte del tile appena scritto è fuoriuscita dal raggio degli 8 pixel, ciò a causa della limitazione grafica del formato. Questo è un caso di overflow che tra un po' vedremo come gestire. Continuando come prima, carichiamo la larghezza del carattere appena disegnato, ovvero 5 pixel. Sommiamo alla variabile del contatore X, per ottenere 9. Come vi ho fatto notare poco sopra, questo è un caso di overflow, per cui abbiamo superato gli 8 pixel massimi. Non potendo andare oltre quella soglia, eliminiamo gli 8 pixel del tile appena disegnato. La nostra variabile X ora vale 1 e sappiamo che 1 pixel era stato tagliato in precedenza dalla lettera 'e', dunque provvediamo a sistemare quei pixel rimasti e incrementiamo il contatore dei tile scritti di 1.
5) Gestione overflow grafico: Qui entra in gioco lo shift a destra (o a sinistra nel caso di bit non invertiti). Recuperiamo la variabile X (valore: 1) e facciamo la stessa operazione di prima moltiplicando per 4, ovvero il numero di bit dello shift. Leggiamo tutte le linee del tile 'e' e applichiamo lo shift di 4 bit, stavolta senza sommarlo al tile precedente (ricordate che siamo in overflow, per cui il tile non dovrà contenere altra grafica se non quella attualmente in lettura). Alla fine dell'operazione il nostro nuovo tile avrà questo aspetto:

L'output globale ha questa forma:

Direi che l'effetto che si voleva raggiungere è stato ottenuto con successo. ^_^
6) Disegna ancora e ancora: Ora che abbiamo scritto anche il tile in overflow, possiamo passare al tile successivo utilizzando il passo 4. Bisognerà ripetere questo procedimento finché non sarà finita la sequenza di caratteri che ci interessa disegnare in vwf.
7) Niente overflow?: Questo è uno dei casi particolari, ovvero il tile scritto è stato riempito tutto, ma senza overflow. In questi casi, incrementate il contatore dei tile disegnati e pulite un nuovo tile se ci fosse bisogno di disegnare un'altra parte della stringa, ovviamente resettando il contatore di posizione della X a 0. Il metodo che consiglio è inserire un piccolo controllo prima del passo 4 che pulisce il tile attuale in caso di X uguale a 0, in modo tale che sarà fatto automaticamente ogni volta che verrà richiamato il vwf.
8) Visualizzare: il sistema che preferisco consiste nel salvare a inizio procedura il valore del contatore di tile disegnati e poi fare una sottrazione con il valore a fine del disegno, in questo modo si ottiene esattamente il numero di tile passati in pasto al vwf. Una volta fatto ciò, basta impostare un bel ciclo per salvare nella mappa grafica a video tanti tile quanti sono stati processati, partendo dal valore iniziale. In altre parole la mappa grafica avrà un aspetto del tipo $00 $01 $02 (etc...) invece che contenere una vera e propria parola.
9) Agganciare il codice: Questo è il passo fondamentale che si unisce il vwf alla lettura di stringhe. Dovrete attaccare il vostro codice vwf a tutte le stringhe in stampa che volete rendere "speciali", ma qui dubito vi possa aiutare una guida. Dipende tutto da quanto è disgraziato il gioco. :B

Spero di non aver dimenticato nulla. :P Appena finisco di sistemare il materiale, faccio un bel pacchetto con la guida in HTML, così quella checca gigantesca di Clomax (o chi ne fa le feci) potrà mettere tutto su FTP. :*
E finalmente i miei incubi ricorrenti sulla guida vwf sono terminati! >_<

Per correzioni o altro, fate sapere.

[edit]Da qui (se viene fuori una robaccia .php, basta rinominare in .rar per risolvere) è possibile scaricare la guida consultabile offline in doppio formato doc e html. Herr Clomax, daje e metti nel database.[/edit]

|GeO|

Ottima guida, chiara ed esauriente. Complimenti. :)

Jegriva

Questa guida me la stampo e la metto con le altre buone...
cacciator di quei lupi in su la riva - Dante, Pg XIV 49

Retrogamer.it
-=E L I V A G A R=-

mentz

La teoria è eccellente, come al solito...
E' la pratica assembler per la roba da modificare che è tragica...

Gemini

CitazioneLa teoria è eccellente, come al solito...
E' la pratica assembler per la roba da modificare che è tragica...
E che ci sarebbe di difficile nella pratica asm? :blink: Io ne ho codificati addirittura due basati su metodi grafici diversi (uno con font GB e l'altro GBA, sempre sullo stesso gioco), eppure non ho trovato tutte queste difficoltà (hook ai buffer di stringhe a parte, ma una volta fatto anche quello...). Se poi lavori su una console potente come il GBA, non sussiste nemmeno il problema degli shift singoli da indicizzare tramite ciclo. -.- Posso capire che ci sia un po' di sbattimento su macchine vecchiotte tipo GB/GBC o Snes a causa delle architetture assolutamente da convulsione, ma sulle quelle più nuove è una boiata incredibile. ._.

Gemini

Ma quanto ci vuole a mettere questa stupida guida sul sito? -.-

[edit]Finalmente ha provveduto mat. Amen. :*[/edit]