Entries from junho 2007 ↓

Mario Theft Auto


[adultswim] domina.

“Hello World!” na SDL

Depois de configurarmos a SDL, está na hora de começar a parte divertida: usá-la!

Para isto, vamos começar com o clássico Hello World!. Ao final do tutorial teremos algo parecido com isto:

Hello World!

Este código foi feito pelo Lazy Foo. Modificado e traduzido por mim.
Então, vamos começar. Abra seu editor preferido.

1
2
3
#include "SDL/SDL.h"
#include <string>
using std::string;

Aqui só incluímos os headers que iremos utilizar. No caso, SDL e String.

4
5
6
7
//Constantes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

Nesta parte setamos as contantes de, respectivamente, o comprimento, altura, e bpp(bytes per pixel) da tela. Usarmos um BPP com 32 significa que além dos valores de vermelho, verde e azul(RGB), também temos o valor da claridade(alpha) de cada pixel.

8
9
10
//Superficies utilizadas
SDL_Surface *tux = NULL;
SDL_Surface *tela = NULL;

Aqui setamos dois ponteiros para os SDL_Surface que iremos utilizar. SDL_Surface é uma estrutura que representa uma área onde nós poderemos desenhar. Imagine-a como um pedaço de papel em branco, até agora.

12
13
14
15
16
17
18
19
//Feito por Lazy Foo
SDL_Surface *load_image( string filename )
{
	//Variável temporária para a imagem que será carregada
	SDL_Surface* loadedImage = NULL;
 
	//Imagem otimizada para o BPP da tela
	SDL_Surface* optimizedImage = NULL;

Esta é a nossa função para carregar uma imagem.
Ela recebe o caminho para a imagem e retorna um ponteiro para um SDL_Surface contendo uma versão otimizada da imagem.
A variável loadedImage é aonde nós iremos carregar temporariamente a imagem que está em filename. optimizedImage é a versão otimizada da imagem.

20
21
	//Carrega a imagem
	loadedImage = SDL_LoadBMP( filename.c_str() );

Aqui nós carregamos a imagem para loadedImage.
Nós não devemos utilizá-la agora pois ela tem 24 bits, e nossa tela tem 32 bits. Devemos evitar blitar(é como "colar" uma superfície em cima da outra) uma superfície em outra que tenha um BPP diferente, pois a SDL terá que convertê-la antes disso, o que irá tornar o jogo mais lento.

22
23
24
25
26
27
28
29
30
	//Se não houveram problemas carregando a imagem
	if( loadedImage != NULL )
	{
		//Cria uma imagem otimizada
		optimizedImage = SDL_DisplayFormat( loadedImage );
 
		//Libera a imagem antiga
		SDL_FreeSurface( loadedImage );
}

Primeiro checamos se ele carregou sem erros a imagem. Se sim, criamos uma versão otimizada da mesma. A função SDL_DisplayFormat() recebe como parâmetro um SDL_Surface* e retorna outro SDL_Surface* com o mesmo BPP da tela.
Depois de termos a imagem otimizada, não precisamos mais da loadedImage, então a liberamos através da SDL_FreeSurface().

31
32
33
	//Retorna a imagem otimizada
	return optimizedImage;
}

Retornamos a versão otimizada da imagem.

34
35
36
37
38
39
40
41
//Feito por Lazy Foo
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
	//Cria um SDL_Rect temporário para guardar as coordenadas para onde blitar a imagem
	SDL_Rect offset;
	//Salva as coordenadas no SDL_Rect
	offset.x = x;
	offset.y = y;

Esta é nossa função para blitar superfícies.
Ela recebe as coordenadas da onde você quer blitar a superfície, qual a superfície que você quer blitar, e em qual superfície você quer blitá-la.
Para isso, primeiro nós colocamos as coordenadas em um SDL_Rect, que é uma estrutura bem simples, com somente quatro elementos: as coordenadas x e y, o comprimento(w) e a altura(h). Fazemos isso pois o método que iremos utilizar, SDL_BlitSurface() só aceita as coordenadas dentro de um SDL_Rect.

42
43
44
	//Blita a superfície
	SDL_BlitSurface( source, NULL, destination, &offset );
}

Aqui nos blitamos a superfície com a função SDL_BlitSurface().
Ela recebe quatro parâmetros: a superfície que você quer blitar; a parte da superfície que você quer blitar(bom para sprites, mas, como queremos que ele envie a imagem inteira, usamos NULL); a superfície onde você quer blitar; o endereço do SDL_Rect com as coordenadas da onde blitar.

