Autore: Luca De Stefani
Questo progetto è un piccolo renderer 2D in stile retro realizzato in Python.
Il programma legge da file esterni tutte le informazioni necessarie per costruire una scena, come la palette dei colori, la disposizione dei tile e gli sprite. Alla fine genera un'immagine PNG con il risultato completo.
Durante lo sviluppo ho lavorato soprattutto sulla gestione di array e matrici con NumPy, sulla lettura di file binari e sulla composizione dei vari elementi all'interno del framebuffer.
Il programma permette di:
- caricare una palette di 16 colori da un file JSON;
- leggere tile e sprite salvati in formato binario;
- costruire una scena partendo da una tile map;
- disegnare gli sprite sopra lo sfondo;
- gestire la trasparenza;
- applicare flip orizzontali e verticali;
- applicare rotazioni;
- gestire elementi parzialmente fuori dallo schermo;
- convertire il framebuffer finale in colori RGB;
- salvare il risultato come immagine PNG.
Il progetto è stato sviluppato usando:
- Python 3;
- NumPy;
- Pillow;
- file JSON;
- file binari.
NumPy viene utilizzato per lavorare con gli array che rappresentano tile, sprite e framebuffer.
Pillow viene usata alla fine del processo per salvare il risultato come immagine PNG.
Per evitare di installare le librerie direttamente nel sistema, è consigliato creare un ambiente virtuale.
python3 -m venv .venvSu Linux o WSL si può attivare con:
source .venv/bin/activateA questo punto si possono installare le dipendenze presenti nel file requirements.txt:
pip install -r requirements.txtIl programma riceve da riga di comando cinque percorsi:
python3 main.py <palette.json> <scene.json> <tiles.bin> <sprites.bin> <output.png>Per eseguire il progetto usando i file di esempio inclusi nella cartella examples:
python3 main.py examples/palette.json examples/scene.json examples/tiles.bin examples/sprites.bin output.pngAl termine dell'esecuzione viene creato il file:
output.png
renderer-2d-python/
│
├── examples/
│ ├── palette.json
│ ├── scene.json
│ ├── tiles.bin
│ ├── sprites.bin
│ ├── tiles.png
│ ├── sprites.png
│ └── reference.png
│
├── screenshots/
│ └── renderer-preview.png
│
├── blitter.py
├── main.py
├── palette.py
├── rendering_pipeline.py
├── scene_parser.py
├── virtual_vram.py
├── requirements.txt
├── README.md
└── .gitignore
È il punto di partenza del programma.
Controlla che siano stati passati tutti gli argomenti necessari e avvia il processo di rendering.
Legge la palette dal file JSON.
Controlla inoltre che siano presenti esattamente 16 colori e che ogni colore sia formato da tre valori RGB validi.
Si occupa della lettura dei file tiles.bin e sprites.bin.
I pixel sono salvati in formato packed: ogni byte contiene due indici di colore da 4 bit. Il modulo legge questi valori e ricostruisce gli array utilizzati durante il rendering.
Legge il file JSON che descrive la scena.
Da questo file vengono ricavate informazioni come:
- dimensioni della tile map;
- identificativi dei tile;
- posizione degli sprite;
- trasformazioni da applicare;
- indice usato per la trasparenza.
Contiene le operazioni usate per copiare tile e sprite nel framebuffer.
Qui vengono gestiti anche:
- trasparenza;
- flip orizzontale;
- flip verticale;
- rotazioni;
- ritaglio degli elementi che escono dai limiti dell'immagine.
Collega tra loro tutte le parti del progetto.
In ordine:
- carica la palette;
- legge tile e sprite;
- carica la scena;
- crea il framebuffer;
- disegna la tile map;
- aggiunge gli sprite;
- converte gli indici della palette in colori RGB;
- salva l'immagine finale.
La cartella examples contiene tutto il necessario per provare subito il programma.
palette.jsoncontiene i 16 colori utilizzati nella scena;scene.jsondescrive la posizione di tile e sprite;tiles.bincontiene i tile in formato binario;sprites.bincontiene gli sprite in formato binario;tiles.pngmostra graficamente il contenuto del tileset;sprites.pngmostra gli sprite disponibili;reference.pngcontiene il risultato corretto usato per il confronto.
Per verificare il funzionamento ho generato l'immagine con questo comando:
python3 main.py examples/palette.json examples/scene.json examples/tiles.bin examples/sprites.bin output.pngSuccessivamente ho confrontato output.png con l'immagine examples/reference.png.
Il confronto ha restituito:
Immagini identiche: True
Pixel differenti: 0
L'immagine generata dal programma coincide quindi con quella di riferimento.
