Sei sulla pagina 1di 46

estando a integrao com o compilador

Vamos escrever um programa bem simples, apenas para testar se a SDL est instalada e
funcionando corretamente. Abra um editor de textos qualquer e digite o programa a seguir:
#include<SDL.h>//usaremosfuncoesdaSDL
#defineSCREEN_W640//tamanhodajanelaqueseracriada
#defineSCREEN_H480
intmain(intargc,char**argv)//funcaodeentrada
{
SDL_Surface*screen;//superficiequerepresentaateladocomputador
SDL_Eventevent;//umeventoenviadopelaSDL
intquit=0;//devemosencerraroprograma?
SDL_Init(SDL_INIT_VIDEO);//inicializaraSDL
screen=SDL_SetVideoMode(SCREEN_W,SCREEN_H,16,SDL_SWSURFACE);//criar
umajanela640x480x16bits
while(!quit)//rodarenquantonaoforparaencerrar:)
{
while(SDL_PollEvent(&event))//checareventos
{
if(event.type==SDL_QUIT)//fecharajanela?
{
quit=1;//sairdoloopprincipal
}
}
SDL_Flip(screen);//atualizaratela
}
SDL_Quit();//encerraraSDL
return0;
}

Para compilar este programa no Windows com MinGW, abra um prompt de comando, navegue at a
pasta onde o seu arquivo est salvo e digite o comando a seguir (substituindo "ex1" pelo nome do
seu arquivo):
gcc ex1.c -o ex1.exe -Wall -lmingw32 -lSDLmain -lSDL
Para compilar no GNU/Linux:
gcc ex1.c -o ex1 -Wall `sdl-config --cflags --libs`
Rode seu programa. Dever aparecer uma janela preta com o ttulo "SDL_app". O programa dever
encerrar-se quando o usurio clica no boto "fechar" na barra de ttulo da janela.
Observao: em programas compilados com SDL para Windows, a sada padro (o arquivo stdout, e

as funes printf, puts, putchar etc) so redirecionados para um arquivo chamado stdout.txt, criado
na mesma pasta do seu executvel. Note que este arquivo ser substitudo sem aviso cada vez que o
seu programa rodar. A entrada padro (arquivo stdin, e as funes scanf, gets, getchar etc) em geral
gera problemas e no deve ser utilizada. Raramente, porm, voc precisar destes ao escrever um
programa to complexo que utilize uma biblioteca grfica--provavelmente voc ir implementar
meios mais elegantes de entrada e sada (por exemplo, leitura de um arquivo de configurao, ou
leitura do teclado utilizando as funes da biblioteca, e sada grfica para a tela ou sada de texto
para um arquivo de log).
Descrio dos parmetros usados na compilao:
- gcc ex1.c -o ex1.exe : operao padro de compilao
- -Wall : mostrar todos os warnings (avisos)
- -lmingw32 -lSDLmain -lSDL : bibliotecas necessrias que sero "linkadas" ao seu programa
Utilize sempre este formato de comando para compilar seus programas feitos em SDL e MinGW. Se
eles possurem mais de um arquivo, adicione outros nomes aps "ex1.c" (ou o nome do seu arquivo
inicial).
O programa acima ser explicado em maiores detalhes na prxima seo.

Os tipos em SDL
A SDL define (typedef) alguns nomes de tipos diferentes para definir as variveis usadas em suas
estruturas e funes. Como estas definies esto no arquivo SDL.h, voc pode tambm utiliz-las
em seus programas, ou usar os tipos padro do C/C++, ou mesmo utilizar seus prprios, desde que
sejam equivalentes.
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef

signed char Sint8;


unsigned char Uint8;
signed short Sint16;
unsigned short Uint16;
signed int Sint32;
unsigned int Uint32;
signed long long Sint64;
unsigned long long Uint64;

Programa bsico em SDL


Vamos entender agora o que o programa escrito na seo anterior faz. Segue abaixo o cdigo:
#include <SDL.h> //usaremos funcoes da SDL
#define SCREEN_W 640 //tamanho da janela que sera criada
#define SCREEN_H 480
int main(int argc, char** argv) //funcao de entrada
{
SDL_Surface* screen; //superficie que representa a tela do
computador
SDL_Event event; //um evento enviado pela SDL
int quit = 0; //devemos encerrar o programa?
SDL_Init(SDL_INIT_VIDEO); //inicializar a SDL
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 16,
SDL_SWSURFACE); //criar uma janela 640x480x16bits
while(!quit) //rodar enquanto nao for para encerrar :)
{
while(SDL_PollEvent(&event)) //checar eventos
{
if(event.type == SDL_QUIT) //fechar a janela?
{
quit = 1; //sair do loop principal
}

}
SDL_Flip(screen); //atualizar a tela
}
SDL_Quit(); //encerrar a SDL
return 0;
}
Os comentrios explicam razoavelmente bem o intuito de cada linha, mas discutamo-nas com
mais detalhes.
#include <SDL.h>
Bem intuitivo. Devemos incluir o arquivo SDL.h porque usaremos funes da biblioteca SDL.
Assim como devemos incluir <math.h> se usarmos funes da biblioteca padro math, por
exemplo.
#define SCREEN_W 640
#define SCREEN_H 480
Definimos aqui, por comodidade, duas constantes que representam o tamanho da janela que iremos
criar mais tarde. Poderamos defini-las na chamada da funo SDL_SetVideoMode (como
fazemos com a profundidade de cores, veremos adiante), mas definindo-as como constantes torna o
cdigo mais legvel e organizado caso queiramos mudar estes valores mais tarde.
int main(int argc, char** argv)
Supomos que voc saiba o que faz essa linha. "main" o nome da funo de entrada de todo
programa escrito em C. "argc" e "argv" so os parmetros que ela recebe do sistema operacional,
e so utilizados para tratar opes de linha de comando. Em um programa normal possvel
declarar esta funo simplesmente como "int main(void)", mas necessrio usar a
declarao completa (com argc e argv) para que seu programa usando SDL compile
corretamente.
SDL_Surface* screen;
Aqui declaramos uma superfcie SDL (na verdade, um ponteiro para uma), que ser (mais tarde)
para ns a representao da tela do computador. Uma superfcie em SDL , a grosso modo,
um espao na memria onde so armazenados pixels (pontos na tela), como uma folha de papel
onde pode-se desenhar com lpis (de cor) e borracha. Uma metfora mais exata definiria isto
como uma folha de papel quadriculado onde pode-se apenas pintar cada quadrado com uma certa
cor (em termos matemticos, o espao discreto e no contnuo). Aprenderemos mais tarde
que possvel fazer vrias operaes com superfcies em SDL, sendo a principal delas
uma cpia ou blit. Por enquanto, lembre-se apenas que tudo que for desenhado em (ou copiado
para) esta superfcie ser apresentado na tela.
SDL_Event event;

Aqui declaramos um evento. Um evento em SDL uma estrutura que guarda dados sobre algum
acontecimento externo ao funcionamento do seu programa, geralmente por interveno do
usurio ou do sistema operacional. Por exemplo, um evento disparado quando o usurio
pressiona (ou solta) uma tecla no teclado, um boto no mouse, ou movimenta um eixo do joystick;
ou o sistema operacional pode mandar uma mensagem "quit" por algum motivo qualquer. O que
estamos declarando aqui uma estrutura vazia, que iremos preencher usando a funo
SDL_PollEvent (veja mais abaixo) com cada evento enviado ao nosso programa (na verdade, os
que nos interessa tratar) para que ento possamos ler os dados do evento e agir de acordo (ou no
fazer nada, se for o caso).
int quit = 0;
Nada muito obscuro aqui. Declaramos uma varivel para funcionar como um indicador de se
devemos continuar executando nosso programa, ou devemos encerr-lo. Utilizar uma varivel
para controlar o estado do programa (simplesmente rodar, parar neste caso) uma abordagem
bastante robusta e flexvel, principalmente quando seu projeto comear a crescer.
SDL_Init(SDL_INIT_VIDEO);
Aqui inicializamos a SDL. Esta funo deve ser chamada antes de qualquer outra funo na
SDL, ou problemas surgiro. Ela toma como parmetro uma combinao binria OU
(usando o smbolo '|') de quais sub-sistemas devemos inicializar. Como no nosso caso iremos
apenas usar o vdeo, passamos (SDL_INIT_VIDEO) como parmetro. Se, por exemplo,
fssemos tratar entradas de um joystick, o parmetro a ser passado seria (SDL_INIT_VIDEO|
SDL_INIT_JOYSTICK).
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 16, SDL_SWSURFACE);
Aqui chamamos a funo SDL_SetVideoMode para criar a janela do programa. Ela toma como
parmetros (nesta ordem) a largura da janela (ou da tela em modo fullscreen), a altura, a
profundidade de cores e um conjunto (binrio OU) de flags opcionais que controlam alguns
aspectos relativos ao modo de vdeo. A flag passada aqui (SDL_SWSURFACE) indica que
queremos criar a superfcie principal de vdeo (para todos os efeitos, a "tela") em memria
RAM comum (no de vdeo). Poderamos tambm, por exemplo, passar
SDL_FULLSCREEN para conseguir uma tela cheia; neste caso o ltimo parmetro seria
(SDL_SWSURFACE|SDL_FULLSCREEN). A funo SDL_SetVideoMode retorna um ponteiro
para a superfcie que representa a tela--a qual ns armazenamos na superfcie "screen",
declarada no topo da funo main. Note que seria possvel tambm ignorar o valor de retorno
completamente e conseguir um ponteiro para a superfcie da tela a qualquer momento com a
funo SDL_GetVideoSurface. Novamente, no se prenda a estes detalhes por agora--todo o
subsistema de vdeo ser explicado em detalhes, incluindo esta funo.
while(!quit)
Definimos aqui o loop principal do programa. A maioria dos programas com algum tipo de
interao com o usurio conta com um loop deste tipo, para manter o programa rodando at
que algum acontecimento externo (direta ou indiretamente) indique uma parada. Sem um loop,
obviamente, o programa seguiria um fluxo sequencial e simplesmente se encerraria assim que

terminasse a inicializao--de modo que a estrutura deste tipo de programa dependente de


interao funciona da seguinte maneira: inicializao-loop principal-encerramento. No nosso
caso, usamos uma varivel de controle chamada "quit" para indicar quando devemos sair do loop
principal e encerrar o programa--a qualquer momento dentro do loop principal, se a varivel "quit"
receber o valor "1" (na verdade, qualquer valor no-zero) o loop ser encerrado ao fim da
iterao atual. Ou seja, o cdigo dentro do loop ainda ser executado at o fim para a
iterao corrente. Para o caso, como este, de um nico loop que no chama funes
externas, voc poderia interromper o loop a qualquer momento e pular direto para o cdigo
aps este (ou seja, no executar o restante da iterao atual) usando a palavra-chave break.
while(SDL_PollEvent(&event))
Nesta linha, chamamos a funo SDL_PollEvent para preencher a estrutura event, definida
anteriormente, com cada um dos eventos esperando para serem processados (ou seja, todos os que
foram gerados desde a ltima iterao do loop principal). Passamos a estrutura com &, ou seja,
seu endereo, para que a funo possa modificar seus valores (a rigor, SDL_PollEvent toma
como parmetro um ponteiro para SDL_Event, ento devemos passar o endereo). Se no
houver mais nenhum evento na fila, SDL_PollEvent retorna zero e samos do loop de
processamento de eventos. Tudo isso ficar claro mais para a frente, quando discutirmos eventos.
if(event.type == SDL_QUIT)
Verificamos se o tipo de evento SDL_QUIT, ou seja, um evento de encerramento enviado pelo
sistema operacional... (sendo que, em nosso caso, o objetivo capturar um clique no boto
"fechar" da janela, o qual faz com que o SO gere este evento para ns)
quit = 1;
...e se for, atribumos o valor 1 varivel quit para que nosso programa se encerre. Sem este
tratamento, no seria possvel encerrarmos nosso programa a no ser executando um
encerramento forado pelo sistema operacional (Gerenciador de Tarefas no Windows). Alm
disso, sem tratamento de eventos, qualquer tentativa de gerar entrada (movimentos/cliques do
mouse, teclas do teclado, mover a janela) causaria um estouro de memria na fila de eventos da
SDL (j que no os estamos retirando com SDL_PollEvent) e consequentemente um travamento
iminente. Por isso lembre-se sempre de tratar eventos em seu programa, se quiser que ele sobreviva
por mais de 5 segundos!
SDL_Flip(screen);
O que esta linha faz atualizar a tela. Ou seja, efetivamente copia o contedo da superfcie da
tela (aqui apontada pela varivel screen) para a tela fsica do computador. Em outras palavras,
qualquer operao na superfcie da tela no ficar visvel no monitor at que haja esta
chamada. Como objetivamos um programa multimdia (como um jogo), que na maior parte do
tempo ter mudanas visuais todo o tempo, atualizaremos a tela a cada iterao do loop
principal--ou seja, a cada quadro. Perceba que, desta forma, a taxa de iteraes do loop principal
de fato a taxa de quadros por segundo (Frames Per Second - FPS) do seu programa, j que a
tela atualizada a cada iterao. possvel tambm no atualizar a tela em toda
iterao, talvez apenas a cada 2 ou 3, para ganhar velocidade ou com qualquer outro objetivo,

entretanto o mais comum atualizar em toda iterao.


SDL_Quit();
J fora do loop principal, devemos chamar SDL_Quit para deinicializar a SDL...
return 0; ao Sistema Operacional que tudo correu bem.

Programa bsico em SDL


Vamos entender agora o que o programa escrito na seo anterior faz. Segue abaixo o cdigo:
#include <SDL.h> //usaremos funcoes da SDL
#define SCREEN_W 640 //tamanho da janela que sera criada
#define SCREEN_H 480
int main(int argc, char** argv) //funcao de entrada
{
SDL_Surface* screen; //superficie que representa a tela do
computador
SDL_Event event; //um evento enviado pela SDL
int quit = 0; //devemos encerrar o programa?
SDL_Init(SDL_INIT_VIDEO); //inicializar a SDL
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 16,
SDL_SWSURFACE); //criar uma janela 640x480x16bits
while(!quit) //rodar enquanto nao for para encerrar :)
{
while(SDL_PollEvent(&event)) //checar eventos
{
if(event.type == SDL_QUIT) //fechar a janela?
{
quit = 1; //sair do loop principal
}
}
SDL_Flip(screen); //atualizar a tela
}
SDL_Quit(); //encerrar a SDL

