From 1d0e28a5b3d930f6ae0692897f4e32f36570290c Mon Sep 17 00:00:00 2001
From: williamistGitHub <[EMAIL REDACTED]>
Date: Sat, 7 Dec 2024 00:14:55 -0500
Subject: [PATCH] Add SDL_RenderDebugTextF & SDL_RenderDebugTextV
This should make it easier to quickly put important numbers and such on
the screen without having to format them into a string manually.
---
examples/renderer/18-debug-text/debug-text.c | 3 +
include/SDL3/SDL_render.h | 58 ++++++++++++++++++++
src/dynapi/SDL_dynapi.c | 10 ++++
src/dynapi/SDL_dynapi.sym | 2 +
src/dynapi/SDL_dynapi_overrides.h | 2 +
src/dynapi/SDL_dynapi_procs.h | 4 ++
src/dynapi/gendynapi.py | 2 +
src/render/SDL_render.c | 47 +++++++++++++++-
8 files changed, 126 insertions(+), 2 deletions(-)
diff --git a/examples/renderer/18-debug-text/debug-text.c b/examples/renderer/18-debug-text/debug-text.c
index 85bc66ca8d720..b4a2ca6660b8f 100644
--- a/examples/renderer/18-debug-text/debug-text.c
+++ b/examples/renderer/18-debug-text/debug-text.c
@@ -62,6 +62,9 @@ SDL_AppResult SDL_AppIterate(void *appstate)
SDL_RenderDebugText(renderer, 14, 65, "It can be scaled.");
SDL_SetRenderScale(renderer, 1.0f, 1.0f);
SDL_RenderDebugText(renderer, 64, 350, "This only does ASCII chars. So this laughing emoji won't draw: 🤣");
+
+ SDL_RenderDebugTextF(renderer, 0, 0, "This program has been running for %llu seconds.", SDL_GetTicks() / 1000);
+
SDL_RenderPresent(renderer); /* put it all on the screen! */
return SDL_APP_CONTINUE; /* carry on with the program! */
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index 5a16d1e88611f..0aabb8f33e9cc 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -2530,10 +2530,68 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int
*
* \since This function is available since SDL 3.1.6.
*
+ * \sa SDL_RenderDebugTextF
+ * \sa SDL_RenderDebugTextV
* \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *str);
+/**
+ * Draw debug text to an SDL_Renderer.
+ *
+ * This function will render a printf() style format string to a renderer. Note
+ * that this is a convinence function for debugging, with severe limitations,
+ * and is not intended to be used for production apps and games.
+ *
+ * For the full list of limitations and other useful information,
+ * see SDL_RenderDebugText.
+ *
+ * \param renderer the renderer which should draw the text.
+ * \param x the x coordinate where the top-left corner of the text will draw.
+ * \param y the y coordinate where the top-left corner of the text will draw.
+ * \param fmt the format string to draw.
+ * \param ... format arguments
+ * \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.1.7.
+ *
+ * \sa SDL_RenderDebugText
+ * \sa SDL_RenderDebugTextV
+ * \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextF(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4);
+
+/**
+ * Draw debug text to an SDL_Renderer.
+ *
+ * This function will render a printf() style format string to a renderer. Note
+ * that this is a convinence function for debugging, with severe limitations,
+ * and is not intended to be used for production apps and games.
+ *
+ * For the full list of limitations and other useful information,
+ * see SDL_RenderDebugText.
+ *
+ * \param renderer the renderer which should draw the text.
+ * \param x the x coordinate where the top-left corner of the text will draw.
+ * \param y the y coordinate where the top-left corner of the text will draw.
+ * \param fmt the format string to draw.
+ * \param ap a variable argument lists representing the format arguments
+ * \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.1.7.
+ *
+ * \sa SDL_RenderDebugText
+ * \sa SDL_RenderDebugTextF
+ * \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextV(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(4);
+
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index da414879b46dc..3229b5014c2ef 100644
--- a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -149,6 +149,16 @@ static void SDL_InitDynamicAPI(void);
va_end(ap); \
return result; \
} \
+ _static bool SDLCALL SDL_RenderDebugTextF##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
+ { \
+ bool result; \
+ va_list ap; \
+ initcall; \
+ va_start(ap, fmt); \
+ result = jump_table.SDL_RenderDebugTextV(renderer, x, y, fmt, ap); \
+ va_end(ap); \
+ return result; \
+ } \
_static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
{ \
va_list ap; \
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index d575bcef93794..7d4ee58d22ab3 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -1207,6 +1207,8 @@ SDL3_0.0.0 {
SDL_SetGPUAllowedFramesInFlight;
SDL_RenderTextureAffine;
SDL_WaitAndAcquireGPUSwapchainTexture;
+ SDL_RenderDebugTextF;
+ SDL_RenderDebugTextV;
# 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 608d59ca1ecb1..6031adab18bf5 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -1232,3 +1232,5 @@
#define SDL_SetGPUAllowedFramesInFlight SDL_SetGPUAllowedFramesInFlight_REAL
#define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL
#define SDL_WaitAndAcquireGPUSwapchainTexture SDL_WaitAndAcquireGPUSwapchainTexture_REAL
+#define SDL_RenderDebugTextF SDL_RenderDebugTextF_REAL
+#define SDL_RenderDebugTextV SDL_RenderDebugTextV_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 4611595282db8..cedc79f58c9ae 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1238,3 +1238,7 @@ SDL_DYNAPI_PROC(bool,SDL_RunOnMainThread,(SDL_MainThreadCallback a,void *b,bool
SDL_DYNAPI_PROC(bool,SDL_SetGPUAllowedFramesInFlight,(SDL_GPUDevice *a,Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_RenderTextureAffine,(SDL_Renderer *a,SDL_Texture *b,const SDL_FRect *c,const SDL_FPoint *d,const SDL_FPoint *e,const SDL_FPoint *f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(bool,SDL_WaitAndAcquireGPUSwapchainTexture,(SDL_GPUCommandBuffer *a,SDL_Window *b,SDL_GPUTexture **c,Uint32 *d,Uint32 *e),(a,b,c,d,e),return)
+#ifndef SDL_DYNAPI_PROC_NO_VARARGS
+SDL_DYNAPI_PROC(bool,SDL_RenderDebugTextF,(SDL_Renderer *a,float b,float c,SDL_PRINTF_FORMAT_STRING const char *d,...),(a,b,c,d),return)
+#endif
+SDL_DYNAPI_PROC(bool,SDL_RenderDebugTextV,(SDL_Renderer *a,float b,float c,SDL_PRINTF_FORMAT_STRING const char *d,va_list e),(a,b,c,d,e),return)
diff --git a/src/dynapi/gendynapi.py b/src/dynapi/gendynapi.py
index a12e68f9f874d..c780dac6d0ea5 100755
--- a/src/dynapi/gendynapi.py
+++ b/src/dynapi/gendynapi.py
@@ -168,9 +168,11 @@ def parse_header(header_path: Path) -> list[SdlProcedure]:
func = func.replace(" SDL_PRINTF_VARARG_FUNC(1)", "")
func = func.replace(" SDL_PRINTF_VARARG_FUNC(2)", "")
func = func.replace(" SDL_PRINTF_VARARG_FUNC(3)", "")
+ func = func.replace(" SDL_PRINTF_VARARG_FUNC(4)", "")
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(1)", "")
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(2)", "")
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(3)", "")
+ func = func.replace(" SDL_PRINTF_VARARG_FUNCV(4)", "")
func = func.replace(" SDL_WPRINTF_VARARG_FUNC(3)", "")
func = func.replace(" SDL_WPRINTF_VARARG_FUNCV(3)", "")
func = func.replace(" SDL_SCANF_VARARG_FUNC(2)", "")
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index a7b4c5e253bea..241916d44dbc7 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -3995,7 +3995,7 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture,
xy[0] = real_dstrect.x;
xy[1] = real_dstrect.y;
}
-
+
// (maxx, miny)
if (right) {
xy[2] = right->x;
@@ -4025,7 +4025,7 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture,
result = QueueCmdGeometry(
renderer, texture,
- xy, xy_stride,
+ xy, xy_stride,
&texture->color, 0 /* color_stride */,
uv, uv_stride,
num_vertices, indices, num_indices, size_indices,
@@ -5589,3 +5589,46 @@ bool SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *s
return result;
}
+
+bool SDL_RenderDebugTextF(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ bool result = SDL_RenderDebugTextV(renderer, x, y, fmt, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool SDL_RenderDebugTextV(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
+{
+ // Probably for the best to check this here, so we don't do a bunch of string formatting before realizing the renderer isn't even valid...
+ CHECK_RENDERER_MAGIC(renderer, false);
+
+ va_list apc;
+ va_copy(apc, ap); // vsnprintf mangles ap, so copy it so it can be used again later
+ int len = SDL_vsnprintf(NULL, 0, fmt, apc);
+ va_end(apc);
+
+ if (len < 0) {
+ return SDL_SetError("Failed to format debug text");
+ }
+
+ char *buf = SDL_malloc(len + 1);
+ if (buf == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ len = SDL_vsnprintf(buf, len + 1, fmt, ap);
+ if (len < 0) {
+ SDL_free(buf);
+ return SDL_SetError("Failed to format debug text");
+ }
+
+ bool result = SDL_RenderDebugText(renderer, x, y, buf);
+
+ SDL_free(buf);
+
+ return result;
+}