Tutorial SDL2 em português: O Renderer - parte 2
No tutorial anterior vimos como criar uma janela no SDL2 com C++. Agora vamos criar um renderer para desenhar coisas na tela.
O Renderer
Certo, chegou o momento de ver algo mais que uma janela: vamos ver o SDL_Renderer.
No SDL1.2, anterior ao SDL2, não existia render, era tudo feito em cima da janela. Como o SDL2 foi feita uma imensa atualização, passou-se a usar o rendering separado da janela. A grosso modo, uma janela no SDL2 é apenas uma rendering (canvas 2D pra alguns) e a janela propriamente.
Com isso precisamos de duas variáveis: um SDL_Window e um SDL_Renderer para poder mostrar alguma coisa na janela.
Vamos ver com que função criamos um SDL_Renderer, veja abaixo:
SDL_Renderer * SDL_CreateRenderer(SDL_Winddow * janela, int id, Uint32 flags);
Onde:
SDL_Window * janela é a janela que criamos e que será agregada ao renderer para desenhar coisas nela
int id é o id do renderer, aqui é um id que você define como quiser, se for criar mais janelas terá de usar cada renderer com um id diferente
Uint32 flags dessa vez são novas flagas, veja em https://wiki.libsdl.org/SDL_CreateRenderer como cada flag se comporta, pro nosso artigo vamos usar somente o SDL_RENDERER_ACCELERATED, para ativar a aceleração por hardware (usar memória de video)
SDL_Renderer * retorno da função, retorna um ponteiro SDL_Renderer *
O SDL_Renderer serve para desenhar na janela, que antes no SDL1.2, era desenhado direto na janela, agora temos de usar uma estrutura intermediária.
Segue um exemplo bem básico com SDL_Renderer:
//exemplo renderer.cpp
//para compilar: g++ -o renderer renderer.cpp -lSDL2
#include <SDL2/SDL.h>
#include <iostream>
int main(int argc, char* argv[])
{
// Inicia o SDL, nesse caso inicia o sistema de vídeo
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
return 1;
}
// declara um ponteiro de janela
SDL_Window *janela;
// cria uma janela com título "Janela SDL2" na posição X=10 e Y=20, com tamanho 640x480
janela = SDL_CreateWindow("Janela SDL2",10,20, 640, 480, SDL_WINDOW_SHOWN);
//poderia criar uma janela com OpenGL:
//janela = SDL_CreateWindow("Janela SDL2",10,20, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
//se janela for nula então...
if (!janela)
{
//imprime mensagem de erro
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
return 1;
}
//Declara o ponteiro para um SDL_Renderer
SDL_Renderer *renderer;
// cria um SDL_Renderer
// SDL_Renderer * SDL_CreateRenderer(SDL_Window * janela, int id, Uint32 flags);
// parametros: janela (um SDL_Window *), id do renderer escolhido pelo programador,
// e as flags, aqui pode ser somente SDL_RENDERER_ACCELERATED
renderer = SDL_CreateRenderer(janela, 0, SDL_RENDERER_ACCELERATED);
//se renderer for nulo, então...
if (!renderer)
{
//imprime mensagem de erro
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
//encerrao programa
return 1;
}
//agora a janela vai aparecer com um fundo preto
// pinta a janela com a cor preta
//define a cor de fundo da janela como preto (0,0,0,255); 255 é o alpha e aqui é opaco
//SDL_SetDrawRenderColor(renderer, R,G,B,A);
// R = Red (vermelho)
// G = Green (verde)
// B = Blue (azul)
// A = Alpha (transparencia)
SDL_SetRenderDrawColor(renderer, 0,0,0,255);
//desenha toda a tela com a cor preto (0,0,0,255)
SDL_RenderClear(renderer);
//esta função faz parecer o resultado do desenho com SDL_RenderClear
//é só depois de chamar esta função abaixo que veremos o resultado na tela
SDL_RenderPresent(renderer);
// pausa o programa por 3000 milissegundos, ou 3 segundos
SDL_Delay(3000);
//agora tem que destruir o renderer também
SDL_DestroyRenderer(renderer);
//lembre-se de liberar a memoria da janela com esta função abaixo
// ou você terá memory leak
SDL_DestroyWindow(janela);
//E por fim, libere o SDL
SDL_Quit();
return 0;
}
[clique aqui para baixar o renderer.cpp]
Veja a doc do SDL_CreateRenderer aqui:
https://wiki.libsdl.org/SDL_CreateRenderer
Veja que temos 3 funções novas: SDL_SetRenderDrawColor, SDL_RenderClear, e SDL_RenderPresent
SDL_SetRenderDrawColor(SDL_Renderer * renderer, Uint8 R, Uint8 G, Uint8 B, Uint8 A );
Onde:
renderer é o nosso renderer do programa.
Uint8 R é o vermelhor (Red), um inteiro de valor de 0 à 255 (1 byte sem sinal)
Uint8 G é o verde (Green), um inteiro de valor de 0 à 255 (1 byte sem sinal)
Uint8 B é o azul (Blue), um inteiro de valor de 0 à 255 (1 byte sem sinal)
Uint8 A é a transparência (Alpha), um inteiro de valor de 0 à 255 (1 byte sem sinal)
Aqui, cada valor de RGBA é uma mistura de cores primárias. Se você colocar SDL_SetRenderDrawColor(renderer, 255,0,0,255), teremos então uma cor vermelha. Se colocar SDL_SetRenderDrawColor(renderer, 255,255,0,255), teremos o amarelo como cor. Agora se colocar SDL_SetRenderDrawColor(renderer, 128,128,128,255), teremos a cor cinza definida. Só pra informar, branco é R=255,G=255,B=255,A=255 e preto total é R=0,G=0,B=0,A=255 (ou 0), alpha não funciona em janelas comuns, é ignorado.
A função SDL_SetRenderDrawColor, define uma cor para que possamos desenhar algo na janela. No exemplo acima, definimos a cor R=255,G=255,B=0,A=255 (amarelo) para desenhar algo com esta cor logo em seguida. Então, usamos SDL_RenderClear para pintar toda a tela com aquele cor definida com SDL_SetRenderDrawColor. Toda vez que terminamos de desenhar a tela, digo, quando montamos toda a cena do jogo, devemos atualizar a tela com SDL_RenderPresent, esta função sempre vai aparecer no final depois de desenharmos imagens na tela.
Ou seja, o algoritmo para se desenhar numa janela é mais ou menos o seguinte:
- Primeiro, defina uma cor com SDL_SetRenderDrawColor
- Segundo, chame uma função que desenhe algo na janela (como a SDL_RenderClear)
- Por último, atualize a janela com SDL_RenderPresent. Ela vem depois de ter desenhado todos os elementos na tela.
//exemplo renderRect.cpp
//para compilar: g++ -o renderRect renderRect.cpp -lSDL2
#include <SDL2/SDL.h>
#include <iostream>
int main(int argc, char* argv[])
{
// Inicia o SDL, nesse caso inicia o sistema de vídeo
//verifica se deu erro
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
//imprime mensagem de erro
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
return 1;
}
// declara um ponteiro de janela
SDL_Window *janela;
// cria uma janela com título "Janela SDL2" na posição X=10 e Y=20, com tamanho 640x480
janela = SDL_CreateWindow("Janela SDL2",10,20, 640, 480, SDL_WINDOW_SHOWN);
//poderia criar uma janela com OpenGL:
//janela = SDL_CreateWindow("Janela SDL2",10,20, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
//se janela for nula então...
if (!janela)
{
//imprime mensagem de erro
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
return 1;
}
//Declara o ponteiro para um SDL_Renderer
SDL_Renderer *renderer;
// cria um SDL_Renderer
// SDL_Renderer * SDL_CreateRenderer(SDL_Window * janela, int id, Uint32 flags);
// parametros: janela (um SDL_Window *), id do renderer escolhido pelo programador,
// e as flags, aqui pode ser somente SDL_RENDERER_ACCELERATED
renderer = SDL_CreateRenderer(janela, 0, SDL_RENDERER_ACCELERATED);
//se renderer for nulo, então...
if (!renderer)
{
//imprime mensagem de erro
std::cout<<"Erro: "<<SDL_GetError()<<std::endl;
//encerrao programa
return 1;
}
//agora a janela vai aparecer com um fundo CINZA
// pinta a janela com a cor CINZA
//define a cor de fundo da janela como CINZA (128,128,128,255); 255 é o alpha e aqui é opaco
//SDL_SetDrawRenderColor(renderer, R,G,B,A);
// R = Red (vermelho)
// G = Green (verde)
// B = Blue (azul)
// A = Alpha (transparencia)
SDL_SetRenderDrawColor(renderer, 128,128,128,255);
//desenha toda a tela com a cor CINZA definida acima
SDL_RenderClear(renderer);
//agora antes de atualizar toda a tela com SDL_RenderPresent precisamos desenhar os retangulos
//primeiro, definimos um SDL_Rect
SDL_Rect retangulo;
//depois posicionamos ele em algum lugar da tela, vou por na posição 32 em X
//observe que a origem do eixo X é no canto esquerdo superior na horizontal para direita é positivo
retangulo.x = 32;
//despois definimos a posição Y
//Observe que a origem do eixo Y é no canto esquerdo superior na vertical pra baixo é positivo
retangulo.y = 200;
//agora definimos as dimensões do retangulo
retangulo.w = 128;//largura
retangulo.h = 12;//altura
//E então definimos uma cor para o retangulo, será vermelho: R=255,G=0,B=0,A=255
SDL_SetRenderDrawColor(renderer, 255,0,0,255);
//E finalmente desenha o retangulo com a cor definida acima
SDL_RenderFillRect(renderer, &retangulo);
//até aqui foi desenhado apenas um retangulo
//agora desenha outro retangulo na posição X=120 e Y=320, com largura = 64 e altura = 32
retangulo.x = 120;
retangulo.y = 320;
retangulo.w = 64;
retangulo.h = 32;
//agoar desenha o retangulo, com a cor vermelha que ainda está definida
SDL_RenderFillRect(renderer, &retangulo);
//Agoar define a cor amarela
SDL_SetRenderDrawColor(renderer, 255,255,0,255);
//muda a poisção do retangulo, preservando a largura e altura
retangulo.x = 320;
retangulo.y = 200;
//agora desenha o retangulo na tela
SDL_RenderFillRect(renderer, &retangulo);
//esta função faz parecer o resultado do desenho com SDL_RenderClear
//é só depois de chamar esta função abaixo que veremos o resultado na tela
SDL_RenderPresent(renderer);
// pausa o programa por 6000 milissegundos, ou 6 segundos
SDL_Delay(6000);
//agora tem que destruir o renderer também
SDL_DestroyRenderer(renderer);
//lembre-se de liberar a memoria da janela com esta função abaixo
// ou você terá memory leak
SDL_DestroyWindow(janela);
//E por fim, libere o SDL
SDL_Quit();
return 0;
}
[clique aqui para baixar renderRect.cpp]Hora do exercício:
- -pegue o programa acima, e então faça o seguinte: faça com que a cor da janela seja cor de rosa. (pesquise os valores RGBA da cor rosa no google)
- -no mesmo programa acima, faça com que a janela apareça com uma cor aleatória. No sistema RGBA do SDL2 cada cor vai de 0 até 255, sendo assim o R pode ser 123, o G pode ser 90, etc. Em fim, cada um deles podem ter valores diferentes e vão produzir cores diferentes. Use rand() do stdlib.h, e use rand()%256 para que cada valor do SDL_SetRenderDrawColor() seja aleatório, e assim aparecer uma cor diferente na tela. (NOTA: precisa recompilar e reexecutar o programa para mudar as cores, óbvio.)
Comentários
Postar um comentário