return 0;
}
Os comentrios explicam razoavelmente bem o intuito de cada linha, mas discutamo-nas com
mais detalhes.
#include <SDL.h>
Bem intuitivo. Devemos incluir o arquivo SDL.h porque usaremos funes da biblioteca SDL.
Assim como devemos incluir <math.h> se usarmos funes da biblioteca padro math, por
exemplo.
#define SCREEN_W 640
#define SCREEN_H 480
Definimos aqui, por comodidade, duas constantes que representam o tamanho da janela que iremos
criar mais tarde. Poderamos defini-las na chamada da funo SDL_SetVideoMode (como
fazemos com a profundidade de cores, veremos adiante), mas definindo-as como constantes torna o
cdigo mais legvel e organizado caso queiramos mudar estes valores mais tarde.
int main(int argc, char** argv)
Supomos que voc saiba o que faz essa linha. "main" o nome da funo de entrada de todo
programa escrito em C. "argc" e "argv" so os parmetros que ela recebe do sistema operacional,
e so utilizados para tratar opes de linha de comando. Em um programa normal possvel
declarar esta funo simplesmente como "int main(void)", mas necessrio usar a
declarao completa (com argc e argv) para que seu programa usando SDL compile
corretamente.
SDL_Surface* screen;
Aqui declaramos uma superfcie SDL (na verdade, um ponteiro para uma), que ser (mais tarde)
para ns a representao da tela do computador. Uma superfcie em SDL , a grosso modo,
um espao na memria onde so armazenados pixels (pontos na tela), como uma folha de papel
onde pode-se desenhar com lpis (de cor) e borracha. Uma metfora mais exata definiria isto
como uma folha de papel quadriculado onde pode-se apenas pintar cada quadrado com uma certa
cor (em termos matemticos, o espao discreto e no contnuo). Aprenderemos mais tarde
que possvel fazer vrias operaes com superfcies em SDL, sendo a principal delas
uma cpia ou blit. Por enquanto, lembre-se apenas que tudo que for desenhado em (ou copiado
para) esta superfcie ser apresentado na tela.
SDL_Event event;
Aqui declaramos um evento. Um evento em SDL uma estrutura que guarda dados sobre algum
acontecimento externo ao funcionamento do seu programa, geralmente por interveno do
usurio ou do sistema operacional. Por exemplo, um evento disparado quando o usurio
pressiona (ou solta) uma tecla no teclado, um boto no mouse, ou movimenta um eixo do joystick;
ou o sistema operacional pode mandar uma mensagem "quit" por algum motivo qualquer. O que
estamos declarando aqui uma estrutura vazia, que iremos preencher usando a funo
SDL_PollEvent (veja mais abaixo) com cada evento enviado ao nosso programa (na verdade, os

que nos interessa tratar) para que ento possamos ler os dados do evento e agir de acordo (ou no
fazer nada, se for o caso).
int quit = 0;
Nada muito obscuro aqui. Declaramos uma varivel para funcionar como um indicador de se
devemos continuar executando nosso programa, ou devemos encerr-lo. Utilizar uma varivel
para controlar o estado do programa (simplesmente rodar, parar neste caso) uma abordagem
bastante robusta e flexvel, principalmente quando seu projeto comear a crescer.
SDL_Init(SDL_INIT_VIDEO);
Aqui inicializamos a SDL. Esta funo deve ser chamada antes de qualquer outra funo na
SDL, ou problemas surgiro. Ela toma como parmetro uma combinao binria OU
(usando o smbolo '|') de quais sub-sistemas devemos inicializar. Como no nosso caso iremos
apenas usar o vdeo, passamos (SDL_INIT_VIDEO) como parmetro. Se, por exemplo,
fssemos tratar entradas de um joystick, o parmetro a ser passado seria (SDL_INIT_VIDEO|
SDL_INIT_JOYSTICK).
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 16, SDL_SWSURFACE);
Aqui chamamos a funo SDL_SetVideoMode para criar a janela do programa. Ela toma como
parmetros (nesta ordem) a largura da janela (ou da tela em modo fullscreen), a altura, a
profundidade de cores e um conjunto (binrio OU) de flags opcionais que controlam alguns
aspectos relativos ao modo de vdeo. A flag passada aqui (SDL_SWSURFACE) indica que
queremos criar a superfcie principal de vdeo (para todos os efeitos, a "tela") em memria
RAM comum (no de vdeo). Poderamos tambm, por exemplo, passar
SDL_FULLSCREEN para conseguir uma tela cheia; neste caso o ltimo parmetro seria
(SDL_SWSURFACE|SDL_FULLSCREEN). A funo SDL_SetVideoMode retorna um ponteiro
para a superfcie que representa a tela--a qual ns armazenamos na superfcie "screen",
declarada no topo da funo main. Note que seria possvel tambm ignorar o valor de retorno
completamente e conseguir um ponteiro para a superfcie da tela a qualquer momento com a
funo SDL_GetVideoSurface. Novamente, no se prenda a estes detalhes por agora--todo o
subsistema de vdeo ser explicado em detalhes, incluindo esta funo.
while(!quit)
Definimos aqui o loop principal do programa. A maioria dos programas com algum tipo de
interao com o usurio conta com um loop deste tipo, para manter o programa rodando at
que algum acontecimento externo (direta ou indiretamente) indique uma parada. Sem um loop,
obviamente, o programa seguiria um fluxo sequencial e simplesmente se encerraria assim que
terminasse a inicializao--de modo que a estrutura deste tipo de programa dependente de
interao funciona da seguinte maneira: inicializao-loop principal-encerramento. No nosso
caso, usamos uma varivel de controle chamada "quit" para indicar quando devemos sair do loop
principal e encerrar o programa--a qualquer momento dentro do loop principal, se a varivel "quit"
receber o valor "1" (na verdade, qualquer valor no-zero) o loop ser encerrado ao fim da
iterao atual. Ou seja, o cdigo dentro do loop ainda ser executado at o fim para a
iterao corrente. Para o caso, como este, de um nico loop que no chama funes

externas, voc poderia interromper o loop a qualquer momento e pular direto para o cdigo
aps este (ou seja, no executar o restante da iterao atual) usando a palavra-chave break.
while(SDL_PollEvent(&event))
Nesta linha, chamamos a funo SDL_PollEvent para preencher a estrutura event, definida
anteriormente, com cada um dos eventos esperando para serem processados (ou seja, todos os que
foram gerados desde a ltima iterao do loop principal). Passamos a estrutura com &, ou seja,
seu endereo, para que a funo possa modificar seus valores (a rigor, SDL_PollEvent toma
como parmetro um ponteiro para SDL_Event, ento devemos passar o endereo). Se no
houver mais nenhum evento na fila, SDL_PollEvent retorna zero e samos do loop de
processamento de eventos. Tudo isso ficar claro mais para a frente, quando discutirmos eventos.
if(event.type == SDL_QUIT)
Verificamos se o tipo de evento SDL_QUIT, ou seja, um evento de encerramento enviado pelo
sistema operacional... (sendo que, em nosso caso, o objetivo capturar um clique no boto
"fechar" da janela, o qual faz com que o SO gere este evento para ns)
quit = 1;
...e se for, atribumos o valor 1 varivel quit para que nosso programa se encerre. Sem este
tratamento, no seria possvel encerrarmos nosso programa a no ser executando um
encerramento forado pelo sistema operacional (Gerenciador de Tarefas no Windows). Alm
disso, sem tratamento de eventos, qualquer tentativa de gerar entrada (movimentos/cliques do
mouse, teclas do teclado, mover a janela) causaria um estouro de memria na fila de eventos da
SDL (j que no os estamos retirando com SDL_PollEvent) e consequentemente um travamento
iminente. Por isso lembre-se sempre de tratar eventos em seu programa, se quiser que ele sobreviva
por mais de 5 segundos!
SDL_Flip(screen);
O que esta linha faz atualizar a tela. Ou seja, efetivamente copia o contedo da superfcie da
tela (aqui apontada pela varivel screen) para a tela fsica do computador. Em outras palavras,
qualquer operao na superfcie da tela no ficar visvel no monitor at que haja esta
chamada. Como objetivamos um programa multimdia (como um jogo), que na maior parte do
tempo ter mudanas visuais todo o tempo, atualizaremos a tela a cada iterao do loop
principal--ou seja, a cada quadro. Perceba que, desta forma, a taxa de iteraes do loop principal
de fato a taxa de quadros por segundo (Frames Per Second - FPS) do seu programa, j que a
tela atualizada a cada iterao. possvel tambm no atualizar a tela em toda
iterao, talvez apenas a cada 2 ou 3, para ganhar velocidade ou com qualquer outro objetivo,
entretanto o mais comum atualizar em toda iterao.
SDL_Quit();
J fora do loop principal, devemos chamar SDL_Quit para deinicializar a SDL...
return 0;
...e avisar ao Sistema Operacional que tudo correu bem.

Funes gerais e tratamento de janelas


Inicializao e deinicializao
int SDL_Init(Uint32 flags);
int SDL_InitSubSystem(Uint32 flags);
void SDL_QuitSubSystem(Uint32 flags);
void SDL_Quit(void);
Uint32 SDL_WasInit(Uint32 flags);
A funo SDL_Init inicializa a SDL e deve ser chamada antes de qualquer outra funo. Ela
toma como parmetro uma combinao em forma de ou-binrio dos subsistemas que voc
deseja inicializar:
- SDL_INIT_VIDEO: Inicializa o vdeo. Em geral voc vai querer passar este valor, a menos
que no queira nenhum tipo de sada visual :)
- SDL_INIT_AUDIO: Inicializa o udio. Passe este valor se voc pretende usar a SDL para
sada de som.
- SDL_INIT_JOYSTICK: Inizializa os joysticks. Passe este valor se pretender utilizar entrada de
joysticks.
- SDL_INIT_CDROM: Inicializa o sistema de CD-Audio. Passe este valor se quiser usar a SDL
para tocar trilhas de um CD-udio.
- SDL_INIT_TIMER: Inicializa os timers (temporizadores). Passe este valor se desejar usar o
sistema de contadores de tempo da SDL. Note que as funes SDL_GetTicks e SDL_Delay no
necessitam que o subsistema de timers seja inicializado.
- SDL_INIT_EVERYTHING: Inicializa todos os anteriores.
- SDL_INIT_NOPARACHUTE, SDL_INIT_EVENTTHREAD: Parmetros avanados que
devem ser deixados de lado na maioria dos casos. Consulte a documentao oficial se desejar
saber mais sobre eles.
Observe que todos os subsistemas sero discutidos com detalhes nas prximas sees, ento
no se preocupe muito em entend-los agora. Note tambm que voc pode inicializar, em
separado e a qualquer momento, quaisquer dos subsistemas, aps ter chamado SDL_Init, com a
funo SDL_InitSubSystem, que toma parmetros da mesma forma que SDL_Init.
A funo SDL_Quit deinicializa todos os sistemas em atividade da SDL e deve ser chamada
antes do final do seu programa. J a funo SDL_QuitSubSystem deinicializa uma
combinao (ou-binrio) de subsistemas, determinada pelo parmetro passado. Por exemplo,
SDL_QuitSubSystem(SDL_INIT_AUDIO|SDL_INIT_JOYSTICK);
ir desligar os subsistemas de udio e joystick. A funo SDL_WasInit checa se certos
subsistemas (passados como uma conbinao de ou-binrio) esto inicializados ou no,
retornando um ou-binrio dos sistemas que j foram ativados.

Tratamento de erros
char *SDL_GetError(void);
A funo SDL_GetError retorna um ponteiro para um string contendo uma mensagem de erro
correspondente ao erro mais recente ocorrido dentro da biblioteca. Exemplo:
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==1)
{
puts(SDL_GetError());
return1;
}

Tratamento de janelas
void SDL_WM_GetCaption(char **title, char **icon);
void SDL_WM_SetCaption(const char *title, const char *icon);
int SDL_WM_IconifyWindow(void);
int SDL_WM_ToggleFullScreen(SDL_Surface *surface);
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode);
Utilize a funo SDL_WM_SetCaption para atribuir um ttulo janela (parmetro title) e/ou
ao boto da barra de tarefas (parmetro icon). Analogamente, passe ponteiros para strings
funo SDL_WM_GetCaption para obeter os ttulos atuais. Exemplo:
char janela[32], botao[32];
SDL_WM_GetCaption(&janela, &botao);
/* ... */
SDL_WM_SetCaption("Meu Jogo", "Jogo"); /* ttulo da janela: "Meu
Jogo" e do boto: "Jogo" */
A funo SDL_WM_IconifyWindow, ao ser chamada, minimiza a janela do seu programa. A
funo SDL_WM_ToggleFullScreen (que funciona apenas em sistemas com janelas X11) troca
entre os modos de janela/tela cheia e vice-versa. Utilize a funo SDL_WM_GrabInput para
"prender" os dispositivos de entrada sua janela, ou seja, o cursor do mouse no consegue sair
da rea da janela, e praticamente toda a entrada do teclado passada diretamente ao seu
programa (sem passar pelo gerenciador de janelas do sistema). Passe SDL_GRAB_ON para
capturar, SDL_GRAB_OFF para "liberar" e SDL_GRAB_QUERY para retornar o estado atual.

/*

SDL
*/

Arquivo: ex_inicia.c
Autor: Bruno Bottino
Data: 10/09/2007
Descrio: Exemplifica o uso das funes de inicializao e janelas com
Observaes: O ttulo da barra de tarefas no funciona em Windows

#include <SDL.h>
int main(int argc, char** argv)

int running = 1; //variavel para controlar se o loop principal deve


continuar
SDL_Surface* screen;
SDL_Event event;
if(SDL_Init(SDL_INIT_VIDEO) == -1)
{
printf("Erro ao inicializar a SDL: %s\n", SDL_GetError());
//observe que, no Windows, isto redirecionado para stdout.txt
return 1;
}
if((screen = SDL_SetVideoMode(640, 480, 16, SDL_DOUBLEBUF)) == NULL)
{
printf("Erro ao inicializar o vdeo: %s\n", SDL_GetError());
return 1;
}
SDL_WM_SetCaption("Meu Programa Legal v1.0 - Pressione Espaco para
prender/soltar o mouse e Esc para sair", "MeuProg");
while(running)
{
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
running = 0;
}
else if(event.type == SDL_KEYDOWN)
{
if(event.key.keysym.sym == SDLK_SPACE)
{
SDL_WM_GrabInput(!
SDL_WM_GrabInput(SDL_GRAB_QUERY));
}
else if(event.key.keysym.sym == SDLK_ESCAPE)
{
running = 0;
}
}
}
}
SDL_Quit();
return 0;
}

