Added SDL_FlipSurface() to flip a surface vertically or horizontally

Fixes https://github.com/libsdl-org/SDL/issues/8857
main
Sam Lantinga 2024-01-20 06:31:37 -08:00
parent 2cd583ee13
commit 308906ba25
13 changed files with 184 additions and 21 deletions

View File

@ -17,6 +17,7 @@ General:
* Added SDL_GetPrimaryDisplay() to get the instance ID of the primary display
* Added SDL_GetWindowParent() to get the parent of popup windows
* Added SDL_CreateSurface() and SDL_CreateSurfaceFrom() which replace SDL_CreateRGBSurface*(), and can also be used to create YUV surfaces
* Added SDL_FlipSurface() to flip a surface vertically or horizontally
* Added SDL_GetJoysticks(), SDL_GetJoystickInstanceName(), SDL_GetJoystickInstancePath(), SDL_GetJoystickInstancePlayerIndex(), SDL_GetJoystickInstanceGUID(), SDL_GetJoystickInstanceVendor(), SDL_GetJoystickInstanceProduct(), SDL_GetJoystickInstanceProductVersion(), and SDL_GetJoystickInstanceType() to directly query the list of available joysticks
* Added SDL_GetGamepads(), SDL_GetGamepadInstanceName(), SDL_GetGamepadInstancePath(), SDL_GetGamepadInstancePlayerIndex(), SDL_GetGamepadInstanceGUID(), SDL_GetGamepadInstanceVendor(), SDL_GetGamepadInstanceProduct(), SDL_GetGamepadInstanceProductVersion(), and SDL_GetGamepadInstanceType() to directly query the list of available gamepads
* Added SDL_GetSensors(), SDL_GetSensorInstanceName(), SDL_GetSensorInstanceType(), and SDL_GetSensorInstanceNonPortableType() to directly query the list of available sensors

View File

@ -1037,6 +1037,7 @@ The following functions have been removed:
* SDL_SetTextureUserData() - use SDL_GetTextureProperties() instead
The following symbols have been renamed:
* SDL_RendererFlip => SDL_FlipMode
* SDL_ScaleModeBest => SDL_SCALEMODE_BEST
* SDL_ScaleModeLinear => SDL_SCALEMODE_LINEAR
* SDL_ScaleModeNearest => SDL_SCALEMODE_NEAREST

View File

