Added floating point versions of cliprect and viewport render functions

Fixes https://github.com/libsdl-org/SDL/issues/14654
This commit is contained in:
Sam Lantinga
2026-09-13 11:32:31 -07:00
parent b290793b78
commit 33b4a9d915
7 changed files with 194 additions and 21 deletions

View File

@@ -1823,6 +1823,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertEventToRenderCoordinates(SDL_Rendere
*
* \sa SDL_GetRenderViewport
* \sa SDL_RenderViewportSet
* \sa SDL_SetRenderViewportFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect);
@@ -1841,11 +1842,59 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, c
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetRenderViewportFloat
* \sa SDL_RenderViewportSet
* \sa SDL_SetRenderViewport
*/
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect);
/**
* Set the drawing area for rendering on the current target.
*
* Drawing will clip to this area (separately from any clipping done with
* SDL_SetRenderClipRect), and the top left of the area will become coordinate
* (0, 0) for future drawing commands.
*
* The area's width and height must be >= 0.
*
* Each render target has its own viewport. This function sets the viewport
* for the current render target.
*
* \param renderer the rendering context.
* \param rect the SDL_FRect structure representing the drawing area, or NULL
* to set the viewport to the entire target.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called on the main thread.
*
* \since This function is available since SDL 3.6.0.
*
* \sa SDL_GetRenderViewportFloat
* \sa SDL_RenderViewportSet
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewportFloat(SDL_Renderer *renderer, const SDL_FRect *rect);
/**
* Get the drawing area for the current target.
*
* Each render target has its own viewport. This function gets the viewport
* for the current render target.
*
* \param renderer the rendering context.
* \param rect an SDL_FRect structure filled in with the current drawing area.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called on the main thread.
*
* \since This function is available since SDL 3.6.0.
*
* \sa SDL_RenderViewportSet
* \sa SDL_SetRenderViewportFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewportFloat(SDL_Renderer *renderer, SDL_FRect *rect);
/**
* Return whether an explicit rectangle was set as the viewport.
*
@@ -1864,7 +1913,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetRenderViewport
* \sa SDL_GetRenderViewportFloat
* \sa SDL_SetRenderViewport
* \sa SDL_SetRenderViewportFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RenderViewportSet(SDL_Renderer *renderer);
@@ -1908,6 +1959,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderSafeArea(SDL_Renderer *renderer, S
*
* \sa SDL_GetRenderClipRect
* \sa SDL_RenderClipEnabled
* \sa SDL_SetRenderClipRectFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect);
@@ -1927,11 +1979,54 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetRenderClipRectFloat
* \sa SDL_RenderClipEnabled
* \sa SDL_SetRenderClipRect
*/
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect);
/**
* Set the clip rectangle for rendering on the specified target.
*
* Each render target has its own clip rectangle. This function sets the
* cliprect for the current render target.
*
* \param renderer the rendering context.
* \param rect an SDL_FRect structure representing the clip area, relative to
* the viewport, or NULL to disable clipping.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called on the main thread.
*
* \since This function is available since SDL 3.6.0.
*
* \sa SDL_GetRenderClipRectFloat
* \sa SDL_RenderClipEnabled
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRectFloat(SDL_Renderer *renderer, const SDL_FRect *rect);
/**
* Get the clip rectangle for the current target.
*
* Each render target has its own clip rectangle. This function gets the
* cliprect for the current render target.
*
* \param renderer the rendering context.
* \param rect an SDL_FRect structure filled in with the current clipping area
* or an empty rectangle if clipping is disabled.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called on the main thread.
*
* \since This function is available since SDL 3.6.0.
*
* \sa SDL_RenderClipEnabled
* \sa SDL_SetRenderClipRectFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRectFloat(SDL_Renderer *renderer, SDL_FRect *rect);
/**
* Get whether clipping is enabled on the given render target.
*
@@ -1947,7 +2042,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, S
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetRenderClipRect
* \sa SDL_GetRenderClipRectFloat
* \sa SDL_SetRenderClipRect
* \sa SDL_SetRenderClipRectFloat
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RenderClipEnabled(SDL_Renderer *renderer);

View File

@@ -1307,3 +1307,7 @@ _SDL_SetJoystickSensorEnabled
_SDL_JoystickSensorEnabled
_SDL_GetJoystickSensorDataRate
_SDL_GetJoystickSensorData
_SDL_SetRenderViewportFloat
_SDL_GetRenderViewportFloat
_SDL_SetRenderClipRectFloat
_SDL_GetRenderClipRectFloat

View File

@@ -1308,6 +1308,10 @@ SDL3_0.0.0 {
SDL_JoystickSensorEnabled;
SDL_GetJoystickSensorDataRate;
SDL_GetJoystickSensorData;
SDL_SetRenderViewportFloat;
SDL_GetRenderViewportFloat;
SDL_SetRenderClipRectFloat;
SDL_GetRenderClipRectFloat;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@@ -1334,3 +1334,7 @@
#define SDL_JoystickSensorEnabled SDL_JoystickSensorEnabled_REAL
#define SDL_GetJoystickSensorDataRate SDL_GetJoystickSensorDataRate_REAL
#define SDL_GetJoystickSensorData SDL_GetJoystickSensorData_REAL
#define SDL_SetRenderViewportFloat SDL_SetRenderViewportFloat_REAL
#define SDL_GetRenderViewportFloat SDL_GetRenderViewportFloat_REAL
#define SDL_SetRenderClipRectFloat SDL_SetRenderClipRectFloat_REAL
#define SDL_GetRenderClipRectFloat SDL_GetRenderClipRectFloat_REAL

View File

@@ -1342,3 +1342,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetJoystickSensorEnabled,(SDL_Joystick *a,SDL_SensorTyp
SDL_DYNAPI_PROC(bool,SDL_JoystickSensorEnabled,(SDL_Joystick *a,SDL_SensorType b),(a,b),return)
SDL_DYNAPI_PROC(float,SDL_GetJoystickSensorDataRate,(SDL_Joystick *a,SDL_SensorType b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_GetJoystickSensorData,(SDL_Joystick *a,SDL_SensorType b,float *c,int d),(a,b,c,d),return)
SDL_DYNAPI_PROC(bool,SDL_SetRenderViewportFloat,(SDL_Renderer *a,const SDL_FRect *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_GetRenderViewportFloat,(SDL_Renderer *a,SDL_FRect *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_SetRenderClipRectFloat,(SDL_Renderer *a,const SDL_FRect *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_GetRenderClipRectFloat,(SDL_Renderer *a,SDL_FRect *b),(a,b),return)

View File

@@ -1165,8 +1165,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
renderer->main_view.pixel_w = surface->w;
renderer->main_view.pixel_h = surface->h;
}
renderer->main_view.viewport.w = -1;
renderer->main_view.viewport.h = -1;
renderer->main_view.viewport.w = -1.0f;
renderer->main_view.viewport.h = -1.0f;
renderer->main_view.scale.x = 1.0f;
renderer->main_view.scale.y = 1.0f;
renderer->main_view.logical_scale.x = 1.0f;
@@ -1558,8 +1558,8 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert
texture->scaleMode = renderer->scale_mode;
texture->view.pixel_w = w;
texture->view.pixel_h = h;
texture->view.viewport.w = -1;
texture->view.viewport.h = -1;
texture->view.viewport.w = -1.0f;
texture->view.viewport.h = -1.0f;
texture->view.scale.x = 1.0f;
texture->view.scale.y = 1.0f;
texture->view.logical_scale.x = 1.0f;
@@ -3160,25 +3160,56 @@ bool SDL_ConvertEventToRenderCoordinates(SDL_Renderer *renderer, SDL_Event *even
}
bool SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect)
{
if (rect) {
SDL_FRect frect;
SDL_RectToFRect(rect, &frect);
return SDL_SetRenderViewportFloat(renderer, &frect);
} else {
return SDL_SetRenderViewportFloat(renderer, NULL);
}
}
bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect)
{
if (rect) {
SDL_zerop(rect);
}
SDL_FRect frect;
if (SDL_GetRenderViewportFloat(renderer, &frect)) {
if (rect) {
rect->x = (int)SDL_floorf(frect.x);
rect->y = (int)SDL_floorf(frect.y);
rect->w = (int)SDL_ceilf(frect.w);
rect->h = (int)SDL_ceilf(frect.h);
}
return true;
} else {
return false;
}
}
bool SDL_SetRenderViewportFloat(SDL_Renderer *renderer, const SDL_FRect *rect)
{
CHECK_RENDERER_MAGIC(renderer, false);
SDL_RenderViewState *view = renderer->view;
if (rect) {
if ((rect->w < 0) || (rect->h < 0)) {
if ((rect->w < 0.0f) || (rect->h < 0.0f)) {
return SDL_SetError("rect has a negative size");
}
SDL_copyp(&view->viewport, rect);
} else {
view->viewport.x = view->viewport.y = 0;
view->viewport.w = view->viewport.h = -1;
view->viewport.x = view->viewport.y = 0.0f;
view->viewport.w = view->viewport.h = -1.0f;
}
UpdatePixelViewport(renderer, view);
return QueueCmdSetViewport(renderer);
}
bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect)
bool SDL_GetRenderViewportFloat(SDL_Renderer *renderer, SDL_FRect *rect)
{
if (rect) {
SDL_zerop(rect);
@@ -3190,15 +3221,15 @@ bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect)
const SDL_RenderViewState *view = renderer->view;
rect->x = view->viewport.x;
rect->y = view->viewport.y;
if (view->viewport.w >= 0) {
if (view->viewport.w >= 0.0f) {
rect->w = view->viewport.w;
} else {
rect->w = (int)SDL_ceilf(view->pixel_w / view->current_scale.x);
rect->w = view->pixel_w / view->current_scale.x;
}
if (view->viewport.h >= 0) {
if (view->viewport.h >= 0.0f) {
rect->h = view->viewport.h;
} else {
rect->h = (int)SDL_ceilf(view->pixel_h / view->current_scale.y);
rect->h = view->pixel_h / view->current_scale.y;
}
}
return true;
@@ -3209,7 +3240,7 @@ bool SDL_RenderViewportSet(SDL_Renderer *renderer)
CHECK_RENDERER_MAGIC(renderer, false);
const SDL_RenderViewState *view = renderer->view;
return (view->viewport.w >= 0 && view->viewport.h >= 0);
return (view->viewport.w >= 0.0f && view->viewport.h >= 0.0f);
}
static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect)
@@ -3221,14 +3252,14 @@ static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect)
rect->x = 0.0f;
rect->y = 0.0f;
if (view->viewport.w >= 0) {
rect->w = (float)view->viewport.w;
if (view->viewport.w >= 0.0f) {
rect->w = view->viewport.w;
} else {
rect->w = view->pixel_w / scale_x;
}
if (view->viewport.h >= 0) {
rect->h = (float)view->viewport.h;
if (view->viewport.h >= 0.0f) {
rect->h = view->viewport.h;
} else {
rect->h = view->pixel_h / scale_y;
}
@@ -3282,11 +3313,40 @@ bool SDL_GetRenderSafeArea(SDL_Renderer *renderer, SDL_Rect *rect)
}
bool SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
{
if (rect) {
SDL_FRect frect;
SDL_RectToFRect(rect, &frect);
return SDL_SetRenderClipRectFloat(renderer, &frect);
} else {
return SDL_SetRenderClipRectFloat(renderer, NULL);
}
}
bool SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect)
{
if (rect) {
SDL_zerop(rect);
}
SDL_FRect frect;
if (SDL_GetRenderClipRectFloat(renderer, &frect)) {
rect->x = (int)SDL_floorf(frect.x);
rect->y = (int)SDL_floorf(frect.y);
rect->w = (int)SDL_ceilf(frect.w);
rect->h = (int)SDL_ceilf(frect.h);
return true;
} else {
return false;
}
}
bool SDL_SetRenderClipRectFloat(SDL_Renderer *renderer, const SDL_FRect *rect)
{
CHECK_RENDERER_MAGIC(renderer, false);
SDL_RenderViewState *view = renderer->view;
if (rect && rect->w >= 0 && rect->h >= 0) {
if (rect && rect->w >= 0.0f && rect->h >= 0.0f) {
view->clipping_enabled = true;
SDL_copyp(&view->clip_rect, rect);
} else {
@@ -3298,7 +3358,7 @@ bool SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
return QueueCmdSetClipRect(renderer);
}
bool SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect)
bool SDL_GetRenderClipRectFloat(SDL_Renderer *renderer, SDL_FRect *rect)
{
if (rect) {
SDL_zerop(rect);

View File

@@ -52,9 +52,9 @@ typedef struct SDL_RenderViewState
{
int pixel_w;
int pixel_h;
SDL_Rect viewport;
SDL_FRect viewport;
SDL_Rect pixel_viewport;
SDL_Rect clip_rect;
SDL_FRect clip_rect;
SDL_Rect pixel_clip_rect;
bool clipping_enabled;
SDL_FPoint scale;