giovedì 22 dicembre 2016

Iniziare a programmare con SDL 2 su Linux - parte 2


Nella prima parte di questo tutorial abbiamo visto come installare tutti gli strumenti di sviluppo e abbiamo creato il nostro primo programma sfruttando la libreria SDL 2. In questa seconda parte approfondiremo meglio l'utilizzo di g++ e valgrind, inoltre miglioreremo il nostro SDL Hello World.

Per tutti coloro che sono nuovi utenti del mondo Linux o che comunque non hanno esperienza nell'invocazione del compilatore g++ ho pensato di fare un po' di chiarezza sulla sintassi di questo comando.

La sintassi più semplice è
$ g++ [file sorgente]

L'eseguibile avrà il nome di default a.out.
Per specificare il nome dell'eseguibile basta aggiungere l'opzione -o [nome eseguibile], quindi
$ g++ [file sorgente] -o [nome eseguibile]

Se ci sono più file sorgenti basta elencarli
$ g++ [file sorgente 1] [file sorgente 2] -o [nome eseguibile]

Per finire, se dobbiamo utilizzare una libreria, come SDL 2 nel nostro caso, dobbiamo comunicarlo al linker tramite l'opzione -l (elle minuscola) seguita dal nome della libreria senza spazi.
$ g++ [file sorgenti] -o [nome eseguibile] -l[nome libreria]

Per la libreria SDL 2 scriveremo -lSDL2

Bene, questo è quanto abbiamo visto finora nella prima parte del tutorial, ma avrete notato che, quando la lista dei file sorgente aumenta, invocare g++ diventa decisamente scomodo.
Per semplificare il tutto possiamo utilizzare il comando make.

Il funzionamento di make è molto semplice, dobbiamo creare un file di testo dove forniremo tutte le informazioni necessarie per la compilazione, quali il compilatore da invocare, la lista dei file sorgente, le opzioni da passare al compilatore, ecc...
Una volta preparato il file chiamato Makefile, basterà invocare make e questo invocherà g++ per noi.
Questo è un esempio di Makefile per compilare il nostro SDL Hello World


Il contenuto del Makefile è abbastanza semplice da capire, man mano che aggiungiamo un file sorgente o un file header basterà aggiungerlo alla lista nel Makefile. Possiamo apportare tutte le modifiche che vogliamo nel Makefile e basterà invocare il comando make per compilare ed ottenere il file eseguibile.
Oltre a questo make si occupa di verificare se dall'ultima compilazione è cambiato qualcosa nei file sorgente, se nulla è cambiato ci verrà notificato.
Copiate ed incollate il testo in un file e salvatelo con il nome Makefile nella stessa directory dei file sorgente. Ora provate ad eseguire il comando
$ make

Decisamente più comodo, non è vero?



Passiamo ad un altro argomento: valgrind.
La scorsa volta avevamo installato valgrind in quanto ottimo strumento di debugging, in particolare per gli errori nella gestione delle allocazioni di memoria. La sintassi è semplice
$ valgrind ./[nome eseguibile]

L'eseguibile verrà avviato all'interno dell'ambiente di debugging di valgrind, il quale analizzerà tutte le allocazioni di memoria e le relative de-allocazioni delle stesse. Al termine del programma verrà stampato sul terminale un resoconto completo con un elenco degli eventuali errori rilevati.

Proviamolo con il nostro SDL Hello World
$ valgrind ./sdl_helloworld

L'esecuzione risulterà più lenta e alla fine avremo sul terminale un resoconto dettagliato.
Senza entrare troppo nei particolari, quello che ci interessa più di tutto il resto è l'ultima riga:
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 2)

Nella sezione LEAK SUMMARY potete trovare altri dettagli sulle allocazioni di memoria.
E' ovvio che non è solo il vostro codice che viene analizzato, ma anche quello delle librerie utilizzate, quindi alcuni memory leaks possono essere causati da quest'ultime.

Bene, torniamo all'argomento principale di questo tutorial, SDL 2.
Nello scorso esempio abbiamo utilizzato la funzione SDL_loadBMP(), che carica un'immagine di tipo BMP (Windows bitmap) in un oggetto SDL_Surface.
Per quanto questa funzione sia molto comoda e semplice da utilizzare, il formato BMP è piuttosto limitato e scarsamente utilizzato al giorno d'oggi.
Nella libreria principale di SDL 2 non ci sono altre funzioni per caricare immagini di tipo diverse, quali ad esempio PNG o JPG, ma fortunatamente c'è un'altra libreria dedicata a questo scopo: SDL_image.