@ -105,16 +105,6 @@ typedef enum
SDL_TEXTUREACCESS_TARGET /**< Texture can be used as a render target */
} SDL_TextureAccess;
/**
* Flip constants for SDL_RenderTextureRotated
*/
typedef enum
{
SDL_FLIP_NONE = 0x00000000, /**< Do not flip */
SDL_FLIP_HORIZONTAL = 0x00000001, /**< flip horizontally */
SDL_FLIP_VERTICAL = 0x00000002 /**< flip vertically */
} SDL_RendererFlip;
/**
* How the logical size is mapped to the output
*/
@ -1494,7 +1484,7 @@ extern DECLSPEC int SDLCALL SDL_RenderTexture(SDL_Renderer *renderer, SDL_Textur
* \param center A pointer to a point indicating the point around which
* dstrect will be rotated (if NULL, rotation will be done
* around dstrect.w/2, dstrect.h/2).
* \param flip An SDL_RendererFlip value stating which flipping actions should
* \param flip An SDL_FlipMode value stating which flipping actions should
* be performed on the texture
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
@ -1504,7 +1494,7 @@ extern DECLSPEC int SDLCALL SDL_RenderTexture(SDL_Renderer *renderer, SDL_Textur
extern DECLSPEC int SDLCALL SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center,
const SDL_RendererFlip flip);
const SDL_FlipMode flip);
/**
* Render a list of triangles, optionally using a texture and indices into the

View File

@ -75,6 +75,15 @@ typedef enum
SDL_SCALEMODE_BEST /**< anisotropic filtering */
} SDL_ScaleMode;
/**
* The flip mode
*/
typedef enum
{
SDL_FLIP_NONE, /**< Do not flip */
SDL_FLIP_HORIZONTAL, /**< flip horizontally */
SDL_FLIP_VERTICAL /**< flip vertically */
} SDL_FlipMode;
/**
* A collection of pixels used in software blitting.
@ -602,6 +611,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface,
extern DECLSPEC int SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface,
SDL_Rect *rect);
/*
* Flip a surface vertically or horizontally.
*
* \param surface the surface to flip
* \param flip the direction to flip
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC int SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip);
/*
* Creates a new surface identical to the existing surface.
*

View File

@ -964,6 +964,7 @@ SDL3_0.0.0 {
SDL_GetHapticInstanceID;
SDL_GetHapticName;
SDL_ReadSurfacePixel;
SDL_FlipSurface;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -989,3 +989,4 @@
#define SDL_GetHapticInstanceID SDL_GetHapticInstanceID_REAL
#define SDL_GetHapticName SDL_GetHapticName_REAL
#define SDL_ReadSurfacePixel SDL_ReadSurfacePixel_REAL
#define SDL_FlipSurface SDL_FlipSurface_REAL

View File

@ -580,7 +580,7 @@ SDL_DYNAPI_PROC(int,SDL_RenderReadPixels,(SDL_Renderer *a, const SDL_Rect *b, Ui
SDL_DYNAPI_PROC(int,SDL_RenderRect,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderRects,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderTexture,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, const SDL_FRect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_RenderTextureRotated,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, const SDL_FRect *d, const double e, const SDL_FPoint *f, const SDL_RendererFlip g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_RenderTextureRotated,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, const SDL_FRect *d, const double e, const SDL_FPoint *f, const SDL_FlipMode g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(SDL_AssertState,SDL_ReportAssertion,(SDL_AssertData *a, const char *b, const char *c, int d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_ResetAssertionReport,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_ResetHint,(const char *a),(a),return)
@ -1014,3 +1014,4 @@ SDL_DYNAPI_PROC(SDL_Haptic*,SDL_GetHapticFromInstanceID,(SDL_HapticID a),(a),ret
SDL_DYNAPI_PROC(SDL_HapticID,SDL_GetHapticInstanceID,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetHapticName,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_ReadSurfacePixel,(SDL_Surface *a, int b, int c, Uint8 *d, Uint8 *e, Uint8 *f, Uint8 *g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_FlipSurface,(SDL_Surface *a, SDL_FlipMode b),(a,b),return)

View File

@ -611,7 +611,7 @@ static int QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_
static int QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcquad, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY_EX, texture);
int retval = -1;
@ -3296,7 +3296,7 @@ int SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FR
int SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip)
{
SDL_FRect real_srcrect;
SDL_FRect real_dstrect;

View File

@ -173,7 +173,7 @@ struct SDL_Renderer
const SDL_FRect *srcrect, const SDL_FRect *dstrect);
int (*QueueCopyEx)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const SDL_FRect *srcquad, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y);
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y);
int (*QueueGeometry)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
int num_vertices, const void *indices, int num_indices, int size_indices,

View File

@ -842,7 +842,7 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex
static int PSP_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
VertTV *verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 4 * sizeof(VertTV), 4, &cmd->data.draw.first);
const float centerx = center->x;

View File

@ -257,14 +257,14 @@ typedef struct CopyExData
SDL_Rect dstrect;
double angle;
SDL_FPoint center;
SDL_RendererFlip flip;
SDL_FlipMode flip;
float scale_x;
float scale_y;
} CopyExData;
static int SW_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const SDL_FRect *srcrect, const SDL_FRect *dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
CopyExData *verts = (CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(CopyExData), 0, &cmd->data.draw.first);
@ -311,7 +311,7 @@ static int Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surf
static int SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Texture *texture,
const SDL_Rect *srcrect, const SDL_Rect *final_rect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
SDL_Surface *src = (SDL_Surface *)texture->driverdata;
SDL_Rect tmp_rect;

View File

@ -1078,11 +1078,97 @@ void SDL_UnlockSurface(SDL_Surface *surface)
#endif
}
static int SDL_FlipSurfaceHorizontal(SDL_Surface *surface)
{
SDL_bool isstack;
Uint8 *row, *a, *b, *tmp;
int i, j, bpp;
if (surface->format->BitsPerPixel < 8) {
/* We could implement this if needed, but we'd have to flip sets of bits within a byte */
return SDL_Unsupported();
}
if (surface->h <= 0) {
return 0;
}
if (surface->w <= 1) {
return 0;
}
bpp = surface->format->BytesPerPixel;
row = (Uint8 *)surface->pixels;
tmp = SDL_small_alloc(Uint8, surface->pitch, &isstack);
for (i = surface->h; i--; ) {
a = row;
b = a + (surface->w - 1) * bpp;
for (j = surface->w / 2; j--; ) {
SDL_memcpy(tmp, a, bpp);
SDL_memcpy(a, b, bpp);
SDL_memcpy(b, tmp, bpp);
a += bpp;
b -= bpp;
}
row += surface->pitch;
}
SDL_small_free(tmp, isstack);
return 0;
}
static int SDL_FlipSurfaceVertical(SDL_Surface *surface)
{
SDL_bool isstack;
Uint8 *a, *b, *tmp;
int i;
if (surface->h <= 1) {
return 0;
}
a = (Uint8 *)surface->pixels;
b = a + (surface->h - 1) * surface->pitch;
tmp = SDL_small_alloc(Uint8, surface->pitch, &isstack);
for (i = surface->h / 2; i--; ) {
SDL_memcpy(tmp, a, surface->pitch);
SDL_memcpy(a, b, surface->pitch);
SDL_memcpy(b, tmp, surface->pitch);
a += surface->pitch;
b -= surface->pitch;
}
SDL_small_free(tmp, isstack);
return 0;
}
int SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip)
{
if (!surface || !surface->format) {
return SDL_InvalidParamError("surface");
}
if (!surface->pixels) {
return 0;
}
switch (flip) {
case SDL_FLIP_HORIZONTAL:
return SDL_FlipSurfaceHorizontal(surface);
case SDL_FLIP_VERTICAL:
return SDL_FlipSurfaceVertical(surface);
default:
return SDL_InvalidParamError("flip");
}
}
/*
* Creates a new surface identical to the existing surface
*/
SDL_Surface *SDL_DuplicateSurface(SDL_Surface *surface)
{
if (!surface) {
SDL_InvalidParamError("surface");
return NULL;
}
return SDL_ConvertSurface(surface, surface->format);
}

