Ponto V!

Home OpenGL Criando uma janela OpenGL
Vinícius Godoy de Mendonça
Criando uma janela OpenGLImprimir
Escrito por Vinícius Godoy de Mendonça

Embora o OpenGL seja extremamente poderoso no que diz respeito à parte gráfica, não existe em sua estrutura uma única função para controlar o ambiente de janelas. Isso porque os projetistas do OpenGL decidiram construir uma biblioteca gráfica, e nada além disso.

Um dos primeiros programadores da API desenvolveu uma camada limitada adicional ao OpenGL chamada glut (OpenGL utilities), que justamente criava a janela e fazia um controle simples do teclado. Embora ele seja prático para o aprendizado, não é adequado para jogos.

Um dos grandes poderes da SDL é justamente preencher esse gap. Podemos usar os recursos da SDL – como o de criação de janelas e controle do mouse, teclado e joystick – para facilmente fazer um jogo completo com OpenGL.

Os atributos do OpenGL

No artigo passado, você aprendeu que todos os subsistemas da SDL são inicializados com SDL_Init. Entretanto, como o OpenGL é uma parte desse subsistema, outra função foi criada para inicializa-lo. Essa função é chamada SDL_GL_SetAttribute. Essa função possui em sua assinatura dois parâmetros. O primeiro, é um inteiro indicando qual atributo será alterado. O segundo, o novo valor do atributo. A lista dos atributos possíveis é:

  • SDL_GL_RED_SIZE: Define o número de bits do componente vermelho no frame buffer. Os valores comumente usados para esse número é o 5 ou manter o default (não usar a função SetAttribute). Existem constantes como essa também para o componente azul e verde, chamadas SDL_GL_GREEN_SIZE, SDL_GL_BLUE_SIZE, respectivamente;
  • SDL_GL_BUFFER_SIZE: Define o tamanho do frame buffer em bits. Esse valor deve ser igual ou superior a soma dos componentes de cor vermelho, verde e azul, descritos no comando anterior. Por exemplo, se você quer 24 bits de cor, com um canal alpha (transparência), o uso dos comandos seria:
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);

//Temos 3x8=24 bits para as cores + 8 bits alpha= 32 bits
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
  • SDL_GL_DEPTH_SIZE: Esse atributo define o tamanho do buffer no eixo Z. O hardware gráfico normalmente suporta 16 e 32 bits. Se um valor não suportado for passado, o comando falhará.
  • SDL_GL_ACCUM_RED_SIZE: Define o valor do buffer de acumulação do OpenGL. Como no outro caso, há versões desse comando para as cores verde e azul. Deixaremos esses atributos definidos para zero. Para mais informações sobre os buffers do OpenGL, leia este material.
  • SDL_GL_DOUBLE_BUFFER: Define se o OpenGL deverá tentar ou não usar double buffering. Os valores para esse atributo podem ser 0 ou 1. É importante ressaltar que, quando estivermos trabalhando com OpenGL é aqui que definimos o double buffering, e não nos parâmetros da função SDL_SetVideoMode.

Não é possível alterar esses valores no decorrer do programa.

Além desses parâmetros, o comando glViewport diz ao OpenGL qual a porção da janela que deve ser utilizada. Veremos mais detalhe sobre esse comando no futuro, no artigo sobre sistemas de coordenadas. No próximo exemplo, usaremos toda a área da janela, mas você pode usar esse comando para definir uma área menor, como no caso de uma resolução de cinema vista numa tela quadrangular. Se esse comando for omitido, algumas versões do OpenGL não desenharão absolutamente nada, enquanto outras usarão o tamanho da tela por padrão.

Agora que sabemos o que cada parâmetro faz, que tal alterarmos o programa anterior para criar a nossa janela?

#include "SDL.h"
#include "GL/gl.h"

#include 
#include 

SDL_Surface* window;

Uint32 createFlags(bool fullscreen)
{
    //Iniciamos com a OpenGL e paleta de hardware
    Uint32 flags = SDL_OPENGL | SDL_HWPALETTE;

    if (fullscreen)
        flags |= SDL_FULLSCREEN;

    const SDL_VideoInfo* info = SDL_GetVideoInfo();

    //Criarmos uma superfície de hardware,
    //se este estiver disponível
    if (info->hw_available)
        flags |= SDL_HWSURFACE;
    else
        flags |= SDL_SWSURFACE;

    //Aceleração por hardware?
    if(info -> blit_hw)
        flags |= SDL_HWACCEL;

    return flags;
}

int setupOpenGL(int bpp, bool fullscreen)
{
    //Atributos do opengl
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, bpp > 24 ? 24 : bpp);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, 0);

    return createFlags(fullscreen);
}