Prima cosa da fare è installare sul nostro sistema questa libreria.
$ su
(verrà richiesta la password di root)
# apt install libsdl2-image-dev



Ora che abbiamo installato SDL_image possiamo modificare il programma per aprire un'immagine di tipo PNG.

Aggiungiamo l'include con il file header di questa libreria in helloengine.h
#include <SDL2/SDL_image.h>

Come la libreria SDL 2 anche questa va inizializzata, quindi nella funzione init() della classe HelloEngine (helloengine.cc) aggiungiamo queste righe di codice per inizializzare SDL_image per il caricamento di immagini PNG, subito sotto l'inizializzazione di SDL 2.

// inizializzazione SDL_image per i file di tipo PNG
if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) != IMG_INIT_PNG)
{
    on_SDL_error(std::cout, "IMG_Init");
    return false;
}

Ora andiamo a modificare la parte di codice che carica l'immagine, è sempre nella funzione init() poco più in basso. Utilizzeremo la funzione IMG_LoadTexture() che ci restituisce direttamente un puntatore ad un oggetto di tipo SDL_Texture, quindi non avremo bisogno di crearla passando per un SDL_Surface.

// carica l'immagine in texture
std::string name = "helloworld.png";
if ((texture = IMG_LoadTexture(renderer, name.c_str())) == nullptr)
    on_SDL_error(std::cout, "IMG_LoadTexture");

Potete convertire l'immagine BMP in una di tipo PNG utilizzando Gimp e salvatela con il nome helloworld.png.

Prima di compilare ricordatevi che stiamo utilizzando un'altra libreria, quindi dovremo modificare il nostro Makefile aggiungendo -lSDL2_image alla lista delle librerie da linkare, subito dopo -lSDL2.

Terminate le modifiche questo è quello che dovreste ottenere
Compilate con
$ make

Ed ora avviate il programma
$ -/sdl_helloworld

Se non avete fatto errori il programma funzionerà come prima.
Bene, in questa seconda parte del tutorial dedicato ad SDL 2 abbiamo preso maggior confidenza con gli strumenti di sviluppo e debugging, inoltre abbiamo visto come usare la libreria SDL_image.
Nel prossimo tutorial faremo ulteriori modifiche e vedremo come funziona la gestione degli eventi.

martedì 20 dicembre 2016

Iniziare a programmare con SDL 2 su Linux


SDL (Simple DirectMedia Layer) è una libreria di sviluppo multi-piattaforma, scritta in linguaggio C, progettata per controllare facilmente video, grafica, audio, tastiera, mouse, joystick, ecc...
Queste capacità la rendono ideale per lo sviluppo di videogiochi, applicazioni multimediali ed emulatori.
Un grande vantaggio è il fatto di essere multi-piattaforma, questo infatti semplifica il porting sulle diverse piattaforme supportate (Linux, OS X, Windows, iOS e Android).
SDL 2.0 è rilasciata con licenza Zlib, che è una licenza per software libero ed è compatibile con la licenza GPL.

Vediamo subito come preparare il nostro sistema con tutti gli strumenti necessari per iniziare a programmare.
In questo tutorial utilizzerò Debian GNU/Linux 8.6 con il desktop manager di default GNOME.
Probabilmente già saprete che Debian è una distribuzione GNU/Linux universale ed è la base di molte altre distribuzioni derivate, tra le quali Ubuntu. Utilizzare Debian in questo tutorial mi permette di abbracciare una grossa fetta di utenti Linux.

La prima cosa di cui abbiamo bisogno sono gli strumenti di sviluppo fondamentali, quali il compilatore, il linker ed un debugger.
Il pacchetto build-essential ci fornirà tutta la suite di programmi utili allo sviluppo.

$ su
vi verrà chiesta la password di root.
Controlliamo se ci sono aggiornamenti del sistema disponibili con
# apt update
Se trovati procediamo con l'aggiornamento con
# apt upgrade

Quindi installiamo build-essential
# apt install build-essential


