Sei sulla pagina 1di 35

Guida

libreria SDL
di
Giovanni Di Liberto
aka Oligoatria
2006-2007
Introduzione
Cos la libreria SDL: Simple DirectMedia Layer - SDL, una libreria multipiattaforma
per lo sviluppo di applicazioni multimediali. In parole semplici, si tratta di unutile
concentrazione di funzioni riguardanti grafica, suoni, eventi, thread, e altro.
Queste si pongono tra lhardware e lapplicazione, rendendo cos possibile la creazione di
videogiochi, demo, emulatori, etc., molto performanti.
Creata nel 1997 da Sam Lantinga, stata utilizzata per effettuare il port di alcuni
famosi videogiochi dal sistema Windows a Linux. La libreria open-source; in particolare
rilasciata sotto licenza GNU LGPL (GNU LESSER GENERAL PUBLIC LICENSE per
informazioni rimando al link http://www.gnu.org/licenses/lgpl.html), dunque pu essere
utilizzata per lo sviluppo di applicazioni commerciali, anche closed-source, a patto che le
modifiche apportate al codice sorgente del software stesso vengano rese pubbliche e che sia
inserito un linking dinamico alla libreria stessa.

Requisiti minimi per affrontare questa guida:

Conoscenza discreta del C++;


M. Visual C++ (solo per la compilazione, senza modifiche, dei sorgenti);
Una release completa SDL, la mia la versione 1.2.9.0;
Tanta voglia di imparare e sperimentare.

Il mio apprendimento: Il mio primo problema, quando ho deciso di provare ad utilizzare


questa libreria, stato trovare una guida che mi facesse procedere passo passo in via pratica
(un po di teoria lavevo gi studiata e ci che mi interessava era solo disegnare un cerchio
sullo schermo). Purtroppo ho trovato solo guide tecniche infinite in inglese, mentre in
italiano solo brevissimi tutorial. I sorgenti presenti in rete erano molto complicati (non tutti
solo in apparenza) e cos il mio apprendimento stato lento e pieno di lacune.
La svolta stata quando mi sono reso conto che la mia versione 1.2.9.0 aveva un
fastidioso bug riguardo la trasparenza delle immagini. Inoltre le guide che stavo studiando
non mi fornivano delle spiegazioni esaustive su tutte le possibilit della release. Cos mi
sono deciso a personalizzare un po la libreria.

Perch questa guida: Sulla rete sono disponibili cos tanti suggerimenti sullSDL che ho
pensato: copia e incolla, metto un titolo e divento famoso! A parte gli scherzi, sono

convinto che ci sia molta gente interessata alla grafica, in particolar modo se mirata alla
creazione di videogiochi, e credo che lSDL sia un ottimo punto di partenza per chiunque
intenda poi approfondire largomento programmazione grafica, sia 2D che 3D. Ovviamente
non sufficiente limitarsi allutilizzo delle funzioni, ma necessario capirne il
funzionamento per poterle utilizzare al meglio e, se necessario, ampliarle.
Lobiettivo di questa guida fornire i concetti chiave e le relative funzioni SDL
per permettere di proseguire da soli, approfondire e implementare le proprie idee,
ancora carichi di interesse.

Quali possibilit fornisce la libreria SDL?: Ci vengono messe a disposizione molte


funzioni, raggruppabili in sette categorie principali:
Video
Gestione delle finestre
Gestione degli eventi
Timer
Multi-threading
Audio
Interfaccia CD-Audio

Nota fondamentale: Gli esempi relativi a questa guida sono scaricabili dal sito
http://www.pierotofy.it, sezione C++. E sufficiente cercare SDL e nella lista saranno
presenti i file SDL_Example* (1, 2, 3, ). La guida e gli esempi sono disponibili anche nel
sito http://www.oligoatria.it.

Perch usare lSDL


Nella rete sono disponibili molte soluzioni al nostro desiderio di realizzare
animazioni, screensaver, giochi o altro:
applicazioni che si concludono in eseguibili, come ad esempio Game Maker o
Game Factory;
software come Flash, che necessitano anche di un player per eseguire il progetto
creato;
librerie grafiche + proprie capacit di programmatore.
Non intendo sminuire in alcun modo il lavoro svolto tramite software dei primi 2 tipi
elencati, in quanto ho lavorato per anni con Game Maker e ho avuto qualche esperienza in
Flash (ed il suo comodo action script); mi sento per di poter affermare che lavorare
utilizzando librerie grafiche, o loro evoluzioni in motore grafico, tramite qualsiasi
linguaggio di programmazione decisamente pi complesso e istruttivo, senza contare che
fornisce la possibilit di realizzare un software performante, portabile e di qualit.
Per capire perch credo sia utile imparare a conoscere ed utilizzare questa libreria
importante distinguerla tra le altre di grande importanza (premetto che parler di quello di
cui ho esperienza pratica, dunque nulla togliere a quelle che non conosco):
Allegro
(da http://www.gameprog.it/?resource=358)
La libreria ha questi pregi:
- Grande portabilit
- Grande ottimizzazione del codice sotto Dos (motivo per il quale molto usata per gli
emulatori)
- Sorgenti disponibili e modificabili a piacere
- Gestisce anche periferiche di nuova concezione (force feedback)
- Semplifica notevolmente la vita del programmatore di videogiochi/emulatori
- Esistono TANTISSIMI pacchetti sviluppati con Allegro per gestire un sacco di cose
(grafica 3D con Open-GL, nuove istruzioni dei processori, Font sfumati, funzioni
ottimizzate per i tile,
Moduli sonorie (.mod, .xm e Mp3) e pensate, anche un piccolo browser HTML!)
La libreria ha questi difetti
- Il supporto 3D molto limitato, ma esiste un plug-in per utilizzare le Open-GL con le
funzioni 3D di Allegro.
- Sotto Windows la libreria un semplice Wrapper per DirectX, e questo purtroppo mina
molto le sue prestazioni (l'ottimizzazione spinta per la versione DOS).
- Le versione pi nuova (WIP) non ancora perfettamente debuggata per tutti i sistemi.

Sono daccordo con quasi tutta la descrizione, tranne che per il fatto che troppo
poco vengono fatti pesare i difetti.. oltre che per il fatto che SDL non da meno,
riguardo gli emulatori!
SDL
Rispetto ai pregi di ALLEGRO modificherei solo la semplicit, che non pi
notevole ma non eccessiva. Il supporto 3D decisamente migliore (anche se

sconveniente) e, con un po di impegno, possibile controllare pi che pienamente


le operazioni anche a basso livello. Lunico aspetto da curare molto
lottimizzazione.
Si pu realizzare di tutto e di pi, dal gioco allo screensaver allemulatore. Ed
proprio un emulatore open-source che mi ha nuovamente sorpreso poco tempo fa;
facilmente reperibile in rete, si chiama DOSBox (ho scaricato la versione 0.70):
emula dos 5 in maniera quasi impeccabile, cos da poter utilizzare vecchi giochetti
o altro a prestazioni ottimali.
OpenGL
Si tratta di una specifica che definisce API per pi linguaggi e sistemi per la
realizzazione di applicazioni 2D o principalmente - 3D. E incredibilmente
performante e con la possibilit di lavorare bene sia ad alto che a basso livello.
E la mia passione del momento, ma sono convinto che sia molto importante
imparare prima lSDL e solo in seguito lOpenGL! E utile prendere
dimestichezza con la mentalit grafica 2D prima di passare alla terza dimensione,
altrimenti si rischia di andare incontro a malintesi, e ad avere grosse lacune che si
rischierebbe di non colmare mai. Invece imparare i concetti dellOpenGL partendo
da una base di SDL render le cose molto pi naturali.
DirectX
E qualcosa in pi dellOpenGL, ovvero, non si occupa solo dellaspetto
grafico, ma anche di quello dei suoni, della riproduzione video, delle periferiche di
input e molto altro. Utilizzando le DirectX si pu concludere unapplicazione
completa, con lOpenGL no, in quanto mancherebbero aspetti fondamentali,
colmabili attraverso altre librerie o singole funzioni, comunque esterne al progetto
OpenGL. Per questo aspetto le DirectX sono simili alla libreria SDL, nel senso
che conglobano pi aspetti.
Problema.. sviluppato dalla Microsoft, quindi , diciamo, esclusivo di
Windows, a differenza dellOpenGL che presenta unarchitettura nota e pu essere
sfruttata da pi piattaforme.
Ritengo fondamentale sottolineare la differenza profonda tra le librerie descritte
sopra: OpenGL e Direct3D sono API grafiche che offrono un'astrazione software della GPU o della
scheda video; queste hanno sostituito i render software come le API Glide. DirectX, SDL, OpenAL
(non citata sopra) sono librerie a basso livello che offrono un accesso diretto anche ad altri
componenti hardware (suoni, periferiche di input, ). Quindi si pu realizzare un software che
sfrutta le OpenGL per la grafica e lSDL, o le DirectX, per tutto il resto. Per questo necessaria una
conoscenza non solo del codice, ma anche dei concetti base stessi.

Come impostare un progetto SDL con Visual Studio 6.0


Copia delle librerie: Puoi scaricare la libreria SDL precompilata dal sito
http://www.libsdl.org/download.php, oppure compilarla da te. Non tratter questultimo caso
dato che lo ritengo un passaggio superfluo inutile spiegare qualcosa che interessa solo chi
ne gi capace.

Creare ed impostare un nuovo progetto per lSDL:

Creare una Win32 Application;


Se non presente (ne dubito) creare un file .cpp principale per il progetto;
Nel menu: Project|Settings|C/C++ tab|Code Generation|Runtime Library
imposta il C runtime su "Multithreaded DLL" ;
Nel menu: Project|Settings|C/C++ tab|Preprocessor|Additional include
directories aggiungi la directory include dellSDL (quella con i .h);
Copia il file SDL.dll nella directory del progetto
Aggiungi i file SDL.lib e SDLmain.lib al tuo progetto (non necessario copiarli nella
cartella come il .dll) per aggiungerli, click destro sul progetto, seleziona Add file sto
project;
In alternativa al precedente e forse necessario al rilascio della release finale, si possono
aggiungere i due file nelle opzioni del linker (Project|Properties|Linker|Command Line),
aggiungendone i nomi nelle Additional Options;
Includi SDL.h nel file .cpp principale.

Attenzione: per poter utilizzare leseguibile, dora in poi, sar sempre necessaria la
presenza del file SDL.dll nella sua stessa directory.
Per impostare il progetto con un IDE diverso da Visual Studio non cambia
praticamente nulla: ovvio che il men sar diverso, ma le operazioni da eseguire sono le
stesse (dopo averlo fatto la prima volta vi potreste domandare: mmm, ma cosa ho fatto?,
se cos andatevi a studiare il funzionamento di un compilatore e gli argomenti correlati).

La prima dialog
La prima cosa da imparare linizializzazione video. Una delle comodit di questa
libreria la semplicit delle operazioni necessarie alla creazione di una dialog.
Inizializzazione: per utilizzare la libreria necessario inizializzare i sottoinsiemi interessati
(SDL_INIT_VIDEO, SDL_INIT_AUDIO, SDL_INIT_CDROM, SDL_INIT_TIMER)
tramite la funzione SDL_Init(FLAGS). Al termine dellapplicazione necessario chiamare la
funzione SDL_Quit() per terminare questi sottosistemi; un metodo alternativo per la chiusura
la funzione atexit(SDL_Quit), solitamente posta subito dopo linizializzazione, per chi ha
paura di dimenticarsi la chiamata alla funzione di chiusura. In questo caso, per, nel main si
dovr utilizzare lexit().
Subito dopo possiamo inizializzare la finestra. In unapplicazione multipiattaforma
non si pu prendere nessuna decisione a priori; necessario, invece, gestire il software in
relazione alle possibilit hardware della macchina e al sistema operativo. A questo proposito
la libreria SDL mette a disposizione una serie di funzioni per ottenere informazioni
riguardanti i driver video (SDL_GetVideoInfo()) e le potenzialit dellhardware video
(SDL_GetVideoInfo()). Non mi soffermo per su questo; vediamo invece i passi base per la
creazione di una dialog:
SDL_Surface *screen;
screen = SDL_SetVideoMode( x, y, bits, Flags );
if(! screen ) return -1; // gestione del possible errore
SDL_LockSurface(screen);
SDL_Surface questo sar dora in poi il tipo fondamentale, infatti questo che contiene
le informazioni relative a unimmagine. Non si deve per confondere questo tipo con la
dialog, la quale viene collegata ad una variabile di questo tipo; infatti molto spesso si
caricano immagini non visualizzate completamente o del tutto, cosa che avremo modo di
approfondire con gli sprite.
SDL_SetVideoMode( int x, int y, int bits, int Flags ) questa appunto la funzione che
alloca la nuova SDL_Surface e crea una nuova Dialog a essa riferita.
x larghezza della superficie
y altezza della superficie
bits numero bit di colori
Flags SDL_OPENGL | SDL_FULLSCREEN | SDL_DOUBLEBUF | ...
SDL_LockSurface si rende utile quando si inizia lo sviluppo di funzioni pi complesse;
il suo scopo quello di bloccare eventuali operazioni di scrittura non desiderate, che
potrebbero causare errori.
Piccolo fastidio: per ogni blocco di operazioni di disegno (blit) sar necessario
sbloccare e poi riboccare la superficie, con appunto SDL_UnlockSurface(SDL_Surface*) e
SDL_LockSurface(SDL_Surface*)

Se si intende caricare unimmagine la superficie si adatter al formato della stessa;


al contrario necessario definirne i parametri base se la propria intenzione di colorare
manualmente limmagine, o comunque senza appoggiarsi a file esterni.
PrimaryLayer = SDL_CreateRGBSurface( (Flags & SDL_HWSURFACE), x, y, bits,
screen->format->Rmask,
screen->format->Gmask,
screen->format->Bmask,
screen->format->Amask
);
if(! PrimaryLayer ) return -1; // gestione del possible errore

Creare un ciclo di gioco


Per rendere utilizzabile una Dialog, utilizzando il procedimento classico di
sfruttamento della libreria SDL, necessaria la creazione di un ciclo di RunTime (1);
allinterno di esso si dovr svolgere lintero programma, o una parte.
Si tratta di re-implementare dalle basi la programmazione oggi definita ad eventi; in
realt non nulla di logicamente complicato. Mi spiego con un esempio:
SDL_Event event, test_event;
Uint8 *keys;
for( ; ; )
{
SDL_Delay(frame_skip);

// ciclo principale di gioco


// rallenta il ciclo di RunTime

if (SDL_PushEvent(&test_event) == 0)

// se si verifica un qualsiasi evento


// causato dallutente/

{
SDL_PollEvent(&event);

// cattura levento; concretamente, aggiorna la


// rilevazione eventi da periferiche esterne;
keys = SDL_GetKeyState(NULL);
// aggiorna larray puntato da keys
if ( keys[SDLK_ESCAPE] == SDL_PRESSED ) // esco dal ciclo su pressione
// di Escape
break;
}
}
SDL_Delay(int) un comando fondamentale, anche concettualmente (vedi il capitolo I
Timer: se viene omesso il ciclo di RunTime rischia di essere eseguito con una frequenza
tale da moltiplicare gli eventi creando effetti sgradevoli. Per essere pi chiari faccio un
esempio: in un men premendo SU si sposta un cursore di una casella, se il RunTime cos
veloce da fare pi di un ciclo mentre premo il tasto potrei ritrovarmi con il cursore sul
soffitto deve essere limitato, o meglio gestito attraverso un parametro variabile intero
(FrameSkip) impostabile manualmente o automaticamente per avere prestazioni ottimali su
ogni PC. Tutto questo senza considerare che, se non viene utilizzata questa funzione, il
software assorbe una parte considerevole della CPU, rendendo cos instabile il sistema.
if (SDL_PushEvent(&test_event) == 0) non necessario che, ad ogni ciclo, si ripetano
tutti i controlli sugli eventi, cos, per lasciare un po di respiro al processore, stato
inventato un controllo generico necessario al funzionamento in RunTime del sistema ad
eventi.
if (keys[SDLK_ESCAPE] == SDL_PRESSED) gestione dellevento tasto ESCAPE
premuto; nel caso riportato se la condizione verificata si esce dal ciclo. Levento
SDL_PRESSED verificabile in keys (di tipo Uint8) grazie alloperazione di aggiornamento
svolta nella riga precedente ( keys = SDL_GetKeyState(NULL) ).

La lista di tutti gli eventi DA tastiera e mouse presente nei file


SDL_Events.h e SDL_keysym.h; per completezza lho riportata
nellappendice1.
(1) Nella programmazione visuale (un esempio sono Java, Delphi, Visual Basic, le MFC app. in Visual C++)
questo ciclo presente per definizione, anche se non immediato il suo riconoscimento nel sorgente
programmazione ad eventi.

Un primo esempio di visualizzazione di unimmagine


Una volta impostato il ciclo principale di gioco non difficile imparare a far visualizzare
unimmagine BMP allutente; cominciamo con la teoria:
Si deve caricare la BMP in una SDL_Surface (*image);
Si deve copiare *image in una determinata posizione (x=20, y=20) nella
SDL_Surface principale (*screen).
Questultima operazione consiste nel prendere ogni pixel dellimmagine e copiarla in
*screen, dunque si tratta di un semplice ciclo annidato (questo verr approfondito per
spiegare la trasparenza).
Il codice seguente fatto per essere inserito appena prima del ciclo di gioco
SDL_Surface *image;
image = SDL_LoadBMP( file_name ); // carica limmagine nella superficie, la quale
// viene allocata automaticamente
SDL_Rect dst; // struttura composta da x,y,w (larghezza), h (altezza)
// necessaria in SDL_BlitSurface per indicare rettangolo sorgente(src)
// o destinazione(dst)
dst.x = 20 ; // nel caso di rect di destinazione sufficiente indicare x e y
dst.y = 20 ;
SDL_UnlockSurface(screen); // sblocco screen // necessario per poter modificare questa
// Surface
// SDL_BlitSurface(SDL_Surface*image, SDL_Rect *src, SDL_Surface*screen,
SDL_Rect *dst);
SDL_BlitSurface(image, NULL, screen, &dst)
SDL_LockSurface(screen); // riblocco screen
//SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h);
SDL_UpdateRect(screen, 0, 0, 0, 0); // aggiorna la superficie visualizzata
// i parametri a 0 stanno a significare che laggiornamento interessar tutto lo schermo,
// altrimenti qualcosa del tipo 1,1,10,50 avrebbe preso il rettangolo con estremi
// A(1,1) B(11,51)
Nel caso qui specificato si copia unimmagine BMP caricata da file nella superficie
principale a partire dalle coordinate 20,20.
Il fatto che il 2 parametro di SDL_BlitSurface sia NULL sta a significare che si
copia limmagine completa; e dunque chiaro che basterebbe passargli un SDL_Rect src per
copiarne solo la parte desiderata.

Per andare sul concreto, faccio lesempio degli sprite: in molti tipi di gioco le
immagini di un personaggio vengono unite in un unico file; nella fase di disegno se ne
prender solo una parte alla volta.
Ma questo lo vedremo nel capitolo degli sprite.. andiamo per gradi.

Muovi limmagine nello schermo


Arrivati a questo punto, per riuscire a muovere limmagine interessata sufficiente
aggiungere due punti principali:
La gestione degli eventi da tastiera.. mi spiego:
Quando premo la freccia destra, sposto limmagine a destra, e cos via;
Laggiornamento della Superficie e poi della visualizzazione.
Prima di proseguire ricordo che per indicare la posizione dellimmagine abbiamo
utilizzato la variabile dst (.x e .y).
Qui di seguito riporto il codice del ciclo di gioco modificato ( le parti nuove sono in
grassetto )

for( ; ; )
{

// ciclo principale di gioco


SDL_Delay(frame_skip);

// rallenta il ciclo di RunTime

if (SDL_PushEvent(&test_event) == 0)
{
SDL_PollEvent(&event);

//

/* gestione degli eventi da tastiera */


keys = SDL_GetKeyState(NULL); // aggiorna la situazione attuale dei
// tasti premuti o no
if ( keys[SDLK_ESCAPE] == SDL_PRESSED ) // esco dal ciclo su
// pressione di Escape
break;
if ( keys[SDLK_UP] == SDL_PRESSED ) dst.y--;
if ( keys[SDLK_DOWN] == SDL_PRESSED ) dst.y++;
if ( keys[SDLK_LEFT] == SDL_PRESSED ) dst.x--;
if ( keys[SDLK_RIGHT] == SDL_PRESSED ) dst.x++;
}
SDL_UnlockSurface(screen);
// sblocco screen
SDL_BlitSurface(image, NULL, screen, &dst);
SDL_LockSurface(screen);
// blocco screen
SDL_UpdateRect(screen, 0, 0, 0, 0);
}

Reblitting: muovere unimmagine su uno sfondo statico


Con lesigenza di uno sfondo caricato da una BMP sorgono le prime difficolt.
Per poter muovere la nostra immagine su uno sfondo statico necessario, ad ogni ciclo,
disegnare prima lo sfondo, poi limmagine interessata (ricordo che lUpdateRect deve essere
effettuato una sola volta per ogni ciclo, altrimenti si ottengono brutti effetti visivi (1)). Per ora
questo tutto ci che ci basta sapere; nel prossimo capitolo analizzeremo il problema del
rallentamento dellapplicazione, ma prima necessario sperimentare.
(1) Carichiamo in una nuova superficie la nostra BMP di sfondo;
SDL_Surface *sfondo;
sfondo = SDL_LoadBMP( "sfondo1.bmp" ); // NEW
(2) Prima del blit dellimmagine da muovere, nel ciclo di gioco, ridisegnamo lo sfondo.
Nellesempio: src==NULL: disegniamo lintero sfondo
dst==NULL: lo sfondo verr disegnato da (0,0)
SDL_BlitSurface(sfondo, NULL, screen, NULL); // NEW

(1) Le librerie SDL utilizzano automaticamente un algoritmo per sincronizzare lUpdateRect con laggiornamento
fisico dello schermo. Se nel ciclo di gioco ci fossero pi aggiornamenti visivi della superficie
(SDL_UpdateRect o anche SDL_Flip, nel caso del DOUBLE_BUFFERING) si visualizzerebbero effetti visivi
che renderebbero lapplicazione normalmente inutilizzabile.

Reblitting: il parziale pi rapido?


Uno dei pi grandi problemi che ci possono assillare lottimizzazione
dellapplicazione, cos da poterla rendere funzionale nei PC pi lenti.
I pi attenti, riguardo il capitolo precedente, si saranno chiesti: Ridisegnando lintera
superficie ad ogni ciclo di gioco non rallenter di molto lapplicazione?. Per capire se
questo vero tentiamo di realizzare un Reblitting parziale, cio
Sappiamo che lUpdateRect gi ottimizzato, in quanto aggiorna visivamente solo la
superficie modificata con il BlitSurface, quindi perch non migliorare la nostra tecnica di
Blitting?
Lidea questa: dobbiamo spostare limmagine da unarea A ad una B; dopo
aver calcolato larea B, copiamo in una SDL_Rect temporanea A e, nel ciclo successivo
prima si ridisegner lo sfondo solo nellarea A, poi si proceder con il Blitting
dellimmagine in B (chiaramente tutto questo si far solo se (A != B)). Per sfruttare
questo concetto anche con pi oggetti dinamici sufficiente creare una lista (preferibilmente
puntata) di SDL_Rect che, ad ogni ciclo, conterranno le aree degli oggetti che si stanno
spostando, baster dunque ridisegnare lo sfondo solo dove c movimento.
La domanda pi ovvia alla quale voglio dare una risposta : Dov il problema?
Implementiamo questo concetto e tutto sar pi veloce. Non sono daccordo perch penso
al caso pi pessimistico, e cio ad unapplicazione con un numero di oggetti dinamici tale da
rendere le operazioni di copia delle SDL_Rect temporanee complesse a tal punto da
rallentare lapplicazione. E evidente che pi rapido ridisegnare il meno possibile dello
sfondo, ma si deve capire che la funzione SDL_BlitSurface relativamente lenta, quindi
meglio richiamarla il meno volte possibile: pi efficace quindi disegnare una volta
lintero sfondo che molte volte piccoli pezzetti di esso. A sommarsi a questo c il tempo
impiegato per la gestione delle aree temporanee, anche se si tratta di un problema minimo in
confronto al richiamare pi volte la funzione BlitSurface.
Ulteriore difficolt da affrontare: se si intende utilizzare una mappa scorrevole e pi
sfondi, si devono gestire contemporaneamente il Reblitting e lo scroll, il che non cosa da
poco. Nelle applicazioni pi avanzate viene calcolato un limite, valicato il quale questa
tecnica diventa svantaggiosa; quindi utilizzo del metodo pi vantaggioso.
Negli esempi preferisco non trattare questo problema in quanto intendo mantenere
una semplicit di codice tale da renderne lanalisi il pi facile possibile.

Primo approccio alla trasparenza


Con gli aspetti visti finora si potrebbe realizzare un men, o al massimo un tetris,
comunque di scarsa qualit. Le nostre possibilit cambiano radicalmente con lutilizzo della
trasparenza, tecnica tramite la quale possibile stampare a video anche figure rotonde o
irregolari.
Ogni oggetto SDL_Surface pu avere un colore di trasparenza diverso e, nel nostro
esempio, utilizzando unimmagine a 8 bit ,ovvero una palette di 256 colori, sufficiente
utilizzare la funzione SDL_SetColorKey per impostare il colore di trasparenza. La logica
questa: quando disegno in *screen limmagine interessata copio solo i pixel diversi da quello
di trasparenza impostato tramite la funzione cos richiamata:
if ( image->format->palette ) {
SDL_SetColorKey(image, (SDL_SRCCOLORKEY|SDL_RLEACCEL),
*(Uint8 *)image->pixels);
}
Questa riga di codice pu essere inserita subito dopo
image = SDL_LoadBMP( "file_name.bmp" ).
Il prototipo della funzione il seguente:
int SDL_SetColorKey(SDL_Surface *surface,
Uint32 flag, Uint32 key);
Ho optato per unimmagine ad 8 bit perch a profondit di colore maggiore si
possono riscontrare dei problemi. In particolare con questa versione delle librerie si
visualizza un brutto effetto visivo che mi ha perseguitato per parecchio tempo. Per
ovviarlo, invece di cambiare versione della libreria, ho pensato di implementare una mia
personale versione di blitting trasparente. Questa mi si poi rivelata fondamentale per la
realizzazione di unapplicazione definibile carina, anche perch fornisce altre possibilit,
come ad esempio la rotazione dellimmagine e lingrandimento. Purtroppo non affatto
veloce, quindi ho dovuto cercare altre soluzioni.
Chi intende provare ad approfondire pu passare allAPPENDICE 2, dove spiego
logica e contenuti della mia implementazione.
Per chi abbia intenzione di utilizzare le funzioni predefinite pu facilmente reperirle
nella documentazione ufficiale, nulla di difficile se si possiede la versione giusta della
libreria; quindi potete passare direttamente al capitolo successivo.
Qui di seguito riporto come utilizzare la funzione SDL_SetColorKey anche con
immagini di profondit di colore maggiore a 8 bit, dunque con i metodi true-color:
SDL_SetColorKey(image, SDL_SRCCOLORKEY | SDL_RLEACCEL,
SDL_MapRGB(image ->format, 0xff, 0x00, 0xff));
(0xff, 0x00, 0xff) indicano il colore RGB (red==255, green==0, blue==255), ovvero
violetto, spesso come colore di default.

Blit parziale delloggetto e introduzione agli sprite


Dopo aver visto come disegnare immagini utilizzando la trasparenza con colore
chiave, non difficile avvicinarsi alla mentalit degli sprite. Prima, per, necessario vedere
come disegnare porzioni di unimmagine sulla superficie.

Blit parziale: Come per indicare le coordinate dello schermo dove disegnare la BMP, si
utilizza una variabile di tipo SDL_Rect:
SDL_Rect src;
src.x = 0;
src.y = 0;
src.w = 23;
src.h = 10;
Eseguendo poi la funzione SDL_BlitSurface(image, &src, screen, &dst ) si comunica alla
libreria di disegnare in screen dst.x, dst.y, la porzione dellimmagine image contenuta nel
rettangolo di larghezza 23 pixel ed altezza 10.

Cos uno sprite: Per definizione uno sprite unimmagine bidimensionale che pu essere
spostata rispetto ad uno sfondo. Nei primi videogame questo veniva gestito direttamente via
hardware, per ottenere quindi leffetto di trasparenza.
Oggi per sprite intendiamo unimmagine 2D, generalmente formata da n frame; questi
vengono visualizzati uno alla volta in successione, in maniera da essere sovrapposti e da
dare limpressione di una continuit, di un movimento, fluido il pi possibile.
Queste immagini sono caratteristiche di varie tipologie di applicazioni, dai giochi di
ruolo 2D, dove sono utilizzati praticamente per ogni cosa, ad applicazioni con gestione del
testo, dove gli stessi font hanno uno sprite per ogni stile di caratteri, o charset.
Per essere eloquenti al massimo, lo stesso sistema adottato per le gif animate,
sostanzialmente.

Come applicare il concetto: Pensando come sviluppare un codice che realizzi questo
concetto, il pi facile che mi viene alla mente il seguente (vedi SDL_Example4):
// Prima del ciclo di loop
/* Variabili riguardanti la gestione degli sprites */
unsigned int frame_attuale=0;
SDL_Rect src;
src.x = (LARGHEZZA_IMMAGINE)*(frame_attuale);
src.y = 0 ;
src.w = LARGHEZZA_IMMAGINE;
src.h = ALTEZZA_IMMAGINE;
// Nel ciclo di loop, prima di disegnare
/* Cambio frame */
if (++frame_attuale >= NUMERO_FRAMES)
frame_attuale=0;
src.x = (LARGHEZZA_IMMAGINE)*(frame_attuale);

/* Disegno la frame */
SDL_BlitSurface_transparent(image, &src, screen, &dst, 0, 0, 0, 1, 0, 0);

Una prima implementazione di motore fisico


Ho pensato di includere in questa guida anche un piccolo esempio che possa far
capire cosa si pu sviluppare utilizzando questa libreria.
Ora che abbiamo la padronanza della tecnica degli sprite necessario almeno dare
unocchiata al movimento, comandato dallutente tramite tastiera, sullo stile platform; quindi
il classico omino che subisce la forza di gravit.
Prima di tutto dobbiamo dichiarare due nuove variabili:
/* Gravit */
int gravita=0;
/* Direzione */
bool sinistra=false;
Poi, nel ciclo di loop togliamo leffetto in seguito alla pressione della freccia verso il
basso, e sostituiamo a quella verso lalto:
if ( (keys[SDLK_UP] == SDL_PRESSED) && ((dst.y+ALTEZZA_IMMAGINE)>=y) )
{
gravita=-20;
}
Lintento di far saltare il personaggio, ora vedremo cosa abbiamo sostanzialmente
fatto con questi comandi.
Prima di disegnare, aggiungiamo il codice seguente:
/* Gravit */
dst.y+=gravita++;
if ((dst.y+ALTEZZA_IMMAGINE)>=y)
{
gravita=0;
dst.y=y-ALTEZZA_IMMAGINE;
}
In questo modo la posizione dellimmagine si sposter verso il basso di un valore
crescente.. nel mondo reale la crescita esponenziale, nei platform questa non sempre lo ;
la tipologia di gioco influenza la forza della gravit.
Come soglia di collisione prendiamo i piedi del personaggio, quindi, essendo che le
coordinate partono dallangolo in alto a sinistra dello schermo (0, 0), posizione y attuale +
altezza immagine.
A questo punto si pu capire che per avere un salto sufficiente, alla pressione del
tasto interessato, assegnare alla gravit un valore negativo; chiaro che tanto pi grande sar
questo numero (in valore assoluto), tanto maggiore sar la forza del salto.

Limportanza della console


Spesso mi capitato di perdere molto tempo nel cercare un problema la cui causa
sembrava introvabile. Intoppi del genere sono alla base del mondo della programmazione, in
particolare web. I linguaggi compilati, come il C++, hanno un fantastico sistema di debug, il
quale facilita sicuramente la ricerca degli errori. Sarebbe per sicuramente meno frustrante
se, al verificarsi di un problema, la sua causa fosse arginata allinterno di poche righe di
codice; queste, certo, sono tanto pi ridotte tanto maggiore la nostra bravura, esperienza ed
intuizione. Non basta, per!
Il mio consiglio di sfruttare al meglio la console predefinita. Con questo intendo
dire che dobbiamo fare un po di fatica in pi e gestire gli errori tramite try/catch, ed in caso
di eccezioni segnalarle con un printf, o cout, nella console. Si possono classificare i tipi di
errori, se il software diventa complesso.
Oltre alla classificazione e segnalazione degli errori si pu utilizzare la console per
segnalare gli eventi, laccesso a funzioni o condizioni, lo stato di thread, connessioni, suoni.
E molto importante decidere se impostare un progetto sotto questo profilo fin
dallinizio dello sviluppo, altrimenti poi, quando il codice raggiunge uno sviluppo avanzato,
risulta molto faticoso scegliere i punti giusti dove inserire i controlli, anche perch capita che
non ci si ricorda pi come fatta una funzione, quindi si perde ulteriore tempo.
Chiaro che, se intenzione dellautore, la console verr nascosta nelle release stabili, o
ridotta a funzione di indicatore di caricamento.

Audio
La libreria SDL gestisce bene anche laspetto riguardante i suoni. Nel dettaglio, la
libreria ci mette a disposizione una serie di funzioni che rendono facile la riproduzione di
file audio: SDL_LoadWav(), SDL_OpenAudio(), SDL_PauseAudio(). SDL chiama
automaticamente una funzione di callback che copia i campioni dalla memoria di sistema al
buffer della scheda audio. Questa funzione devessere creata dallutente e il suo indirizzo,
assieme ai valori della frequenza di campionamento e della risoluzione dei campioni, deve
essere specificato nella struttura SDL_AudioSpec:
typedef struct{
int freq;
Uint16 format;
Uint8 channels;
Uint8 silence;
Uint16 samples;
Uint32 size;
void (*callback)(void *userdata, Uint8 *stream, int len);
void *userdata;
} SDL_AudioSpec;
freq - Frequenza di campionamento
Il numero di campioni copiati nel buffer della scheda audio al secondo. I valori pi comuni
sono 11025, 22050 e 44100. Pi il valore alto, migliore il suono.
format - Formato audio (1)
Specifica la dimensione ed il tipo di ogni campione:
AUDIO_U8 Campioni di tipo Unsigned 8-bit
AUDIO_S8 Signed 8-bit
AUDIO_U16 o AUDIO_U16LSB Unsigned 16-bit little-endian
AUDIO_S16 o AUDIO_S16LSB Signed 16-bit little-endian
AUDIO_U16MSB Unsigned 16-bit big-endian
AUDIO_S16MSB Signed 16-bit big-endian
AUDIO_U16SYS Sia AUDIO_U16LSB che AUDIO_U16MSB dipendenti
dal sistema endianness specifico
AUDIO_S16SYS Sia AUDIO_S16LSB che AUDIO_S16MSB dipendenti
dal sistema endianness specifico.
channels Numero di canali: 1 mono, 2 stereo
silence Valore di silenzio del buffer audio (calcolato automaticamente)
samples Dimensione del buffer audio, in campioni
size Dimensione, in byte, del buffer audio (calcolato automaticamente)
callback(..) Funzone di callback per copiare i campioni nel buffer della
scheda audio
userdata Puntatore ai parametri da passare alla funzione di callback.

Riporto qui di seguito un esempio di funzione di callback, presa da http://www.libsdl.org:


#define NUM_SOUNDS 2
struct sample {
Uint8 *data;
Uint32 dpos;
Uint32 dlen;
} sounds[NUM_SOUNDS];
void mixaudio(void *unused, Uint8 *stream, int len)
{
int i;
Uint32 amount;
for ( i=0; i<NUM_SOUNDS; ++i ) {
amount = (sounds[i].dlen-sounds[i].dpos);
if ( amount > len ) {
amount = len;
}
SDL_MixAudio(stream, &sounds[i].data[sounds[i].dpos],
amount, SDL_MIX_MAXVOLUME);
sounds[i].dpos += amount;
}
}

Questo invece un esempio di struttura SDL_AudioSpec.


SDL_AudioSpec fmt;
/* Setta l'audio a 16-bit stereo 22Khz */
fmt.freq = 22050;
fmt.format = AUDIO_S16;
fmt.channels = 2;
fmt.samples = 512;
/* Un buon valore per i giochi */
fmt.callback = mixaudio;
fmt.userdata = NULL;

SDL permette anche la gestione dellaudio da CD-ROM. Riporto qui di seguito la semplice
funzione ricavata dal sito http://www.libsdl.org:
void PlayTrack(SDL_CD *cdrom, int track)
{
if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) {
SDL_CDPlayTracks(cdrom, track, 0, track+1, 0);
}
while ( SDL_CDStatus(cdrom) == CD_PLAYING ) {
SDL_Delay(1000);
}
}

Si spiega da sola.
(1) Big, Middle e Little Endian sono le tre tipologie alternative alla memorizzazione di dati con dimensione base
superiore al byte. Per endianness si intende generalmente lordine dei byte.

Applicazioni Multi-threaded
A volte capita di dover affrontare problemi che trovano soluzione solo con
operazioni svolte in parallelo; purtroppo la gestione di 2 processi pesa parecchio al sistema,
quindi sono stati creati i thread, definibili come processi leggeri; ogni processo pu avere
pi thread, i quali condividono lo stesso spazio di indirizzamento.
La libreria SDL ci mette a disposizione funzioni per creare thread e per poterli
gestire. Prima di vedere quali sono queste funzioni necessario sapere a cosa necessario
prestare attenzione per evitare effetti indesiderati:
Prima di tutto pensa a tutte le possibili soluzioni alternative allutilizzo di un nuovo
thread;
Se non c altro modo, o se questo il pi efficace, bene evitare lutilizzo di
variabili globali su thread differenti;
Non terminare i threads, utilizza invece un flag e fai in modo che si chiuda
autonomamente; questo sia per evitare errori di esecuzione che il possibile memoryleak;
E preferibile non fare chiamate SDL Video/Event su pi threads.
SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data);
Questa funzione permette la creazione di un nuovo thread, avviando la funzione fn con
parametri data.
void SDL_WaitThread(SDL_Thread *thread, int *status);
Aspetta che un thread finisca; status il valore restituito dalla funzione main del thread
terminato.
void SDL_KillThread(SDL_Thread *thread);
Termina un determinato thread.
SDL permette anche la risoluzione del problema delle variabili condivise tramite
mutex, ovvero il procedimento di sincronizzazione che impedisce laccesso contemporaneo
di pi threads alla stessa risorsa, evitando cos errori parecchio fastidiosi. La conoscenza del
loro utilizzo v oltre lo scopo di questa guida.
Un esempio di operazione da svolgere in multi-threading la gestione della
comunicazione di rete; in questo caso, a meno che non si intenda bloccare il software in
attesa di un determinato pacchetto, o fino alla scadenza di un timeout, risulta fondamentale
lutilizzo di un secondo thread che gestisca in maniera autonoma la connessione.

I Timer
Tutte le operazioni svolte da un computer sono intervallate da un determinato tempo,
denominato clock. Questo devessere necessariamente gestito dal programmatore in questo
genere di applicazioni, ovvero dove si mette mano direttamente al codice del ciclo di loop. Il
non affrontare questo argomento compromette sensibilmente lesecuzione del software, il
quale sfrutterebbe tutta la memoria concessagli, rischiando di mandare in crash il sistema,
oltre che lapplicazione stessa.
La libreria SDL mette a disposizione delle funzioni per la gestione del tempo, una
delle quali SDL_GetTicks(), che restituisce il tempo trascorso dallavvio dellapplicazione
(in ms); anzi, per essere precisi, questo tempo riferito allinizializzazione della libreria.
Laltra funzione fondamentale SDL_Delay(), che attende il tempo, in ms, passatogli come
parametro. Questa funzione particolarmente precisa, se la rapportiamo ad altre disponibili
nelle librerie standard. Unaltra possibilit fornitaci dalla libreria quella di creare timer e
collegarci funzioni; si tratta quindi del classico evento OnTimer disponibile in quasi tutti i
linguaggi visuali.
ATTENZIONE: SDL mette a disposizione funzioni comode e molto utili, ma
compito del programmatore gestire in maniera efficace quello che nelle applicazioni grafiche
sono chiamati FPS (Frame per second). Non si tratta affatto di un argomento banale, anzi, ci
si sbatte la testa pi volte, nello sviluppo di applicazioni grafiche.

SDL sopra OpenGL


SDL mette a disposizione una serie di funzioni per laccesso al buffer video, quindi
permette un approccio a basso livello. Tuttavia non ci viene fornita alcuna funzione per il
disegno di primitive. La caratteristica che ci pu far dimenticare questa piccola mancanza
la facile integrazione con la libreria OpenGL (per dettagli a riguardo rimando al capitolo
Perch usare lSDL). Questultima ha la caratteristica di non interfacciarsi direttamente
con il S.O., bens attraverso un contesto grafico in cui poter disegnare la scena. E qui che
entra in campo lSDL, mettendo a disposizione questo contesto attraverso una serie di
funzioni:
SDL_GL_SetAttribute() consente limpostazione degli attributi del contesto grafico (bit per
colore, flag per il DOUBLE_BUFFERING o per il DEPTH_TEST);
In SDL_SetVideoMode() necessario passare come flag SDL_OPENGL;
SDL_GL_SwapBuffers() Effettua lo scambio tra back-buffer e frame-buffer;
SDL_GL_GetProcAddress() Restituisce lindirizzo di una funzione contenuta in
unestensione OpenGL.
Ci sarebbe molto da dire in questo capitolo, ma andrei al di fuori dellargomento
SDL. C gi abbastanza da capire in questa libreria. Penso che solo la convinzione di essere
interessati ad approfondire possa portare a qualche risultato; altrimenti lo studio si riduce a
semplice lettura, di scarsa utilit, oltretutto. Il dare unocchiata pu servire solo a spaventare
e ad allontanare la persona da un argomento del quale meglio pensare pi ai concetti che al
codice.

Appendice1 lista degli eventi da tastiera e mouse


Lutilizzo il seguente:
Per la tastiera:
Uint8 *keys;
keys = SDL_GetKeyState(NULL);
// aggiorna il vettore keys
if ( keys[SDLK_EVENTO] == SDL_PRESSED )

Per il mouse:
Uint8 mouse;
mouse = SDL_GetMouseState(mx,my); // mx e my sono puntatori a int
// in essi saranno salvate le coordinate del puntatore del mouse
// possono essere NULL
if ( mouse == SDL_EVENTO )

EVENTI TASTIERA
/* The keyboard syms have been cleverly chosen to map to ASCII */
SDLK_UNKNOWN
= 0,
SDLK_FIRST
= 0,
SDLK_BACKSPACE
= 8,
SDLK_TAB
= 9,
SDLK_CLEAR
= 12,
SDLK_RETURN
= 13,
SDLK_PAUSE
= 19,
SDLK_ESCAPE
= 27,
SDLK_SPACE
= 32,
SDLK_EXCLAIM
= 33,
SDLK_QUOTEDBL
= 34,
SDLK_HASH
= 35,
SDLK_DOLLAR
= 36,
SDLK_AMPERSAND
= 38,
SDLK_QUOTE
= 39,
SDLK_LEFTPAREN
= 40,
SDLK_RIGHTPAREN
= 41,
SDLK_ASTERISK
= 42,
SDLK_PLUS
= 43,
SDLK_COMMA
= 44,
SDLK_MINUS
= 45,
SDLK_PERIOD
= 46,
SDLK_SLASH
= 47,
SDLK_0
= 48,
SDLK_1
= 49,
SDLK_2
= 50,
SDLK_3
= 51,

SDLK_4
= 52,
SDLK_5
= 53,
SDLK_6
= 54,
SDLK_7
= 55,
SDLK_8
= 56,
SDLK_9
= 57,
SDLK_COLON
= 58,
SDLK_SEMICOLON
= 59,
SDLK_LESS
= 60,
SDLK_EQUALS
= 61,
SDLK_GREATER
= 62,
SDLK_QUESTION
= 63,
SDLK_AT
= 64,
/*
Skip uppercase letters
*/
SDLK_LEFTBRACKET = 91,
SDLK_BACKSLASH
= 92,
SDLK_RIGHTBRACKET= 93,
SDLK_CARET
= 94,
SDLK_UNDERSCORE
= 95,
SDLK_BACKQUOTE
= 96,
SDLK_a
= 97,
SDLK_b
= 98,
SDLK_c
= 99,
SDLK_d
= 100,
SDLK_e
= 101,
SDLK_f
= 102,
SDLK_g
= 103,
SDLK_h
= 104,
SDLK_i
= 105,
SDLK_j
= 106,
SDLK_k
= 107,
SDLK_l
= 108,
SDLK_m
= 109,
SDLK_n
= 110,
SDLK_o
= 111,
SDLK_p
= 112,
SDLK_q
= 113,
SDLK_r
= 114,
SDLK_s
= 115,
SDLK_t
= 116,
SDLK_u
= 117,
SDLK_v
= 118,
SDLK_w
= 119,
SDLK_x
= 120,
SDLK_y
= 121,

SDLK_z
= 122,
SDLK_DELETE
= 127,
/* End of ASCII mapped keysyms */
/* International keyboard syms */
SDLK_WORLD_0
= 160,
/* 0xA0 */
SDLK_WORLD_1
= 161,
SDLK_WORLD_2
= 162,
SDLK_WORLD_3
= 163,
SDLK_WORLD_4
= 164,
SDLK_WORLD_5
= 165,
SDLK_WORLD_6
= 166,
SDLK_WORLD_7
= 167,
SDLK_WORLD_8
= 168,
SDLK_WORLD_9
= 169,
SDLK_WORLD_10
= 170,
SDLK_WORLD_11
= 171,
SDLK_WORLD_12
= 172,
SDLK_WORLD_13
= 173,
SDLK_WORLD_14
= 174,
SDLK_WORLD_15
= 175,
SDLK_WORLD_16
= 176,
SDLK_WORLD_17
= 177,
SDLK_WORLD_18
= 178,
SDLK_WORLD_19
= 179,
SDLK_WORLD_20
= 180,
SDLK_WORLD_21
= 181,
SDLK_WORLD_22
= 182,
SDLK_WORLD_23
= 183,
SDLK_WORLD_24
= 184,
SDLK_WORLD_25
= 185,
SDLK_WORLD_26
= 186,
SDLK_WORLD_27
= 187,
SDLK_WORLD_28
= 188,
SDLK_WORLD_29
= 189,
SDLK_WORLD_30
= 190,
SDLK_WORLD_31
= 191,
SDLK_WORLD_32
= 192,
SDLK_WORLD_33
= 193,
SDLK_WORLD_34
= 194,
SDLK_WORLD_35
= 195,
SDLK_WORLD_36
= 196,
SDLK_WORLD_37
= 197,
SDLK_WORLD_38
= 198,
SDLK_WORLD_39
= 199,
SDLK_WORLD_40
= 200,
SDLK_WORLD_41
= 201,

SDLK_WORLD_42
SDLK_WORLD_43
SDLK_WORLD_44
SDLK_WORLD_45
SDLK_WORLD_46
SDLK_WORLD_47
SDLK_WORLD_48
SDLK_WORLD_49
SDLK_WORLD_50
SDLK_WORLD_51
SDLK_WORLD_52
SDLK_WORLD_53
SDLK_WORLD_54
SDLK_WORLD_55
SDLK_WORLD_56
SDLK_WORLD_57
SDLK_WORLD_58
SDLK_WORLD_59
SDLK_WORLD_60
SDLK_WORLD_61
SDLK_WORLD_62
SDLK_WORLD_63
SDLK_WORLD_64
SDLK_WORLD_65
SDLK_WORLD_66
SDLK_WORLD_67
SDLK_WORLD_68
SDLK_WORLD_69
SDLK_WORLD_70
SDLK_WORLD_71
SDLK_WORLD_72
SDLK_WORLD_73
SDLK_WORLD_74
SDLK_WORLD_75
SDLK_WORLD_76
SDLK_WORLD_77
SDLK_WORLD_78
SDLK_WORLD_79
SDLK_WORLD_80
SDLK_WORLD_81
SDLK_WORLD_82
SDLK_WORLD_83
SDLK_WORLD_84
SDLK_WORLD_85
SDLK_WORLD_86
SDLK_WORLD_87
SDLK_WORLD_88

= 202,
= 203,
= 204,
= 205,
= 206,
= 207,
= 208,
= 209,
= 210,
= 211,
= 212,
= 213,
= 214,
= 215,
= 216,
= 217,
= 218,
= 219,
= 220,
= 221,
= 222,
= 223,
= 224,
= 225,
= 226,
= 227,
= 228,
= 229,
= 230,
= 231,
= 232,
= 233,
= 234,
= 235,
= 236,
= 237,
= 238,
= 239,
= 240,
= 241,
= 242,
= 243,
= 244,
= 245,
= 246,
= 247,
= 248,

SDLK_WORLD_89
SDLK_WORLD_90
SDLK_WORLD_91
SDLK_WORLD_92
SDLK_WORLD_93
SDLK_WORLD_94
SDLK_WORLD_95

= 249,
= 250,
= 251,
= 252,
= 253,
= 254,
= 255,

/* Numeric keypad */
SDLK_KP0
= 256,
SDLK_KP1
= 257,
SDLK_KP2
= 258,
SDLK_KP3
= 259,
SDLK_KP4
= 260,
SDLK_KP5
= 261,
SDLK_KP6
= 262,
SDLK_KP7
= 263,
SDLK_KP8
= 264,
SDLK_KP9
= 265,
SDLK_KP_PERIOD
= 266,
SDLK_KP_DIVIDE
= 267,
SDLK_KP_MULTIPLY = 268,
SDLK_KP_MINUS
= 269,
SDLK_KP_PLUS
= 270,
SDLK_KP_ENTER
= 271,
SDLK_KP_EQUALS
= 272,
/* Arrows + Home/End pad */
SDLK_UP
= 273,
SDLK_DOWN
= 274,
SDLK_RIGHT
= 275,
SDLK_LEFT
= 276,
SDLK_INSERT
= 277,
SDLK_HOME
= 278,
SDLK_END
= 279,
SDLK_PAGEUP
= 280,
SDLK_PAGEDOWN
= 281,
/* Function keys */
SDLK_F1
SDLK_F2
SDLK_F3
SDLK_F4
SDLK_F5
SDLK_F6
SDLK_F7
SDLK_F8

= 282,
= 283,
= 284,
= 285,
= 286,
= 287,
= 288,
= 289,

/* 0xFF */

SDLK_F9
SDLK_F10
SDLK_F11
SDLK_F12
SDLK_F13
SDLK_F14
SDLK_F15

= 290,
= 291,
= 292,
= 293,
= 294,
= 295,
= 296,

/* Key state modifier keys */


SDLK_NUMLOCK
= 300,
SDLK_CAPSLOCK
= 301,
SDLK_SCROLLOCK
= 302,
SDLK_RSHIFT
= 303,
SDLK_LSHIFT
= 304,
SDLK_RCTRL
= 305,
SDLK_LCTRL
= 306,
SDLK_RALT
= 307,
SDLK_LALT
= 308,
SDLK_RMETA
= 309,
SDLK_LMETA
= 310,
SDLK_LSUPER
= 311,
/* Left "Windows" key */
SDLK_RSUPER
= 312,
/* Right "Windows" key */
SDLK_MODE
= 313,
/* "Alt Gr" key */
SDLK_COMPOSE
= 314,
/* Multi-key compose key */
/* Miscellaneous function keys */
SDLK_HELP
= 315,
SDLK_PRINT
= 316,
SDLK_SYSREQ
= 317,
SDLK_BREAK
= 318,
SDLK_MENU
= 319,
SDLK_POWER
= 320,
SDLK_EURO
= 321,
SDLK_UNDO
= 322,

/* Power Macintosh power key */


/* Some european keyboards */
/* Atari keyboard has Undo */

EVENTI MOUSE
#define SDL_BUTTON(X)
(SDL_PRESSED << ((X)-1))
#define SDL_BUTTON_LEFT
1
#define SDL_BUTTON_MIDDLE
2
#define SDL_BUTTON_RIGHT 3
#define SDL_BUTTON_WHEELUP 4
#define SDL_BUTTON_WHEELDOWN
5
#define SDL_BUTTON_LMASK
SDL_BUTTON(SDL_BUTTON_LEFT)
#define SDL_BUTTON_MMASK
SDL_BUTTON(SDL_BUTTON_MIDDLE)
#define SDL_BUTTON_RMASK
SDL_BUTTON(SDL_BUTTON_RIGHT)

Appendice2 funzioni di blitting personalizzate


Le seguenti sono due funzioni fondamentali in SDL_BlitSurface_transparent; il loro
sorgente in SDL_Example3.
La fonte http://docs.huihoo.com/sdl/1.2/guidevideo.html - SDL Library Documentation
Uint32 getpixel(SDL_Surface *surface, int x, int y) ;
/*
* Imposta il pixel di coordinate (x, y)
* ATTENZIONE: la superficie deve essere bloccata prima di eseguire questa funzione
*/
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) ;
Utilizzando getpixel e putpixel ho scritto SDL_BlitSurface_transparent, una funzione
che mi era necessaria per la realizzazione di un motore di rendering che mi permettesse di
disegnare immagini utilizzando la trasparenza. Per farlo stato sufficiente disegnare
limmagine tralasciando i pixel di colore uguale a quello di (x, y)==(0, 0).
Oltre a questo la funzione permette di gestire altri aspetti, come il flip dellimmagine,
la rotazione, la scala.
int SDL_BlitSurface_transparent(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
SDL_Rect *dstrect, int ang_rotaz, int flip, int decentramento_y, int scala, int dec_scala, int
fantasma)
/*
*src -> source - sorgente
*srcrect -> parte(rettangolo) della sorgente da copiare
*dst -> destinazione
*dstrect -> dove copio nella superficie di dst
ang_rotaz -> 0 - 360 rotazione immagine *** DA IMPLEMENTARE ***
flip
-> 0 none
1 specchio orizzontalmente
2 specchio verticalmente
scala -> 1 normale
-2 met
2 doppio
decimale -> come inserire 3.1: scala.decimale
concretamente disegno ogni volta che l'accumulo dei decimali mi d 1
..
fantasma -> 0 normale
1 fantasma (immagine "tirata su")
2 + immagine sempre pi tirata verso l'alto
*/
{
// SDL_Surface sono gi sbloccate

int i,j,decimale=0,aggiunta;
int xs, ys, xd, yd, ystmp, ydtmp;
int condizione_x, condizione_y;
Uint32 color, trpcolor;
trpcolor=getpixel(src, 0, 0);
if ( (srcrect==NULL) && (dstrect==NULL) )
{
xs=0;
ystmp=0;
xd=0;
ydtmp=0+decentramento_y;
condizione_x=src->w;
condizione_y=src->h;
if (flip==1) // flip orizzontale
xd+=src->w;
}
else
if (srcrect==NULL)
{
xs=0;
ystmp=0;
xd=dstrect->x;
ydtmp=dstrect->y+decentramento_y;
condizione_x=src->w;
condizione_y=src->h;
if (flip==1) // flip orizzontale
xd+=src->w;
}
else
if (dstrect==NULL)
{
xs=srcrect->x;
ystmp=srcrect->y;
xd=0;
ydtmp=0+decentramento_y;
condizione_x=(srcrect->w + srcrect->x);
condizione_y=(srcrect->h + srcrect->y);
if (flip==1) // flip orizzontale
xd+=srcrect->w;
}
else
{

xs=srcrect->x;
ystmp=srcrect->y;
xd=dstrect->x;
ydtmp=dstrect->y+decentramento_y;
condizione_x=(srcrect->w + srcrect->x);
condizione_y=(srcrect->h + srcrect->y);
if (flip==1) // flip orizzontale
xd+=srcrect->w;
}

for (; xs<(condizione_x); xs++) // copio il pixel se all'interno della superficie e se !


= dal transparent color (lo intendo come il bit 0, 0 della sorgente)
{
if ( (xd>=0) && (xd<=dst->w) )
// disegno solo se all'interno della
superficie
for (ys=ystmp, yd=ydtmp; ys<(condizione_y); ys++,
yd+=scala+aggiunta)
{
if ( (yd>=0) && (yd<=dst->h) )
// disegno solo se all'interno
della superficie
{
/* Scala decimale */
decimale+=dec_scala; // per la scala decimale
if (decimale>=10){
decimale-=10;
aggiunta=1;
}
else
aggiunta=0;
color=getpixel(src, xs, ys);
if ((color!=trpcolor) && (color!=getpixel(dst,xd,yd)) ){
for (i=0; i<scala+aggiunta; i++) // scala
for (j=0; j<scala+aggiunta; j++) // scala
putpixel(dst, xd+i, yd+j, color); // per
l'effetto semi-trasparenza xd+1 xd-1
****************************************************
yd-=fantasma;
}
}
}
if (flip==1) xd-=scala;

else xd+=scala;
}
return 0;
}

Bibliografia
Using SDL with Microsoft Visual C++ 5,6 and 7 di Sam Lantinga, modificato da
Lion Kimbro and revisionato da James Turk;
SDL Library Documentation - http://docs.huihoo.com/sdl/1.2/guidevideo.html;
http://www.gameprog.it;
http://www.libsdl.org, sito ufficiale della libreria;
http://www.gnu.org/licenses/lgpl.html, citato relativamente alla licenza della libreria
SDL.

Potrebbero piacerti anche