Wie zeichne ich 2D-Bilder mit OpenGL in SDL?

8

Nach allem gelang es mir, einen einfachen Code zu finden, der zeigt, wie man mit openGL ein 2D-Bild zeichnet:

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

Ich bin unerfahren in 2D und habe vor ungefähr einer Woche angefangen, mich mit SDL zu beschäftigen. Erstellte einige einfache Strukturen, um Bilder zu erhalten, die sich auf Ebenen befinden, sodass ich meine eigene Zeichenreihenfolge festlegen konnte, sodass Sprites nach dem Hintergrund usw. gezeichnet wurden, und führte dann eine kleine "Sprite-Engine" aus. Ich habe ein Megaman-Sprite nach links und rechts laufen lassen, genau wie ich es wollte, über einem einfachen 900x900ish Hintergrundbild.

Die CPU hat auf meinem i5 fast 20% erreicht ... also habe ich mir überlegt, die Grafikkarte zum Zeichnen zu verwenden! Ich habe mich ein wenig mit OpenGL beschäftigt und heute endlich geschafft, gl3w zum Laufen zu bringen!

Jetzt suche ich nach einer einfachen Möglichkeit, meine Sprites / Bilder mithilfe von OpenGL im Fenster anzuzeigen. Ich habe alle Arten von Code ausprobiert, auf die ich gestoßen bin, aber ich kann nichts anzeigen lassen, obwohl ich im Grunde überall Fehlerprüfungen durchgeführt habe und alles richtig zu sein scheint!

TL: DR; Ich suchte nach einem einfachen Arbeitscode mit SDL zum Zeichnen von 2D-Bildern (der, wenn er nicht funktioniert, sicher etwas falsch macht).

Vielen Dank!

GigaBass
quelle
1
Verwenden Sie integrierte Bitblit-Funktionen oder zeichnen Sie Sprites selbst? es kann einen großen Unterschied machen!
Ali1S232
Ich benutze nur SDL_Blit () für das Spiel, dessen Leistung schrecklich war
GigaBass
Könnten Sie eigentlich klarstellen, was Sie meinen? Was zeichnet ich selbst?
GigaBass
Pixel im Puffer setzen
Ali1S232
In diesem Fall verwende ich nur die von SDL bereitgestellten BLITS direkt.
GigaBass

Antworten:

7

Ich empfehle, Ihre Sprites mit SOIL zu laden und sie dann zu rendern, indem Sie nur strukturierte Quads zeichnen. Wenn Sie es ohne veraltete Funktionalität tun (verwenden Sie Shader), werden Sie feststellen, dass es sehr schnell ist.

Eric B.
quelle
Ich habe mir die Bibliothek kurz angesehen, und das hört sich gut an. Könnten Sie möglicherweise einen sehr kleinen Beispielcode für die Verwendung von SOIL bereitstellen, wäre ein Beispiel für die Ausgabe eines einfachen Bildes großartig! Danke
GigaBass
es gibt Code - Schnipsel auf den Link in das Bild zu laden. Wie Sie es auf Sie machen hängen, aber wenn man es den „richtigen Weg“ machen wollen, wollen Sie so etwas wie folgen dieser . Leider ist das Einrichten von OpenGL mit Shadern usw. nicht so schnell und einfach, aber es lohnt sich wahrscheinlich, besonders wenn Sie viele Sprites gleichzeitig haben.
Eric B
3

Hier ist ein ziemlich einfacher, aber guter Ausgangspunkt zum Zeichnen strukturierter Quads in OpenGL. Von diesem Funktionsstartpunkt aus habe ich 7 weitere Funktionen, die etwas andere Funktionen bieten, zum Zeichnen mit getönten Farben, zum Zeichnen von Elementen mit unterschiedlichen Alpha-Werten und dann haben wir Rotation. Clipping usw. usw. Aber dies sollte Ihnen den Einstieg erleichtern :).

Bearbeiten: Aktualisierter Code;

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

Bild ist eine Grundstruktur, die die Texturdaten (GLuint) und dann zwei Ganzzahlen für Breite und Höhe enthält.

dan369
quelle
Ich habe herumgelesen, dass glBegin, glEnd OpenGL-Funktionen veraltet sind, weil sie viel langsamer sind als die aktuellen. Ist das richtig? Für ein einfaches 2D-Spiel ist dies jedoch mehr als genug, um alle Sprites zu erhalten, die ich jemals haben möchte, ohne dass die GPU jemals 50% überschreitet, oder?
GigaBass
Ja, es ist besser, glDrawArrays zu verwenden und alle Scheitelpunktdaten auf einmal zu senden. Aber ich nehme an, der Unterschied ist eher gering, besonders wenn Sie nur mit 4 Eckpunkten zu tun haben.
dan369
Angenommen, ich habe 500 x 500 Bilder, 20 davon pro Bild, auf einen Bildschirm mit 1000 x 1000 Pixel gezeichnet? Wäre der Unterschied bemerkenswert? Nur damit ich
verstehe,
Nein, ich glaube nicht, dass es in diesem Fall auffällt. Denken Sie daran, dass Sie sich nicht zu viele Gedanken über die Optimierung machen sollten, bis Sie tatsächlich auf Probleme stoßen. Es ist eine häufige Gefahr.
dan369
Ich war schockiert zu sehen, dass es 20% meiner CPU beanspruchte und dachte sofort, ich müsste etwas tun, um es zu reparieren ... auf mehreren Computern meines Freundes konnte es nicht mit normaler Geschwindigkeit laufen!
GigaBass
0

Ist SDL für Sie notwendig? SFML ist eine Alternative zu SDL, die OpenGL zum Rendern verwendet. Aufgrund der objektorientierten API kann dies auch für Anfänger einfacher sein.

szotp
quelle
Downvote, weil Ihre Antwort sein Problem nicht löst. Er möchte wissen, wie man mit OpenGL arbeitet. Er verwendet keine alternative Lösung.
Ali1S232
Ja, ich wollte irgendwie vermeiden, von SDL zu SFML zu wechseln, ich mag es ziemlich gut ... daran gewöhnt, dass es funktioniert. Meinen Sie damit, dass SFML das einfache Zeichnen von SDL mit Blits ausführen kann und OpenGL zum Rendern verwendet? Das wäre eigentlich sehr gut.
GigaBass
2
@ user1896797: Ja, SFML verwendet OpenGL für alle grafischen Inhalte.
Szotp
Das ist großartig, wenn es so ist, wie du sagst, ich werde es versuchen! Würde mich freuen, wenn ich könnte!
GigaBass
Bestätigt, verwendet tatsächlich OpenGL. Ich kann deine aber nicht akzeptieren, nur weil sich die Antwort auf die Frage beziehen muss. Aber ein großes Dankeschön!
GigaBass