Skip to content
Draft
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
5 changes: 3 additions & 2 deletions demo/sdl3_renderer/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@
#define NK_VSNPRINTF(s, n, f, a) SDL_vsnprintf(s, n, f, a)
#define NK_STRTOD(str, endptr) SDL_strtod(str, endptr)

/* sadly, SDL3 does not provide "dtoa" (only integer version) */
/*#define NK_DTOA (str, d)*/
/* HACK: SDL3 does not provide "dtoa" (only integer version)
* so we use sprintf with %g formatting to get almost the same result */
#define NK_DTOA(str, d) (SDL_snprintf(str, 999, "%g", d), str)
Copy link
Contributor Author

@sleeptightAnsiC sleeptightAnsiC Nov 19, 2025

Choose a reason for hiding this comment

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

This is quite evil but works just fine. Comma-operator with "((...), str)" at the very end makes sure that we get the proper return value. The 999 indicates that we don't care about buffer length (dtoa is unsafe anyway). Formatting with %g turns longer values into scientific notation (nk_dtoa does a very same thing). I hope I didn't miss any case.

Copy link
Contributor Author

@sleeptightAnsiC sleeptightAnsiC Nov 19, 2025

Choose a reason for hiding this comment

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

I hope I didn't miss any case.

Actually, I missed the str == NULL case, I thought that SDL handles it (because it does... just not correctly).

EDIT: Actually actually, SDL makes a correct nullcheck, but only for it's build-in version. If it uses the libc version, it has no such check, lol :D

I'll fix it in few days. I should probably test this thing more deeply.

EDIT: nah, the doc for SDL_snprintf clearly says that neither of pointers should be null, so it does not matter what SDL does internally. dtoa is unsafe and should never take null. However, I still want to ensure this macro is fully correct, and I don't like its current form. I think, I will just reimplement it into the function.


/* SDL can also provide us with math functions, but beware that Nuklear's own
* implementation can be slightly faster at the cost of some precision */
Expand Down
50 changes: 33 additions & 17 deletions nuklear.h
Original file line number Diff line number Diff line change
Expand Up @@ -4040,6 +4040,7 @@ NK_API int nk_strtoi(const char *str, char **endptr);
NK_API float nk_strtof(const char *str, char **endptr);
#ifndef NK_STRTOD
#define NK_STRTOD nk_strtod
#define NK_STRTOD_IMPLEMENTATION
NK_API double nk_strtod(const char *str, char **endptr);
#endif
NK_API int nk_strfilter(const char *text, const char *regexp);
Expand Down Expand Up @@ -6146,18 +6147,28 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};

/* math */
#ifndef NK_INV_SQRT
#define NK_INV_SQRT nk_inv_sqrt
#define NK_INV_SQRT_IMPLEMENTATION
NK_LIB float nk_inv_sqrt(float n);
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
#define NK_SIN_IMPLEMENTATION
NK_LIB float nk_sin(float x);
#endif
#ifndef NK_COS
#define NK_COS nk_cos
#define NK_COS_IMPLEMENTATION
NK_LIB float nk_cos(float x);
#endif
#ifndef NK_ATAN
#define NK_ATAN nk_atan
#define NK_ATAN_IMPLEMENTATION
NK_LIB float nk_atan(float x);
#endif
#ifndef NK_ATAN2
#define NK_ATAN2 nk_atan2
#define NK_ATAN2_IMPLEMENTATION
NK_LIB float nk_atan2(float y, float x);
#endif
NK_LIB nk_uint nk_round_up_pow2(nk_uint v);
Expand All @@ -6179,15 +6190,21 @@ NK_LIB int nk_to_upper(int c);
NK_LIB int nk_to_lower(int c);

#ifndef NK_MEMCPY
#define NK_MEMCPY nk_memcopy
#define NK_MEMCPY_IMPLEMENTATION
NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);
#endif
#ifndef NK_MEMSET
#define NK_MEMSET nk_memset
#define NK_MEMSET_IMPLEMENTATION
NK_LIB void nk_memset(void *ptr, int c0, nk_size size);
#endif
NK_LIB void nk_zero(void *ptr, nk_size size);
NK_LIB char *nk_itoa(char *s, long n);
NK_LIB int nk_string_float_limit(char *string, int prec);
#ifndef NK_DTOA
#define NK_DTOA nk_dtoa
#define NK_DTOA_IMPLEMENTATION
NK_LIB char *nk_dtoa(char *s, double n);
#endif
NK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);
Expand Down Expand Up @@ -6463,8 +6480,7 @@ nk_stbtt_free(void *ptr, void *user_data) {
/// (it can actually approximate a lot more functions) can be
/// found here: www.lolengine.net/wiki/oss/lolremez
*/
#ifndef NK_INV_SQRT
#define NK_INV_SQRT nk_inv_sqrt
#ifdef NK_INV_SQRT_IMPLEMENTATION
NK_LIB float
nk_inv_sqrt(float n)
{
Expand All @@ -6478,8 +6494,7 @@ nk_inv_sqrt(float n)
return conv.f;
}
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
#ifdef NK_SIN_IMPLEMENTATION
NK_LIB float
nk_sin(float x)
{
Expand All @@ -6494,8 +6509,7 @@ nk_sin(float x)
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
}
#endif
#ifndef NK_COS
#define NK_COS nk_cos
#ifdef NK_COS_IMPLEMENTATION
NK_LIB float
nk_cos(float x)
{
Expand All @@ -6513,8 +6527,7 @@ nk_cos(float x)
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));
}
#endif
#ifndef NK_ATAN
#define NK_ATAN nk_atan
#ifdef NK_ATAN_IMPLEMENTATION
NK_LIB float
nk_atan(float x)
{
Expand All @@ -6533,8 +6546,7 @@ nk_atan(float x)
return u;
}
#endif
#ifndef NK_ATAN2
#define NK_ATAN2 nk_atan2
#ifdef NK_ATAN2_IMPLEMENTATION
NK_LIB float
nk_atan2(float y, float x)
{
Expand Down Expand Up @@ -6797,8 +6809,7 @@ NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 &&
NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}

