Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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
}
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
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.
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)
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;
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 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;
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.
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.
constante)
if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
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);
/* ... */
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)
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;
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.
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
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);
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;
+; 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));
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.
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>
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.
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);
}
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>
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);
}