45
46
47
//Início do main
int main (int argc, char* args[])
{

Finalmente iniciamos a main. Quando usar a SDL você tem que ter cuidado para só usar a main assim como usamos ou

int main (int argc, char** args)

Qualquer outro jeito não irá funcionar.

48
49
50
51
52
	// Inicializamos a SDL e todos seus subsistemas
	if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
	{
	return 1;
	}

Aqui inicializamos a SDL pela função SDL_Init(). Passamos SDL_INIT_EVERYTHING para ele iniciar todos os subsistemas, como audio, vídeo, timers, etc..
Caso ela não consiga inicializar, a função irá retornar -1, e nós sairemos do programa com o código de erro 1.

53
54
	//Inicializa a tela
	tela = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

A função SDL_SetVideoMode() cria nossa tela com o tamanho, altura, bpp especificados. O último parâmetro são as flags da tela. Como, por exemplo, se usaremos OpenGL, a memória da placa-de-vídeo, etc. Aqui nós criamos a tela na memória do sistema.

55
56
57
58
59
	//Se houve algum erro na inicialização da tela
	if (tela == NULL)
	{
	return 1;
	}

Caso a SDL não tenha conseguido inicializar a tela, paramos a execução com o código de erro 1.

60
61
	//Muda o nome da janela
	SDL_WM_SetCaption( "Hello World", NULL );

Mudamos o nome da janela para Hello World. O segundo parâmetro da função é para o nome do ícone, que não usaremos.

62
63
	//Pinta a tela de branco
	SDL_FillRect(tela, NULL, 0xFFFFFFFF);

Usamos a função SDL_FillRect() para pintar a tela de branco. Esta função recebe como parâmetros a superfície que você quer pintar, um SDL_Rect*, caso você queira pintar só uma parte da superfície, e a cor, em RGBA, para pintar.

64
65
	//Carrega a imagem
	tux = load_image("tux.bmp");

Carregamos a imagem do tux usando a função load_image() do Lazy Foo.

66
67
	//Aplicamos o Tux à tela
	apply_surface( 180, 140, tux, tela );

Aplicamos, ou blitamos, o tux a tela usando a função apply_surface() do Lazy Foo.
Lembre-se que na SDL, como na maioria dos lugares em computação, a coordenada y é diferente da matemática. Ela cresce de cima para baixo, ao invés de ser de baixo pra cima.

68
69
70
71
72
	//Atualiza a tela
	if (SDL_Flip(tela) == -1)
	{
	return 1;
	}

Até agora nós só estavamos escrevendo no buffer. As imagens só são mostradas quando chamamos o método SDL_Flip() com a superfície que queremos atualizar. Esta função retorna -1 em caso de erro. Nós testamos isso e, caso positivo, paramos a execução do programa com o código de erro 1.

73
74
	//Para a execução por 5 segundos
	SDL_Delay(5000);

Nós chamamos a função SDL_Delay() para que consigamos ver alguma coisa, caso contrário o programa iria abrir e fechar tão rápido que não veríamos nada. Ele recebe como parâmetro o tempo em milissegundos(um segundo tem 1000 milissegundos) que queremos pausar a execução.

75
76
77
78
79
80
81
82
83
	//Libera a superfície
	SDL_FreeSurface(tux);
 
	//Destrói a SDL
	SDL_Quit();
 
	//Termina a execução
	return 0;
}

Aqui nós limpamos o que usamos durante a execução do programa. Com a função SDL_FreeSurface() nós liberamos a memória das superfícies que usamos. Não precisamos liberar a tela, pois o SDL_Quit() cuida disso.

Baixe os fontes e a imagem deste tutorial aqui.

Configurando a SDL – Windows

Dev-C++
Para configurar a SDL para o Dev-C++ da Bloodshed no Windows, temos duas opções. Podemos ou baixar a LibSDL direto do site dela, onde podemos encontrar os últimos pacotes, ou baixar um arquivo .DevPak, que é um pacote para o Dev-C++ que facilita a instalação de bibliotecas. Vamos ver os dois métodos.

    1. Baixe o pacote para Mingw32, em Development Libraries;
    2. Descompacte o conteúdo da pasta lib para o subdiretório lib do Dev-C++(Por padrão ele fica em C:/Dev-Cpp/lib);
    3. Faça o mesmo com a pasta bin, descompactando-a em C:/Dev-Cpp/bin;
    4. Abra a pasta include no pacote e descompacte a pasta SDL para C:/Dev-Cpp/include/SDL;
    5. Copie o SDL.dll, que está na pasta bin, para C:/Windows/System32;
    6. Abra o Dev-C++ e crie um novo Empty Project indo em File/New/Project/Empty Project;
    7. Vá nas opções do projeto em Project/Project Options;
    8. Escolha o Type para Win32 GUI;
    9. Na mesma tela, abra a aba Parameters e escreva no Linker:

      -lmingw32 -lSDLmain -lSDL

  • Usando o .DevPak
    1. Baixe a Development Package da SDL aqui;
    2. Vá em Tools/Package Manager;
    3. Clique em Install;
    4. Uma tela irá aparecer para você mostrar aonde está o .DevPak;
    5. No Installation Wizard, vá clicando em Next até ele instalar o pacote;
    6. Depois de instalado, crie um novo Empty Project indo em File/New/Project/Empty Project;
    7. Deve haver uma nova aba SDL, crie um projeto deste tipo.

Agora você já deve ter o Dev-C++ configurado para compilar usando a SDL. Para testar, adicione um novo arquivo ao projeto, indo em File/New/Source File e clicando em Yes na caixa de diálogo que irá aparecer, copie e tente compilar o seguinte código nele:

