SDL: Added SDL_GetRenderLogicalPresentationRect()

From 473257cce652773118a0042adbc2636100654b2a Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 29 Jun 2024 14:12:50 -0700
Subject: [PATCH] Added SDL_GetRenderLogicalPresentationRect()

Fixes https://github.com/libsdl-org/SDL/issues/8815
---
 include/SDL3/SDL_render.h         | 17 +++++++++
 src/dynapi/SDL_dynapi.sym         |  1 +
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  1 +
 src/render/SDL_render.c           | 27 ++++++++++++++
 test/testautomation_render.c      | 60 +++++++++++++++++++++++++++++++
 6 files changed, 107 insertions(+)

diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index ee94ee9bbb510..a7302b68139e4 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -1297,6 +1297,7 @@ extern SDL_DECLSPEC SDL_Texture *SDLCALL SDL_GetRenderTarget(SDL_Renderer *rende
  *
  * \sa SDL_ConvertEventToRenderCoordinates
  * \sa SDL_GetRenderLogicalPresentation
+ * \sa SDL_GetRenderLogicalPresentationRect
  */
 extern SDL_DECLSPEC int SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode, SDL_ScaleMode scale_mode);
 
@@ -1320,6 +1321,22 @@ extern SDL_DECLSPEC int SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *r
  */
 extern SDL_DECLSPEC int SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode, SDL_ScaleMode *scale_mode);
 
+/**
+ * Get the final presentation rectangle for rendering.
+ *
+ * This function returns the calculated rectangle used for logical presentation, based on the presentation mode and output size. If logical presentation is disabled, it will fill the rectangle with the output size, in pixels.
+ *
+ * \param renderer the rendering context.
+ * \param rect a pointer filled in with the final presentation rectangle, may be NULL.
+ * \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.
+ *
+ * \sa SDL_SetRenderLogicalPresentation
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_GetRenderLogicalPresentationRect(SDL_Renderer *renderer, SDL_FRect *rect);
+
 /**
  * Get a point in render coordinates when given a point in window coordinates.
  *
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 8ca96c833db45..b54b9fd052694 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -393,6 +393,7 @@ SDL3_0.0.0 {
     SDL_GetRenderDrawColorFloat;
     SDL_GetRenderDriver;
     SDL_GetRenderLogicalPresentation;
+    SDL_GetRenderLogicalPresentationRect;
     SDL_GetRenderMetalCommandEncoder;
     SDL_GetRenderMetalLayer;
     SDL_GetRenderOutputSize;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index d809adcd724e6..b8c98467b2d63 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -418,6 +418,7 @@
 #define SDL_GetRenderDrawColorFloat SDL_GetRenderDrawColorFloat_REAL
 #define SDL_GetRenderDriver SDL_GetRenderDriver_REAL
 #define SDL_GetRenderLogicalPresentation SDL_GetRenderLogicalPresentation_REAL
+#define SDL_GetRenderLogicalPresentationRect SDL_GetRenderLogicalPresentationRect_REAL
 #define SDL_GetRenderMetalCommandEncoder SDL_GetRenderMetalCommandEncoder_REAL
 #define SDL_GetRenderMetalLayer SDL_GetRenderMetalLayer_REAL
 #define SDL_GetRenderOutputSize SDL_GetRenderOutputSize_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 43b85743922f3..740da8cf6aba3 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -438,6 +438,7 @@ SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColor,(SDL_Renderer *a, Uint8 *b, Uint8 *c,
 SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColorFloat,(SDL_Renderer *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetRenderDriver,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderLogicalPresentation,(SDL_Renderer *a, int *b, int *c, SDL_RendererLogicalPresentation *d, SDL_ScaleMode *e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(int,SDL_GetRenderLogicalPresentationRect,(SDL_Renderer *a, SDL_FRect *b),(a,b),return)
 SDL_DYNAPI_PROC(void*,SDL_GetRenderMetalCommandEncoder,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(void*,SDL_GetRenderMetalLayer,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderOutputSize,(SDL_Renderer *a, int *b, int *c),(a,b,c),return)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 0b504ca1d9c9b..ed705272df389 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -2607,6 +2607,33 @@ int SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL
     return 0;
 }
 
+int SDL_GetRenderLogicalPresentationRect(SDL_Renderer *renderer, SDL_FRect *rect)
+{
+    if (rect) {
+        SDL_zerop(rect);
+    }
+
+    CHECK_RENDERER_MAGIC(renderer, -1);
+
+    if (rect) {
+        if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) {
+            int output_w = 0, output_h = 0;
+
+            if (SDL_GetRenderOutputSize(renderer, &output_w, &output_h) < 0) {
+                return -1;
+            }
+
+            rect->x = 0.0f;
+            rect->y = 0.0f;
+            rect->w = (float)output_w;
+            rect->h = (float)output_h;
+        } else {
+            SDL_copyp(rect, &renderer->logical_dst_rect);
+        }
+    }
+    return 0;
+}
+
 static void SDL_RenderLogicalBorders(SDL_Renderer *renderer)
 {
     const SDL_FRect *dst = &renderer->logical_dst_rect;
diff --git a/test/testautomation_render.c b/test/testautomation_render.c
index 704bb41e362bb..644c6f4534d6e 100644
--- a/test/testautomation_render.c
+++ b/test/testautomation_render.c
@@ -920,6 +920,10 @@ static int render_testLogicalSize(void *arg)
     SDL_Rect viewport;
     SDL_FRect rect;
     int w, h;
+    int set_w, set_h;
+    SDL_RendererLogicalPresentation set_presentation_mode;
+    SDL_ScaleMode set_scale_mode;
+    SDL_FRect set_rect;
     const int factor = 2;
 
     viewport.x = ((TESTRENDER_SCREEN_W / 4) / factor) * factor;
@@ -940,6 +944,20 @@ static int render_testLogicalSize(void *arg)
     CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, w / factor, h / factor,
                                            SDL_LOGICAL_PRESENTATION_LETTERBOX,
                                            SDL_SCALEMODE_NEAREST))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    SDLTest_AssertCheck(
+        set_w == (w / factor) &&
+        set_h == (h / factor) &&
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX &&
+        set_scale_mode == SDL_SCALEMODE_NEAREST,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+    CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
+    SDLTest_AssertCheck(
+        set_rect.x == 0.0f &&
+        set_rect.y == 0.0f &&
+        set_rect.w == 320.0f &&
+        set_rect.h == 240.0f,
+        "Validate result from SDL_GetRenderLogicalPresentationRect, got {%g, %g, %gx%g}", set_rect.x, set_rect.y, set_rect.w, set_rect.h);
     CHECK_FUNC(SDL_SetRenderDrawColor, (renderer, 0, 255, 0, SDL_ALPHA_OPAQUE))
     rect.x = (float)viewport.x / factor;
     rect.y = (float)viewport.y / factor;
@@ -949,6 +967,20 @@ static int render_testLogicalSize(void *arg)
     CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0,
                                            SDL_LOGICAL_PRESENTATION_DISABLED,
                                            SDL_SCALEMODE_NEAREST))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    SDLTest_AssertCheck(
+        set_w == 0 &&
+        set_h == 0 &&
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED &&
+        set_scale_mode == SDL_SCALEMODE_NEAREST,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+    CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
+    SDLTest_AssertCheck(
+        set_rect.x == 0.0f &&
+        set_rect.y == 0.0f &&
+        set_rect.w == 320.0f &&
+        set_rect.h == 240.0f,
+        "Validate result from SDL_GetRenderLogicalPresentationRect, got {%g, %g, %gx%g}", set_rect.x, set_rect.y, set_rect.w, set_rect.h);
 
     /* Check to see if final image matches. */
     compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE);
