¿Cómo dibujar imágenes 2D usando OpenGL, en SDL?

8

Después de todo, logré encontrar un código simple que muestra cómo dibujar una imagen 2D con 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;
    }

No tengo experiencia en 2D, y hace aproximadamente una semana comencé a jugar con SDL. Construí algunas estructuras simples para tener imágenes, que estarían en capas, para poder tener mi propio orden de dibujo, para que los sprites se dibujaran después del fondo, etc., y luego hice un pequeño "motor de sprites". Obtuve un megaman sprite caminando de izquierda a derecha tal como lo quería, sobre una simple imagen de fondo de 900x900.

La cosa es que la CPU casi alcanzó el 20% en mi i5 ... ¡así que pensé en usar la tarjeta gráfica para hacer el dibujo! Profundicé en OpenGL y hoy, ¡finalmente logré que gl3w funcione!

Así que ahora estoy buscando una manera simple de mostrar mis sprites / imágenes, en la ventana, mediante el uso de OpenGL. He intentado todo tipo de código con el que me encontré, pero no puedo mostrar nada, a pesar de que he realizado comprobaciones de errores básicamente en todas partes, ¡y todo parece ser correcto!

TL: DR; Estaba buscando un código de trabajo simple, usando SDL, sobre cómo dibujar imágenes 2D (que, si no funciona, seguro que tengo algo mal).

¡Gracias!

GigaBass
fuente
1
¿Está utilizando funciones incorporadas de bitblit o está dibujando sprites por su cuenta? ¡Puede hacer una enorme diferencia!
Ali1S232
Solo estoy usando SDL_Blit (), en el juego cuyo rendimiento fue horrible
GigaBass
En realidad, ¿podrías aclarar a qué te refieres? ¿Qué es dibujar sprites por mi cuenta?
GigaBass
configuración de píxeles en el búfer
Ali1S232
En ese caso, no, estoy usando los únicos BLITS proporcionados por SDL directamente.
GigaBass

Respuestas:

7

Recomiendo cargar tus sprites usando SOIL y luego renderizarlos simplemente dibujando quads texturizados. Si lo hace sin ninguna funcionalidad obsoleta (use sombreadores), encontrará que es muy rápido.

Eric B
fuente
Eché un vistazo rápido a la biblioteca, y eso suena bien. ¿Podría proporcionar un código de ejemplo muy pequeño sobre el uso de SOIL, un ejemplo que muestre una imagen simple sería genial! Gracias
GigaBass
hay fragmentos de código en el enlace para cargar la imagen. La forma en que lo represente dependerá de usted, pero si desea hacerlo de la "manera correcta", querrá seguir algo como esto . Lamentablemente, configurar OpenGL con sombreadores, etc. no es tan rápido y fácil, pero probablemente valga la pena, especialmente si tendrá muchos sprites a la vez.
Eric B
3

Aquí hay un punto de partida bastante básico pero excelente para dibujar quads texturizados en OpenGL, desde el punto de partida de esta función tengo otras 7 funciones que proporcionan una funcionalidad ligeramente diferente, para dibujar con colores tintados, para dibujar elementos con diferentes valores alfa y luego tenemos rotación, recorte, etc., etc. Pero esto debería ayudarlo a comenzar :).

Editar: Código actualizado;

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);
}

La imagen es una estructura básica que contiene los datos de textura (GLuint) y luego dos enteros para mantener el ancho y la altura.

dan369
fuente
Sin embargo, he estado leyendo que glBegin, glEnd tipo de funciones OpenGL han quedado en desuso porque son mucho más lentas que las actualizadas, ¿es esto correcto? Aún así, para un simple juego en 2d, esto será más que suficiente para obtener todos los sprites que alguna vez quiera sin que la GPU supere el 50% ¿verdad?
GigaBass
Sí, es mejor usar glDrawArrays y enviar todos los datos de vértices de una vez. Pero supongo que la diferencia es bastante marginal, especialmente cuando solo se trata de 4 vértices.
dan369
¿Digamos que estaba dibujando imágenes de 500x500, 20 de ellas, cada cuadro, en una pantalla de 1000x1000 píxeles? ¿Sería notable la diferencia? Solo así tengo una idea de lo mejor que es
GigaBass
No, no creo que sea notable en ese caso. Recuerde que no debe preocuparse demasiado por la optimización hasta que se encuentre con problemas. Es una trampa común.
dan369
Me sorprendió ver que tomaba el 20% de mi CPU e inmediatamente pensé que tenía que hacer algo para solucionarlo ... en varias de las computadoras de mi amigo, ¡no podía funcionar a la velocidad normal!
GigaBass
0

¿SDL es necesario para ti? SFML es una alternativa a SDL que usa OpenGL para renderizar. También puede ser más fácil para los principiantes, debido a la API orientada a objetos.

szotp
fuente
voto negativo porque su respuesta no está resolviendo su problema. Quiere saber cómo trabajar con OpenGL. No está usando una solución alternativa.
Ali1S232
Sí, quería evitar pasar de SDL a SFML, me gusta bastante ... acostumbrado a su funcionamiento. ¿Quieres decir que SFML puede hacer el dibujo fácil que SDL puede hacer con blits, usando OpenGL para renderizar? Eso en realidad sería muy bueno.
GigaBass
2
@ user1896797: Sí, SFML usa OpenGL para todas las cosas gráficas.
szotp
Eso es genial si es como tú dices, ¡lo probaré! ¡Votaría si pudiera!
GigaBass
Confirmado, de hecho usa OpenGL. Sin embargo, no puedo aceptar la suya, solo porque la respuesta tiene que relacionarse con la pregunta. Pero muchas gracias!
GigaBass