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

From HalfgeekKB
Jump to navigation Jump to search
Line 44: Line 44:
 
     }
 
     }
  
     return 1;
+
     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>
 +
#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;
 
}
 
}
 
</nowiki>
 
</nowiki>

Revision as of 03:56, 1 June 2005

This code flips an SDL_Surface 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.

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


Here's another one that does one fewer memcpy per two rows, but then must do a large memmove near the end. This one I believe would be less computationally intensive. And, of course, I haven't tested this code in SDL yet.

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