O subsistema de vdeo
Definies bsicas
Um rect (retngulo) em SDL uma estrutura que representa um retngulo com largura, altura e
coordenadas de posio x e y. Geralmente utilizado para representar uma rea retangular em
uma superfcie (veja mais sobre superfcies adiante).

typedef struct{
Sint16 x, y; /* posicao (note que tem sinal) */
Uint16 w, h; /* largura e altura (width, height) */
} SDL_Rect;
Uma superfcie em SDL uma estrutura que representa uma rea de memria onde
possvel fazer operaes grficas. A superfcie primordial representa a tela, mas outras
superfcies podem ser criadas em tempo de execuo para armazenar dados grficos
temporariamente (por exemplo, para guardar uma imagem carregada de um arquivo). A cada
quadro, so feitas operaes sobre a superfcie de vdeo, principalmente de cpia de outras
superfcies para esta, para obter o resultado visual desejado. Todas as superfcies em SDL so
tratadas como ponteiros, de modo que a SDL cuida da alocao, de-alocao e
armazenamento em baixo nvel.
typedef struct SDL_Surface {
Uint32 flags;
/* flags (parametros) usados na
criacao da superficie (somente leitura) */
SDL_PixelFormat *format; /* formato dos pixels nesta
superficie (explicado adiante - somente leitura) */
int w, h;
/* largura e altura (somente leitura)
*/
Uint16 pitch;
/* quantidade de bytes por linha
(somente leitura) */
void *pixels;
/* dados brutos dos pixels (leitura e
escrita) */
SDL_Rect clip_rect;
leitura) */
} SDL_Surface;

/* retangulo de 'clipping' (somente

H tambm outros campos que so usados internamente pela SDL para lidar com superfcies,
e no nos interessam agora. Alguma explicao sobre os campos acima:
- O campo flags armazena os flags (parmetros) passados na criao da superfcie--no caso
desta ser a tela, os parmetros so os mesmos que foram passados para a funo
SDL_SetVideoMode. Veremos adiante como criar outras superfcies.
- O campo format armazena o formato dos pixels armazenados nesta superfcie. Um pixel ,
basicamente, uma cor, mas h diversas maneiras de se representar uma cor--8 bits (com palheta),
16 ou 32 bits ("true color"), e, ainda, a distribuio das componentes R, G e B nos modos de 16 e
32 bits. Veremos adiante uma explicao dos diferentes formatos e da estrutura
SDL_PixelFormat.
- Os campos w e h representam, respectivamente, a largura e a altura da superfcie em questo.
- O campo pitch indica o tamanho real, em bytes, de uma linha como esta armazenada na
memria. Observe que este valor nem sempre igual a um mltiplo da largura (w) da
superfcie. Por exemplo, voc poderia ter uma superfcie de largura 500, mas por qualquer
motivo, o hardware de vdeo s permite superfcies com largura igual a uma potncia de dois.

Neste caso, a SDL alocaria uma superfcie de 512 pixels de largura, apesar de usar o valor 500
para todos os efeitos prticos. Voc deve utilizar este valor para calcular a posio de um pixel
ao acessar a memria de vdeo diretamente (e no o campo w).
- O campo pixels um ponteiro real e efetivo para os dados dos pixels da imagem. Utilizando este
ponteiro, possvel modificar diretamente a imagem no nvel dos pixels. Observe que este
um ponteiro para void, e, como tal, voc deve fazer um type-cast para o tipo apropriado de
ponteiro antes de acessar um valor. Por exemplo, se a profundidade de cores da superfcie for de
8bits, voc deve fazer um type-cast para (unsigned char*), que um ponteiro de 8 bits. Em
geral, voc converter este ponteiro para um ponteiro para varivel sem sinal, j que os
valores representam cores e no faz muito sentido representar cores com valores negativos.
Veremos adiante com mais detalhes como acessar diretamente os pixels de uma superfcie.
- O campo clip_rect um retngulo do tipo SDL_Rect que define a rea de clipping da
superfcie. Isto funciona como uma mscara--quando um blit (cpia) for realizado com destino
nesta superfcie, s ser desenhado na rea contida no retngulo.
Uma color (cor) em SDL uma estrutura que representa (obviamente) uma cor, em formato RGB
(Red, Green, Blue - vermelho, verde, azul) nesta ordem. Cada valor de R, G e B varia de 0 a 255
(Uint8 ou unsigned char).
typedef struct{
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 unused;
} SDL_Color;

/*
/*
/*
/*

componente vermelha */
componente verde */
componente azul */
campo reservado (ignore-o) */

Um palette (palheta) em SDL uma estrutura que representa uma palheta, ou conjunto, de cores.
Tipicamente usada para representar as cores em um modo grfico de 8-bits; neste caso, esto
disponveis 256 cores diferentes em um dado momento--cujos valores so armazenados em uma
palheta. Um nmero de 8 bits representando uma cor entre 256, na verdade referencia uma das 256
entradas de uma palheta, onde cada cor de fato definida com maior preciso. Voc pode
acessar o campo colors como um vetor normal, por exemplo my_palette.colors[5].
typedef struct{
int ncolors;
/* quantidade de cores na palheta */
SDL_Color *colors; /* ponteiro para um vetor de SDL_Color com
a informao de cada cor */
} SDL_Palette;
Um PixelFormat (formato de pixels) em SDL uma estrutura que representa o modo como os
pixels so armazenados em determinada superfcie, incluindo a profundidade de cores, a palheta
(se a profundidade de cores for igual a 8 bits), e alguns valores que indicam como as cores esto
armazenadas em cada pixel nos modos de 16 e 32 bits. Explicando: cada componente R, G e B (e A
de Alpha-transprncia-s vezes) tem 8 bits. Em um modo de 32 bits, os 3 (ou 4) valores cabem
sem modificao em um valor de 32 bits, sendo que os canais R, G, B e A esto simplesmente
copiados dentro do valor de 32 bits (de 8 em 8); claro que voc ainda deve saber em que ordem.

J em 16 bits, necessrio perder preciso em um ou mais canais para que todos caibam em
16 bits--por exemplo, no modo chamado RGB565, so reservados 5 bits para R, 6 para G e 5 para
B. Veremos agora como a estrutura PixelFormat nos ajuda a obter (ou construir) as cores.
typedef struct{
SDL_Palette *palette;
/* ponteiro para uma
palheta (se o modo for 8 bits, senao NULL) */
Uint8 BitsPerPixel;
/* quantidade de BITS
por pixel */
Uint8 BytesPerPixel;
/* quantidade de BYTES
por pixel (em geral BytesPerPixel/8) */
Uint32 Rmask, Gmask, Bmask, Amask;
/* mascara para acessar
os componentes */
Uint8 Rshift, Gshift, Bshift, Ashift; /* deslocamento para
acessar os componentes */
Uint8 Rloss, Gloss, Bloss, Aloss;
/* perda de precisao de
cada componente */
Uint32 colorkey;
/* cor transparente */
Uint8 alpha;
/* valor geral de
transparencia alpha */
} SDL_PixelFormat;
- O campo palette aponta para a palheta utilizada, caso este seja um formato de 8 bits.
- O campo BitsPerPixel indica quantos bits usamos para representar cada pixel.
- O campo BytesPerPixel indica quantos bytes usamos para representar cada pixel. Geralmente
igual a (BitsPerPixel / 8).
- Os campos Rmask, Gmask, Bmask, Amask indicam as mscaras usadas para isolar cada
componente de cor do valor de um pixel. Se temos um valor de 32/16 bits com as trs cores
concatenadas, interessante usar uma mscara de bits (um valor que contm 1 onde desejamos
ler e 0 onde desejamos ignorar) para, aps realizar uma operao de 'E' binrio, enxergarmos
apenas o valor da cor que queremos (R, G, B, A)--ainda que reste reposicionar e compensar a perda
(no caso do modo 16 bits).
- Os campos Rshift, Gshift Bshift, Ashift indicam o deslocamento--ou seja, a posio a contar do
bit menos significativo--de cada componente de cor dentro do valor montado. Aps fazer um 'E'
binrio com a mscara correspondente, devemos realizar um shift para a esquerda, de tantas
casas quantas forem este valor, para compensar o deslocamento realizado na hora que a cor foi
montada. AInda resta, porm, compensar a preda de preciso...
- Os campos Rloss, Gloss, Bloss, Aloss indicam a perda de preciso, em nmero de bits, para
cada componente. Por exemplo, em um modo RGB565, a perda do R seria 8-5, ou seja, 3, e a perda
do G seria 2 (8-6). Ou seja, a perda igual a 8 bits (maior preciso) subtrado da quantidade de
bits utilizadas para representar a cor em dado modo.
- O campo colorkey indica a cor (armazenada no formato descrito por esta estrutura em um
nmero de 32 bits) que considerada transparente na hora de um blit--ou seja, ao realizar-se um
blit com este formato sendo o formato da superfcie de origem, toda cor igual a esta ser
considerada transparente e no ser copiada para a tela.

- O campo alpha indica a transparncia geral da superfcie, em um valor de 0 a 255. Esta


transparncia aplicada a TODA a superfcie, diferente da transparncia por-pixel (o canal de
cor A). Um valor de 0 totalmente transparente enquanto um valor de 255 totalmente opaco.
No caso de haver um valor alpha para a superfcie ao mesmo tempo que um valor alpha para um
pixel, o valor do pixel ser usado prioritariamente.
Exemplo: Representao de um pixel em modo RGB565 (16-bits sem alpha)

O subsistema de vdeo
Conseguindo informaes sobre o hardware de vdeo
Vejamos agora como obter dados sobre o hardware de vdeo--as capacidades e modos grficos
suportados. Para isso, temos as funes SDL_GetVideoInfo, SDL_ListModes e
SDL_VideoModeOK. Adicionalmente, a funo SDL_VideoDriverName pode ser usada para obter
o nome do driver de vdeo sendo usado.
SDL_VideoInfo *SDL_GetVideoInfo(void);
A funo SDL_GetVideoInfo retorna um ponteiro para uma estrutura SDL_VideoInfo contendo
informaes sobre as capacidades de vdeo. Descrevendo a estrutura SDL_VideoInfo...
typedef struct{
Uint32 hw_available:1; /* e possivel criar uma superficie de
hardware? */
Uint32 wm_available:1; /* ha um gerenciador de janelas
disponivel? */
Uint32 blit_hw:1;
/* blits de hardware para hardware sao
acelerados? */
Uint32 blit_hw_CC:1;
/* blits de hardware para hardware com
color-key sao acelerados? */
Uint32 blit_hw_A:1;
/* blits de hardware para hardware com
alpha sao acelerados? */
Uint32 blit_sw:1;
/* blits de software para hardware sao
acelerados? */
Uint32 blit_sw_CC:1;
/* blits de software para hardware com
color-key sao acelerados? */
Uint32 blit_sw_A:1;
/* blits de software para hardware com
alpha sao acelerados? */
Uint32 blit_fill;
/* preenchimentos com cor sao acelerados?
*/
Uint32 video_mem;
/* quantidade total de memoria de video em
kilobytes */
SDL_PixelFormat *vfmt; /* PixelFormat do dispositivo de video */
} SDL_VideoInfo;

- Uma superfcie de hardware uma superfcie armazenada diretamente na memria de vdeo, e


pode ser criada passando-se o parmetro SDL_HWSURFACE para funes que criam superfcies
(veremos adiante). A vantagem deste tipo de superfcie que alguns blits (cpias) so acelerados
por hardware. Observe que, mesmo que o hardware no suporte superfcies de hardware, toda a
funcionalidade de vdeo ainda poder ser usada (a biblioteca implementa toda a funcionalidade
tambm por software). Para saber se determinado blit acelerado ou no, consulte os campos
respectivos na estrutura--blit_hw a blit_fill.
- Um blit com color-key um blit onde, na superfcie de origem, uma nica cor considerada
transparente. Um blit com alpha um blit onde cada ponto da superfcie de origem tem a ele
associado, ou por ponto, ou por toda a superfcie (sendo que o valor da superfcie tem precedncia),
um valor de transparncia parcial entre 0 e 255. Ou seja, uma transparncia alpha uma
transparncia parcial, ou semi-transparncia. - Um preenchimento com cor , como o nome sugere,
um simples preenchimento retangular com uma nica cor, ou, em outros termos, o desenho de um
retngulo de cor nica. Muito til para limpar a tela no comeo de um novo quadro, por exemplo.
- O PixelFormat do dispositivo de vdeo o formato em que os pixels so, de fato, armazenados no
dispositivo de vdeo. Cheque a seo anterior para a descrio do que um PixelFormat.
SDL_Rect **SDL_ListModes(SDL_PixelFormat *format, Uint32 flags);
A funo SDL_ListModes retorna uma lista dos modos grficos (na forma de um vetor de ponteiros
para SDL_Rect) suportados pelo hardware de vdeo, dados um PixelFormat e os parmetros de
criao da janela. Os parmetros so os mesmos que podem ser passados para a funo
SDL_SetVideoMode (descrita adiante). A funo retorna -1 se qualquer tamanho de tela for aceito
por esta combinao de formato e parmetros, ou NULL se no houver um modo grfico
apropriado. Passando-se NULL no parmetrto format, a lista de modos grficos ser relativa ao
formato retornado pela funo SDL_GetVideoInfo (veja acima). O vetor de ponteiros para
SDL_Rect ter tamanho (n + 1), sendo n o nmero de modos suportados. O n-simo elemento (ou
seja, o ltimo) ser igual a NULL, de modo que voc possa detectar o fim do vetor.
int SDL_VideoModeOK(int width, int height, int bpp, Uint32 flags);
A funo SDL_VideoModeOK checa se um determinado modo grfico suportado pelo hardware de
vdeo dados a largura, altura, profundidade de cores e os parmetros de criao da janela. Ela
retorna 0 (zero) se o modo no suportado por nenhuma profundidade de cor, ou o valor da
profundidade do modo mais prximo suportado (que pode ser ou no a profundidade requisitada).
char *SDL_VideoDriverName(char *namebuf, int maxlen);
A funo SDL_VideoDriverName pode ser usada para conseguir o nome do driver grfico sendo
usado atualmente. Passe um buffer (vetor) de char no parmetro namebuf, e o tamanho do buffer -1
(tamanho mximo do retorno) no parmetro maxlen. A funo retorna NULL se o vdeo no foi
inicializado.
O arquivo ex_videocap.c ilustra a utilizao das funes descritas acima.

Criando uma janela


SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp,

Uint32 flags);
A funo SDL_SetVideoMode cria a janela de video, dados a largura, altura, profundidade e
parmetros de criao; e retorna um ponteiro para a superfcie que a representa. Os parmetros
width, height e bpp representam, respectivamente, a largura, altura e a profundidade de cores da
janela a ser criada. Se a profundidade passada for 0 (zero), ser mantida a profundidade atual. Os
parmetros, apresentados adiante, determinam como a janela deve ser criada. Eles devem ser
passados como uma combinao de OU binrio, exemplo: (SDL_SWSURFACE |
SDL_FULLSCREEN).
- SDL_SWSURFACE : Cria a janela na memria RAM do sistema.
- SDL_HWSURFACE : Cria a janela na memria de vdeo.
- SDL_ASYNCBLIT : Faz os blits assncronamente com o resto d programa--pode torn-los mais
rpidos em sistemas multiprocessador.
- SDL_ANYFORMAT : Se a profundidade requisitada no estiver disponvel, a SDL vai criar uma
superfcie virtual da profundidade pedida, e copi-la para a superfcie real depois. Passe este
parmetro para evitar isso e faz-la usar sempre uma superfcie real para a tela (ou seja, criar uma
superfcie da profundidade mais prxima da requisitada).
- SDL_HWPALETTE : Faz com que a SDL tenha acesso direto palheta de cores do hardware de
vdeo. Sem este parmetro, pode ser que voc no consiga exatamente uma cor requisitada com a
funo SDL_SetColors.
- SDL_DOUBLEBUF : Ativa double buffering para a tela sendo criada. Double buffering uma
tcnica grfica que consiste em ter-se dois buffers (reas de memria) distintos para a tela: um sobre
o qual so realizadas as operaes de desenho (back buffer), e um cujos dados so efetivamente
copiados para a tela fsica (front buffer), enquanto desenho feito sobre o ourto. Aps a cpia da
imagem para a tela fsica, a funo dos dois buffers invertida, de modo que o back buffer passa a
funcionar como o front buffer e vice-vesa. Essa tcnica evita um defeito visual conhecido como
tearing, que ocorre na ocasio da tela ser desenhada enquando se est realizando uma operao de
desenho no buffer--causando uma impresso de "desenho pela metade".
- SDL_FULLSCREEN : Cria uma janela em tela cheia (ocupando toda a rea da tela).
- SDL_OPENGL : Cria uma janela onde possvel desenhar usando-se a biblioteca 3D OpenGL.
- SDL_OPENGLBLIT : Assim como a opo acima, cria uma janela onde possvel usar OpenGL,
mas ainda deixa funcionar os blits da SDL.
- SDL_RESIZABLE : Cria uma janela redimensionvel pelo usurio.
- SDL_NOFRAME : Cria, se possvel, uma janela sem borda.
O programa contido no arquivo ex_videomode.c ilustra os diferentes modos com um quadrado
colorido que se move pela tela. Compile-o de acordo com as instrues da parte 1 e execute-o na
linha de comando passando as opes acima como parmetros para o programa, por exemplo:
set_video_mode SDL_DOUBLEBUF SDL_FULLSCREEN
Ir mostrar uma janela que foi criada passando-se como parmetros SDL_DOUBLEBUF e
SDL_FULLSCREEN. Pode ser que, em seu sistema, nem todos os parmetros surtem algum
efeito--o que normal, j que eles dependem da implementao interna para cada sistema.
Obviamente, este programa no cobre os parmetros SDL_OPENGL e SDL_OPENGLBLIT porque
a biblioteca OpenGL foge do escopo desta apostila.

Atualizando a tela
void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y,
Sint32 w, Sint32 h);
void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect
*rects);
int SDL_Flip(SDL_Surface *screen);
J sabemos que, para desenhar algo na tela, deevem ser feitas operaes de desenho sobre a
superfcie que representa a tela (retornada pela funo SDL_SetVidedoMode). Mas para que essas
operaes sejam efetivamente mostradas na tela fsica do computador, necessrio explicitar que
queremos atualizar uma determinada rea da tela (ou toda ela). As funes acima servem a este
propsito.
- A funo SDL_UpdateRect atualiza uma rea da tela representada pela superfcie passada no
parmetro screen, e determinada pelas coordenadas x e y (posio) e w e h (largura e altura,
respectivamente).
- A funo SDL_UpdateRects atualiza vrias reas da tela em uma mesma chamada, representadas
por um vetor (array) de SDL_Rect. O parmetro screen determina a superfcie que representa a tela;
o parmetro numrects determina quantos Rect's sero passados, e o parmetro rects toma um
ponteiro para o vetor de SDL_Rect (ou seja, simplesmente o nome do vetor). Exemplo:
/* ... */
SDL_Rect my_rects[2];
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 8, 0);
/* ... */
my_rects[2] = {{0, 0, 20, 30}, {100, 150, 50, 300}};
SDL_UpdateRects(screen, 2, my_rects);
/* ... */
- A funo SDL_Flip atualiza a tela, por inteiro, e deve ser usada quando a janela de vdeo for
criada passando-se o parmetro SDL_DOUBLEBUF. Se a janela no tiver sido criada com este
parmetro, chamar esta funo tem exatamente o mesmo efeito que chamar SDL_UpdateRect para a
tela inteira, de modo que voc pode escrever seu programa para aceitar ou no este parmetro, e
usar esta funo para garantir que a tela seja atualizada em qualquer hiptese. Observe que, estando
em modo double buffering, mesmo aps chamar SDL_UpdateRect para uma determinada rea da
tela, voc dever chamar SDL_Flip ou a tela como um todo no ser atualizada no dispositivo de
vdeo.

Ajustando o Gamma da tela


int SDL_SetGamma(float redgamma, float greengamma, float
bluegamma);
int SDL_GetGammaRamp(Uint16 *redtable, Uint16 *greentable, Uint16
*bluetable);
int SDL_SetGammaRamp(Uint16 *redtable, Uint16 *greentable, Uint16
*bluetable);

O gamma um valor, aplicado pela SDL separadamente em cada componente de cor, utilizado para
fazer correes na imagem final. Geralmente, um valor de gamma maior gera uma imagem mais
clara. Considera-se o valor 1.0 o valor identidade, ou seja, um valor gamma de 1.0 mantm a cor
igual--sendo assim, valores menores que 1.0 escurecem a imagem, e valores maiores a clareiam.
- Voc pode usar a funo SDL_SetGamma para estabelecer os valores de gamma para as trs
componentes de cor, correspondentes aos parmetros redgamma, greengamma e bluegamma.
- Um outro modo de se ajustar o gamma, diferente do anterior (onde cada componente
transformada por um valor), atravs de uma tabela, associando um valor de gamma a cada um dos
256 valores possveis para cada componente. Voc pode ajustar esta tabela atravs da funo
SDL_SetGammaRamp e ler os seus valores atravs da funo SDL_GetGammaRamp. Ambas
tomam como parmetros um ponteiro para um vetor de 256 posies de Uint16 a serem preenchidas
(SDL_GetGammaRamp) ou lidas (SDL_SetGammaRamp), para cada componente. Alm disso,
voc pode passar NULL em um dos parmetros da funo SDL_SetGammaRamp se no desejar
mudar os valores daquela tabela.

Trabalhando com pixels


Uint32 SDL_MapRGB(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8
b);
Uint32 SDL_MapRGBA(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8
b, Uint8 a);
void SDL_GetRGB(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r,
Uint8 *g, Uint8 *b);
void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r,
Uint8 *g, Uint8 *b, Uint8 *a);
J sabemos que uma cor pode ser representada por trs componentes: red, green e blue. Porm, a
representao real de um pixel (em um nico valor) depende do PixelFormat sendo utilizado na
superfcie da tela. As funes SDL_MapRGB(A) e SDL_GetRGB(A) fazem um mapeamento entre
componentes de cor e valores reais.
- As funes SDL_MapRGB e SDL_MapRGBA transformam uma cor, representada pelas
componentes R, G e B (e A--Alpha--para a funo SDL_MapRGBA) em um nico valor que
representa a cor como ela seria armazenada na memria para um dado PixelFormat.
- As funes SDL_GetRGB e SDL_GetRGBA transformam um valor de cor (parmetro pixel),
representado no PixelFormat especificado, nas trs componentes correspondentes. As trs
componentes so retornadas para as variveis apontadas pelos parmetros r, g e b.
Observe que, com isso, j sabemos como desenhar um pixel na tela, com posio e cor arbitrrias.
Sabemos que para calcular o offset de um pixel na memria, em relao ao campo pixels de uma
superfcie, basta calcular
int offset = y * surface->w + x;
supondo a posio (x, y). Observe que isto no leva em conta o tamanho que cada pixel ocupa (1-4
bytes); isto ser compensando abaixo pela aritmtica de ponteiros. Sabemos tambm que, para
mapear um valor de cor RGB para um valor real numa superfcie, podemos fazer

Uint32 color = SDL_MapRGB(surface->format, r, g, b);


supondo a cor (r, g, b). Ento, para desenharmos um pixel de cor (r, g, b) na posio (x, y) da tela
(supondo screen ser a superfcie que a representa):
int offset = y * screen->w + x;
Uint32 color = SDL_MapRGB(screen->format, r, g, b);
if(screen->format->BytesPerPixel == 1)
*( ((Uint8*)screen->pixels) + offset) = (Uint8)color;
else if(screen->format->BytesPerPixel == 2)
*( ((Uint16*)screen->pixels) + offset) = (Uint16)color;
else
*( ((Uint32*)screen->pixels) + offset) = (Uint32)color;
Se voc no consegue entender o cdigo acima, apenas copie e use a funo abaixo para plotar um
pixel RGB:
void put_pixel(SDL_Surface* surface, int x, int y, Uint8 r, Uint8
g, Uint8 b)
{
int offset = y * surface->w + x;
Uint32 color = SDL_MapRGB(surface->format, r, g, b);
if(surface->format->BytesPerPixel == 1)
*( ((Uint8*)surface->pixels) + offset) = color;
else if(surface->format->BytesPerPixel == 2)
*( ((Uint16*)surface->pixels) + offset) = color;
else
*( ((Uint32*)surface->pixels) + offset) = color;
}
Observe, ainda, que algumas vezes necessrio "trancar" uma superfcie enquanto se acessa o
campo pixels. O que isso faz manter a superfcie no mesmo lugar da memria, j que
normalmente os dados da imagem podem ser movidos pela memria a fim de otimizar certas
tarefas. Isto resolvido muito facilmente: A macro SDL_MUSTLOCK(surface) verifica se uma
superfcie precisa ser trancada, e as funes SDL_LockSurface(surface) e
SDL_UnlockSurface(surface) trancam e destrancam uma superfcie, respectivamente. O que
queremos aqui, por exemplo, plotar vrios pixels em uma superfcie, ento:
if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
putpixel(screen, 100, 200, 255,
em (100, 200)
putpixel(screen, 100, 201, 255,
putpixel(screen, 100, 202, 255,
putpixel(screen, 100, 203, 255,
(...) //pode-se ver que estamos

0, 0); //pinta um pixel vermelho


0, 0);
0, 0);
0, 0);
desenhando uma linha vertical (x =

constante)
if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

Trabalhando com superfcies


SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int
height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
Uint32 Amask);
SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int
height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32
Bmask, Uint32 Amask);
As duas funes acima podem ser utilizadas para criar novas superfcies. A funo
SDL_CreateRGBSurface cria uma superfcie vazia, enquanto a funo
SDL_CreateRGBSurfaceFrom cria uma superfcie com base na imagem bruta passada pelo
parmetro pixels. Os parmetros width e height especificam (repectivamente) a largura e a altura da
superfcie sendo criada, e o parmetro depth especifica a profundidade de cores (em bits). Caso esta
seja 8 bits, ser alocada uma palheta vazia e os parmetros Rmask, Gmask, Bmask e Amask sero
descartados. Caso contrrio, estes valores sero usados para criar um PixelFormat onde cada pixel
guarda os valores "empacotados" das componentes R, G, B, A (de acordo com a descrio de
PixelFormat). O parmetro flags um ou-binrio dos valores:
- SDL_SWSURFACE: Cria a superfcie em memria RAM. Acessos a nvel de pixel so mais
rpidos.
- SDL_HWSURFACE: Cria a superfcie em memria de vdeo. Blits talvez sejam acelerados por
hardware.
- SDL_SRCCOLORKEY: Possibilita transparncia color-key, ou seja, uma cor considerada
transparente.
- SDL_SRCALPHA: Possibilita transparncia alpha.
Por exemplo, para criar uma superfcie com o mesmo PixelFormat (mscaras iguais), basta chamar
a funo como
my_surf = SDL_CreateRGBSurface(flags, width, height, depth,
screen->format->Rmask, screen->format->Gmask, screen->format>Bmask, screen->format->Amask);
supondo screen a superfcie que representa a tela.
void SDL_FreeSurface(SDL_Surface *surface);
A funo SDL_FreeSurface destri uma superfcie, liberando a memria utilizada por ela. Observe
que voc no poder fazer mais nada com uma superfcie aps esta chamada.
int SDL_LockSurface(SDL_Surface *surface);
void SDL_UnlockSurface(SDL_Surface *surface);
Pode ser que, antes de poder acessar diretamente os pixels de uma superfcie (incluindo a funo
put_pixel descrita acima), seja necessrio tranc-la em sua posio na memria. Para isso, basta

chamar a funo SDL_LockSurface. Aps isso, pode-se acessar o campo pixels vontade, e, ao
trmino, chamar a funo SDL_UnlockSurface para destrancar a superfcie. Note que voc no
deve chamar nenhuma funo do sistema ou da biblioteca enquanto uma superfcie estiver trancada,
pois um trancamento acarreta a paralisao de vrios outros sistemas crticos. Para saber se uma
superfcie deve ser trancada (e destrancada) ou no, utilize a macro SDL_MUSTLOCK(surface).
Exemplo:
/* ... */
SDL_Surface* my_surf;
/* ... */
if(SDL_MUSTLOCK(my_surf)) SDL_LockSurface(my_surf);
/* acesse my_surf->pixels, por exemplo com put_pixel */
if(SDL_MUSTLOCK(my_surf)) SDL_UnockSurface(my_surf);
/* ... */