void setup(int width, int height, int bpp, bool fullscreen)
{
    //Inicializamos o subsistema de video.
    if (SDL_Init(SDL_INIT_VIDEO) == -1)
        throw std::runtime_error(SDL_GetError());

    //Tentamos criar a janela
    window = SDL_SetVideoMode(width, height, bpp,
    setupOpenGL(bpp, fullscreen));

    //Sem sucesso? Lançamos uma exceção com o erro.
    if (window == NULL)
        throw std::runtime_error(SDL_GetError());
     //Dizemos para o OpenGL usar toda a tela
     glViewport(0,0, width, height);
    //Configuramos a função de des-inicialização
    atexit (SDL_Quit);
}

/** Espera o usuário pressionar o x da janela. */
void processEvents()
{
    SDL_Event event;

    while (SDL_PollEvent(&event) != 0)
    {
        switch (event.type)
        {
            case SDL_QUIT:
                exit(0); //Fechamos a apliação
                break;
        }
    }
}

int main(int argc,char* argv[])
{
    try
    {
        setup(640, 480, 8, false); //Faz a mágica acontecer

        //Desenhamos um triângulo
        while (true)
        {
            processEvents();
            glClearColor(0.0, 0.0, 0.0, 0.0);
            glClear(GL_COLOR_BUFFER_BIT);

            glBegin(GL_TRIANGLES);
                glColor3f(1,0,0); glVertex2f(0.0f,0.5f);
                glColor3f(0,1,0); glVertex2f(-0.5f, -0.5f);
                glColor3f(0,0,1); glVertex2f(0.5f, -0.5f);
            glEnd();
            SDL_GL_SwapBuffers();
        }
    }
    catch (std::exception &e)
    {
        std::cout << "Error: " << e.what();
        exit(1);
    }
}

Se você conseguiu rodar esse programa corretamente, deve ter obtido uma janela como essa:

Janela opengl

Algumas notas sobre o programa

Nesse programa, usamos a função SDL_GetVideoInfo() para obter informações a respeito do hardware do jogador antes de desenhar a janela. Isso mostra mais um dos poderes da SDL e porque é uma boa idéia utilizá-la juntamente com o OpenGL. Essa função retorna um objeto do tipo SDL_VideoInfo, capaz informar se existe hardware, que tipo de aceleração ele possui e até mesmo, como está configurada a resolução do monitor.Também usamos a função SDL_GL_SwapBuffers(). Essa função garante que os comandos de pintura foram enviados para o hardware e que os buffers serão trocados, exibindo a imagem para o usuário.

Algumas funções de pintura do OpenGL foram utilizadas para desenhar o triângulo colorido. Não se preocupe com esse trecho de código agora, pois entrarei em mais detalhes sobre ele no futuro. Ele só foi inserido para demonstrar que a janela criada é realmente uma janela OpenGL.