Analizzando la lista dei pacchetti installati, forse avrete notato che gdb (il debugger GNU) è nella lista dei pacchetti consigliati, ma non è stato installato. Possiamo installarlo manualmente con
# apt install gdb
Oppure verrà installato automaticamente quando andremo ad installare Valgrind.
Valgrind è un ottimo software di debug e profiling che, tra le altre cose, permette di scovare gli errori nella gestione della memoria, come ad esempio i memory leaks, ossia le allocazioni di memoria che non vengono liberate al termine del loro utilizzo.
# apt install valgrind


Ora che abbiamo gli strumenti fondamentali per lo sviluppo, possiamo installare la libreria SDL 2.0.

# apt install libsdl2-dev


Il pacchetto libsdl2-dev contiene la libreria SDL 2.0 e tutti i componenti fondamentali per sviluppare applicazioni con SDL, ma se provate a cercare i pacchetti libsdl2 disponibili troverete altri componenti che ne espandono le funzionalità.
# apt search libsdl2


Analizzeremo ed installeremo gli altri pacchetti nel prossimo tutorial, quando ci serviranno, per il momento iniziamo a fare un piccolo test di compilazione per verificare che tutte le operazioni di preparazione siano andate a buon fine.

Per questo tutorial utilizzerò gedit, l'editor di testo del desktop GNOME, semplice e leggero, sicuramente adatto per scrivere/modificare file di codice sorgente di piccole dimensioni.
Nonostante la sua estrema semplicità, con qualche piccolo accorgimento possiamo renderlo un discreto strumento di sviluppo.
Dopo aver lanciato gedit, clicchiamo sul menù dell'applicazione sulla barra dello schermo in alto accanto ad Attività, e selezioniamo la voce Preferenze. Comparirà una finestra con diverse opzioni divise per categorie, clicchiamo su Editor e modifichiamo l'ampiezza di tabulazione da 8 a 4. Personalmente trovo che 8 spazi siano decisamente troppi, ma siete liberi di impostare il numero di spazi che più vi aggrada.

Preferenze di gedit
Ora cliccate su Plugin e scorrete la lista in basso fino a trovare e spuntare l'opzione Terminale integrato. Questo ci permetterà di avere un Terminale nella parte bassa della finestra di gedit, evitando di dover passare da una finestra ad un'altra quando dobbiamo compilare o effettuare operazioni di debugging.


Adesso clicchiamo sull'icona menù, posta sulla finestra di gedit accanto al tasto x di chiusura, selezioniamo Vista e spuntiamo le voci Riquadro laterale e Riquadro inferiore.



Queste faranno visualizzare un riquadro laterale con la lista dei file aperti ed un riquadro inferiore con il Terminale integrato.
Per finire, nella barra di stato di gedit, cliccate su Testo semplice per far comparire un menù e selezionate C++ per usufruire della colorazione automatica del testo per la sintassi del linguaggio di programmazione che andremo ad utilizzare nel tutorial.


Al termine di queste personalizzazioni, gedit ha un aspetto decisamente più orientato alla programmazione e meno minimalista.

Facciamo un test veloce per verificare che tutto funzioni regolarmente, scriveremo il classico Hello World e proveremo a compilarlo.

E' indispensabile avere una conoscenza minima del linguaggio C++, altrimenti vi consiglio di andare a consultare un manuale o un tutorial specifico.
Salvate il file in Documenti con il nome helloworld.cc, quindi dal Terminale integrato di gedit, andate in Documenti e provate a compilare il vostro programma.

$ g++ helloworld.cc -o helloworld

Se non avete fatto errori la compilazione andrà a buon fine e potrete eseguire helloworld

$ ./helloworld
Hello World!

A questo punto facciamo un altro test, un nuovo Hello World, ma questa volta utilizzando SDL 2.
Andremo a creare una classe chiamata HelloEngine che sarà il motore della nostra applicazione, mentre nel file principale, chiamato sdl_helloworld.cc ci sarà la funzione main() che si occuperà di creare un'istanza di HelloEngine ed avviarne l'esecuzione.
E' una struttura simile a quello che si utilizza per lo sviluppo di un videogioco, in questo caso è molto semplificata in quanto non ha un loop e non gestisce alcun evento. Questo programma si limiterà ad aprire una finestra e visualizzare il messaggio Hello World, dopo 2 secondi d'attesa chiude la finestra e termina.

