Difference between revisions of "Vertically invert a surface in SDL"

From HalfgeekKB
Jump to navigation Jump to search
Line 1: Line 1:
This code flips an <code>SDL_Surface</code> upside-down by using a buffer the size of one line of the image to swap the first and last successively until the middle is reached.
+
This code vertically flips the content of an <code>SDL_Surface</code>.  It operates by first copying out the first row of the image, then overwriting the first with the last, then the last with the second, the second with the next to last, the next to last with the third, and so onAfter this shuffling has been completed, the top half of the image is already correct, and the bottom half begins one row too late.  At this point, a single <code>memmove</code> corrects that shift, and the row copied out at the beginning of the process is put back.
 
 
  <nowiki>
 
int invert_surface_vertical(SDL_Surface *surface)
 
{
 
    /* buffer big enough for one line of this image */
 
    Uint8 *line;
 
    Uint8 *a, *b;
 
    Uint16 pitch;
 
 
 
    if( SDL_MUSTLOCK(surface) ) {
 
        if( SDL_LockSurface(surface) < 0 ) {
 
            return -2;
 
        }
 
    }
 
 
 
    pitch = surface->pitch * sizeof(Uint8);
 
 
 
    line = (Uint8*)malloc(pitch);
 
 
 
    if( line == NULL )
 
        return -1;
 
 
 
    /* let us begin swapping the first and last lines
 
        of an ever-narrowing area of the image */
 
    a = (Uint8*)surface->pixels;
 
    b = a + pitch * (surface->h - 1);
 
 
 
 
 
    while( a < b ) {
 
        /* memcpy(dest, src, len) */
 
        memcpy(line, b, pitch);
 
        memcpy(b, a, pitch);
 
        memcpy(a, line, pitch);
 
 
 
        a += pitch;
 
        b -= pitch;
 
    }
 
 
 
    free(line);
 
 
 
    if( SDL_MUSTLOCK(surface) ) {
 
        SDL_UnlockSurface(surface);
 
    }
 
 
 
    return 0;
 
}
 
</nowiki>
 
 
 
 
 
Here's another one that does one fewer <code>memcpy</code> per two rows, but then must do a large <code>memmove</code> near the end.  This one I believe would be less computationally intensive.  And, of course, I haven't tested this code in SDL yet.
 
  
 
  <nowiki>
 
  <nowiki>

Revision as of 03:36, 1 June 2005

This code vertically flips the content of an SDL_Surface. It operates by first copying out the first row of the image, then overwriting the first with the last, then the last with the second, the second with the next to last, the next to last with the third, and so on. After this shuffling has been completed, the top half of the image is already correct, and the bottom half begins one row too late. At this point, a single memmove corrects that shift, and the row copied out at the beginning of the process is put back.

#define SDL_LOCKIFMUST(s) (SDL_MUSTLOCK(s) ? SDL_LockSurface(s) : 0)
#define SDL_UNLOCKIFMUST(s) { if(SDL_MUSTLOCK(s)) SDL_UnlockSurface(s); }

int invert_surface_vertical(SDL_Surface *surface)
{
    Uint8 *t;
    register Uint8 *a, *b;
    Uint8 *last;
    register Uint16 pitch;
    
    if( SDL_LOCKIFMUST(surface) < 0 )
        return -2;

    /* do nothing unless at least two lines */
    if(surface->h < 2) {
        SDL_UNLOCKIFMUST(surface);
        return 0;
    }

    /* get a place to store a line */
    pitch = surface->pitch;
    t = (Uint8*)malloc(pitch);

    if(t == NULL) {
        SDL_UNLOCKIFMUST(surface);
        return -2;
    }

    /* get first line; it's about to be trampled */
    memcpy(t,surface->pixels,pitch);

    /* now, shuffle the rest so it's almost correct */
    a = (Uint8*)surface->pixels;
    last = a + pitch * (surface->h - 1);
    b = last;

    while(a < b) {
        memcpy(a,b,pitch);
        a += pitch;
        memcpy(b,a,pitch);
        b -= pitch;
    }

    /* in this shuffled state, the bottom slice is too far down */
    memmove( b, b+pitch, last-b );

    /* now we can put back that first row--in the last place */
    memcpy(last,t,pitch);

    /* everything is in the right place; close up. */
    free(t);
    SDL_UNLOCKIFMUST(surface);

    return 0;
}