Как рисовать 2D-изображения, используя OpenGL, в SDL?

8

После всего, мне удалось найти простой кусок кода, который показывает, как рисовать 2D-изображение с 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;
    }

Я неопытный в 2D, и около недели назад начал возиться с SDL. Построил несколько простых структур для изображений, которые были бы на слоях, чтобы у меня был свой порядок рисования, чтобы спрайты рисовались после фона и т. Д., А затем выполнялся небольшой «движок спрайтов». Я получил спрайт Megaman, идущий влево и вправо, как я и хотел, над простым фоновым изображением 900x900.

Дело в том, что процессор почти достиг 20% на моем i5 ... поэтому я подумал об использовании графической карты для рисования! Добавил abit в OpenGL и сегодня, наконец-то, удалось запустить gl3w!

Поэтому сейчас я ищу простой способ отображения моих спрайтов / изображений в окне с помощью OpenGL. Я перепробовал все виды кода, с которым столкнулся, но ничего не могу отобразить, несмотря на то, что я делал проверки ошибок практически везде, и все, кажется, оказалось правильным!

TL: DR; Я искал какой-то простой рабочий код с использованием SDL для рисования 2D-изображений (который, если он не работает, наверняка у меня что-то не так).

Спасибо!

GigaBass
источник
1
Вы используете встроенные функции bitblit или вы рисуете спрайты самостоятельно? это может иметь огромное значение!
Ali1S232
Я просто использую SDL_Blit (), в игре, производительность которой была ужасной
GigaBass
На самом деле не могли бы вы уточнить, что вы имеете в виду? Что такое рисование спрайтов самостоятельно?
GigaBass
установка пикселей в буфере
Ali1S232
В этом случае нет, я использую только БЛИТЫ, предоставленные непосредственно SDL.
GigaBass

Ответы:

7

Я рекомендую загружать ваши спрайты с помощью SOIL , а затем рендерить их, просто рисуя текстурированные квадраты. Если вы сделаете это без каких-либо устаревших функций (используйте шейдеры), вы обнаружите, что это очень быстро.

Эрик Б
источник
Я быстро взглянул на библиотеку, и это звучит хорошо. Не могли бы вы предоставить очень маленький пример кода по использованию SOIL, пример вывода простого изображения был бы великолепен! Спасибо
GigaBass
в ссылке есть фрагменты кода для загрузки изображения. От того, как вы отрендерите его, зависит от вас, но если вы хотите сделать это «правильным способом», вам нужно будет выполнить что-то вроде этого . К сожалению, настроить OpenGL с шейдерами и т. Д. Не так быстро и просто, но, вероятно, оно того стоит, особенно если у вас будет много спрайтов одновременно.
Эрик Б
3

Вот довольно простая, но отличная отправная точка для рисования текстурированных четырехугольников в OpenGL, от этой отправной точки функции у меня есть 7 других функций, которые предоставляют немного другие функциональные возможности, рисование с тонированными цветами, рисование элементов с другими альфа-значениями, и затем у нас есть вращение, отсечение и т. д. и т. д. Но это должно помочь вам начать :).

Редактировать: обновленный код;

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

Изображение - это базовая структура, содержащая данные текстуры (GLuint), а затем два целых числа для хранения ширины и высоты.

dan369
источник
Я читал, хотя, что glBegin, glEnd-функции OpenGL устарели, потому что они намного медленнее, чем современные, это правильно? Тем не менее, для простой 2d игры этого будет более чем достаточно, чтобы получить все спрайты, которые я когда-либо захочу, без того, чтобы gpu превысил 50%, верно?
GigaBass
Да, лучше использовать glDrawArrays и отправлять все данные вершин за один раз. Но я полагаю, что разница довольно незначительна, особенно если вы имеете дело только с 4 вершинами.
dan369
Скажем, я рисовал изображения размером 500x500, 20 из которых в каждом кадре, на экране размером 1000x1000 пикселей? Будет ли разница заметна? Просто я понимаю, насколько он лучше
GigaBass
Нет, я не думаю, что это было бы заметно в этом случае. Помните, что вы не должны слишком беспокоиться об оптимизации, пока не столкнетесь с проблемами. Это распространенная ошибка.
dan369
Я был шокирован, увидев, что он занимал 20% моего процессора, и сразу подумал, что мне нужно что-то сделать, чтобы это исправить ... на нескольких компьютерах моего друга он не мог работать с нормальной скоростью!
GigaBass
0

Вам нужен SDL? SFML является альтернативой SDL, которая использует OpenGL для рендеринга. Это также может быть проще для начинающих из-за объектно-ориентированного API.

szotp
источник
понизить голос, потому что ваш ответ не решает его проблему. Он хочет знать, как работать с OpenGL. Он не использует для альтернативного решения.
Ali1S232
Да, я как бы хотел избежать перехода от SDL к SFML, мне это нравится, совсем немного ... привыкло к его работе. Вы имеете в виду, что SFML может легко рисовать SDL с блитами, используя OpenGL для рендеринга? Это было бы очень хорошо.
GigaBass
2
@ user1896797: Да. SFML использует OpenGL для всего графического.
szotp
Здорово, если ты так говоришь, я сделаю это! Я бы поднял голос, если бы мог!
GigaBass
Подтверждено, действительно использует OpenGL. Не могу принять ваше, хотя, просто из-за ответа на вопрос. Но большое спасибо!
GigaBass