Questi sono i tre file del nostro SDL Hello World.

Iniziamo ad esaminare il file header della classe HelloEngine, all'inizio del file andiamo ad includere iostream e SDL2/SDL.h.
Il secondo è ovviamente indispensabile per utilizzare la libreria SDL2, mentre il primo è necessario quando andiamo a stampare gli eventuali messaggi d'errore tramite std::ostream.

Le funzioni membro sono solo 4:
- init() si occupa di inizializzare HelloEngine;
- start() avvia l'esecuzione;
- render() disegna l'immagine caricata nella finestra;
- on_SDL_error() stampa il messaggio d'errore sullo std::ostream indicato.

Per il resto il file header è piuttosto semplice, andiamo a vedere come queste 4 funzioni sono implementate in helloengine.cc.

Init() è la funzione che inizializza l'ambiente SDL invocando SDL_Init(), prima di poter utilizzare qualsiasi funzione della libreria SDL2 dobbiamo inizializzarla con questa funzione. Successivamente viene creata una finestra con SDL_CreateWindow(), quindi viene creata un'istanza di SDL_Renderer che ci servirà per tutte le operazioni grafiche.
Per finire viene caricata un'immagine BMP ottenendo un oggetto SDL_Surface con il quale viene creato un oggetto SDL_Texture.
Dopo aver ottenuto la nostra texture, viene distrutto l'oggetto SDL_Surface con la funzione SDL_FreeSurface() liberando la memoria allocata.

render() è incaricata di disegnare sulla finestra.
SDL_RenderClear() cancella il contenuto di renderer, SDL_RenderCopy() disegna la texture ottenuta dal caricamento dell'immagine su renderer, infine con SDL_RenderPresent() viene visualizzato il contenuto di renderer sulla finestra.

Start() avvia l'esecuzione vera e proprio di HelloEngine, inizialmente invoca init() per effettuare tutte le inizializzazioni, quindi esegue la funzione render() per disegnare sulla finestra. SDL_Delay() attende per il numero di millesecondi indicato, nel nostro caso attende 2 secondi e quindi esce con valore 0 per indicare che non ci sono stati errori.

on_SDL_error() stampa un messaggio d'errore sullo std::ostream indicato, di fatto è sempre std::cout.

Infine è bene soffermarsi sul distruttore della classe HelloEngine, che si occupa di de-allocare tutta la memoria utilizzata dal programma.
SDL2 ha una funzione specifica per ogni tipo di oggetto da de-allocare, non possiamo utilizzare il semplice delete. Abbiamo visto in init() la funzione SDL_FreeSurface() per distruggere l'SDL_Surface, qui utilizziamo SDL_DestroyTexture per l'SDL_Texture, SDL_DestroyRenderer per l'SDL_Renderer e SDL_Quit per chiudere l'intero ambiente SDL.

Il file sdl_helloworld.cc contiene la funzione main() del programma, il funzionamento è estremamente semplice, crea un'istanza di HelloEngine e ne invoca l'esecuzione con start(). Al termine dell'esecuzione distrugge l'istanza con il delete ed esce con lo stesso codice d'uscita dell'istanza.


Andiamo a compilare SDL Hello World con

$ g++ -std=c++11 helloengine.h helloengine.cc sdl_helloworld.cc -o sdl_helloworld -lSDL2


Prima di eseguire ricordatevi di mettere l'immagine helloworld.bmp nella stessa directory dell'eseguibile, altrimenti verrà visualizzata una finestra completamente nera.


Immagine BMP utilizzata per questo test


L'immagine verrà salvata come JPG, potete esportarla in formato BMP utilizzando Gimp oppure ne potete creare una voi. Ricordatevi che per poter essere caricata correttamente da SDL_LoadBMP() l'immagine deve avere un unico livello.
 
$ ./sdl_helloworld


SDL Hello World in esecuzione

In questo tutorial abbiamo installato gli strumenti di sviluppo e la libreria SDL 2 sul nostro sistema ed abbiamo visto un primo esempio di applicazione sviluppata con questa libreria.
Nel prossimo tutorial vedremo come caricare immagini di altri formati, gestire eventi come la pressione di un tasto o il click del mouse ed altro ancora.