Como desenhar imagens 2D usando OpenGL, em SDL?

8

Depois de tudo, consegui encontrar um trecho de código simples que mostra como desenhar uma imagem 2D com o openGL:

    #include "SDL/SDL.h"
    #include "SDL/SDL_opengl.h"
    #include "SDL/SDL_image.h"

    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int SCREEN_BPP = 32;

    int tex;

    int loadTexture(char* fileName){
        SDL_Surface *image=IMG_Load(fileName);
        SDL_DisplayFormatAlpha(image);
        GLuint object;
        glGenTextures(1,&object);
        glBindTexture(GL_TEXTURE_2D,object);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,image->w,image ->h,0,GL_RGBA,GL_UNSIGNED_BYTE,image->pixels);
        SDL_FreeSurface(image);
        return object;
    }
    void init(){
        glClearColor(0.0,0.0,0.0,0.0);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0.0,800,600,1.0,-1.0,1.0);
        glEnable(GL_BLEND);
        glEnable(GL_TEXTURE_2D);
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
        tex = loadTexture("hi.png");
    }
    void draw(){
        glClear(GL_COLOR_BUFFER_BIT);
        glBindTexture(GL_TEXTURE_2D,tex);
        glBegin(GL_QUADS);
            glTexCoord2f(0,0);
            glVertex2f(0,0);
            glTexCoord2f(1,0);
            glVertex2f(500,0);
            glTexCoord2f(1,1);
            glVertex2f(500,500);
            glTexCoord2f(0,1);
            glVertex2f(0,500);
        glEnd();
        glFlush();
    }
    int main(int argc,char** argv){
        SDL_Init(SDL_INIT_EVERYTHING);
        SDL_Surface* screen=SDL_SetVideoMode(800,600,32,SDL_SWSURFACE|SDL_OPENGL);
        bool running=true;
        Uint32 start;
        SDL_Event event;
        init();
        while(running){
            start=SDL_GetTicks();
            draw();
            while(SDL_PollEvent(&event)){
                switch(event.type){
                    case SDL_QUIT:
                        running=false;
                        break;
                }
            }
            SDL_GL_SwapBuffers();
            if(1000/60>(SDL_GetTicks()-start))
                SDL_Delay(1000/60-(SDL_GetTicks()-start));
        }
        SDL_Quit();
        return 0;
    }

Sou inexperiente em 2D e, cerca de uma semana atrás, comecei a mexer com SDL. Criei algumas estruturas simples para ter imagens, que estariam em camadas, para que eu pudesse ter minha própria ordem de desenho, para que os sprites fossem desenhados após o fundo, etc. Eu tenho um sprite Megaman andando para a esquerda e para a direita como eu queria, acima de uma imagem de fundo simples de 900x900.

O problema é que a CPU quase atingiu 20% no meu i5 ... então pensei em usar a placa gráfica para fazer o desenho! Mergulhei no OpenGL e hoje finalmente consegui fazer o gl3w funcionar!

Então agora estou procurando uma maneira simples de exibir meus sprites / imagens, na janela, através do uso do OpenGL. Eu tentei todos os tipos de código que encontrei, mas não consigo exibir nada, apesar de ter feito verificações de erro basicamente em todos os lugares, e tudo parece estar certo!

TL: DR; Eu estava procurando por um código de trabalho simples, usando SDL, sobre como desenhar imagens 2D (que, se não funcionar, com certeza eu entendi algo errado).

Obrigado!

GigaBass
fonte
11
você está usando funções integradas de bitbit ou está desenhando sprites por conta própria? isso pode fazer uma enorme diferença!
Ali1S232
Estou apenas usando SDL_Blit (), no jogo que seu desempenho foi horrível
GigaBass
Na verdade, você poderia esclarecer o que quer dizer? O que é desenhar sprites sozinho?
GigaBass
definindo pixels no buffer
Ali1S232
Nesse caso, não, estou usando apenas os BLITS fornecidos diretamente pelo SDL.
GigaBass

Respostas:

7

Eu recomendo carregar seus sprites usando SOIL e renderizá-los apenas desenhando quads texturizados. Se você fizer isso sem nenhuma funcionalidade obsoleta (use shaders), descobrirá que é muito rápido.

Eric B
fonte
Dei uma rápida olhada na biblioteca, e isso parece bom. Você poderia fornecer um código de exemplo muito pequeno para usar SOIL? Um exemplo de saída de uma imagem simples seria ótimo! Obrigado
GigaBass
há trechos de código no link para carregar a imagem. Como você torná-lo vai depender de você, mas se você quiser fazê-lo o "caminho certo", você vai querer seguir algo como este . Infelizmente, configurar o OpenGL com shaders etc. não é tão rápido e fácil, mas provavelmente vale a pena, especialmente se você tiver muitos sprites de uma só vez.
Eric B
3

Aqui está um ponto de partida bastante básico, mas ótimo, para desenhar quads texturizados no OpenGL, a partir dessa função, eu tenho 7 outras funções que fornecem funcionalidades ligeiramente diferentes, para desenhar com cores coloridas, para desenhar itens com valores alfa diferentes e então temos rotação, recortes etc. etc. Mas isso deve ajudar você a começar :).

Editar: Código Atualizado;

void Draw(int x, int y, Image* texture, bool blendFlag) {
//Bind Texture
glBindTexture(GL_TEXTURE_2D, texture->getData());

if (blendFlag)
{
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GLfloat Vertices[] = {(float)x, (float)y, 0,
                    (float)x + texture->getWidth(), (float)y, 0,
                    (float)x + (float)texture->getWidth(), (float)y + (float)texture->getHeight(), 0,
                    (float)x, (float)y + (float)texture->getHeight(), 0};
GLfloat TexCoord[] = {0, 0,
    1, 0,
    1, 1,
    0, 1,
};
GLubyte indices[] = {0,1,2, // first triangle (bottom left - top left - top right)
                     0,2,3}; // second triangle (bottom left - top right - bottom right)

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, Vertices);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, TexCoord);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

if (blendFlag) glDisable(GL_BLEND);
}

A imagem é uma estrutura básica que contém os dados de textura (GLuint) e, em seguida, dois números inteiros para armazenar largura e altura.

dan369
fonte
Eu tenho lido por aí que as funções do glBegin, glEnd do OpenGL foram obsoletas porque são muito mais lentas que as atualizadas, está correto? Ainda assim, para um jogo 2D simples, isso será mais do que suficiente para obter todos os sprites que eu desejar, sem que a gpu exceda 50%, certo?
GigaBass
Sim, é melhor usar glDrawArrays e enviar todos os dados de vértice de uma só vez. Mas suponho que a diferença seja bastante marginal, especialmente quando você lida apenas com 4 vértices.
dan369
Digamos que eu estava desenhando imagens de 500 x 500, 20 delas, todos os quadros, em uma tela de 1000 x 1000 pixels? A diferença seria notável? Apenas para que eu tenha uma idéia de quanto que é melhor
GigaBass
Não, eu não acho que seria perceptível nesse caso. Lembre-se de que você não deve se preocupar muito com a otimização até encontrar problemas. É uma armadilha comum.
dan369
Fiquei chocado ao ver que estava usando 20% da minha CPU e imediatamente pensei que tinha que fazer algo para corrigi-lo ... em vários computadores dos meus amigos, ele não podia funcionar na velocidade normal!
GigaBass 4/13/13
0

O SDL é necessário para você? O SFML é uma alternativa ao SDL que usa o OpenGL para renderização. Também pode ser mais fácil para iniciantes, devido à API orientada a objetos.

szotp
fonte
voto negativo porque sua resposta não está resolvendo o problema dele. Ele quer saber como trabalhar com o OpenGL. Ele não está usando uma solução alternativa.
Ali1S232
Sim, eu meio que queria evitar passar do SDL para o SFML, eu gosto disso ... acostumado com o funcionamento. Você quer dizer que o SFML pode fazer o desenho fácil que o SDL pode fazer com os blits, usando o OpenGL para renderização? Isso seria realmente muito bom.
GigaBass
2
@ user1896797: Sim, o SFML usa o OpenGL para todo o material gráfico.
Szotp
Isso é ótimo se é como você diz, eu vou dar uma volta! Gostaria de votar se eu pudesse!
GigaBass
Confirmado, realmente usa o OpenGL. Não é possível aceitar o seu, apenas por causa da resposta ter que se relacionar com a pergunta. Mas um grande obrigado!
GigaBass