Comentários (21)
  • Andre  - Parabéns
    avatar

    Muito bom.

    Torço muito para vcs da equipe, que continue com o esse ótimo trabalho.

    Infelizmente muitos a maiorias dos sites sobre desenvolvimento de games são abandonados, poucos continuam. :(

    Desejo sorte! :)

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado. Nós estamos completando um ano. E a idéia não é parar por aqui.

  • Mateus Pires  - Pergunta um pouco mais avançada.
    avatar

    Se eu dou um rotate de 180 graus no eixo Z num objeto e depois translado ele em ( 2,0,0), como eu faço para pegar a posição atual do objeto?? (POr que nesse caso se eu for me orientar somente pelo que eu vejo na tela ele estaria em (-2,0,0).)

  • Bruno Crivelari Sanches
    avatar

    Olá Mateus,

    num jogo 3d você não busca de volta a posição do objeto, o correto é seu jogo e/ou engine manter uma estrutura de dados onde ele armazena a orientação e posição de todos os objetos, sendo que essa mesma estrutura vai ser usada todo frame para desenhar os objetos na sua posição correta.

    Neste artigo eu abordo superficialmente esse assunto: Como funciona um jogo

  • Vinícius Godoy de Mendonça  - Descobrindo a posição
    avatar

    Não tem jeito. Você tem que usar no vetor de posição do seu objeto as mesmas transformações que você fez na forma dele. Para isso, multiplica-se também o vetor pela matriz de rotação e translação.

    O vetor resultante será o que você falou.

    Agora, o correto é fazer ao contrário. Você movimenta os vetores de direção e posição e então faz o translate e o rotate para representar esses vetores.

    A representação gráfica do objeto deve ser uma das últimas coisas a serem processadas. Até porque, vários rotates e translates acumulados começam a apresentar erros. Sem falar que é muito mais fácil desenvolver olhano para seus vetores e não para as geometrias.

  • Fabiano Vasconcelos  - Pipe
    avatar

    Poderiam esmiuçar esta linha para mim?

    Uint32 flags = SDL_OPENGL | SDL_HWPALETTE;

    Sei que Uint32 é um tipo, flags é a variável, mas não estou entendendo estas duas flags (que certamente representam ints) separadas por pipe. Porque elas estão separadas por pipe? Porque são duas, aderindo a mesma variável?

  • Bruno Crivelari Sanches
    avatar

    O pipe no C significa ou a nível de bit. Quando você faz || tem se um OU com base nos valores das variáveis, já um único | faz isso bit a bit.

    Exemplo:

    Código:
    int a = 2; //0010
    int b = 1; //0001

    //Fazendo o pipe:
    int x = a | b; //0011

    No caso da SDL isso é uma técnica comum para representar flags usando os bits de uma variável, cada bit representa um flag e usa-se o | para combinar múltiplos flags, depois usa-se um & (binário) para checar se um flag esta ligado, por exemplo:

    Código:

    Uint32 flags = SDL_OPENGL|SDL_HWPALETTE;

    //ligado opengl?
    if(flags & SDL_OPENGL)
    {
    }

    T+

  • Fabiano Vasconcelos
    avatar

    Pois é... Honestamente eu havia esquecido que o pipe sozinho era um OU binário. Obrigado pela lembrança. Mas o conceito que você explicou sobre o SDL só ficará claro com a prática. Eu me lembro de ter visto isso com o nome de mascaramento de bits. Estou correto ou delirando? Mas é interessante.
    Obrigado pela explicação, Bruno.
    Abs! :D

  • Bruno Crivelari Sanches
    avatar

    Sim, não deixa de ser uma mascara de bits. É uma técnica comum para se armazenar flags.

  • Rafael Vieira Braga  - Dúvida
    avatar

    Onde fica o comando gluortho2D ??? Como faço pra usar? Estava programando em opengl, mas a forma de programar com o SDL é um pouco diferente... Como eu faço? Tipo, no opengl, vc tem que definir as callbacks, depois é só chamar na main e no final usar o loop. E no SDL?

  • Bruno Crivelari Sanches
    avatar

    Na verdade programar OpenGL com SDL não é diferente, os comandos OpenGL não mudam.

    Agora o gluortho2d é parte da biblioteca GLU, que é uma biblioteca de utilidades para OpenGL, mas acredito que nada impede de ser usado com SDL.

  • Paulo  - OpenGl
    avatar

    ér... as funçoes da OpenGl nao funcionam aqui, tem algum tutorial de como instala-las?
    obrg.

    ae cara, parabens e obrigado mesmo, esse tutorial é o melhor que eu ja vi!
    =]

  • Bruno Crivelari Sanches
    avatar

    Nas plataformas mais comuns ele já costuma vir com as bibliotecas que acompanham o compilador. Qual compilador você esta usando e qual erro ocorre?

  • paulo  - SDL
    avatar

    Ta dando problema em tudo aqui, antes tava funcionando de boua mas agora paro tudo fica dizedo: error:'SDL_QUIT' was not declared in this scope

    fala isso para todas as funçoes, se alguem puder me ajudar.
    :/

  • Bruno Crivelari Sanches
    avatar

    Algum include foi removido, ou falta um ; ou um } em algum lugar.

    Se poder postar o código em algum lugar fica mais fácil ajudar, sem código, só é possível chutar soluções, pode usar o notepad.cc: http://notepad.cc

    T+

  • Anônimo
    avatar

    Pode postar o download do codigo ,pq copiando e colando não vai

  • Bruno  - escrever na tela
    avatar

    Olá, gostaria de saber, como eu poderia escrever textos na tela, qual biblioteca eu deveria usar? a SDL ou OpenGL, porque eu criei uma janela com as duas juntas mas não to consiguindo com SDL.

  • Anônimo
    avatar

    O mais comum quando se usa SDL é utilizar a SDL_ttf. Se você esta usando opengl, vai ter que transformar os textos que a SDL_tff gera em uma textura, se for apenas SDL, basta fazer um blit.

    T+

  • Maxwell  - Olá, agradeço sua ajuda
    avatar

    Nossa, vinigodoy, kra vc é foda man :) to no curso tecnico informatica, já no 2° módulo, é estou fazendo um jogo onde o usuario se cadastra com banco mysql, e ja está td pronto, falta só a parte grafica e as funçoes internas do jogo, agradeço mto sua ajuda kra, se possivel poderia mandar algumas video auloas sobre como manipular melhor o opengl e a jmonkeyEngine? se possivel agradeço desde já :)

  • ViniGodoy  - Vídeo aulas
    avatar

    Oi. Não disponho dessas vídeo aulas. Inclusive, se fosse fazer, dificilmente faria sobre JMonkey, já que o Java não é uma boa plataforma para jogos em geral. O ideal é você buscar essas aulas no YouTube.

  • Anônimo  - re: Olá, agradeço sua ajuda
    avatar
    Maxwell Escreveu:
    Nossa, vinigodoy, kra vc é foda man :) to no curso tecnico informatica, já no 2° módulo, é estou fazendo um jogo onde o usuario se cadastra com banco mysql, e ja está td pronto, falta só a parte grafica e as funçoes internas do jogo, agradeço mto sua ajuda kra, se possivel poderia mandar algumas video auloas sobre como manipular melhor o opengl e a jmonkeyEngine? se possivel agradeço desde já :)

    apropósito, meu e-mail é maxwellcoutodeoliveira@gmail.com

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter