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:
  1. Primeiro, defina uma cor com SDL_SetRenderDrawColor
  2. Segundo, chame uma função que desenhe algo na janela (como a SDL_RenderClear)
  3. Por último, atualize a janela com SDL_RenderPresent. Ela vem depois de ter desenhado todos os elementos na tela.
Exemplo de desenho de três retângulos, dois vermelhos e um amarelo numa janela cinza (fundo):
//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.)
Até a próxima.

Comentários

Postagens mais visitadas deste blog

Lógica em Naruto parte 1

The God Brazil