Carregando e salvando imagens BMP


SDL_Surface *SDL_LoadBMP(const char *file);
int SDL_SaveBMP(SDL_Surface *surface, const char *file);
A funo SDL_LoadBMP carrega uma figura de um arquivo BMP e retorna um ponteiro para uma
superfcie com a imagem armazenada no arquivo. Analogamente, a funo SDL_SaveBMP salva a
imagem de uma superfcie para um arquivo BMP especificado. Veremos adiante como carregar
imagens de outros formatos com a biblioteca SDL_image.

Trabalhando com transparncias


int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32
key);
int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha);
Existem dois tipos de transparncia que podem ser usados com SDL: color-key e alpha. Na
transparncia com color-key, uma certa cor na imagem considerada 100% transparente e tudo que
h atrs dela pode ser visto. Uma transparncia alpha atribui a cada pixel um valor numrico
proporcional transparncia parcial desejada, de modo que um valor de 0
(SDL_ALPHA_TRANSPARENT) considerado completamente transparente e um valor de 255
(SDL_ALPHA_OPAQUE) considerado 100% opaco. Qualquer valor entre 0 e 255 parcialmente
transparente, com um valor de 128 tendo 50% de transparncia, e sendo especialmente otimizado, e
por conseguinte mais eficiente que os outros. Para atribuir uma transparncia color-key a uma certa
superfcie:
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color);
onde color a cor a ser considerada transparente e pode ser obtida com SDL_MapRGB passando-se
surface->format no parmetro format. Adicionalmente, pode-se adicionar o parmetro
SDL_RLEACCEL (com um ou-binrio) a SDL_SRCCOLORKEY, para ativar acelerao RLE nos
blits desta superfcie, o que geralmente torna blits mais rpidos em imagens com grandes pores de
uma nica cor.

Para aplicar um valor de transparncia alpha a todos os pixels de uma superfcie:


SDL_SetAlpha(surface, SDL_SRCALPHA, alpha);
onde alpha o valor da transparncia desejado entre 0 e 255 inclusive. Assim como para
transparncias color-key, pode-se fazer um ou-binrio de SDL_SRCALPHA com
SDL_RLEACCEL para ativar a acelerao RLE nos blits da superfcie.

Mscaras
void SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect);
void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect);
Voc pode criar uma mscara retangular (clipping rectangle) em uma superfcie. Quando esta
superfcie o destino de um blit, apenas a rea dentro do retngulo definido pela mscara ser
sobrescrito pela imagem de origem. Utilize a funo SDL_SetClipRect para configurar uma
mscara (definida por um rect cujo endereo passado no segundo parmetro) em uma superfcie
(cujo ponteiro passado no primeiro parmetro). Analogamente, a funo SDL_GetClipRect
retorna para o ponteiro passado no segundo parmetro, a mscara atualmente definida na superfcie
passada. Observe que, passando-se NULL para SDL_SetClipRect significa toda a rea da
superfcie, e que os retngulos so automaticamente lmitados pela rea total da superccie.

Convertendo superfcies
SDL_Surface *SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat
*fmt, Uint32 flags);
s vezes conveniente converter o formato de uma superfcie, mantendo os dados da imagem. Para
isto, usa-se a funo SDL_ConvertSurface, a qual converte a superfcie src para o formato fmt com
os parmetros flags. Observe que o parametro flags formado da mesma maneira que na funo
SDL_CreateRGBSurface. O valor de retorno da funo um ponteiro para a nova superfcie,
convertida. Voc no deve liberar a superfcie antiga pois a SDL se encarrega disto.
SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface);
SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface);
J estas funes realizam uma verso especial de converso--elas convertem uma superfcie para o
formado da superfcie da tela (equivalente a passar screen->format para a funo
SDL_ConvertSurface no parmetro fmt, sendo screen a superfcie de vdeo). Utilize a funo
SDL_DisplayFormat se no desejar que a nova superfcie tenha transparcia alpha, ou
SDL_DisplayFormatAlpha caso contrrio.

Desenhando Retngulos
int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32
color);
Chame SDL_FillRect (passando uma superfcie de destino dst, um ponteiro para uma regio de
destino dstrect e uma cor color) para desenhar um simples retngulo preenchido. Exemplo: (para
desenhar um retngulo vermelho)

SDL_Rect drect = {100, 50, 300, 300};


SDL_FillRect(screen, &drect, SDL_MapRGB(screen->format, 25, 0,
0));

Copiando superfcies (blitting)


Um blit , com boa argumentao, uma das operaes mais importantes de uma biblioteca grfica,
seno a mais importante delas. com um blit que voc copia uma imagem de um lugar para outro-incluindo para a tela. E um blit examente isso--uma cpia de uma regoo, ou o todo, de uma
imagem (superfcie) para uma determinada posio em outra. Para fazermos blits em SDL existe a
funo SDL_BlitSurface.
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect);
SDL_BlitSurface faz uma cpia de uma regio srcrect da superfcie src para a posio dstrect na
superfcie dst. Observe que em dstrect os campos w e h (tamanho) so ignorados, sendo
aproveitados apenas os campos x e y (posio). Em outras palavras, esta funo no estica ou
comprime as inagens (ela apenas faz cpias na mesma escala). Ao final da operao, porm, os
campos w e h de dstrect recebero a largura e a altura, respectivamente, da regio que de fato foi
sobrescrita na superfcie de destino. Pode acontecer que nem toda, ou nenhuma parte, da regio de
origem seja copiada por estar fora das bordas da superfcie de destino, ou fora da jenela de blit
(definida por SDL_SetClipRect).

O cursor do mouse
void SDL_WarpMouse(Uint16 x, Uint16 y);
int SDL_ShowCursor(int toggle);
A funco SDL_WarpMouse move o cursor do mouse para a posio da tela determinada por (x, y),
dentro da janela da sua aplicao, e gera um evento de movimentao do mouse enquanto isso. J
SDL_ShowCursor determina se o cursor do mouse deve ser mostrado--passe SDL_ENABLE se
quiser que ele aparea, e SDL_DISABLE caso contrrio. Passando SDL_QUERY a funo
retornar o estado atual, ou seja, SDL_ENABLE ou SDL_DISABLE.

#include <stdio.h>
#include <string.h>
#include <SDL.h>
#define N_PARAM 9
char* param_text[N_PARAM] = {"SDL_SWSURFACE", "SDL_HWSURFACE", "SDL_ASYNCBLIT",
"SDL_ANYFORMAT", "SDL_HWPALETTE", "SDL_DOUBLEBUF", "SDL_FULLSCREEN",
"SDL_RESIZABLE", "SDL_NOFRAME"};
int param_code[N_PARAM] = {SDL_SWSURFACE, SDL_HWSURFACE, SDL_ASYNCBLIT,
SDL_ANYFORMAT, SDL_HWPALETTE, SDL_DOUBLEBUF, SDL_FULLSCREEN, SDL_RESIZABLE,
SDL_NOFRAME};
int str_to_param(char* str)
{
int i;

for(i=0; i<N_PARAM; i++)


{
if(!strcmp(str, param_text[i])) return param_code[i];
}
return -1;

int main(int argc, char** argv)


{
SDL_Surface* screen;
int flags = 0;
int i;
SDL_Rect quad = {0, 0, 64, 64};
SDL_Event event;
int quit = 0;
int incx = 1;
int incy = 1;
for(i=1; i<argc; i++)
{
flags |= str_to_param(argv[i]);
}
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(640, 480, 8, flags);
{

while(!quit)
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
quit = 1;
}
}
quad.x += incx;
quad.y += incy;
if(((quad.x + quad.w) > screen->w) || (quad.x < 0))
{
incx = -incx;
quad.x += incx;
}
if(((quad.y + quad.h) > screen->h) || (quad.y < 0))
{
incy = -incy;
quad.y += incy;
}
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_FillRect(screen, &quad, SDL_MapRGB(screen->format, 255, 0,

0));

SDL_Flip(screen);
}
SDL_Quit();
}

return 0;

Eventos
O que so eventos?
De um modo geral, um evento uma mensagem para o seu programa, advinda do sistema ou da
biblioteca, indicando que algo externo occoreu, por exemplo, o usurio moveu o mouse ou
pressionou uma tecla no joystick. Um exemplo de evento advindo do sistema uma mensagem de
sada--o usurio pode ter enviado uma ordem de desligamento para o sistema, que por sua vez envia
aos programas abertos uma mensagem de encerramento.

Trabalhando com eventos


No momento em que um evento ocorre no sistema, a SDL insere informaes sobre o mesmo em
uma estrutura chamada fila de eventos, que funciona como o nome indica: o primeiro elemento a ser
inserido (pela biblioteca, em razo de um acontecimento externo) ser o primeiro a ser retirado,
quando voc (o programa) assim o pedir. A maneira mais usual de proceder com o tratamento de
eventos a seguinte:
Loop principal
(...)
Enquanto houver eventos na fila
Retirar evento da fila
Tratar (ou ignorar) evento
A SDL prov uma funo chamada SDL_PollEvent que verifica se ainda h eventos a serem
tratados, e se for o caso, retorna informaes sobre eles.
int SDL_PollEvent(SDL_Event *event);
Retorna 1 se ainda houverem eventos a serem tratados (incluindo o atual) e 0 se a fila estiver vazia.
Em outras palavras, retorna um valor indicando se voc deve processar o evento ou no. Passe o
endereo de uma varivel do tipo SDL_Event como parmetro para que ela seja preenchida com as
informaes do evento retornado (se houver). A estrutura SDL_Event possui um campo chamado
type, que indica o tipo do evento (teclado, mouse, joystick, etc) e um campo para cada tipo de
evento, sendo que as informaes sobre o evento atual esto dentro do campo correspondente. Por
exemplo, em um evento de teclado, as informaes sobre ele, tal como tecla pressionada, estaro
armazenadas em event.key.
while(SDL_PollEvent(&event)) /* Repetir enquanto houverem eventos
*/
{
switch(event.type)
/* Processar o tipo do evento */
{
case SDL_KEYDOWN:
/* Tratar um evento KEYDOWN (tecla
pressionada) */
printf("Foi pressionada uma tecla!\n");
if(event.key.keysym.sym == SDLK_LEFT)
printf("Ande para a esquerda!\n");

break;
case SDL_MOUSEMOTION:
.
.
.
default:
/* Evento no tratado */
printf("Eu no sei que evento esse!\n");
}
}
Outras funes teis para tratar eventos:
Uint8 SDL_EventState(Uint8 type, int state);
int SDL_JoystickEventState(int state);
void SDL_PumpEvents(void);
int SDL_WaitEvent(SDL_Event *event);
int SDL_PushEvent(SDL_Event *event);
Voc pode utilizar a funo SDL_EventState para determinar que um certo tipo de evento type seja
ignorado ou no (atravs do parmetro state: SDL_IGNORE ou SDL_ENABLE). Um evento
ignorado no colocado na fila de eventos. Passe SDL_QUERY em state para retornar o estado
atual de um determinado tipo de evento. De modo similar, SDL_JoystickEventState habilita ou
desabilita o processamento de eventos relacionados a joysticks. Uma chamada a SDL_PumpEvents
atualiza, dentro da biblioteca, o estado dos dispositivos (teclado, joystick, etc) e deve ser chamada
antes de ler diretamente dos dispositivos (sem eventos, veja mais abaixo). A funo SDL_WaitEvent
espera indefinidamente at que um evento ocorra, e o retorna atravs do parmetro event (da mesma
forma que SDL_PollEvent). Ela retorna 1 se conseguiu um evento (aps esperar por ele), ou 0 se
houve algum erro. Por sua vez, SDL_PushEvent pode ser usada para forar a insero de um evento
na fila, ou seja, simular a ocorrncia de um evento. Para isto, basta criar uma estrutura do tipo
SDL_Event, preench-la com os dados apropriados, e passar seu endereo como parmetro. Os
eventos enviados sero posteriormente recebidos por SDL_PollEvent (seguindo a ordem da fila).
Exemplo:
SDL_Event event;
/* Simulando um evento do teclado */
event.type = SDL_KEYDOWN;
event.key.state = SDL_PRESSED;
event.key.keysym.sym = SDLK_LEFT;
SDL_PushEvent(&event);
/* Enviando um evento personalizado */
event.type = SDL_USEREVENT;
event.user.code = 2; /* Aqui voc define o que quiser... */
event.user.data1 = &dados_importantes;
event.user.data2 = NULL;

SDL_PushEvent(&event);
/* Recebendo o evento personalizado */
while(SDL_PollEvent(&event))
{
if(event.type == SDL_USEREVENT)
{
if(event.user.code == 2)
{
processar(event.user.data1);
}
}
}

Tipos de eventos
Existem vrios tipos diferentes de eventos que podem ser enviados ao seu programa. Supe-se que,
antes de tratar cada evento, feita uma chamada funo SDL_PollEvent para que ela preencha
uma estrutura chamada event, como no exemplo acima. Os nomes indicados a seguir so passados
no campo event.type, de modo que voc pode us-los para detectar o tipo de cada evento recebido.
Observe que, para os eventos dos joysticks serem ativados, necessrio passar o parmetro
SDL_INIT_JOYSTICK para SDL_Init ou SDL_InitSubSystem e chamar SDL_JoystickEventState.
1. SDL_ACTIVEEVENT: Acontece quando o seu programa ganha ou perde o foco do teclado
ou do mouse, ou a janela minimizada/restaurada. event.active.state contm o motivo do
evento (SDL_APPMOUSEFOCUS para mouse, SDL_APPINPUTFOCUS para teclado e
SDL_APPACTIVE para minimizao), e event.active.gain contm 1 se o seu programa
ganhou o foco, ou 0 se ele o perdeu.
2. SDL_KEYDOWN e SDL_KEYUP: Acontecem quando uma tecla do teclado pressionada
(SDL_KEYDOWN) ou solta (SDL_KEYUP). event.key.state indica o estado atual da tecla
(aps o evento--SDL_PRESSED ou SDL_RELEASED). event.key.keysym.sym contm um
valor indicando qual tecla foi pressionada, uma das constantes listadas no Apndice A.
event.key.keysym.mod contm um ou-binrio de valores, representando quais das teclas
modificadoras (Alt, Ctrl, etc) esto pressionadas (uma combinao das constantes de teclas
modificadoras listadas no Apndice A). event.key.keysym.unicode contm o cdigo Unicode
(ou ASCII se menor que 256), se voc chamou a funo SDL_EnableUNICODE(1) em
algum momento antes do evento ocorrer. Mais informaes sobre a funo
SDL_EnableUNICODE mais abaixo. Observe que este valor leva em considerao o estado
do Num Lock e Caps Lock, assim como o estado da tecla Shift (maisculas e minsculas so
reportadas de acordo).
3. SDL_MOUSEMOTION: Ocorre quando o cursor do mouse movido dentro da sua janela.
event.motion.x e event.motion.y contm a nova posio do cursor do mouse.
event.motion.xrel e event.motion.yrel contm o movimento relativo do cursor(diferena entre
a nova posio e a antiga). event.motion.state contm um valor indicando quais botes do
mouse esto pressionados no momento do evento. Este valor pode ser interpretado da

