diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 579cea3dac..bb2a298139 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -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); diff --git a/src/dynapi/SDL_dynapi.exports b/src/dynapi/SDL_dynapi.exports index a06f0f21d6..5d5df5d17c 100644 --- a/src/dynapi/SDL_dynapi.exports +++ b/src/dynapi/SDL_dynapi.exports @@ -1307,3 +1307,7 @@ _SDL_SetJoystickSensorEnabled _SDL_JoystickSensorEnabled _SDL_GetJoystickSensorDataRate _SDL_GetJoystickSensorData +_SDL_SetRenderViewportFloat +_SDL_GetRenderViewportFloat +_SDL_SetRenderClipRectFloat +_SDL_GetRenderClipRectFloat diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 6e03541481..63864e372b 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -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: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 1f8ba18a01..d8deffc20e 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -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 diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 6bf988441a..cd2fc200a2 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -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) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 059eaf5f6d..51516b6ef6 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -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); diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 6642fe693a..552999ad46 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -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;