Tutorial SDL
Tutorial sobre a biblioteca SDL com exemplos práticos.
Parte 2: Aplicação básica
Uma janela
Agora, vamos criar uma aplicação básica em SDL. Ela mostrará uma janela simples e como iniciar/fechar o SDL e, após alguns segundos, fechará.Arquivo: janela_01.c
#include <SDL/SDL.h> // Inclui a biblioteca SDL
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
Para compilar:
gcc -o janela_01 janela_01.c -lSDL
Onde:
- #include <SDL/SDL.h> :: "include a biblioteca SDL. Em SDL.h", estão todos os headers que precisamos.
- SDL_Init(SDL_INIT_VIDEO); :: inicializa o SDL e o subsistema de vídeo. É possível inicializar mais subsistemas com essa função. Por enquanto, apenas o subsistema de vídeo é o bastante pra esse tutorial.
- SDL_Surface * screen; :: declara uma SDL_Surface para a janela principal.
- screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); :: cria uma janela com largura de 640 e altura 480 com 16 bits de profundidade. A flag SDL_SWSURFACE indica que a janela será criada na memória RAM, há outra flag que usa a memória de vídeo (SDL_HWSURFACE) para outras flags digite man SDL_SetVideoMode no terminal. Se ocorrer erro na criação da janela, será retornado NULL, caso contrário, será retornado um ponteiro para uma surface (janela principal).
- SDL_Delay(5000); :: SDL_Delay faz o programa parar por um tempo determinado. O tempo de espera é um número inteiro e positivo. Geralmente, 10 milissegundos é o bastante para um loop principal.
- SDL_Quit(); :: essa função deve ser chamada sempre que o programa for terminar. Ela encerra o SDL liberando as SDL_Surfaces alocadas e fechando todos os subsistemas antes inicializados.
Uma janela com imagem
Arquivo: janela_02.c
#include <SDL/SDL.h>
#include <stdio.h>
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
SDL_Surface * image; // A imagem
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
image = SDL_LoadBMP("ball.bmp"); // Carrega a imagem no formato BMP
// Verifica se carregou a imagem corretamente
if (image == NULL)
{
printf("Não foi possivel abrir ball.bmp\n");
return 1;
}
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, NULL); // Joga a imagem na tela
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
#include <stdio.h>
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
SDL_Surface * image; // A imagem
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
image = SDL_LoadBMP("ball.bmp"); // Carrega a imagem no formato BMP
// Verifica se carregou a imagem corretamente
if (image == NULL)
{
printf("Não foi possivel abrir ball.bmp\n");
return 1;
}
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, NULL); // Joga a imagem na tela
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
Para compilar:
gcc -o janela_02 janela_02.c -lSDL
No SDL, as imagens também são SDL_Surface (e ponteiros). Para declarar uma imagem em SDL, basta usar o tipo SDL_Surface:
SDL_Surface * nome_da_variável;
Por padrão, o SDL só carrega imagens no formato BMP, se quiser carregar em PNG, por exemplo, precisará usar outra biblioteca auxiliar (SDL_image). Por enquanto, vou usar apenas o padrão SDL.
De forma geral, para carregar uma imagem, use:
SDL_Surface * nome_da_variável = SDL_LoadBMP("caminho_para_o_arquivo.bmp");
SDL_LoadBMP retorna um ponteiro SDL_Surface, ou NULL, se não conseguir carregar o arquivo. O parâmetro "caminho_para_arquivo.bmp", é o caminho completo para o arquivo de imagem em formato BMP. Toda surface possui largura(w de width) e altura(h de height).
Para acessá-los, use:
nome_da_variável->w para largura e nome_da_variável->h para altura
SDL_FillRect(screen, NULL, 0x0); :: pinta de preto todo o screen.
SDL_BlitSurface(image, NULL, screen, NULL); :: essa função joga uma imagem (ou parte dela) em cima de outra SDL_Surface. O primeiro parâmetro image, é a surface de origem.
O segundo parâmetro NULL é o clip, como ele é nulo, toda a imagem será usada como clip, com ele poderia usar um SDL_Rect para pegar uma parte interna da imagem e jogar no screen.
O terceiro parâmetro screen é a SDL_Surface de destino, é onde será jogada a imagem.
O quarto parâmetro é o destino da imagem dentro da SDL_Surface de destino (o screen). Com esse parâmetro, é possível alterar a posição de image dentro do screen. Como ele, é nulo significa que a image será jogada no destino x = 0 e y = 0. Veremos mais a frente mais informação sobre ele.
SDL_UpdateRect(screen, 0,0,0,0); :: atualiza o screen inteiro. Sempre é preciso atualizar o screen quando se "blita" uma imagem. Mas, não é necessário atualizar todo o screen, poderia atualizar somente uma parte dele, onde se blitou/colocou a imagem. Para mais informações sobre essa função use man SDL_UpdateRect no terminal.
Blitando uma imagem em várias posições
No SDL, os eixo X e Y são orientados da seguinte maneira:Sendo o canto superior esquerdo da tela, como o ponto (0, 0). A largura e altura da janela são o máximo de visão que se pode ter. Ou seja, se uma imagem estiver além dos limites da altura e largura da janela, não será vista.
Arquivo: janela_03.c
#include <SDL/SDL.h>
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
SDL_Surface * image; // A imagem
SDL_Rect dest; // Destino da imagem
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
image = SDL_LoadBMP("ball.bmp"); // Carrega a imagem no formato BMP
// Verifica se carregou a imagem corretamente
if (image == NULL)
{
printf("Não foi possivel abrir ball.bmp\n");
return 1;
}
// Move a imagem para o ponto X = 0 e Y = 0
dest.x = 0; // Ponto de destino no eixo X
dest.y = 0; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
// Move a imagem para o ponto X = 10 e Y = 15
dest.x = 10; // Ponto de destino no eixo X
dest.y = 15; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
// Move a imagem para o ponto X = 40 e Y = 25
dest.x = 40; // Ponto de destino no eixo X
dest.y = 25; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
int main()
{
SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
SDL_Surface * screen; // A janela principal
SDL_Surface * image; // A imagem
SDL_Rect dest; // Destino da imagem
screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
image = SDL_LoadBMP("ball.bmp"); // Carrega a imagem no formato BMP
// Verifica se carregou a imagem corretamente
if (image == NULL)
{
printf("Não foi possivel abrir ball.bmp\n");
return 1;
}
// Move a imagem para o ponto X = 0 e Y = 0
dest.x = 0; // Ponto de destino no eixo X
dest.y = 0; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
// Move a imagem para o ponto X = 10 e Y = 15
dest.x = 10; // Ponto de destino no eixo X
dest.y = 15; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
// Move a imagem para o ponto X = 40 e Y = 25
dest.x = 40; // Ponto de destino no eixo X
dest.y = 25; // Ponto de destino no exito Y
SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no screen em dest
SDL_UpdateRect(screen, 0,0,0,0); // Atualiza o screen com a imagem blitada
SDL_Delay(5000); // Espera 5000 milissegundos OU 5 segundos
SDL_Quit(); // Fecha o SDL
return 0;
}
Para compilar:
gcc -o janela_03 janela_03.c -lSDL
Observe que, antes da chamada de SDL_BlitSurface, chamei SDL_FillRect para pintar todo o screen de preto. O segundo parâmetro NULL indica que vamos pintar todo o screen com uma cor.
A cor usada no screen é 0x0 em hexadecimal, mas se quiser outra cor, é só usar no lugar de 0x0 SDL_MapRGB(screen->format, "VERMELHO", "VERDE", "AZUL") "VERMELHO", "VERDE" e "AZUL" são números inteiros.
SDL_MapRGB criará uma cor com o valor de "VERMELHO", "VERDE" e "AZUL". Cada cor primária é um número inteiro de 0 até 255, indicando a quantidade de cada cor primária para criar uma cor combinada.
Por exemplo, para pintar todo o screen de amarelo, use (antes de SDL_BlitSurface): SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 0).
SDL_Rect dest; :: essa variável será usada para colocar a image em várias posições diferentes dentro do screen.
Todo SDL_Rect tem 4 membros: x, y, w e h. Os membros x e y são as coordenadas da tela, e o w e h são largura (w de width) e altura (h de height).
Toda vez que mudar a posição da imagem através de dest, será preciso reblitar a imagem no screen.