mesma forma que com a funo SDL_GetMouseState, descrita mais abaixo.


4. SDL_MOUSEBUTTONDOWN e SDL_MOUSEBUTTONUP: So disparados quando um
boto do mouse pressionado ou liberado. event.button.button indica o boto referido
(SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, SDL_BUTTON_RIGHT).
event.button.state indica o estado atual do boto (apx o evento--SDL_PRESSED ou
SDL_RELEASED). event.button.x e event.button.y contm a posio do cursor no momento
do evento.
5. SDL_JOYAXISMOTION: Acontece quando um eixo de um joystick movimentado.
event.jaxis.which contm um nmero associado a qual joystick disparou o evento (0, 1,
2, ...). event.jaxis.axis indica qual dos eixos foi movido (0, 1, 2, ...). event.jaxis.value indica
o valor da posio do eixo (-32768 a 32767). Mais informaes sobre Joysticks na prxima
seo.
6. SDL_JOYBALLMOTION: Acontece quando uma "bola" (trackball) de um joystick
movimentada. event.jball.which contm um nmero associado a qual joystick disparou o
evento (0, 1, 2, ...). event.jball.ball indica qual das trackballs foi movida (0, 1, 2, ...).
event.jball.xrel e event.jball.yrel indicam o movimento relativo da trackball nas direes X e
Y, respectivamente.
7. SDL_JOYHATMOTION: Acontece quando um "chapu" (hat, POV, ponto-de-vista) de um
joystick movimentado. event.jhat.which contm um nmero associado a qual joystick
disparou o evento (0, 1, 2, ...). event.jhat.hat indica qual dos "hats" foi movido (0, 1, 2, ...).
event.jhat.value indica a posio do hat (SDL_HAT_CENTERED, SDL_HAT_UP,
SDL_HAT_RIGHT, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHTUP,
SDL_HAT_RIGHTDOWN, SDL_HAT_LEFTUP, SDL_HAT_LEFTDOWN)
8. SDL_JOYBUTTONDOWN e SDL_JOYBUTTONUP: Acontece quando um boto de um
joystick pressionado/liberado. event.jbutton.which contm um nmero associado a qual
joystick disparou o evento (0, 1, 2, ...). event.jbutton.button indica qual dos botes ativou o
evento (0, 1, 2, ...). event.jbutton.state indica o estado atual do boto (SDL_PRESSED ou
SDL_RELEASED).
9. SDL_QUIT: ativado quando o seu programa deve ser encerrado, ou porque o usurio o
pediu ao sistema d ejanelas, ou por algum outro motivo inerente ao sistema (por exemplo,
desligamento). Observe que se voc simplesmente ignorar este evento o usurio no poder
fechar a janela do seu programa.
10.SDL_VIDEORESIZE: Quando o parmetro SDL_RESIZABLE passado para a funo
SDL_SetVideoMode na inicializao, a janela pode ser redimensionada pelo usurio.
Quando isto acontece, este evento enviado, contendo as novas dimenses da janela em
event.resize.w e event.resize.h. Ao receber um evento deste tipo, deve-se reinicializar a
janela com SDL_SetVideoMode (passando as novas coordenadas de largura e altura).
11.SDL_VIDEOEXPOSE: Um evento deste tipo ativado quando, por algum motivo externo
sua janela, o sistema operacional modificou ("sujou") a tela, e voc deve redesenh-la. Isto
faz mais sentido quando voc est fora de um loop de desenho, onde a tela sempre
atualizada vrias vezes por segundo. Mas, se voc mentm uma tela esttica, sem atualiz-la
regularmente (por exemplo, uma tela de pausa), interessante tratar deste evento,
redesenhando a tela (possivelmente uma chamada a SDL_Flip).
12.SDL_USEREVENT: Este evento ativado quando o programa (ou seja, voc) chama

SDL_PushEvent com um evento do tipo SDL_USEREVENT. Voc pode usar o campo


event.user.code para definir um cdigo para os seus eventos personalizados, e os campos
event.user.data1 e event.user.data2 como ponteiros para dados que voc ache
particularmente teis ao cdigo que vai receber o evento.

Outras funes relacionadas a eventos


Existem algumas outras funes que no tratam diretamente de eventos, mas esto de alguma forma
relacionadas, por exemplo, a leitura direta do estado das teclas do teclado. Observe que, como dito
anteriormente, antes de ler diretamente o teclado ou o mouse com as teclas acima, necessria uma
chamada a SDL_PumpEvents().
Uint8 *SDL_GetKeyState(int *numkeys);
SDLMod SDL_GetModState(void);
void SDL_SetModState(SDLMod modstate);
SDL_GetKeyState retorna um ponteiro para um vetor de estados das teclas do teclado. A posio x
deste vetor indica o estado de cada tecla (1: pressionado ou 0: solto), sendo x um dos valores de
teclas enumerados no Apndice A. numkeys um ponteiro para uma varivel inteira que ser
preenchida com o tamanho do vetor retornado. Passe NULL para ignorar. Exemplo:
Uint8 *keystate = SDL_GetKeyState(NULL);
if(keystate[SDLK_RETURN]) puts("Voce acaba de pressionar enter!");
De maneira parecida, SDL_GetModState retorna o estado das teclas modificadoras (Ctrl, Alt, etc).
O valor de retorno um ou-binrio dos valores de teclas modificadoras enumarados no Apndice A.
Analogamente, passe um ou-binrio destes valores a SDL_SetModState para forar o estado de uma
ou mais destas teclas (por exemplo, para forar a entrada de letras maisculas).
char *SDL_GetKeyName(SDLKey key);
int SDL_EnableUNICODE(int enable);
A funo SDL_GetKeyName retorna um ponteiro para um string contendo o nome (em ingls) da
tecla passada no parmetro key. Exemplo:
int i, nkeys;
Uint8 *keystate = SDL_GetKeyState(&nkeys);
for(i=0; i<nkeys; i++)
{
if(keystate[i]) printf("A tecla %s esta pressionada!\n",
SDL_GetKeyName(i));
}
A funo SDL_EnableUNICODE faz com que os eventos de tecla contenham, no campo
event.key.keysym.unicode, o cdigo Unicode (ASCII se menor que 256) da tecla pressionada, ou
no. Passe 1 para habilitar, ou 0 para desabilitar. Esta operao causa um pequeno overhead
(lentido) ao processar eventos de tecla, ento est desabilitada por padro.
int SDL_EnableKeyRepeat(int delay, int interval);

SDL_EnableKeyRepeat determina se os eventos de tecla sero reenviados continuamente caso uma


tecla seja mantida pressionada por algum tempo, assim como permite ajustar o tempo mnimo para
a repetio ocorrer (delay), e o tempo entre o envio dos eventos (interval). Bons valores so
SDL_DEFAULT_REPEAT_DELAY e SDL_DEFAULT_REPEAT_INTERVAL, respectivamente.
Passe 0 em delay para desligar a repetio totalmente. til para simular, por exemplo, o efeito de
repetio de uma caixa de texto, como em uma tela que pede para o usurio digitar seu nome.
Uint8 SDL_GetMouseState(int *x, int *y);
Uint8 SDL_GetRelativeMouseState(int *x, int *y);
Uint8 SDL_GetAppState(void);
SDL_GetMouseState pode ser usada para retornar o estado dos botes e do ponteiro do mouse. A
posio do ponteiro ser armazenada nas variveis cujos endereos so passados em x e y. O valor
de retorno da funo ser um ou-binrio dos botes pressionados, e pode-se usar a macro
SDL_BUTTON para testar qual oto foi pressionado:
int x, y;
if(SDL_GetMouseState(&x, &y) & SDL_BUTTON(1))
printf("O boto 1 (esquerdo) do mouse est pressionado sobre
(%d, %d)\n", x, y);
SDL_GetRelativeMouseState funciona exetamente como SDL_GetMouseState, exceto que retorna
coordenadas relativas, isto , a diferena entre as coordenadas atuais e as coordenadas retornadas
pela ltima chamada funo, ou desde a inicializao (caso seja a primeira chamada).
SDL_GetAppState retorna um ou-binrio dos seguintes valores, indicando o estado da sua janela:
- SDL_APPMOUSEFOCUS: A janela tem o foco do mouse.
- SDL_APPINPUTFOCUS A janela tem o foco do teclado.
- SDL_APPACTIVE: A janela est visvel.
E por favor, observe novamente que antes de ler diretamente o teclado ou o mouse com as teclas
acima, necessria uma chamada a SDL_PumpEvents().

Joysticks
A SDL prov vrias funes para tratamento direto de Joysticks, apesar de que a maioria dos casos
pode tambm ser tratada via eventos. Observe que, para poder ler dados dos joysticks, seja por
eventos ou pelas funes listadas abaixo, necessrio passar o parmetro SDL_INIT_JOYSTICK
para SDL_Init ou SDL_InitSubSystem.
int SDL_NumJoysticks(void);
const char *SDL_JoystickName(int index);
SDL_Joystick *SDL_JoystickOpen(int index);
int SDL_JoystickOpened(int index);
int SDL_JoystickIndex(SDL_Joystick *joystick);
void SDL_JoystickClose(SDL_Joystick *joystick);
A funo SDL_NumJoysticks retorna a quantidade de joysticks instalados. Voc pode ento usar
SDL_JoystickName para saber o nome (dado pelo Sistema Operacional) de cada um dos joysticks

instalados. Exemplo:
int i;
for(i = 0; i < SDL_NumJoysticks(); i++)
{
printf("Nome do joystick %d: %s\n");
}
Aps descobrir quantos joysticks esto instalados, antes de poder usar as funes aqui listadas, voc
precisa abrir (inicializar) um ou mais joysticks com a funo SDL_JoystickOpen. Esta retorna um
ponteiro para SDL_Joystick, uma estrutura interna da SDL cuja organizao no nos interessa-apenas devemos conseguir um ponteiro para cada joystick que queiramos utilizar e passar este
ponteiro para as funes chamadas. Voc deve passar a SDL_JoystickOpen o ndice (nmero de
identificao) do joystick que quer abrir. Os joysticks so numerados de 0 a (SDL_NumJoysticks() 1). Intuitivamente, a funo SDL_JoystickOpened retorna um valor que indica se um dado joystick
(descrito pelo ponteiro passado como parmetro) est aberto (foi inicializado com sucesso) ou no.
J SDL_JoystickIndex retorna o ndice de um joystick, passando-se um ponteiro para
SDL_Joystick. Para completar, SDL_JoystickClose fecha (deinicializa) um joystick previamente
aberto.
int
int
int
int

SDL_JoystickNumAxes(SDL_Joystick *joystick);
SDL_JoystickNumBalls(SDL_Joystick *joystick);
SDL_JoystickNumHats(SDL_Joystick *joystick);
SDL_JoystickNumButtons(SDL_Joystick *joystick);

Estas funes tomam como parmetro um joystick previamente inicializado com


SDL_JoystickOpen e retornam a quantidade de Eixos, Trackballs, Hats (POVs) e Botes
(respectivamente) deste joystick. Os eixos normalmente correspondem ao direcional de um joystick
(um D-Pad, ou um manche). Em geral os dois primeiros eixos (X e Y) so o direcional, e outros
eixos que porventura existam correspondem a sliders. Em alguns casos, joysticks implementam
botes extra usando eixos (explicado mais abaixo). Trackballs so bolinhas fixas, mas que podem
ser giradas sobre seu prprio centro--elas funcionam mais ou menos como dois eixos (X e Y) que s
tm movimento relativo (j que as trackballs no tm uma "origem" da rotao). Hats, ou POVs
(Point-of-View) so botes especiais que possuem 9 estados: centro, cima, baixo, esquerda, direita e
as diagonais. Voc pode empurr-los para uma das oito direes e eles voltam ao centro ao serem
soltos--funcionam mais ou menos como joysticks de fliperama. Por ltimo, deixemos por sua conta
descobrir quem so os botes.
void SDL_JoystickUpdate(void);
Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis);
Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat);
Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button);
int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx,
int *dy);
Estas so as funes efetivamente usadas para ler diretamente os dados de um joystick. Antes de
tentar ler qualquer dado, preciso chamar SDL_JoystickUpdate para que as variveis internas sobre

os joysticks recebam os valores do estado do hardware. Se voc ativou processamento de eventos de