1
2
3
4
5
6
7
8
9
10
11
12
// Inclui o header da SDL
#include "SDL/SDL.h"
 
int main(int argc, char* args[]) {
	// Inicia todos os subsistemas da SDL
	SDL_Init(SDL_INIT_EVERYTHING);
 
	// Destrói a SDL
	SDL_Quit();
 
	return 0;
}

Como esperado, ele deve abrir uma janela e, instantâneamente, fechá-la. Se ocorreu tudo bem, ótimo! Aguarde o próximo artigo. Se não, tente refazer os passos para ver se você não esqueceu de nada. Se, mesmo assim, não conseguir, dê uma lida no FAQ oficial para o Windows ou envie um comentário aqui que eu tentarei ajudar.

No próximo artigo iremos fazer nosso “Hello, World!”. Até lá!

Configurando a SDL – Linux

Para configurar a SDL no Linux vamos primeiro baixar a LibSDL. A maioria das distribuições incluem a libsdl nos seus repositórios. No caso do Gentoo basta usar, como root:

emerge libsdl

Já no Ubuntu, usamos:

apt-get install libsdl1.2-dev

Para o Fedora e o Debian há um link na página de downloads da SDL. Baixe as Development Libraries.

Caso você não consiga encontrar um pacote nos repositórios da sua distribução, terá de baixar e compilar os fontes. Infelizmente, nesta tarefa não poderei ajudar, mas não deve ser muito complicado.

Iremos agora ver como compilar pelo Anjuta e no shell.

Anjuta Logo
Anjuta

  1. Abra o Anjuta e crie um novo projeto indo em File/New Project;
  2. No wizard, escolha Generic/Terminal Project;
  3. Nesta tela só precisamos nos preocupar na opção Programming Language, que deve estar em C++;
  4. Quando o wizard terminar de configurar o nosso projeto, vá em Settings/Compiler and Linker Settings;
  5. Na orelha Libraries, escreva SDL no campo de texto e clique em Add. Feche esta janela;
  6. Irá aparecer uma caixa de diálogo, clique em Yes.

Pronto, seu Anjuta está configurado corretamente. Siga até o final deste artigo e tente compilar o programa-teste para checar se está tudo certo.

Shell
Shell

  1. Compile usando

    g++ -o programa programa.cpp -lSDL

Para testar se a configuração está funcionando, tente compilar o seguinte programa:

1
2
3
4
5
6
7
8
9
10
11
12
// Inclui o header da SDL
#include "SDL/SDL.h"
 
int main(int argc, char* args[]) {
	// Inicia todos os subsistemas da SDL
	SDL_Init(SDL_INIT_EVERYTHING);
 
	// Destrói a SDL
	SDL_Quit();
 
	return 0;
}

Ele deve compilar sem erros, abrir uma tela e, quase que instantâneamente, fechá-la. Se tudo ocorreu como o esperado, ótimo! Se não, volte e refaça todos os passos, cheque se a SDL está instalada no diretório padrão e, se mesmo assim não funcionar, procure seu problema no FAQ oficial para o Linux ou escreva um comentário aqui que tentarei ajudar.

No próximo artigo irei explicar como configurar a SDL no Windows. Até mais.

O que é a SDL?

SDL Simple DirectMedia Layer

Simple DirectMedia Layer é uma biblioteca multiplataforma feita para prover acesso de baixo nível ao áudio, teclado, mouse, joystick, aceleração 3D por hardware(via OpenGL), e framebuffer de vídeo 2D. Ele é usado por reprodutores de MPEG, emuladores, e vários jogos populares, incluindo o premiado port para Linux do “Civilization: Call To Power”.

A SDL suporta Linux, Windows, Windows CE, BeOS, MacOS, Mac OS X, FreeBSD, NetBSD, OpenBSD, BSD/OS, Solaris, IRIX, e QNX. O código contêm suporte para AmigaOS, Dreamcast, Atari, AIX, OSF/Tru64, RISC OS, SymbianOS, e OS/2, mas estes não são suportados oficialmente.

Ela é escrita em C, mas funciona nativamente com C++, e tem bindings para diversas outras linguagens, incluindo Ada, C#, Eiffel, Erlang, Euphoria, Guile, Haskell, Java, Lisp, Lua, ML, Objective C, Pascal, Perl, PHP, Pike, Pliant, Python, Ruby, e Smalltalk.

A biblioteca é distribuida sob a GNU LGPL versão 2. Esta licensa permite que você use a SDL livremente em jogos comerciais, contanto que você ligue dinâmicamente com a biblioteca.

Como você pôde notar pela descrição acima, traduzida diretamente do site oficial da SDL, ela é uma biblioteca extremamente poderosa. Não acredita? Pois é a mais pura verdade!

Este é o primeiro post de uma série de artigos onde pretendo ensinar como programar usando a SDL e C++. Ao final teremos feito, a partir do zero, um clone do Pong.

No próximo artigo irei mostrar como configurar sua IDE para usar a SDL. Até mais.