#ifndef NK_MEMCPY
#define NK_MEMCPY nk_memcopy
#ifdef NK_MEMCPY_IMPLEMENTATION
NK_LIB void*
nk_memcopy(void *dst0, const void *src0, nk_size length)
{
Expand Down Expand Up @@ -6856,8 +6867,7 @@ nk_memcopy(void *dst0, const void *src0, nk_size length)
return (dst0);
}
#endif
#ifndef NK_MEMSET
#define NK_MEMSET nk_memset
#ifdef NK_MEMSET_IMPLEMENTATION
NK_LIB void
nk_memset(void *ptr, int c0, nk_size size)
{
Expand Down Expand Up @@ -6948,6 +6958,7 @@ nk_strtoi(const char *str, char **endptr)
*endptr = (char *)p;
return neg*value;
}
#ifdef NK_STRTOD_IMPLEMENTATION
NK_API double
nk_strtod(const char *str, char **endptr)
{
Expand Down Expand Up @@ -7005,6 +7016,7 @@ nk_strtod(const char *str, char **endptr)
*endptr = p;
return number;
}
#endif
NK_API float
nk_strtof(const char *str, char **endptr)
{
Expand Down Expand Up @@ -7283,8 +7295,7 @@ nk_itoa(char *s, long n)
nk_strrev_ascii(s);
return s;
}
#ifndef NK_DTOA
#define NK_DTOA nk_dtoa
#ifdef NK_DTOA_IMPLEMENTATION
NK_LIB char*
nk_dtoa(char *s, double n)
{
Expand Down Expand Up @@ -28950,7 +28961,7 @@ nk_do_property(nk_flags *ws,
break;
case NK_PROPERTY_DOUBLE:
nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
variant->value.d = nk_strtod(buffer, 0);
variant->value.d = NK_STRTOD(buffer, 0);
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
break;
}
Expand Down Expand Up @@ -30731,6 +30742,11 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
/// - [y]: Minor version with non-breaking API and library changes
/// - [z]: Patch version with no direct changes to the API
///
/// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro
/// - Fix: failure to build from source, due to
/// nuklear_math/util.c not declaring some functions
/// - Fix: guard nk_strtod implementation with preprocessor
/// - Fix: nuklear_sdl3_renderer now provides NK_DTOA
/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'
/// Add new updated demo: sdl3_renderer
/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,
Expand Down
5 changes: 5 additions & 0 deletions src/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
/// - [y]: Minor version with non-breaking API and library changes
/// - [z]: Patch version with no direct changes to the API
///
/// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro
/// - Fix: failure to build from source, due to
/// nuklear_math/util.c not declaring some functions
/// - Fix: guard nk_strtod implementation with preprocessor
/// - Fix: nuklear_sdl3_renderer now provides NK_DTOA
/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'
/// Add new updated demo: sdl3_renderer
/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,
Expand Down
1 change: 1 addition & 0 deletions src/nuklear.h
Original file line number Diff line number Diff line change
Expand Up @@ -3817,6 +3817,7 @@ NK_API int nk_strtoi(const char *str, char **endptr);
NK_API float nk_strtof(const char *str, char **endptr);
#ifndef NK_STRTOD
#define NK_STRTOD nk_strtod
#define NK_STRTOD_IMPLEMENTATION
Copy link
Contributor Author

@sleeptightAnsiC sleeptightAnsiC Nov 19, 2025

Choose a reason for hiding this comment

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

Note: nk_strtod is the only public utility function that you can overwrite with the macro. Other similar ones have their declarations kept private inside of src/nuklear_internal.h. I thought this is worth mentioning (but I don't remember why, lol)

NK_API double nk_strtod(const char *str, char **endptr);
#endif
NK_API int nk_strfilter(const char *text, const char *regexp);
Expand Down
16 changes: 16 additions & 0 deletions src/nuklear_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,28 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};

/* math */
#ifndef NK_INV_SQRT
#define NK_INV_SQRT nk_inv_sqrt
#define NK_INV_SQRT_IMPLEMENTATION
NK_LIB float nk_inv_sqrt(float n);
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
#define NK_SIN_IMPLEMENTATION
NK_LIB float nk_sin(float x);
#endif
#ifndef NK_COS
#define NK_COS nk_cos
#define NK_COS_IMPLEMENTATION
NK_LIB float nk_cos(float x);
#endif
#ifndef NK_ATAN
#define NK_ATAN nk_atan
#define NK_ATAN_IMPLEMENTATION
NK_LIB float nk_atan(float x);
#endif
#ifndef NK_ATAN2
#define NK_ATAN2 nk_atan2
#define NK_ATAN2_IMPLEMENTATION
NK_LIB float nk_atan2(float y, float x);
#endif
NK_LIB nk_uint nk_round_up_pow2(nk_uint v);
Expand All @@ -128,15 +138,21 @@ NK_LIB int nk_to_upper(int c);
NK_LIB int nk_to_lower(int c);

#ifndef NK_MEMCPY
#define NK_MEMCPY nk_memcopy
#define NK_MEMCPY_IMPLEMENTATION
NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);
#endif
#ifndef NK_MEMSET
#define NK_MEMSET nk_memset
#define NK_MEMSET_IMPLEMENTATION
NK_LIB void nk_memset(void *ptr, int c0, nk_size size);
#endif
NK_LIB void nk_zero(void *ptr, nk_size size);
NK_LIB char *nk_itoa(char *s, long n);
NK_LIB int nk_string_float_limit(char *string, int prec);
#ifndef NK_DTOA
#define NK_DTOA nk_dtoa
#define NK_DTOA_IMPLEMENTATION
NK_LIB char *nk_dtoa(char *s, double n);
#endif
NK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);
Expand Down
15 changes: 5 additions & 10 deletions src/nuklear_math.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
/// (it can actually approximate a lot more functions) can be
/// found here: www.lolengine.net/wiki/oss/lolremez
*/
#ifndef NK_INV_SQRT
#define NK_INV_SQRT nk_inv_sqrt
#ifdef NK_INV_SQRT_IMPLEMENTATION
NK_LIB float
nk_inv_sqrt(float n)
{
Expand All @@ -49,8 +48,7 @@ nk_inv_sqrt(float n)
return conv.f;
}
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
#ifdef NK_SIN_IMPLEMENTATION
NK_LIB float
nk_sin(float x)
{
Expand All @@ -65,8 +63,7 @@ nk_sin(float x)
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
}
#endif
#ifndef NK_COS
#define NK_COS nk_cos
#ifdef NK_COS_IMPLEMENTATION
NK_LIB float
nk_cos(float x)
{
Expand All @@ -84,8 +81,7 @@ nk_cos(float x)
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));
}
#endif
#ifndef NK_ATAN
#define NK_ATAN nk_atan
#ifdef NK_ATAN_IMPLEMENTATION
NK_LIB float
nk_atan(float x)
{
Expand All @@ -104,8 +100,7 @@ nk_atan(float x)
return u;
}
#endif
#ifndef NK_ATAN2
#define NK_ATAN2 nk_atan2
#ifdef NK_ATAN2_IMPLEMENTATION
NK_LIB float
nk_atan2(float y, float x)
{
Expand Down
2 changes: 1 addition & 1 deletion src/nuklear_property.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ nk_do_property(nk_flags *ws,
break;
case NK_PROPERTY_DOUBLE:
nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
variant->value.d = nk_strtod(buffer, 0);
variant->value.d = NK_STRTOD(buffer, 0);
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
break;
}
Expand Down
11 changes: 5 additions & 6 deletions src/nuklear_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 &&
NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}