joystick com SDL_JoystickEventState(SDL_ENABLE), esta funo chamada automaticamente
por SDL_PollEvent dentro do seu loop de eventos. Abaixo descrevemos as funes de leitura--todas
elas tomam como primeiro parmetro um ponteiro para um joystick aberto.
1. SDL_JoystickGetAxis: retorna um valor (-32768 a 32768) representando a posio do eixo
de nmero axis. Em geral, o eixo 0 o X e o eixo 1 o Y. Alguns joysticks implementam
botes extras usando valores de eixo. Neste caso, um dos valores extremos do eixo (-32768
ou 32768) indica um boto pressionado, e um valor zero indica que o boto no est
pressionado.
2. SDL_JoystickGetHat: Retorna o estado do Hat (POV) indicado por hat. O valor de retorno
ser igual a uma das seguintes constantes: SDL_HAT_CENTERED, SDL_HAT_UP,
SDL_HAT_RIGHT, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHTUP,
SDL_HAT_RIGHTDOWN, SDL_HAT_LEFTUP, SDL_HAT_LEFTDOWN.
3. SDL_JoystickGetButton: Retorna o estado do boto button: 1 (pressionado) ou 0 (solto).
4. SDL_JoystickGetBall: Retorna o movimento relativo da trackball ball. Os valores so
retornados pelos ponteiros dx e dy. Retorna -1 em caso de erro. Exemplo:
int delta_x, delta_y;
SDL_Joystick *joy;
.
.
.
SDL_JoystickUpdate();
SDL_JoystickGetBall(joy, 0, &delta_x, &delta_y);
printf("Variao da Trackball- X:%d, Y:%d\n", delta_x,
delta_y);
/*

Arquivo: ex_joystick.c
Autor: Bruno Bottino
Data: 10/09/2007
Descrio: Exemplifica o uso das funes de leitura de joysticks com SDL
Observaes: No funciona bem em Windows porque utiliza a entrada e
sada padres
*/
//comente a linha abaixo para ver a tela de seleo de joysticks
#define WINDOWS
#include <SDL.h>
int main(int argc, char** argv)
{
int running = 1; //variavel para controlar se o loop principal deve
continuar
SDL_Surface* screen;
SDL_Event event;
SDL_Rect my_rect = {(640-40)/2, (480-40)/2, 40, 40};
int r = 255, g = 0, b = 0;
int i;

int njoy = -1;


SDL_Joystick* joy;
int xball, yball;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
if(SDL_NumJoysticks() == 0)
{
puts("Nenhum joystick encontrado.");
return 0;
}
#ifdef WINDOWS
njoy = 0; //seleciona o joystick primrio
#else
printf("Lista de joysticks instalados:\n");
for(i=0; i<SDL_NumJoysticks(); i++)
{
printf("%2d. %s\n", i, SDL_JoystickName(i));
}
while((njoy < 0) || (njoy >= SDL_NumJoysticks()))
{
printf("Digite o nmero para selecionar um joystick e pressione
ENTER: ");
while(scanf("%d", &njoy) != 1)
{
printf("Digite o nmero para selecionar um joystick e
pressione ENTER: ");
}
}
#endif
screen = SDL_SetVideoMode(640, 480, 16, SDL_DOUBLEBUF);
joy = SDL_JoystickOpen(njoy);
while(running)
{
//ler do joystick
if(SDL_JoystickNumAxes(joy) >= 2)
{
//comparamos com 16 em vez de zero para contornar
desvios de calibragem
if(SDL_JoystickGetAxis(joy, 0) < 16) my_rect.x--;
if(SDL_JoystickGetAxis(joy, 0) > 16) my_rect.x++;
if(SDL_JoystickGetAxis(joy, 1) < 16) my_rect.y--;
if(SDL_JoystickGetAxis(joy, 1) > 16) my_rect.y++;
}
if(SDL_JoystickNumBalls(joy) > 0)
{
SDL_JoystickGetBall(joy, 0, &xball, &yball);
if(xball < 0) my_rect.x--;
if(xball > 0) my_rect.x++;
if(yball < 0) my_rect.y--;
if(yball > 0) my_rect.y++;
}
if(SDL_JoystickNumHats(joy) > 0)
{
switch(SDL_JoystickGetHat(joy, 0))
{
case SDL_HAT_CENTERED: break; //mantm a posio
case SDL_HAT_UP:
my_rect.y--; break;
case SDL_HAT_RIGHT: my_rect.x++; break;
case SDL_HAT_DOWN: my_rect.y++; break;

case SDL_HAT_LEFT: my_rect.x--; break;


case SDL_HAT_RIGHTUP:
my_rect.x++;
my_rect.y--; break;

case SDL_HAT_RIGHTDOWN: my_rect.x++; my_rect.y+

+; break;
my_rect.y--; break;
+; break;

case SDL_HAT_LEFTUP:

my_rect.x--;

case SDL_HAT_LEFTDOWN:

my_rect.x--; my_rect.y+

}
}
for(i=0; i < SDL_JoystickNumButtons(joy); i++)
{
if(SDL_JoystickGetButton(joy, i))
{
r = 255 - r;
g = 255 - g;
b = 255 - b;
break;
}

//limpar a tela
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 50,

100));

//desenhar um quadrado
SDL_FillRect(screen, &my_rect, SDL_MapRGB(screen->format, r, g,

b));

//lemos o joystick diretamente, ento no processar seus eventos


while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
running = 0;
}
}
}

SDL_Flip(screen);

SDL_Quit();
return 0;
}

Temporizadores (Timers)
As duas funes abaixo no requerem que se passe SDL_INIT_TIMER na inicializao.
Uint32 SDL_GetTicks(void);
void SDL_Delay(Uint32 ms);
SDL_GetTicks retorna a quantidade de milissegundos decorridos desde a inicializao da
biblioteca. Voc pode usar isso, por exemplo, para descobrir quantos milissegundos um frame
tomou. SDL_Delay, por sua vez, espera ms milissegundos antes de retornar. Por exemplo, para
aguardar ("enrolar" o programa) por 1 segundo, chame SDL_Delay(1000); . Observe que o valor
retornado por SDL_GetTicks volta a zero ("d a volta") se o programa rodar por mais de 48 dias.

Alm disso, SDL_Delay garante uma espera de no mnimo o valor passado, geralmente um pouco
mais; e a resuloo do timer do sistema por volta de 10ms. Ou seja, se voc quer esperar x
milissegundos, passe o mltiplo de 10 mais prximo abaixo. Exemplo: quero esperar por 33 ms.
Chamo SDL_Delay(30); que provavelmente esperar algum tempo entre 30-40 ms.
As prximas funes lidam com temporizadores em si. Um temporizador (timer) , basicamente,
um agendamento. Um temporizador criado, agendando uma certa funo para ser chamada depois
de um certo tempo. Estas funes precisam de SDL_INIT_TIMER.
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback
callback, void *param);
SDL_bool SDL_RemoveTimer(SDL_TimerID id);
Use SDL_AddTimer para criar um novo temporizador. A funo callback ser chamada daqui a
interval milissegundos (e poder ser chamada novamente mais tarde, explicado adiante), e para ela
ser repassada a varivel param. Esta um ponteiro para qualquer coisa que voc julgue til ou
necessria para utilizao na funo callback, ou pode simplesmente ser NULL; o valor ser
simplesmente copiado. A funo retorna um SDL_TimerID que identifica seu temporizador--o
funcionamente interno deste tipo irrelevante--voc soment o usar em SDL_RemoveTImer mais
tarde (provavelmente na deinicializao) para cancelar seu temporizador. Observe o formato da
funo callback:
Uint32 callback_func(Uint32 interval, void *param);
Claro que voc pode dar o nome que quiser sua funo, mas ela deve retornar Uint32 e tomar
estes parmetros. interval conter o intervalo de tempo decorrido desde a ativao do timer ou a
ltima vez que a funo foi chamada (inicialmente, o valor passado a SDL_AddTimer). param,
como dito anteriormente, uma cpia do valor passado a SDL_AddTimer. O que mais importa,
entretanto, o valor de retorno (ou seja, o valor que a sua funo retornar)--ele indica o intervalo
de tempo at a prxima chamada. Se voc quiser um temporizador que seja chamado a intervalos
regulares, simplesmente retorne interval.

Utilizando udio com SDL_mixer


A prpria SDL prov maneiras de se trabalhar com som, mas em um nvel muito baixo
(preenchimento de um buffer de sada atravs de uma funo callback), ento usaremos a biblioteca
auxiliar SDL_mixer, que trabalha de uma maneira bem mais intuitiva. Observe que a biblioteca
SDL_mixer no ser explicada em sua totalidade nem com muita riqueza de detalhes--queremos
apenas o suficiente para suprir as deficincias da SDL, ou seja, tocar arquivos de som e msicas
sem muitas firulas.

Instalando
Visite http://www.libsdl.org/projects/SDL_mixer/ e baixe a verso de desenvolvimento mais recente
para o seu sistema. No Linux, a melhor opo geralmente baixar o pacote, enquanto no Windows
com MinGW sua melhor opo baixar o ZIP de desenvolvimento para Visual C++ (SDL_mixerdevel-x.y.z-VC8.zip) e copiar as pastas include e lib sobre as respectivas no MinGW. Para compilar
ento, apenas adicione -lSDL_mixer linha de comando padro para compilar programas em SDL;

no Windows:
gcc ex1.c -o ex1.exe -Wall -lmingw32 -lSDLmain -lSDL -lSDL_mixer
E no GNU/Linux:
gcc ex1.c -o ex1 -Wall `sdl-config --cflags --libs` -lSDL_mixer
Finalmente, em todos os arquivos onde vocs desejar utilizar funes da biblioteca SDL_mixer,
necessrio incluir o header adequado:
#include <SDL_mixer.h>

Inicializao e tratamento de erros


Observe que, antes de poder usar SDL_mixer, preciso passar SDL_INIT_AUDIO para SDL_Init
ou SDL_InitSubsystem.
int Mix_OpenAudio(int frequency, Uint16 format, int channels, int
chunksize);
int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels);
void Mix_CloseAudio();
A funo Mix_OpenAudio inicializa a biblioteca SDL_mixer e deve ser chamada antes de se
utilizar qualquer outra, e aps SDL_Init. Existem constantes definidas pela biblioteca como valor
padro que podem ser passadas a a alguns dos parmetos abaixo. Explicando os parmetros:
- frequency: A frequncia da onda sonora de sada (aps a mixagem final), em Hertz. 44100
qualidade de CD, 22050 qualidade de fita K7. Em geral use 44100 se puder, ou 22050 para ganhar
mais eficincia (a custo da qualidade do som). Padro: MIX_DEFAULT_FREQUENCY (22050).
- format: O formato em que cada amostra armazenada. Isto engloba se as amostras tero sinal
(signed) ou no (unsigned), se tero 8 ou 16 bits, e caso tenham 16, se os dois bytes sero
armazenados em little-endian ou big-endian (para mais detalhes sobre endianness, veja aqui, em
ingls). Em geral, o que importa mais o tamanho da amostra, ou seja, 8 ou 16 bits, que influem na
qualidade do som. Alm disso, geralmente voc usar amostras com sinal. Ento, se quiser 8 bits
(bixa qualidade, mais velocidade) use AUDIO_S8, e se quiser 16 bits (alta qualidade, menos
velocidade) use AUDIO_S16SYS (16 bits com a mesma endianness do sistema hospedeiro).
Padro: MIX_DEFAULT_FORMAT (AUDIO_S16SYS).
- channels: Nmero de canais de sada. Passe 1 para mono ou 2 para estreo.
- chunksize:: Tamanho do buffer de sada. Valores entre 1024 e 4096 (1KB e 4KB, respectivamente)
so uma boa faixa. Se este valor for muito grande, a reproduo poder ficar atrasada, e se for muito
pequeno, o som poder "engasgar". 4096 um valor bem adequado para 16-bits e 44100 hz.
Em geral, uma boa chamada de inicializao (para alta qualidade de som estreo) seria:
Mix_OpenAudio(44100, MIXER_DEFAULT_FORMAT, 2, 4096);
Aps ter inicializado o som, voc pode chamar Mix_QuerySpec para descobrir quais foram os
valores passados na inicializao, passando endereos (ponteiros) como parmetros para
Mix_QuerySpec--cada valor retornado corresponde ao seu homnimo em Mix_OpenAudio.
Exemplo:

int freq, fmt, chan;


