surface: Surface rotation property should be float, not int.

Adjusted camera internals to work in floats, too.

Reference Issue #14616.
This commit is contained in:
Ryan C. Gordon
2025-12-07 15:26:31 -05:00
parent 9918d6cb5e
commit 4194879df1
13 changed files with 23 additions and 23 deletions

View File

@@ -37,7 +37,7 @@ General:
* Added SDL_FLIP_HORIZONTAL_AND_VERTICAL to flip a surface both horizontally and vertically * 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_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_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 * 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 * 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 * Added SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, which is sent when the usable desktop bounds change

View File

@@ -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. * 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 * - `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. * 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. * 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 * 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 * differently than what its camera provides (i.e. - the camera always
@@ -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_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x" #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_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. * Set the colorspace used by a surface.

View File

@@ -150,7 +150,7 @@ static size_t GetFrameBufLen(const SDL_CameraSpec *spec)
return wxh * SDL_BYTESPERPIXEL(fmt); 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; const SDL_CameraSpec *spec = &device->actual_spec;
@@ -832,7 +832,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
SDL_Surface *output_surface = NULL; SDL_Surface *output_surface = NULL;
SurfaceList *slist = NULL; SurfaceList *slist = NULL;
Uint64 timestampNS = 0; 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! // 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); const SDL_CameraFrameResult rc = device->AcquireFrame(device, device->acquire_surface, &timestampNS, &rotation);
@@ -929,7 +929,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
acquired->pixels = NULL; acquired->pixels = NULL;
acquired->pitch = 0; 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. // make the filled output surface available to the app.
SDL_LockMutex(device->lock); SDL_LockMutex(device->lock);

View File

@@ -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. // These are, initially, set from camera_driver, but we might swap them out with Zombie versions on disconnect/failure.
bool (*WaitDevice)(SDL_Camera *device); 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); void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame);
// All supported formats/dimensions for this device. // All supported formats/dimensions for this device.
@@ -178,7 +178,7 @@ typedef struct SDL_CameraDriverImpl
bool (*OpenDevice)(SDL_Camera *device, const SDL_CameraSpec *spec); bool (*OpenDevice)(SDL_Camera *device, const SDL_CameraSpec *spec);
void (*CloseDevice)(SDL_Camera *device); void (*CloseDevice)(SDL_Camera *device);
bool (*WaitDevice)(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 (*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 (*FreeDeviceHandle)(SDL_Camera *device); // SDL is done with this device; free the handle from SDL_AddCamera()
void (*Deinitialize)(void); void (*Deinitialize)(void);

View File

@@ -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. 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; SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
media_status_t res; media_status_t res;
@@ -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. 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; return result;
} }

View File

@@ -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. 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; SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden; SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden;
@@ -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. // there is probably math for this, but this is easy to slap into a table.
// rotation = rotations[uiorientation-1][devorientation-1]; // rotation = rotations[uiorientation-1][devorientation-1];
if (device->position == SDL_CAMERA_POSITION_BACK_FACING) { 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 { 90, 90, 90, 90 }, // ui portrait
{ 270, 270, 270, 270 }, // ui portait upside down { 270, 270, 270, 270 }, // ui portait upside down
{ 0, 0, 0, 0 }, // ui landscape left { 0, 0, 0, 0 }, // ui landscape left
{ 180, 180, 180, 180 } // ui landscape right { 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 { } else {
static const int front_rotations[4][4] = { static const Uint16 front_rotations[4][4] = {
{ 90, 90, 270, 270 }, // ui portrait { 90, 90, 270, 270 }, // ui portrait
{ 270, 270, 90, 90 }, // ui portait upside down { 270, 270, 90, 90 }, // ui portait upside down
{ 0, 0, 180, 180 }, // ui landscape left { 0, 0, 180, 180 }, // ui landscape left
{ 180, 180, 0, 0 } // ui landscape right { 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 #endif

View File

@@ -38,7 +38,7 @@ static bool DUMMYCAMERA_WaitDevice(SDL_Camera *device)
return SDL_Unsupported(); 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(); SDL_Unsupported();
return SDL_CAMERA_FRAME_ERROR; return SDL_CAMERA_FRAME_ERROR;

View File

@@ -39,7 +39,7 @@ static bool EMSCRIPTENCAMERA_WaitDevice(SDL_Camera *device)
return false; 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); void *rgba = SDL_malloc(device->actual_spec.width * device->actual_spec.height * 4);
if (!rgba) { if (!rgba) {

View File

@@ -430,7 +430,7 @@ static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value)
SDL_free(objs); 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); SDL_assert(device->hidden->current_sample != NULL);
@@ -562,7 +562,7 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_CopyFrame(SDL_Surface *frame, const
return SDL_CAMERA_FRAME_READY; 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); SDL_assert(device->hidden->current_sample != NULL);

View File

@@ -577,7 +577,7 @@ static bool PIPEWIRECAMERA_WaitDevice(SDL_Camera *device)
return true; 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; struct pw_buffer *b;

View File

@@ -125,7 +125,7 @@ static bool V4L2_WaitDevice(SDL_Camera *device)
return false; 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 int fd = device->hidden->fd;
const io_method io = device->hidden->io; const io_method io = device->hidden->io;

View File

@@ -190,7 +190,7 @@ static bool VITACAMERA_WaitDevice(SDL_Camera *device)
return true; 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}; SceCameraRead read = {0};
read.size = sizeof(SceCameraRead); read.size = sizeof(SceCameraRead);

View File

@@ -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 // 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 // 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. // 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); SDL_GetRenderOutputSize(renderer, &win_w, &win_h);
d.x = ((win_w - texture->w) / 2.0f); d.x = ((win_w - texture->w) / 2.0f);
d.y = ((win_h - texture->h) / 2.0f); d.y = ((win_h - texture->h) / 2.0f);