#ifndef NK_MEMCPY
#define NK_MEMCPY nk_memcopy
#ifdef NK_MEMCPY_IMPLEMENTATION
NK_LIB void*
nk_memcopy(void *dst0, const void *src0, nk_size length)
{
Expand Down Expand Up @@ -72,8 +71,7 @@ nk_memcopy(void *dst0, const void *src0, nk_size length)
return (dst0);
}
#endif
#ifndef NK_MEMSET
#define NK_MEMSET nk_memset
#ifdef NK_MEMSET_IMPLEMENTATION
NK_LIB void
nk_memset(void *ptr, int c0, nk_size size)
{
Expand Down Expand Up @@ -164,6 +162,7 @@ nk_strtoi(const char *str, char **endptr)
*endptr = (char *)p;
return neg*value;
}
#ifdef NK_STRTOD_IMPLEMENTATION
NK_API double
nk_strtod(const char *str, char **endptr)
{
Expand Down Expand Up @@ -221,6 +220,7 @@ nk_strtod(const char *str, char **endptr)
*endptr = p;
return number;
}
#endif
NK_API float
nk_strtof(const char *str, char **endptr)
{
Expand Down Expand Up @@ -499,8 +499,7 @@ nk_itoa(char *s, long n)
nk_strrev_ascii(s);
return s;
}
#ifndef NK_DTOA
#define NK_DTOA nk_dtoa
#ifdef NK_DTOA_IMPLEMENTATION
NK_LIB char*
nk_dtoa(char *s, double n)
{
Expand Down