Mix_QuerySpec(&freq, &fmt, &channels);
printf("O som foi inicializado em %d Hz, formato = %d em modo
%s.\n", freq, fmt, (chan == 1 ? "mono" : "estereo"));
Adicionalmente, voc pode chamar Mix_CloseAudio() a qualquer momento para deinicializar o
udio. Provavelmente voc far isto ao final do seu programa, mas esta funo pode ser til tambm
para inicializar novamente o sistema de som com configuraes diferentes (por exemplo, estreo em
vez de mono).
char *Mix_GetError();
Voc pode utilizar Mix_GetError para ter um string com a descrio do ltimo erro ocorrido dentro
da biblioteca SDL_mixer--o seu uso anlogo a SDL_GetError (vide seo respectiva).

Carregando arquivos de som


Mix_Chunk *Mix_LoadWAV(char *file);
int Mix_VolumeChunk(Mix_Chunk *chunk, int volume);
void Mix_FreeChunk(Mix_Chunk *chunk);
Um Mix_Chunk, como chamado pela biblioteca, o que chamaremos de "som" daqui em diante-representa um arquivo de som (tipo wave) carregado na memria. Sendo assim, para carregar um
som do disco e armazen-lo em uma estrutura Mix_Chunk basta utilizar a funo Mix_LoadWAV
passando um caminho absoluto ou relativo indicando onde est seu arquivo, em formato .wav ou
.voc. Aps carregado, voc pode alterar o volume de um som previamente carregado utilizando a
funo Mix_VolumeChunk (que toma como parmetros um ponteiro para o som e o volume
desejado, entre 0 e MIX_MAX_VOLUME = 128). Desta forma, sempre que este som for tocado ele
o ser com o volume especificado, combinado com o volume geral do canal de sada. Aps ter
terminado com um som (geralmente ao fim do seu programa, mas poderia ser, por exemplo, ao fim
de uma fase), voc deve liber-lo com Mix_FreeChunk, passando seu respectivo ponteiro. Exemplo
de utilizao segue abaixo. Observe que no preciso se preocupar com os ponteiros, basta apenas
declarar sua varivel como um ponteiro e pass-la a todas as funes, assim como uma
SDL_Surface:
Mix_Chunk* boom_snd = Mix_LoadWAV("boom.wav"); /* supondo que
boom.wav esteja na pasta do seu programa */
Mix_VolumeChunk(boom_snd, 64); /* quero que ele toque com meio
volume */
/* seu programa rodando e tocando o som... */
Mix_FreeChunk(boom_snd); /* liberando na sada... */

Trabalhando com canais e tocando sons


Para tocar sons com SDL_mixer, voc precisa alocar canais de sada. Estes funcionam

analogamente a uma mesa de som: voc tem vrios canais com uma entrada (por exemplo, um
microfone, ou no caso, uma estrutura de som), atributos (volume, efeitos) e uma sada. As sadas
sero combinadas pela biblioteca para gerar a sada final que ser tocada.
int Mix_AllocateChannels(int numchans);
int Mix_Volume(int channel, int volume);
Antes de poder tocar algum som, precisamos definir quantos canais de sada desejamos. Para isso,
basta usar a funo Mix_AllocateChannels, passando o nmero de canais desejado. Aps isto,
podemos definir o volume da sada de um canal especfico com Mix_Volume, passando o nmero
do canal e o volume desejado. Observe que os canais comeam a ser contados em zero, e passando
-1 como canal significa que o volume de todos os canais ser ajustado. Alm disso, volume varia
entre 0 (mudo) e MIX_MAX_VOLUME(128 - mximo).
int Mix_PlayChannel(int channel, Mix_Chunk *chunk, int loops);
int Mix_FadeInChannel(int channel, Mix_Chunk *chunk, int loops,
int ms);
Utilize a funo Mix_PlayChannel para tocar um som em um determinado canal, sem fade-in
(comeando com volume mximo). Observe que cada canal s pode tocar um som de cada vez, ou
seja, ao mandar tocar um som em um canal, se outro estiver em execuo no momento, esta ser
interrompida. Passe o canal desejado em channel (ou -1 para o primeiro canal disponvel), o
ponteiro para o som desejado (previamente carregado) em chunk e em loops o nmero de vezes que
o som ser tocado aps a primeira (ou seja, 0 toca uma vez, 1 toca duas vezes, e assim por diante).
Passe -1 para tocar para sempre.
Da mesma forma, utilize a funo Mix_FadeInChannel para tocar um som com um aumento
gradual de volume (fade-in). Alm dos parmetros anlogos a Mix_PlayChannel, ms indica o
nmero de milissegundos que ir durar o efeito (tempo at o volume chegar a a 100%).
void Mix_Pause(int channel);
void Mix_Resume(int channel);
int Mix_HaltChannel(int channel);
int Mix_FadeOutChannel(int channel, int ms);
Utilize as funes Mix_Pause e Mix_Resume para pausar e "despausar" (voltar a tocar) um canal
(channel). Analogamente, Mix_HaltChannel para parar completamente a reproduo de um certo
canal, e Mix_FadeOutChannel para fazer um canal parar gradualmente (diminuindo o volume),
sendo que ele ir demorar ms milissegundos para parar completamente. Para todas estas, passe -1
em channel para afetar a todos os canais.
int Mix_Playing(int channel);
int Mix_Paused(int channel);
As funes Mix_Playing e Mix_Paused retornam se em um canal h um som sendo tocado no
momento, e se ele est pausado, respescitvamente. Observe que se voc pausar um canal com
Mix_Pause, e depois interromp-lo com Mix_HaltChannel, Mix_Paused ainda retornar 1
(verdadeiro). Passando -1 em channel retornar quantos canais esto tocando, ou pausados.

Trabalhando com msica


No preciso reservar canais para tocar msica; em uma essncia, h um nico canal sempre
reservado para tocar msicas. Uma msica representada por um ponteiro para Mix_Music. Os
formatos de msica suportados por SDL_mixer so Ogg Vorbis (.ogg), MPEG-1 Layer 3 (.mp3),
.mod, .s3m, .it, .xm e MIDI (.mid). Para tocar MIDI, preciso instalar os arquivos contidos neste
link em /usr/local/lib/ em sistemas Unix/Linux, ou C:\ em sistemas Windows.
Mix_Music *Mix_LoadMUS(const char *file);
void Mix_FreeMusic(Mix_Music *music);
Carregue uma msica do arquivo file para um ponteiro Mix_Music com a funo Mix_LoadMUS.
Quando tiver terminado de us-la (provavelmente ao fim do programa), chame Mix_FreeMusic
para liberar os recursos alocados.
int Mix_PlayMusic(Mix_Music *music, int loops);
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms);
int Mix_VolumeMusic(int volume);
Chame Mix_PlayMusic para tocar uma msica previamente carregada em music, repetida loops
vezes (analogamente a sons: 0 significa uma reproduo, 1 duas, etc, e -1 infinitamente). Chame
Mix_FadeInMusic com os parmetros anlogos a Mix_PlayMusic para iniciar uma msica com
efeito de fade-in (volume aumentando gradualmente), sendo que a msica levar ms milissegundos
para atingir seu volume total. Chame Mix_VolumeMusic para ajustar o volume de sada da msica
(lembrando que s um canal). Os volumes variam entre 0 e MIX_MAX_VOLUME(128). Passe -1
para retornar o volume atual.
void Mix_PauseMusic();
void Mix_ResumeMusic();
void Mix_RewindMusic();
Chame Mix_PauseMusic para pausar uma msica, certificando-se que ela est em execuo, e
Mix_ResumeMusic para que ela volte a tocar. Chame Mix_RewindMusic para retornar a msica ao
incio, observando que isto s funciona para MOD, OGG, MP3 e MIDI.
int Mix_HaltMusic();
int Mix_FadeOutMusic(int ms);
Mix_HaltMusic pra a msica tocando atualmente. Mix_FadeOutMusic a faz parar gradualmente,
diminuindo o volume, sobre um tempo de ms milissegundos.
int Mix_PlayingMusic();
int Mix_PausedMusic();
Mix_PlayingMusic retorna se h uma msica tocando (ainda que pausada), e Mix_PausedMusic
retorna se h uma msica pausada (ainda que tenha sido parada enquanto pausada).

Carregando imagens com SDL_image


A SDL prov uma funo para carregar imagens em formato BMP--mas este formato tem vrias

limitaes, principalmente seus arquivos geralmente serem grandes por no serem comprimidos,
alm de falta de suporte a transparncias, etc. Temos ento a biblioteca SDL_image, que consiste
basicamente de uma funo chamada IMG_Load, que carrega um arquivo em formato TGA, BMP,
PNM, XPM, XCF, PCX, GIF, JPG, TIF, LBM ou PNG diretamente para uma SDL_Surface, assim
como SDL_LoadBMP.

Instalando
Visite http://www.libsdl.org/projects/SDL_image/ e baixe a verso de desenvolvimento mais recente
para o seu sistema. No Linux, a melhor opo geralmente baixar o pacote, enquanto no Windows
com MinGW sua melhor opo baixar o ZIP de desenvolvimento para Visual C++ (SDL_imagedevel-x.y.z-VC8.zip) e copiar as pastas include e lib sobre as respectivas no MinGW. Para compilar
ento, apenas adicione -lSDL_image linha de comando padro para compilar programas em SDL;
no Windows:
gcc ex1.c -o ex1.exe -Wall -lmingw32 -lSDLmain -lSDL -lSDL_image
E no GNU/Linux:
gcc ex1.c -o ex1 -Wall `sdl-config --cflags --libs` -lSDL_image
Finalmente, em todos os arquivos onde vocs desejar utilizar funes da biblioteca SDL_image,
necessrio incluir o header adequado:
#include <SDL_image.h>

Carregando Imagens
SDL_Surface *IMG_Load(const char *file);
char *IMG_GetError();
Simplesmente utilize IMG_Load, passando um nome de arquivo (caminho absoluto ou relativo)
para obter uma SDL_Surface com o contedo do arquivo, j com transparncias caso o formato as
suporte. Observe que imprescindvel que a extenso do arquivo esteja de acordo com o formato do
arquivo, pois por a que o reconhecimento feito. Alm disso, IMG_GetError retorna um texto
referente ao ltimo erro ocorrido durante uma chamada a IMG_Load (a qual retorna NULL em caso
de erro). Exemplo:
SDL_Surface* pic = IMG_Load("blah.png");
if(pic == NULL)
{
printf("Erro ao carregar a imagem: %s\n", IMG_GetError());
exit(0);
}

esenhando texto com SDL_ttf


Diferentemente de outras bibliotecas, a SDL no prov nativamente nenhuma funcionalidade de

desenho de texto. Para suprir esta deficincia, foi criada a biblioteca auxiliar SDL_ttf, que desenha
um texto (retorna uma SDL_Surface com o texto j renderizado) de acordo com um arquivo de
fonte em formato TTF, o tamanho (altura) em pixels, e um estilo (itlico, negrito, sublinhado).
Alm disso, a renderizao pode ser feita de trs maneiras diferentes:
- Solid (slido): Renderiza o texto para uma superfcie, com uma nica cor. A superfcie retornada
de 8 bits com palheta, sendo que a entrada 0 da palheta a cor de fundo, transparente, e a entrada 1
a cor do texto (de modo que voc pode mudar a cor do texto apenas mudando a entrada da
palheta, sem ter que renderizar novamente). Esta a maneira mais rpida, mas tambm a mais feia.
- Shaded (suave): Desenha o texto sem transparncia, porm suaviza as bordas, provendo-se uma
cor de texto e de fundo. Este modo parece bastante bom, mas precisa masnter fixas as cores do texto
E do fundo para parecer bom (ou seja, a suavizao da borda depende da cor do fundo).
- Blended (mesclado): Cria uma superfcie com canal alpha, e suaviza as bordas com transparncia
parcial por-pixel. Este modo o mais bonito, e tambm o mais demorado--demora tanto quanto o
blended para renderizar, e bem mais para copiar para a tela (pois um blit com alpha). Outra
desvantagem uqe voc no poder utilizar um valor de alpha geral na superfcie gerada (pois ela j
conter valores alpha por-pixel).
Observe tambm que esta biblioteca no ser explorada exaustivamente nesta referncia, apenas as
partes mais necessrias para a renderizao propriamente dita.

Instalando
Visite http://www.libsdl.org/projects/SDL_ttf/ e baixe a verso de desenvolvimento mais recente
para o seu sistema. No Linux, a melhor opo geralmente baixar o pacote, enquanto no Windows
com MinGW sua melhor opo baixar o ZIP de desenvolvimento para Visual C++ (SDL_ttfdevel-x.y.z-VC8.zip) e copiar as pastas include e lib sobre as respectivas no MinGW. Para compilar
ento, apenas adicione -lSDL_ttf linha de comando padro para compilar programas em SDL; no
Windows:
gcc ex1.c -o ex1.exe -Wall -lmingw32 -lSDLmain -lSDL -lSDL_ttf
E no GNU/Linux:
gcc ex1.c -o ex1 -Wall `sdl-config --cflags --libs` -lSDL_ttf
Finalmente, em todos os arquivos onde vocs desejar utilizar funes da biblioteca SDL_image,
necessrio incluir o header adequado:
#include <SDL_ttf.h>

Inicializao e tratamento de erros


int TTF_Init();
void TTF_Quit();
char *TTF_GetError();
Voc deve chamar TTF_Init antes de qualquer outra funo da biblioteca, para inicializ-la; ela
retorna -1 em caso de erro. No necessrio inicializar a SDL antes disso. Por outro lado, antes do

fim do programa deve-se chamar TTF_Quit para fazer a deinicializao e liberao de recursos
adequada. Por fim, TTF_GetError retorna um ponteiro para uma mensagem de erro referente ao
ltimo erro ocorrido (use-a caso alguma funo retorne um erro). Exemplo:
if(TTF_Init() == -1)
{
printf("Cus, erro ao abrir SDL_ttf: %s\n", TTF_GetError());
exit(0);
}

Gerenciando fontes
O que chamaremos de "fonte" daqui em diante se refere a um ponteiro para TTF_Font, uma
estrutura que representa uma fonte carregada de um arquivo, juntamente com seus atributos. Ou
seja, uma "fonte" carregada de times.ttf com tamanho 10 e negrito no a mesma que uma outra
carregada de times.ttf com tamanho 10 plana, ou outra carregada de times.ttf com tamanho 14 e
itlico. Se voc deseja utilizar tamanhos e estilos variados em seu programa, deve carregar uma
fonte para cada caso.
TTF_Font *TTF_OpenFont(const char *file, int ptsize);
void TTF_CloseFont(TTF_Font *font);
TTF_OpenFont retorna para voc uma nova fonte, carregada do arquivo file, com tamanho ptsize;
posteriormente veremos como adicionar um ou mais estilos a ela. Aps terminar de usar uma fonte
(provavelmente ao fim do programa), chame TTF_CloseFont para liberar a memria relativa a ela.
int TTF_GetFontStyle(TTF_Font *font);
void TTF_SetFontStyle(TTF_Font *font, int style);
Estilos de fonte suportados por SDL_ttf so itlico, negrito e sublinhado. Uma combinao de
estilos simplesmente uma varivel do tipo int, representando um ou-binrio dos seguintes valores:
TTF_STYLE_ITALIC, TTF_STYLE_BOLD e TTF_STYLE_UNDERLINE, representando itlico,
negrito e sublinhado respectivamente. O conjunto de estilos atual de uma fonte font guardado em
sua estrutura e pode ser lido com TTF_GetFontStyle e setado com TTF_SetFontStyle (passando-se
um ou-binrio dos estilos em style).

Renderizando
SDL_Surface *TTF_RenderText_Solid(TTF_Font *font, const char
*text, SDL_Color fg);
SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font, const char
*text, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderText_Blended(TTF_Font *font, const char
*text, SDL_Color fg);
As funes acima retornam uma superfcie pronta com o texto text renderizado, dependendo da
funo, em modo solid, shaded ou blended, com a cor fg.

Exemplo de utilizao
#include <SDL.h>
#include <SDL_ttf.h>
TTF_Font* my_font;
#define FONTSIZE 18
void desenha_texto(char* texto, SDL_Surface* dst, int x, int y);
int main(int agc, char** argv)
{
SDL_Surface* screen;
SDL_Init(SDL_INIT_VIDEO);
if(TTF_Init() == -1) return -1;
my_font = TTF_OpenFont("myfont.ttf", FONTSIZE);
screen = SDL_SetVideoMode(640, 480, 16, SDL_DOUBLEBUF);
desenha_texto("Hello, world!", screen, 250, 100);
TTF_SetFontStyle(my_font, TTF_STYLE_ITALIC);
desenha_texto("Hello, italic world!", screen, 250, 300);
SDL_Flip(screen);
SDL_Delay(5000); //espera 5 segundos
TTF_Quit();
SDL_Quit();
return 0;
}
void desenha_texto(char* texto, SDL_Surface* dst, int x, int y)
{
SDL_Color cor = {255, 0, 0}; //vermelho
SDL_Surface* src = TTF_RenderText_Blended(my_font, texto, cor);
SDL_Rect dst_rect = {x, y, 0, 0};
SDL_BlitSurface(src, NULL, dst, &dst_rect);
SDL_FreeSurface(src);
}

Potrebbero piacerti anche