c++sdl-2sdl-image

Flipping a surface vertically in SDL2


The closest i've gotten is this:

void Engine::flipSurfaceVertically(SDL_Surface* surface)
{
    SDL_LockSurface(surface);

    Uint8* pixels = reinterpret_cast<Uint8*>(surface->pixels);
    for (int k = 0; k < sizeof(Uint32); ++k)
    {
        for (int i = 0; i < surface->w; ++i)
        {
            for (int j = 0; j < surface->h / 2; ++j)
            {
                Uint32 currentPos = (j * surface->pitch) + (i * sizeof(Uint32)) + k;
                Uint32 target = ((surface->h - j - 1) * surface->pitch) + (i * sizeof(Uint32)) + k;
                Uint8 temp = pixels[target];
                pixels[target] = pixels[currentPos];
                pixels[currentPos] = temp;
            }
        }
    }

    SDL_UnlockSurface(surface);
}

But it doesn't keep the transparency. How can i go about actually achieving this?


Solution

  • I don't know where is the error exactly, I tried your code on my machine and it works well on the image I used. I suspect that your code indeed preserves transparency, but it is removed later in your implementation.

    Anyway, if I may suggest an improvement for your code: you don't need such complicated operations to vertically flip a surface. The SDL_Surface structure stores the pixel data in row-major order, meaning that the pixels array is a sequence of rows, where each of these rows have a size of pitch bytes. Thus, to flip your surface vertically, you can simply iterate over the rows and swap them. The advantage of this method is that it does not require knowledge about pixel format, so it can be implemented for all image types (alpha channel or not), and it is pretty simple to implement.

    Here is a minimal example that you can compile and experiment with:

    #include <SDL2/SDL.h>
    #include <SDL2/SDL_image.h>
    
    void flip_surface(SDL_Surface* surface) 
    {
        SDL_LockSurface(surface);
        
        int pitch = surface->pitch; // row size
        char* temp = new char[pitch]; // intermediate buffer
        char* pixels = (char*) surface->pixels;
        
        for(int i = 0; i < surface->h / 2; ++i) {
            // get pointers to the two rows to swap
            char* row1 = pixels + i * pitch;
            char* row2 = pixels + (surface->h - i - 1) * pitch;
            
            // swap rows
            memcpy(temp, row1, pitch);
            memcpy(row1, row2, pitch);
            memcpy(row2, temp, pitch);
        }
        
        delete[] temp;
    
        SDL_UnlockSurface(surface);
    }
    
    int main(int argc, char* argv[]) 
    {
        SDL_Init(SDL_INIT_VIDEO);
        
        SDL_Surface* surface = IMG_Load("image.png");
        flip_surface(surface);
        IMG_SavePNG(surface, "result.png");
        
        SDL_Quit();
        
        return 0;
    }