Simple Directmedia Layer

render: Updates to format-string versions of SDL_RenderDebugText.

- Removes SDL_RenderDebugTextV
- Changes SDL_RenderDebugTextF to SDL_RenderDebugTextFormat and tweaks it to
work in a world without SDL_RenderDebugTextV.
- Tweaked rendering position of formatted text in the example program.

Changed files
+46 -79
examples
renderer
18-debug-text
include
src
+3 -1
examples/renderer/18-debug-text/debug-text.c
··· 46 46 /* This function runs once per frame, and is the heart of the program. */ 47 47 SDL_AppResult SDL_AppIterate(void *appstate) 48 48 { 49 + const int charsize = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; 50 + 49 51 /* as you can see from this, rendering draws over whatever was drawn before it. */ 50 52 SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); /* black, full alpha */ 51 53 SDL_RenderClear(renderer); /* start with a blank canvas. */ ··· 63 65 SDL_SetRenderScale(renderer, 1.0f, 1.0f); 64 66 SDL_RenderDebugText(renderer, 64, 350, "This only does ASCII chars. So this laughing emoji won't draw: 🤣"); 65 67 66 - SDL_RenderDebugTextF(renderer, 0, 0, "This program has been running for %" SDL_PRIu64 " seconds.", SDL_GetTicks() / 1000); 68 + SDL_RenderDebugTextFormat(renderer, (float) ((WINDOW_WIDTH - (charsize * 46)) / 2), 400, "(This program has been running for %" SDL_PRIu64 " seconds.)", SDL_GetTicks() / 1000); 67 69 68 70 SDL_RenderPresent(renderer); /* put it all on the screen! */ 69 71
+7 -36
include/SDL3/SDL_render.h
··· 2530 2530 * 2531 2531 * \since This function is available since SDL 3.1.6. 2532 2532 * 2533 - * \sa SDL_RenderDebugTextF 2534 - * \sa SDL_RenderDebugTextV 2533 + * \sa SDL_RenderDebugTextFormat 2535 2534 * \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE 2536 2535 */ 2537 2536 extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *str); ··· 2539 2538 /** 2540 2539 * Draw debug text to an SDL_Renderer. 2541 2540 * 2542 - * This function will render a printf() style format string to a renderer. Note 2543 - * that this is a convinence function for debugging, with severe limitations, 2544 - * and is not intended to be used for production apps and games. 2541 + * This function will render a printf()-style format string to a renderer. 2542 + * Note that this is a convinence function for debugging, with severe 2543 + * limitations, and is not intended to be used for production apps and games. 2545 2544 * 2546 2545 * For the full list of limitations and other useful information, 2547 2546 * see SDL_RenderDebugText. ··· 2550 2549 * \param x the x coordinate where the top-left corner of the text will draw. 2551 2550 * \param y the y coordinate where the top-left corner of the text will draw. 2552 2551 * \param fmt the format string to draw. 2553 - * \param ... format arguments 2552 + * \param ... additional parameters matching % tokens in the `fmt` string, if 2553 + * any. 2554 2554 * \returns true on success or false on failure; call SDL_GetError() for more 2555 2555 * information. 2556 2556 * ··· 2559 2559 * \since This function is available since SDL 3.1.7. 2560 2560 * 2561 2561 * \sa SDL_RenderDebugText 2562 - * \sa SDL_RenderDebugTextV 2563 2562 * \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE 2564 2563 */ 2565 - 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); 2566 - 2567 - /** 2568 - * Draw debug text to an SDL_Renderer. 2569 - * 2570 - * This function will render a printf() style format string to a renderer. Note 2571 - * that this is a convinence function for debugging, with severe limitations, 2572 - * and is not intended to be used for production apps and games. 2573 - * 2574 - * For the full list of limitations and other useful information, 2575 - * see SDL_RenderDebugText. 2576 - * 2577 - * \param renderer the renderer which should draw the text. 2578 - * \param x the x coordinate where the top-left corner of the text will draw. 2579 - * \param y the y coordinate where the top-left corner of the text will draw. 2580 - * \param fmt the format string to draw. 2581 - * \param ap a variable argument lists representing the format arguments 2582 - * \returns true on success or false on failure; call SDL_GetError() for more 2583 - * information. 2584 - * 2585 - * \threadsafety This function should only be called on the main thread. 2586 - * 2587 - * \since This function is available since SDL 3.1.7. 2588 - * 2589 - * \sa SDL_RenderDebugText 2590 - * \sa SDL_RenderDebugTextF 2591 - * \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE 2592 - */ 2593 - 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); 2564 + extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4); 2594 2565 2595 2566 /* Ends C function definitions when using C++ */ 2596 2567 #ifdef __cplusplus
+18 -4
src/dynapi/SDL_dynapi.c
··· 149 149 va_end(ap); \ 150 150 return result; \ 151 151 } \ 152 - _static bool SDLCALL SDL_RenderDebugTextF##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 152 + _static bool SDLCALL SDL_RenderDebugTextFormat##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 153 153 { \ 154 - bool result; \ 154 + char buf[128], *str = buf; \ 155 + int result; \ 155 156 va_list ap; \ 156 157 initcall; \ 157 158 va_start(ap, fmt); \ 158 - result = jump_table.SDL_RenderDebugTextV(renderer, x, y, fmt, ap); \ 159 + result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \ 159 160 va_end(ap); \ 160 - return result; \ 161 + if (result >= 0 && (size_t)result >= sizeof(buf)) { \ 162 + str = NULL; \ 163 + va_start(ap, fmt); \ 164 + result = jump_table.SDL_vasprintf(&str, fmt, ap); \ 165 + va_end(ap); \ 166 + } \ 167 + bool retval = false; \ 168 + if (result >= 0) { \ 169 + retval = jump_table.SDL_RenderDebugTextFormat(renderer, x, y, "%s", str); \ 170 + } \ 171 + if (str != buf) { \ 172 + jump_table.SDL_free(str); \ 173 + } \ 174 + return retval; \ 161 175 } \ 162 176 _static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ 163 177 { \
+1 -2
src/dynapi/SDL_dynapi.sym
··· 1207 1207 SDL_SetGPUAllowedFramesInFlight; 1208 1208 SDL_RenderTextureAffine; 1209 1209 SDL_WaitAndAcquireGPUSwapchainTexture; 1210 - SDL_RenderDebugTextF; 1211 - SDL_RenderDebugTextV; 1210 + SDL_RenderDebugTextFormat; 1212 1211 # extra symbols go here (don't modify this line) 1213 1212 local: *; 1214 1213 };
+1 -2
src/dynapi/SDL_dynapi_overrides.h
··· 1232 1232 #define SDL_SetGPUAllowedFramesInFlight SDL_SetGPUAllowedFramesInFlight_REAL 1233 1233 #define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL 1234 1234 #define SDL_WaitAndAcquireGPUSwapchainTexture SDL_WaitAndAcquireGPUSwapchainTexture_REAL 1235 - #define SDL_RenderDebugTextF SDL_RenderDebugTextF_REAL 1236 - #define SDL_RenderDebugTextV SDL_RenderDebugTextV_REAL 1235 + #define SDL_RenderDebugTextFormat SDL_RenderDebugTextFormat_REAL
+1 -2
src/dynapi/SDL_dynapi_procs.h
··· 1239 1239 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) 1240 1240 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) 1241 1241 #ifndef SDL_DYNAPI_PROC_NO_VARARGS 1242 - 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) 1242 + SDL_DYNAPI_PROC(bool,SDL_RenderDebugTextFormat,(SDL_Renderer *a,float b,float c,SDL_PRINTF_FORMAT_STRING const char *d,...),(a,b,c,d),return) 1243 1243 #endif 1244 - 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)
+15 -32
src/render/SDL_render.c
··· 5590 5590 return result; 5591 5591 } 5592 5592 5593 - bool SDL_RenderDebugTextF(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 5593 + bool SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 5594 5594 { 5595 5595 va_list ap; 5596 - 5597 5596 va_start(ap, fmt); 5598 - bool result = SDL_RenderDebugTextV(renderer, x, y, fmt, ap); 5599 - va_end(ap); 5600 5597 5601 - return result; 5602 - } 5603 - 5604 - bool SDL_RenderDebugTextV(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) 5605 - { 5606 - // 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... 5607 - CHECK_RENDERER_MAGIC(renderer, false); 5608 - 5609 - va_list apc; 5610 - va_copy(apc, ap); // vsnprintf mangles ap, so copy it so it can be used again later 5611 - int len = SDL_vsnprintf(NULL, 0, fmt, apc); 5612 - va_end(apc); 5613 - 5614 - if (len < 0) { 5615 - return SDL_SetError("Failed to format debug text"); 5598 + // fast path to avoid unnecessary allocation and copy. If you're going through the dynapi, there's a good chance 5599 + // you _always_ hit this path, since it probably had to process varargs before calling into the jumptable. 5600 + if (SDL_strcmp(fmt, "%s") == 0) { 5601 + const char *str = va_arg(ap, const char *); 5602 + va_end(ap); 5603 + return SDL_RenderDebugText(renderer, x, y, str); 5616 5604 } 5617 5605 5618 - char *buf = SDL_malloc(len + 1); 5619 - if (buf == NULL) { 5620 - return SDL_OutOfMemory(); 5621 - } 5606 + char *str = NULL; 5607 + const int rc = SDL_vasprintf(&str, fmt, ap); 5608 + va_end(ap); 5622 5609 5623 - len = SDL_vsnprintf(buf, len + 1, fmt, ap); 5624 - if (len < 0) { 5625 - SDL_free(buf); 5626 - return SDL_SetError("Failed to format debug text"); 5610 + if (rc == -1) { 5611 + return false; 5627 5612 } 5628 5613 5629 - bool result = SDL_RenderDebugText(renderer, x, y, buf); 5630 - 5631 - SDL_free(buf); 5632 - 5633 - return result; 5614 + const bool retval = SDL_RenderDebugText(renderer, x, y, str); 5615 + SDL_free(str); 5616 + return retval; 5634 5617 }