Comment dessiner des images 2D en utilisant OpenGL, en SDL?

8

Après tout, j'ai réussi à trouver un simple morceau de code qui montre comment dessiner une image 2D avec 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;
    }

Je n'ai pas d'expérience en 2D et il y a environ une semaine, j'ai commencé à jouer avec SDL. Construit des structures simples pour avoir des images, qui seraient sur des calques, afin que je puisse avoir mon propre ordre de dessin, afin que les sprites soient dessinés après l'arrière-plan, etc., puis fait un petit "moteur de sprite". J'ai eu un sprite Megaman marchant à gauche et à droite comme je le voulais, au-dessus d'une simple image d'arrière-plan 900x900ish.

Le truc, c'est que le CPU a presque atteint 20% sur mon i5 ... alors j'ai pensé à utiliser la carte graphique pour faire le dessin! Abit fouillé dans OpenGL et aujourd'hui, a finalement réussi à faire fonctionner gl3w!

Alors maintenant, je cherche un moyen simple d'afficher mes sprites / images, sur la fenêtre, en utilisant OpenGL. J'ai essayé toutes sortes de codes que j'ai rencontrés, mais je ne peux rien afficher, malgré le fait que j'ai fait des vérifications d'erreurs pratiquement partout, et tout semble vérifier que tout va bien!

TL: DR; Je cherchais un code de travail simple, en utilisant SDL, sur la façon de dessiner des images 2D (qui, si cela ne fonctionne pas, c'est sûr que j'ai quelque chose de mal).

Merci!

GigaBass
la source
1
utilisez-vous des fonctions bitblit intégrées ou dessinez-vous des sprites par vous-même? cela peut faire une énorme différence!
Ali1S232
J'utilise simplement SDL_Blit (), sur le jeu dont les performances ont été horribles
GigaBass
En fait, pourriez-vous clarifier ce que vous voulez dire? Qu'est-ce que dessiner des sprites par moi-même?
GigaBass
mise en pixels dans le tampon
Ali1S232
Dans ce cas, non, j'utilise directement les seuls BLITS fournis par SDL.
GigaBass

Réponses:

7

Je recommande de charger vos sprites en utilisant SOIL , puis de les rendre en dessinant simplement des quads texturés. Si vous le faites sans aucune fonctionnalité obsolète (utilisez des shaders), vous constaterez que c'est très rapide.

Eric B
la source
J'ai jeté un rapide coup d'œil à la bibliothèque, et ça sonne bien. Pourriez-vous éventuellement fournir un très petit exemple de code sur l'utilisation de SOIL, un exemple de sortie d'une image simple serait génial! Merci
GigaBass
il y a des extraits de code sur le lien pour charger l'image. La façon dont vous la rendrez dépendra de vous, mais si vous voulez le faire de la "bonne façon", vous voudrez suivre quelque chose comme ça . Malheureusement, la configuration d'OpenGL avec des shaders, etc. n'est pas si rapide et facile, mais en vaut probablement la peine, surtout si vous aurez beaucoup de sprites à la fois.
Eric B
3

Voici un point de départ plutôt basique mais excellent pour dessiner des quads texturés dans OpenGL, à partir de ce point de départ de la fonction, j'ai 7 autres fonctions qui fournissent des fonctionnalités légèrement différentes, au dessin avec des couleurs teintées, au dessin d'éléments avec des valeurs alpha différentes et puis nous avons la rotation, écrêtage etc. etc. Mais cela devrait vous aider à démarrer :).

Edit: Code mis à jour;

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

L'image est une structure de base contenant les données de texture (GLuint), puis deux entiers pour contenir la largeur et la hauteur.

dan369
la source
J'ai lu que les fonctions glBegin, glEnd de OpenGL sont obsolètes car elles sont beaucoup plus lentes que celles à jour, est-ce correct? Pourtant, pour un jeu 2d simple, ce sera plus que suffisant pour obtenir tous les sprites que je veux sans que le GPU ne dépasse jamais 50%, n'est-ce pas?
GigaBass
Oui, il vaut mieux utiliser glDrawArrays et envoyer toutes les données de sommet en une seule fois. Mais je suppose que la différence est plutôt marginale, surtout lorsque vous ne traitez qu'avec 4 sommets.
dan369
Supposons que je dessine des images de 500 x 500, 20 d'entre elles, chaque image, sur un écran de 1 000 x 1 000 pixels? La différence serait-elle notable? Juste pour que je comprenne à quel point c'est mieux
GigaBass
Non, je ne pense pas que ce serait perceptible dans ce cas. N'oubliez pas que vous ne devez pas trop vous soucier de l'optimisation jusqu'à ce que vous rencontriez des problèmes. C'est un piège commun.
dan369
J'ai été choqué de voir qu'il occupait 20% de mon processeur et j'ai immédiatement pensé que je devais faire quelque chose pour le réparer ... sur plusieurs ordinateurs de mon ami, il ne pouvait pas fonctionner à vitesse normale!
GigaBass
0

SDL est-il nécessaire pour vous? SFML est une alternative à SDL qui utilise OpenGL pour le rendu. Cela peut également être plus facile pour les débutants, en raison de l'API orientée objet.

szotp
la source
downvote parce que votre réponse ne résout pas son problème. Il veut savoir comment travailler avec OpenGL. Il n'utilise pas de solution alternative.
Ali1S232
Ouais, je voulais un peu éviter de passer de SDL à SFML, je l'aime assez ... habitué à son fonctionnement. Voulez-vous dire que SFML peut faire le dessin facile que SDL peut faire avec les blits, en utilisant OpenGL pour le rendu? Ce serait en fait très bien.
GigaBass
2
@ user1896797: Oui SFML utilise OpenGL pour toutes les choses graphiques.
szotp
C'est super si c'est comme tu dis, je vais faire un tour! Je voterais si je le pouvais!
GigaBass
Confirmé, utilise en effet OpenGL. Je ne peux cependant pas accepter la vôtre, simplement parce que la réponse doit être liée à la question. Mais un grand merci!
GigaBass