View File

@ -22,6 +22,15 @@
#include "testautomation_suites.h"
#include "testautomation_images.h"
#define CHECK_FUNC(FUNC, PARAMS) \
{ \
int result = FUNC PARAMS; \
if (result != 0) { \
SDLTest_AssertCheck(result == 0, "Validate result from %s, expected: 0, got: %i, %s", #FUNC, result, SDL_GetError()); \
} \
}
/* ================= Test Case Implementation ================== */
/* Shared test surface */
@ -791,6 +800,54 @@ static int surface_testOverflow(void *arg)
return TEST_COMPLETED;
}
static int surface_testFlip(void *arg)
{
SDL_Surface *surface;
Uint8 *pixels;
int offset;
const char *expectedError;
surface = SDL_CreateSurface(3, 3, SDL_PIXELFORMAT_RGB24);
SDLTest_AssertCheck(surface != NULL, "SDL_CreateSurface()");
SDL_ClearError();
expectedError = "Parameter 'surface' is invalid";
SDL_FlipSurface(NULL, SDL_FLIP_HORIZONTAL);
SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
"Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
SDL_ClearError();
expectedError = "Parameter 'flip' is invalid";
SDL_FlipSurface(surface, SDL_FLIP_NONE);
SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
"Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
pixels = (Uint8 *)surface->pixels;
*pixels = 0xFF;
offset = 0;
SDLTest_AssertPass("Call to SDL_FlipSurface(surface, SDL_FLIP_VERTICAL)");
CHECK_FUNC(SDL_FlipSurface, (surface, SDL_FLIP_VERTICAL));
SDLTest_AssertCheck(pixels[offset] == 0x00,
"Expected pixels[%d] == 0x00 got 0x%.2X", offset, pixels[offset]);
offset = 2 * surface->pitch;
SDLTest_AssertCheck(pixels[offset] == 0xFF,
"Expected pixels[%d] == 0xFF got 0x%.2X", offset, pixels[offset]);
SDLTest_AssertPass("Call to SDL_FlipSurface(surface, SDL_FLIP_HORIZONTAL)");
CHECK_FUNC(SDL_FlipSurface, (surface, SDL_FLIP_HORIZONTAL));
SDLTest_AssertCheck(pixels[offset] == 0x00,
"Expected pixels[%d] == 0x00 got 0x%.2X", offset, pixels[offset]);
offset += (surface->w - 1) * surface->format->BytesPerPixel;
SDLTest_AssertCheck(pixels[offset] == 0xFF,
"Expected pixels[%d] == 0xFF got 0x%.2X", offset, pixels[offset]);
SDL_DestroySurface(surface);
return TEST_COMPLETED;
}
/* ================= Test References ================== */
/* Surface test cases */
@ -849,11 +906,15 @@ static const SDLTest_TestCaseReference surfaceTestOverflow = {
surface_testOverflow, "surface_testOverflow", "Test overflow detection.", TEST_ENABLED
};
static const SDLTest_TestCaseReference surfaceTestFlip = {
surface_testFlip, "surface_testFlip", "Test surface flipping.", TEST_ENABLED
};
/* Sequence of Surface test cases */
static const SDLTest_TestCaseReference *surfaceTests[] = {
&surfaceTest1, &surfaceTest2, &surfaceTest3, &surfaceTest4, &surfaceTest5,
&surfaceTest6, &surfaceTest7, &surfaceTest8, &surfaceTest9, &surfaceTest10,
&surfaceTest11, &surfaceTest12, &surfaceTestOverflow, NULL
&surfaceTest11, &surfaceTest12, &surfaceTestOverflow, &surfaceTestFlip, NULL
};
/* Surface test suite (global) */