Home > Software engineering >  How can I get at the raw pixel buffer of the window after drawing with OpenGL in SDL2?
How can I get at the raw pixel buffer of the window after drawing with OpenGL in SDL2?

Time:11-07

This piece of SDL2 code draws some white pixels on-screen using OpenGL, then grabs the pixels field of the window's SDL_Surface and loops through it, printing out the values of the contents. Even though I just drew a white triangle, the loop shows that there's nothing but zeros in that buffer (the code just prints 0 to standard out over and over).

How can I actually get at the modified pixel buffer, in something like RGB or ARGB or RGBA format?

#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <GL/glu.h>

int main()
{
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);

    const int WINDOW_WIDTH  = 100;
    const int WINDOW_HEIGHT = 100;
    SDL_Window *window = SDL_CreateWindow("OpenGL Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL);
    
    SDL_GLContext gl_context = SDL_GL_CreateContext(window);
    SDL_GL_SetSwapInterval(1);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    GLenum error = glGetError();
    if( error != GL_NO_ERROR )
    {
        printf( "Error initializing OpenGL! %s\n", gluErrorString(error));
    }

    glClearColor(0, 0, 0, 1);
    
    int quit = 0;
    SDL_Event event;
    while (!quit)
    {
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_QUIT:
                quit = 1;
                break;
            }
        }

        glBegin(GL_TRIANGLES);
        glColor3f(255, 255, 255);
        glVertex2f(0, 0);
        glVertex2f(0, 1);
        glVertex2f(1, 0);
        glEnd();

        SDL_GL_SwapWindow(window);

        SDL_Surface *surface = SDL_GetWindowSurface(window);
        int pixel_depth = SDL_BYTESPERPIXEL(surface->format->format);
        char *pixels = (char*) surface->pixels;
        int max_value = 0;
        for (int i = 0; i < WINDOW_WIDTH * WINDOW_HEIGHT * pixel_depth; i  )
        {
            if (pixels[i] > max_value)
            {
                max_value = pixels[i];
            }
        }
        SDL_FreeSurface(surface);

        SDL_Log("%d", max_value);
    }

    SDL_Quit();

    return 0;
}

CodePudding user response:

SDL_GetWindowSurface() doesn't work with OpenGL:

You may not combine this with 3D or the rendering API on this window.

Use glReadPixels() instead.

CodePudding user response:

Use PBO to read data from from the pixel buffer.

glReadBuffer(GL_COLOR_ATTACHMENT0);
writeIndex = (writeIndex   1) % 2;
readIndex = (readIndex   1) % 2;
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]);
                    // copy from framebuffer to PBO asynchronously. it will be ready in the NEXT frame
glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
                    // now read other PBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]);
unsigned char* Data = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);                    
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
  • Related