1

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?

Nadpher
  • 186
  • 1
  • 10

1 Answers1

4

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;
}
vvanpelt
  • 791
  • 1
  • 6
  • 13
  • Yes, i realized some things trying stuff out. First of all, i decided to repurpose stb_image's implementation of the flip on load function for sdl2; then i realized that it was carrying on the trasparency, and i just didn't realize because i'm not well versed with shaders yet. – Nadpher Jan 20 '21 at 20:41
  • Very nice @wanpelt! It's a shame this functionality is not part of the library. – AntonioCS Apr 16 '21 at 15:26
  • I assume something similar like this could be used to flip the image horizontally – AntonioCS Apr 19 '21 at 17:40
  • @AntonioCS Sadly it is not the same operation to flip the image horizontally, no. Here in my code I am using the fact that rows are stored in contiguous memory blocks, so I can read and write rows in single operations safely. This isn't the case for columns, so you will need to swap the image pixels by pixels if you want to flip it horizontally. – vvanpelt Apr 20 '21 at 09:39
  • @wanpelt Right right, you can't fully use the code but yeah, the principle of swapping will still be ok. I thought there might be an issue regarding the horizontal flip. Thanks – AntonioCS Apr 21 '21 at 17:03