@@ -999,11 +1031,39 @@ static int render_testLogicalSize(void *arg)
                                            h,
                                            SDL_LOGICAL_PRESENTATION_LETTERBOX,
                                            SDL_SCALEMODE_LINEAR))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    SDLTest_AssertCheck(
+        set_w == w - 2 * (TESTRENDER_SCREEN_W / 4) &&
+        set_h == h &&
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX &&
+        set_scale_mode == SDL_SCALEMODE_LINEAR,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+    CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
+    SDLTest_AssertCheck(
+        set_rect.x == 20.0f &&
+        set_rect.y == 0.0f &&
+        set_rect.w == 280.0f &&
+        set_rect.h == 240.0f,
+        "Validate result from SDL_GetRenderLogicalPresentationRect, got {%g, %g, %gx%g}", set_rect.x, set_rect.y, set_rect.w, set_rect.h);
     CHECK_FUNC(SDL_SetRenderDrawColor, (renderer, 0, 255, 0, SDL_ALPHA_OPAQUE))
     CHECK_FUNC(SDL_RenderFillRect, (renderer, NULL))
     CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0,
                                            SDL_LOGICAL_PRESENTATION_DISABLED,
                                            SDL_SCALEMODE_NEAREST))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    SDLTest_AssertCheck(
+        set_w == 0 &&
+        set_h == 0 &&
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED &&
+        set_scale_mode == SDL_SCALEMODE_NEAREST,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+    CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
+    SDLTest_AssertCheck(
+        set_rect.x == 0.0f &&
+        set_rect.y == 0.0f &&
+        set_rect.w == 320.0f &&
+        set_rect.h == 240.0f,
+        "Validate result from SDL_GetRenderLogicalPresentationRect, got {%g, %g, %gx%g}", set_rect.x, set_rect.y, set_rect.w, set_rect.h);
 
     /* Check to see if final image matches. */
     compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE);