Difference between revisions of "Vertically invert a surface in SDL"
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 02: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;
}