Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SDL_RenderDebugTextF & SDL_RenderDebugTextV #11602

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/demo/02-woodeneye-008/woodeneye-008.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ static void draw(SDL_Renderer *renderer, const float (*edges)[6], const Player p
}
SDL_SetRenderClipRect(renderer, 0);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, 0, 0, debug_string);
SDL_RenderDebugText(renderer, 0, 0, "%s", debug_string);
SDL_RenderPresent(renderer);
}

Expand Down
4 changes: 2 additions & 2 deletions examples/demo/03-infinite-monkeys/infinite-monkeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ static void DisplayLine(float x, float y, Line *line)
}
*spot = '\0';

SDL_RenderDebugText(renderer, x, y, utf8);
SDL_RenderDebugText(renderer, x, y, "%s", utf8);
SDL_free(utf8);
}
}
Expand Down Expand Up @@ -343,7 +343,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
hours = (int)elapsed;
SDL_asprintf(&caption, "Monkeys: %d - %dH:%dM:%dS", monkeys, hours, minutes, seconds);
if (caption) {
SDL_RenderDebugText(renderer, x, y, caption);
SDL_RenderDebugText(renderer, x, y, "%s", caption);
SDL_free(caption);
}
y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
Expand Down
4 changes: 2 additions & 2 deletions examples/demo/04-bytepusher/bytepusher.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ static bool load_file(BytePusher* vm, const char* path) {

static void print(BytePusher* vm, int x, int y, const char* str) {
SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderDebugText(vm->renderer, (float)(x + 1), (float)(y + 1), str);
SDL_RenderDebugText(vm->renderer, (float)(x + 1), (float)(y + 1), "%s", str);
SDL_SetRenderDrawColor(vm->renderer, 0xff, 0xff, 0xff, SDL_ALPHA_OPAQUE);
SDL_RenderDebugText(vm->renderer, (float)x, (float)y, str);
SDL_RenderDebugText(vm->renderer, (float)x, (float)y, "%s", str);
SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
}

Expand Down
2 changes: 1 addition & 1 deletion examples/input/01-joystick-polling/joystick-polling.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
x = (((float) winw) - (SDL_strlen(text) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2.0f;
y = (((float) winh) - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) / 2.0f;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, x, y, text);
SDL_RenderDebugText(renderer, x, y, "%s", text);
SDL_RenderPresent(renderer);

return SDL_APP_CONTINUE; /* carry on with the program! */
Expand Down
2 changes: 1 addition & 1 deletion examples/input/02-joystick-events/joystick-events.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
}

SDL_SetRenderDrawColor(renderer, msg->color.r, msg->color.g, msg->color.b, (Uint8) (((float) msg->color.a) * (1.0f - life_percent)));
SDL_RenderDebugText(renderer, x, y, msg->str);
SDL_RenderDebugText(renderer, x, y, "%s", msg->str);

prev_y = y;
msg = msg->next;
Expand Down
3 changes: 3 additions & 0 deletions examples/renderer/18-debug-text/debug-text.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_RenderDebugText(renderer, 0, 0, "This program has been running for %" SDL_PRIu64 " seconds.", SDL_GetTicks() / 1000);

SDL_RenderPresent(renderer); /* put it all on the screen! */

return SDL_APP_CONTINUE; /* carry on with the program! */
Expand Down
19 changes: 14 additions & 5 deletions include/SDL3/SDL_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -2497,9 +2497,11 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int
/**
* Draw debug text to an SDL_Renderer.
*
* This function will render a string of text to an SDL_Renderer. Note that
* this is a convenience function for debugging, with severe limitations, and
* not intended to be used for production apps and games.
* This function will render a string of text to an SDL_Renderer. This
* function accepts a printf-style formatting.
*
* Note that this is a convenience function for debugging, with severe
* limitations, and not intended to be used for production apps and games.
*
* Among these limitations:
*
Expand All @@ -2519,10 +2521,17 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int
*
* The text is drawn in the color specified by SDL_SetRenderDrawColor().
*
* **WARNING**: Note that in SDL 3.1.6, this function accepted a single string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this warning. We can put it in the patch notes, but we don't need to carry it forward.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that's fine.

* _without_formatting, and was changed after this one release to accept
* printf-style arguments. This _should_ be binary compatible with the one
* prerelease before this change, assuming there are no '%' characters in
* the string, but we encourage everyone to update their library and headers
* to a later version to avoid confusion.
*
* \param renderer the renderer which should draw a line of 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 str the string to render.
* \param fmt the string to render.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
Expand All @@ -2532,7 +2541,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int
*
* \sa SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *str);
extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
Expand Down
34 changes: 27 additions & 7 deletions src/dynapi/SDL_dynapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,10 @@ static void SDL_InitDynamicAPI(void);
result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
if (result >= 0 && (size_t)result >= sizeof(buf)) { \
size_t len = (size_t)result + 1; \
str = (char *)jump_table.SDL_malloc(len); \
if (str) { \
va_start(ap, fmt); \
result = jump_table.SDL_vsnprintf(str, len, fmt, ap); \
va_end(ap); \
} \
str = NULL; \
va_start(ap, fmt); \
result = SDL_vasprintf(&str, fmt, ap); \
va_end(ap); \
} \
if (result >= 0) { \
jump_table.SDL_SetError("%s", str); \
Expand Down Expand Up @@ -152,6 +149,29 @@ static void SDL_InitDynamicAPI(void);
va_end(ap); \
return result; \
} \
_static bool SDLCALL SDL_RenderDebugText##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
{ \
char buf[128], *str = buf; \
int result; \
va_list ap; \
initcall; \
va_start(ap, fmt); \
result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
if (result >= 0 && (size_t)result >= sizeof(buf)) { \
str = NULL; \
va_start(ap, fmt); \
result = SDL_vasprintf(&str, fmt, ap); \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the jump table version of this?

va_end(ap); \
} \
if (result >= 0) { \
jump_table.SDL_RenderDebugText(renderer, x, y, "%s", str); \
} \
if (str != buf) { \
jump_table.SDL_free(str); \
} \
return false; \
} \
_static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
{ \
va_list ap; \
Expand Down
4 changes: 3 additions & 1 deletion src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,9 @@ SDL_DYNAPI_PROC(void,SDL_DelayPrecise,(Uint64 a),(a),)
SDL_DYNAPI_PROC(Uint32,SDL_CalculateGPUTextureFormatSize,(SDL_GPUTextureFormat a, Uint32 b, Uint32 c, Uint32 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(bool,SDL_SetErrorV,(SDL_PRINTF_FORMAT_STRING const char *a,va_list b),(a,b),return)
SDL_DYNAPI_PROC(SDL_LogOutputFunction,SDL_GetDefaultLogOutputFunction,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_RenderDebugText,(SDL_Renderer *a,float b,float c,const char *d),(a,b,c,d),return)
#ifndef SDL_DYNAPI_PROC_NO_VARARGS
SDL_DYNAPI_PROC(bool,SDL_RenderDebugText,(SDL_Renderer *a,float b,float c,const char *d,...),(a,b,c,d),return)
#endif
SDL_DYNAPI_PROC(SDL_Sandbox,SDL_GetSandbox,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_CancelGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_SaveFile_IO,(SDL_IOStream *a,const void *b,size_t c,bool d),(a,b,c,d),return)
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/gendynapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)", "")
Expand Down
42 changes: 39 additions & 3 deletions src/render/SDL_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -5561,7 +5561,7 @@ static bool DrawDebugCharacter(SDL_Renderer *renderer, float x, float y, Uint32
return SDL_RenderTexture(renderer, renderer->debug_char_texture_atlas, &srect, &drect);
}

bool SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *s)
static bool RenderDebugTextInternal(SDL_Renderer *renderer, float x, float y, const char *s)
{
CHECK_RENDERER_MAGIC(renderer, false);

Expand All @@ -5582,10 +5582,46 @@ bool SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *s
float curx = x;
Uint32 ch;

// !!! FIXME: stop rendering if x or y is obviously past the render target.
while (result && ((ch = SDL_StepUTF8(&s, NULL)) != 0)) {
result &= DrawDebugCharacter(renderer, curx, y, ch);
curx += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
}

return result;
}

bool SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
// 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);

char stackbuf[128];
char *buf = stackbuf;
va_list ap;

va_start(ap, fmt);
int len = SDL_vsnprintf(stackbuf, sizeof (stackbuf), fmt, ap);
va_end(ap);

if (len < 0) {
return SDL_SetError("Failed to format debug text");
} else if (len > sizeof (stackbuf)) {
buf = NULL;
va_start(ap, fmt);
len = SDL_vasprintf(&buf, fmt, ap);
va_end(ap);
if (len < 0) {
SDL_free(buf);
return SDL_SetError("Failed to format debug text");
}
}

const bool result = RenderDebugTextInternal(renderer, x, y, buf);
if (buf != stackbuf) {
SDL_free(buf);
}

return result;
}

4 changes: 2 additions & 2 deletions src/test/SDL_test_font.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ bool SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
char str[5];
char *ptr = SDL_UCS4ToUTF8(c, str);
*ptr = '\0';
return SDL_RenderDebugText(renderer, x, y, str);
return SDL_RenderDebugText(renderer, x, y, "%s", str);
}

bool SDLTest_DrawString(SDL_Renderer *renderer, float x, float y, const char *s)
{
return SDL_RenderDebugText(renderer, x, y, s);
return SDL_RenderDebugText(renderer, x, y, "%s", s);
}

SDLTest_TextWindow *SDLTest_TextWindowCreate(float x, float y, float w, float h)
Expand Down
2 changes: 1 addition & 1 deletion test/testyuv.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ static bool run_colorspace_test(void)

SDL_RenderTexture(renderer, texture, NULL, NULL);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, 4, 4, colorspaces[i].name);
SDL_RenderDebugText(renderer, 4, 4, "%s", colorspaces[i].name);
SDL_RenderPresent(renderer);
SDL_Delay(10);
}
Expand Down