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.

mercoledì 14 dicembre 2016

QEMU - Emulatore e gestore di macchine virtuali su Linux

Prima di iniziare ad utilizzare QEMU su Linux facciamo un po di chiarezza sulla differenza tra un emulatore ed una macchina virtuale.

Il primo ha lo scopo di emulare l'hardware di una macchina (che può essere totalmente differente dal sistema emulante, o sistema host) al fine di eseguire il software originariamente scritto per girare sul sistema emulato. Ad esempio, sul nostro PC con processore x86 potremmo emulare una macchina con processore POWER o ARM. Sono molto popolari anche gli emulatori di console e vecchi computer degli anni 80 che ci permettono di giocare ai vecchi classici di un tempo, come ad esempio il MAME (Multiple Arcade Machine Emulator).

Una macchina virtuale invece ci permette di creare una macchina all'interno di un'altra, sulla quale potremmo installare un sistema operativo che rimarrà in un ambiente “protetto” e separato dal sistema ospitante. Una macchina virtuale pura non emula un hardware differente da quello in cui gira, ma si limita a replicarlo.

Ci sono diversi software di virtualizzazione piuttosto conosciuti quali VirtualBox (ora di Oracle) e soluzioni commerciali quali WMware Workstation Player o Pro.

Preferendo utilizzare un software libero ed open source abbiamo QEMU che ci permette sia di emulare un hardware differente da quello host, sia di creare una macchina virtuale sulla quale poter installare un secondo sistema operativo.
Un grande vantaggio di QEMU è la possibilità di utilizzare KVM (Kernel Virtual Machine), un modulo del kernel Linux che permette di ottenere prestazioni migliori grazie allo sfruttamento delle funzioni di virtualizzazione hardware offerte dai processori che li supportano.

In questa breve guida introduttiva utilizzerò un sistema basato su processore x86 64 bit con sistema operativo Debian GNU/Linux 8.6.

Iniziamo con l'installazione del software:

$ su
Per iniziare una sessione come utente amministratore root, vi verrà richiesta la password di root.

# apt update

# apt upgrade
Per aggiornare il sistema.

# apt install qemu
Installerà tutti i pacchetti necessari per l'utilizzo di QEMU.

# exit
Per tornare a lavorare con il vostro id utente e non più come root.

Prima cosa da fare è creare un'immagine disco virtuale che verrà utilizzata da QEMU come fosse un hard disk, a questo scopo utilizziamo il comando qemu-img.

$ qemu-img create virtualhd.img 20G
Questo comando crea un file di immagine disco chiamato virtualhd.img della grandezza di 20 Gb.
Per ottenere ulteriori informazioni sulla sintassi di qemu-img potete invocare l'aiuto veloce con il seguente comando:
$ qemu-img –help

A questo punto abbiamo un'immagine disco vuota dove poter installare il nostro sistema operativo, ora andremo ad utilizzare un file .iso del primo CD di installazione di Debian per sperimentare il funzionamento di QEMU. Se preferite potete ovviamente utilizzare un sistema operativo differente.
In questo caso non voglio emulare una macchina diversa da quella ospitante, quindi utilizzerò il comando dedicato ai sistemi x86 64 bit.

$ qemu-system-x86_64 -cdrom debian-8.6.0-amd64-CD-1.iso -drive file=virtualhd.img -m size=2048 -enable-kvm

qemu-system-x86_64 è il comando che invoca l'utilizzo di una macchina virtuale x86 64 bit.
-cdrom è l'opzione che indica quali immagine disco è da considerarsi come CD virtuale, in questo caso abbiamo indicato debian-8.6.0-amd64-CD-1.iso come file di immagine.
-drive invece indica il file da considerare come hard disk virtuale, utilizzeremo quello appena creato virtualhd.img.
-m è l'opzione che indica la quantità di memoria da utilizzare sulla nostra macchina virtuale, size=2048 assegna 2 Gb di RAM.
-enable-kvm per finire attiva l'utilizzo del modulo kernel KVM.
Anche con questo comando potete accedere alla guida sulla sintassi e le tante opzioni disponibili con il solito –help.

Non appena avrete eseguito questo comando si aprirà una finestra che visualizzerà lo schermo della macchina virtuale in esecuzione e potrete procedere all'installazione del sistema operativo.
Il sistema ospite sarà eseguito in modo indipendente dal sistema ospitante e qualsiasi operazione su disco sarà in realtà eseguita sul file immagine del disco virtuale, sarete quindi liberi di sperimentare senza rischiare di danneggiare il vostro sistema principale.

Avvio del disco di installazione di Debian 8.6

Avvio della macchina virtuale dopo l'installazione del sistema, menù di GRUB

Debian 8.6 in funzione sulla macchina virtuale