Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion WhatsNew.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ General:
* Added SDL_FLIP_HORIZONTAL_AND_VERTICAL to flip a surface both horizontally and vertically
* Added SDL_LoadPNG(), SDL_LoadPNG_IO(), SDL_SavePNG(), and SDL_SavePNG_IO() to load and save PNG images
* Added SDL_LoadSurface() and SDL_LoadSurface_IO() to detect BMP and PNG formats and load them as surfaces
* Added SDL_PROP_SURFACE_ROTATION_NUMBER to indicate the rotation needed to display camera images upright
* Added SDL_PROP_SURFACE_ROTATION_FLOAT to indicate the rotation needed to display camera images upright
* Added SDL_RotateSurface() to create a rotated copy of a surface
* SDL_EVENT_WINDOW_EXPOSED now sets data1 to true if it is sent during live resizing
* Added SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, which is sent when the usable desktop bounds change
Expand Down
12 changes: 10 additions & 2 deletions include/SDL3/SDL_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
* left edge of the image, if this surface is being used as a cursor.
* - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the
* top edge of the image, if this surface is being used as a cursor.
* - `SDL_PROP_SURFACE_ROTATION_NUMBER`: the number of degrees a surface's
* - `SDL_PROP_SURFACE_ROTATION_FLOAT`: the number of degrees a surface's
* data is meant to be rotated clockwise to make the image right-side up.
* Default 0. This is used by the camera API, if a mobile device is oriented
* differently than what its camera provides (i.e. - the camera always
Expand All @@ -263,7 +263,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x"
#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y"
#define SDL_PROP_SURFACE_ROTATION_NUMBER "SDL.surface.rotation"
#define SDL_PROP_SURFACE_ROTATION_FLOAT "SDL.surface.rotation"

/**
* Set the colorspace used by a surface.
Expand Down Expand Up @@ -1027,6 +1027,14 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM
* larger than the original, with the background filled in with the colorkey,
* if available, or RGBA 255/255/255/0 if not.
*
* If `surface` has the SDL_PROP_SURFACE_ROTATION_FLOAT property set on it,
* the new copy will have the adjusted value set: if the rotation property is
* 90 and `angle` was 30, the new surface will have a property value of 60
* (that is: to be upright vs gravity, this surface needs to rotate 60 more
* degrees). However, note that further rotations on the new surface in this
* example will produce unexpected results, since the image will have resized
* and padded to accommodate the not-90 degree angle.
*
* \param surface the surface to rotate.
* \param angle the rotation angle, in degrees.
* \returns a rotated copy of the surface or NULL on failure; call
Expand Down
6 changes: 3 additions & 3 deletions src/camera/SDL_camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ static size_t GetFrameBufLen(const SDL_CameraSpec *spec)
return wxh * SDL_BYTESPERPIXEL(fmt);
}

static SDL_CameraFrameResult ZombieAcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult ZombieAcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
const SDL_CameraSpec *spec = &device->actual_spec;

Expand Down Expand Up @@ -832,7 +832,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
SDL_Surface *output_surface = NULL;
SurfaceList *slist = NULL;
Uint64 timestampNS = 0;
int rotation = 0;
float rotation = 0.0f;

// AcquireFrame SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice instead!
const SDL_CameraFrameResult rc = device->AcquireFrame(device, device->acquire_surface, &timestampNS, &rotation);
Expand Down Expand Up @@ -929,7 +929,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
acquired->pixels = NULL;
acquired->pitch = 0;

SDL_SetNumberProperty(SDL_GetSurfaceProperties(output_surface), SDL_PROP_SURFACE_ROTATION_NUMBER, rotation);
SDL_SetFloatProperty(SDL_GetSurfaceProperties(output_surface), SDL_PROP_SURFACE_ROTATION_FLOAT, rotation);

// make the filled output surface available to the app.
SDL_LockMutex(device->lock);
Expand Down
4 changes: 2 additions & 2 deletions src/camera/SDL_syscamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ struct SDL_Camera

// These are, initially, set from camera_driver, but we might swap them out with Zombie versions on disconnect/failure.
bool (*WaitDevice)(SDL_Camera *device);
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation);
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation);
void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame);

// All supported formats/dimensions for this device.
Expand Down Expand Up @@ -178,7 +178,7 @@ typedef struct SDL_CameraDriverImpl
bool (*OpenDevice)(SDL_Camera *device, const SDL_CameraSpec *spec);
void (*CloseDevice)(SDL_Camera *device);
bool (*WaitDevice)(SDL_Camera *device);
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation); // set frame->pixels, frame->pitch, *timestampNS, and *rotation!
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation); // set frame->pixels, frame->pitch, *timestampNS, and *rotation!
void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame); // Reclaim frame->pixels and frame->pitch!
void (*FreeDeviceHandle)(SDL_Camera *device); // SDL is done with this device; free the handle from SDL_AddCamera()
void (*Deinitialize)(void);
Expand Down
4 changes: 2 additions & 2 deletions src/camera/android/SDL_camera_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ static bool ANDROIDCAMERA_WaitDevice(SDL_Camera *device)
return true; // this isn't used atm, since we run our own thread via onImageAvailable callbacks.
}

static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
media_status_t res;
Expand Down Expand Up @@ -380,7 +380,7 @@ static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_
dev_rotation = -dev_rotation; // we want to subtract this value, instead of add, if back-facing.
}

*rotation = dev_rotation + device->hidden->rotation; // current phone orientation, static camera orientation in relation to phone.
*rotation = (float) (dev_rotation + device->hidden->rotation); // current phone orientation, static camera orientation in relation to phone.

return result;
}
Expand Down
10 changes: 5 additions & 5 deletions src/camera/coremedia/SDL_camera_coremedia.m
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static bool COREMEDIA_WaitDevice(SDL_Camera *device)
return true; // this isn't used atm, since we run our own thread out of Grand Central Dispatch.
}

static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden;
Expand Down Expand Up @@ -243,21 +243,21 @@ static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surf
// there is probably math for this, but this is easy to slap into a table.
// rotation = rotations[uiorientation-1][devorientation-1];
if (device->position == SDL_CAMERA_POSITION_BACK_FACING) {
static const int back_rotations[4][4] = {
static const Uint16 back_rotations[4][4] = {
{ 90, 90, 90, 90 }, // ui portrait
{ 270, 270, 270, 270 }, // ui portait upside down
{ 0, 0, 0, 0 }, // ui landscape left
{ 180, 180, 180, 180 } // ui landscape right
};
*rotation = back_rotations[ui_orientation - 1][device_orientation - 1];
*rotation = (float) back_rotations[ui_orientation - 1][device_orientation - 1];
} else {
static const int front_rotations[4][4] = {
static const Uint16 front_rotations[4][4] = {
{ 90, 90, 270, 270 }, // ui portrait
{ 270, 270, 90, 90 }, // ui portait upside down
{ 0, 0, 180, 180 }, // ui landscape left
{ 180, 180, 0, 0 } // ui landscape right
};
*rotation = front_rotations[ui_orientation - 1][device_orientation - 1];
*rotation = (float) front_rotations[ui_orientation - 1][device_orientation - 1];
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion src/camera/dummy/SDL_camera_dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static bool DUMMYCAMERA_WaitDevice(SDL_Camera *device)
return SDL_Unsupported();
}

static SDL_CameraFrameResult DUMMYCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult DUMMYCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SDL_Unsupported();
return SDL_CAMERA_FRAME_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion src/camera/emscripten/SDL_camera_emscripten.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static bool EMSCRIPTENCAMERA_WaitDevice(SDL_Camera *device)
return false;
}

static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
void *rgba = SDL_malloc(device->actual_spec.width * device->actual_spec.height * 4);
if (!rgba) {
Expand Down
4 changes: 2 additions & 2 deletions src/camera/mediafoundation/SDL_camera_mediafoundation.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value)
SDL_free(objs);
}

static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SDL_assert(device->hidden->current_sample != NULL);

Expand Down Expand Up @@ -562,7 +562,7 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_CopyFrame(SDL_Surface *frame, const
return SDL_CAMERA_FRAME_READY;
}

static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SDL_assert(device->hidden->current_sample != NULL);

Expand Down
2 changes: 1 addition & 1 deletion src/camera/pipewire/SDL_camera_pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ static bool PIPEWIRECAMERA_WaitDevice(SDL_Camera *device)
return true;
}

static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
struct pw_buffer *b;

Expand Down
2 changes: 1 addition & 1 deletion src/camera/v4l2/SDL_camera_v4l2.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ static bool V4L2_WaitDevice(SDL_Camera *device)
return false;
}

static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
const int fd = device->hidden->fd;
const io_method io = device->hidden->io;
Expand Down
2 changes: 1 addition & 1 deletion src/camera/vita/SDL_camera_vita.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ static bool VITACAMERA_WaitDevice(SDL_Camera *device)
return true;
}

static SDL_CameraFrameResult VITACAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
static SDL_CameraFrameResult VITACAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
{
SceCameraRead read = {0};
read.size = sizeof(SceCameraRead);
Expand Down
8 changes: 8 additions & 0 deletions src/video/SDL_surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -2198,6 +2198,14 @@ SDL_Surface *SDL_RotateSurface(SDL_Surface *surface, float angle)
SDL_DestroySurface(convert);
}
}

if (rotated) {
if (SDL_HasProperty(surface->props, SDL_PROP_SURFACE_ROTATION_FLOAT)) {
const float rotation = (SDL_GetNumberProperty(surface->props, SDL_PROP_SURFACE_ROTATION_FLOAT, 0) - angle);
SDL_SetFloatProperty(SDL_GetSurfaceProperties(rotated), SDL_PROP_SURFACE_ROTATION_FLOAT, rotation);
}
}

return rotated;
}

Expand Down
2 changes: 1 addition & 1 deletion test/testcamera.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
// device might be rotated to a different one (like an iPhone providing portrait images even if you hold
// the phone in landscape mode). The rotation is how far to rotate the image clockwise to put it right-side
// up, for how the user would expect it to be for how they are holding the device.
const int rotation = (int) SDL_GetNumberProperty(SDL_GetSurfaceProperties(frame_current), SDL_PROP_SURFACE_ROTATION_NUMBER, 0);
const float rotation = SDL_GetFloatProperty(SDL_GetSurfaceProperties(frame_current), SDL_PROP_SURFACE_ROTATION_FLOAT, 0.0f);
SDL_GetRenderOutputSize(renderer, &win_w, &win_h);
d.x = ((win_w - texture->w) / 2.0f);
d.y = ((win_h - texture->h) / 2.0f);
Expand Down
Loading