main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /* nuklear - public domain */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. #include <stdarg.h>
  6. #include <string.h>
  7. #include <math.h>
  8. #include <assert.h>
  9. #include <limits.h>
  10. #include <time.h>
  11. #include <SDL3/SDL.h>
  12. /* This demo uses "main callbacks" which are new in SDL3
  13. * Those provide highly portable entry point and event loop for the app
  14. * see: https://wiki.libsdl.org/SDL3/README-main-functions
  15. * */
  16. #define SDL_MAIN_USE_CALLBACKS
  17. #include <SDL3/SDL_main.h>
  18. /* ===============================================================
  19. *
  20. * CONFIG
  21. *
  22. * ===============================================================*/
  23. /* optional: sdl3_renderer does not need any of these defines
  24. * (but some examples might need them, so be careful) */
  25. #define NK_INCLUDE_STANDARD_VARARGS
  26. #define NK_INCLUDE_STANDARD_IO
  27. /* note that sdl3_renderer comes with nk_sdl_style_set_debug_font()
  28. * so you may wish to use that instead of font baking */
  29. #define NK_INCLUDE_FONT_BAKING
  30. #define NK_INCLUDE_DEFAULT_FONT
  31. /* note that sdl3_renderer comes with nk_sdl_allocator()
  32. * and you probably want to use that allocator instead of the default ones */
  33. /*#define NK_INCLUDE_DEFAULT_ALLOCATOR*/
  34. /* mandatory: sdl3_renderer depends on those defines */
  35. #define NK_INCLUDE_COMMAND_USERDATA
  36. #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
  37. /* We can re-use the types provided by SDL which are extremely portable,
  38. * so there is no need for Nuklear to detect those on its own */
  39. /*#define NK_INCLUDE_FIXED_TYPES*/
  40. #ifndef NK_INCLUDE_FIXED_TYPES
  41. #define NK_INT8 Sint8
  42. #define NK_UINT8 Uint8
  43. #define NK_INT16 Sint16
  44. #define NK_UINT16 Uint16
  45. #define NK_INT32 Sint32
  46. #define NK_UINT32 Uint32
  47. /* SDL guarantees 'uintptr_t' typedef */
  48. #define NK_SIZE_TYPE uintptr_t
  49. #define NK_POINTER_TYPE uintptr_t
  50. #endif
  51. /* FIXME: We could also use the `bool` symbol provided by SDL,
  52. * but this is currently broken due to internal Nuklear issue, see:
  53. * https://github.com/Immediate-Mode-UI/Nuklear/issues/849
  54. * */
  55. #define NK_INCLUDE_STANDARD_BOOL
  56. #ifndef NK_INCLUDE_STANDARD_BOOL
  57. #define NK_BOOL bool
  58. #endif
  59. /* We can re-use various portable libc functions provided by SDL */
  60. #define NK_ASSERT(condition) SDL_assert(condition)
  61. #define NK_STATIC_ASSERT(exp) SDL_COMPILE_TIME_ASSERT(, exp)
  62. #define NK_MEMSET(dst, c, len) SDL_memset(dst, c, len)
  63. #define NK_MEMCPY(dst, src, len) SDL_memcpy(dst, src, len)
  64. #define NK_VSNPRINTF(s, n, f, a) SDL_vsnprintf(s, n, f, a)
  65. #define NK_STRTOD(str, endptr) SDL_strtod(str, endptr)
  66. /* sadly, SDL3 does not provide "dtoa" (only integer version) */
  67. /*#define NK_DTOA (str, d)*/
  68. /* SDL can also provide us with math functions, but beware that Nuklear's own
  69. * implementation can be slightly faster at the cost of some precision */
  70. #define NK_INV_SQRT(f) (1.0f / SDL_sqrtf(f))
  71. #define NK_SIN(f) SDL_sinf(f)
  72. #define NK_COS(f) SDL_cosf(f)
  73. /* HACK: Nuklear pulls two stb libraries in order to use font baking
  74. * those libraries pull in some libc headers internally, creating a linkage dependency,
  75. * so you’ll most likely want to use SDL symbols instead */
  76. #define STBTT_ifloor(x) ((int)SDL_floor(x))
  77. #define STBTT_iceil(x) ((int)SDL_ceil(x))
  78. #define STBTT_sqrt(x) SDL_sqrt(x)
  79. #define STBTT_pow(x,y) SDL_pow(x,y)
  80. #define STBTT_fmod(x,y) SDL_fmod(x,y)
  81. #define STBTT_cos(x) SDL_cosf(x)
  82. #define STBTT_acos(x) SDL_acos(x)
  83. #define STBTT_fabs(x) SDL_fabs(x)
  84. #define STBTT_assert(x) SDL_assert(x)
  85. #define STBTT_strlen(x) SDL_strlen(x)
  86. #define STBTT_memcpy SDL_memcpy
  87. #define STBTT_memset SDL_memset
  88. #define stbtt_uint8 Uint8
  89. #define stbtt_int8 Sint8
  90. #define stbtt_uint16 Uint16
  91. #define stbtt_int16 Sint16
  92. #define stbtt_uint32 Uint32
  93. #define stbtt_int32 Sint32
  94. #define STBRP_SORT SDL_qsort
  95. #define STBRP_ASSERT SDL_assert
  96. /* There is no need to define STBTT_malloc/STBTT_free macros
  97. * Nuklear will define those to user-provided nk_allocator */
  98. #define NK_IMPLEMENTATION
  99. #include "../../nuklear.h"
  100. #define NK_SDL3_RENDERER_IMPLEMENTATION
  101. #include "nuklear_sdl3_renderer.h"
  102. #define WINDOW_WIDTH 1200
  103. #define WINDOW_HEIGHT 800
  104. /* ===============================================================
  105. *
  106. * EXAMPLE
  107. *
  108. * ===============================================================*/
  109. /* These are some code examples to provide a small overview of what can be
  110. * done with this library. To try out an example uncomment the defines */
  111. /*#define INCLUDE_ALL */
  112. /*#define INCLUDE_STYLE */
  113. /*#define INCLUDE_CALCULATOR */
  114. /*#define INCLUDE_CANVAS */
  115. #define INCLUDE_OVERVIEW
  116. /*#define INCLUDE_CONFIGURATOR */
  117. /*#define INCLUDE_NODE_EDITOR */
  118. #ifdef INCLUDE_ALL
  119. #define INCLUDE_STYLE
  120. #define INCLUDE_CALCULATOR
  121. #define INCLUDE_CANVAS
  122. #define INCLUDE_OVERVIEW
  123. #define INCLUDE_CONFIGURATOR
  124. #define INCLUDE_NODE_EDITOR
  125. #endif
  126. #ifdef INCLUDE_STYLE
  127. #include "../../demo/common/style.c"
  128. #endif
  129. #ifdef INCLUDE_CALCULATOR
  130. #include "../../demo/common/calculator.c"
  131. #endif
  132. #ifdef INCLUDE_CANVAS
  133. #include "../../demo/common/canvas.c"
  134. #endif
  135. #ifdef INCLUDE_OVERVIEW
  136. #include "../../demo/common/overview.c"
  137. #endif
  138. #ifdef INCLUDE_CONFIGURATOR
  139. #include "../../demo/common/style_configurator.c"
  140. #endif
  141. #ifdef INCLUDE_NODE_EDITOR
  142. #include "../../demo/common/node_editor.c"
  143. #endif
  144. /* ===============================================================
  145. *
  146. * DEMO
  147. *
  148. * ===============================================================*/
  149. struct nk_sdl_app {
  150. SDL_Window* window;
  151. SDL_Renderer* renderer;
  152. struct nk_context * ctx;
  153. struct nk_colorf bg;
  154. enum nk_anti_aliasing AA;
  155. };
  156. static SDL_AppResult
  157. nk_sdl_fail()
  158. {
  159. SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error: %s", SDL_GetError());
  160. return SDL_APP_FAILURE;
  161. }
  162. SDL_AppResult
  163. SDL_AppInit(void** appstate, int argc, char* argv[])
  164. {
  165. struct nk_sdl_app* app;
  166. struct nk_context* ctx;
  167. float font_scale;
  168. NK_UNUSED(argc);
  169. NK_UNUSED(argv);
  170. if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
  171. return nk_sdl_fail();
  172. }
  173. app = SDL_malloc(sizeof(*app));
  174. if (app == NULL) {
  175. return nk_sdl_fail();
  176. }
  177. if (!SDL_CreateWindowAndRenderer("Nuklear: SDL3 Renderer", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &app->window, &app->renderer)) {
  178. SDL_free(app);
  179. return nk_sdl_fail();
  180. }
  181. *appstate = app;
  182. if (!SDL_SetRenderVSync(app->renderer, 1)) {
  183. SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "SDL_SetRenderVSync failed: %s", SDL_GetError());
  184. }
  185. app->bg.r = 0.10f;
  186. app->bg.g = 0.18f;
  187. app->bg.b = 0.24f;
  188. app->bg.a = 1.0f;
  189. font_scale = 1;
  190. {
  191. /* This scaling logic was kept simple for the demo purpose.
  192. * On some platforms, this might not be the exact scale
  193. * that you want to use. For more information, see:
  194. * https://wiki.libsdl.org/SDL3/README-highdpi */
  195. const float scale = SDL_GetWindowDisplayScale(app->window);
  196. SDL_SetRenderScale(app->renderer, scale, scale);
  197. font_scale = scale;
  198. }
  199. ctx = nk_sdl_init(app->window, app->renderer, nk_sdl_allocator());
  200. app->ctx = ctx;
  201. #if 0
  202. {
  203. /* If you don't want to use advanced Nuklear font baking API
  204. * you can use simple ASCII debug font provided by SDL
  205. * just change the `#if 0` above to `#if 1` */
  206. nk_sdl_style_set_debug_font(ctx);
  207. /* Note that since debug font is extremely small (only 8x8 pixels),
  208. * scaling it does not make much sense. The font would appear blurry. */
  209. NK_UNUSED(font_scale);
  210. /* You may wish to change a few style options, here are few recommendations: */
  211. ctx->style.button.rounding = 0.0f;
  212. ctx->style.menu_button.rounding = 0.0f;
  213. ctx->style.property.rounding = 0.0f;
  214. ctx->style.property.border = 0.0f;
  215. ctx->style.option.border = -1.0f;
  216. ctx->style.checkbox.border = -1.0f;
  217. ctx->style.property.dec_button.border = -2.0f;
  218. ctx->style.property.inc_button.border = -2.0f;
  219. ctx->style.tab.tab_minimize_button.border = -2.0f;
  220. ctx->style.tab.tab_maximize_button.border = -2.0f;
  221. ctx->style.tab.node_minimize_button.border = -2.0f;
  222. ctx->style.tab.node_maximize_button.border = -2.0f;
  223. ctx->style.checkbox.spacing = 5.0f;
  224. /* It's better to disable anti-aliasing when using small fonts */
  225. app->AA = NK_ANTI_ALIASING_OFF;
  226. }
  227. #else
  228. {
  229. struct nk_font_atlas *atlas;
  230. struct nk_font_config config = nk_font_config(0);
  231. struct nk_font *font;
  232. /* set up the font atlas and add desired font; note that font sizes are
  233. * multiplied by font_scale to produce better results at higher DPIs */
  234. atlas = nk_sdl_font_stash_begin(ctx);
  235. font = nk_font_atlas_add_default(atlas, 13 * font_scale, &config);
  236. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14 * font_scale, &config);*/
  237. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16 * font_scale, &config);*/
  238. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13 * font_scale, &config);*/
  239. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12 * font_scale, &config);*/
  240. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10 * font_scale, &config);*/
  241. /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13 * font_scale, &config);*/
  242. nk_sdl_font_stash_end(ctx);
  243. /* this hack makes the font appear to be scaled down to the desired
  244. * size and is only necessary when font_scale > 1 */
  245. font->handle.height /= font_scale;
  246. /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
  247. nk_style_set_font(ctx, &font->handle);
  248. app->AA = NK_ANTI_ALIASING_ON;
  249. }
  250. #endif
  251. return SDL_APP_CONTINUE;
  252. }
  253. SDL_AppResult
  254. SDL_AppEvent(void *appstate, SDL_Event* event)
  255. {
  256. struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
  257. switch (event->type) {
  258. case SDL_EVENT_QUIT:
  259. return SDL_APP_SUCCESS;
  260. case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
  261. /* You may wish to rescale the renderer and Nuklear during this event.
  262. * Without this the UI and Font could appear too small or too big.
  263. * This is not handled by the demo in order to keep it simple,
  264. * but you may wish to re-bake the Font whenever this happens. */
  265. SDL_Log("Unhandled scale event! Nuklear may appear blurry");
  266. return SDL_APP_CONTINUE;
  267. }
  268. /* Remember to always rescale the event coordinates,
  269. * if your renderer uses custom scale. */
  270. SDL_ConvertEventToRenderCoordinates(app->renderer, event);
  271. nk_sdl_handle_event(app->ctx, event);
  272. return SDL_APP_CONTINUE;
  273. }
  274. SDL_AppResult
  275. SDL_AppIterate(void *appstate)
  276. {
  277. struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
  278. struct nk_context* ctx = app->ctx;
  279. #ifdef INCLUDE_CONFIGURATOR
  280. static struct nk_color color_table[NK_COLOR_COUNT];
  281. NK_MEMCPY(color_table, nk_default_color_style, sizeof(color_table));
  282. #endif
  283. nk_input_end(ctx);
  284. /* GUI */
  285. if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
  286. NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
  287. NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
  288. {
  289. enum {EASY, HARD};
  290. static int op = EASY;
  291. static int property = 20;
  292. nk_layout_row_static(ctx, 30, 80, 1);
  293. if (nk_button_label(ctx, "button")) {
  294. SDL_Log("button pressed");
  295. }
  296. nk_layout_row_dynamic(ctx, 30, 2);
  297. if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
  298. if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
  299. nk_layout_row_dynamic(ctx, 25, 1);
  300. nk_property_int(ctx, "Compression:", 0, &property, 1000, 1, 1);
  301. nk_layout_row_dynamic(ctx, 20, 1);
  302. nk_label(ctx, "background:", NK_TEXT_LEFT);
  303. nk_layout_row_dynamic(ctx, 25, 1);
  304. if (nk_combo_begin_color(ctx, nk_rgb_cf(app->bg), nk_vec2(nk_widget_width(ctx),400))) {
  305. nk_layout_row_dynamic(ctx, 120, 1);
  306. app->bg = nk_color_picker(ctx, app->bg, NK_RGBA);
  307. nk_layout_row_dynamic(ctx, 25, 1);
  308. app->bg.r = nk_propertyf(ctx, "#R:", 0, app->bg.r, 1.0f, 0.01f,0.005f);
  309. app->bg.g = nk_propertyf(ctx, "#G:", 0, app->bg.g, 1.0f, 0.01f,0.005f);
  310. app->bg.b = nk_propertyf(ctx, "#B:", 0, app->bg.b, 1.0f, 0.01f,0.005f);
  311. app->bg.a = nk_propertyf(ctx, "#A:", 0, app->bg.a, 1.0f, 0.01f,0.005f);
  312. nk_combo_end(ctx);
  313. }
  314. }
  315. nk_end(ctx);
  316. /* -------------- EXAMPLES ---------------- */
  317. #ifdef INCLUDE_CALCULATOR
  318. calculator(ctx);
  319. #endif
  320. #ifdef INCLUDE_CANVAS
  321. canvas(ctx);
  322. #endif
  323. #ifdef INCLUDE_OVERVIEW
  324. overview(ctx);
  325. #endif
  326. #ifdef INCLUDE_CONFIGURATOR
  327. style_configurator(ctx, color_table);
  328. #endif
  329. #ifdef INCLUDE_NODE_EDITOR
  330. node_editor(ctx);
  331. #endif
  332. /* ----------------------------------------- */
  333. SDL_SetRenderDrawColorFloat(app->renderer, app->bg.r, app->bg.g, app->bg.b, app->bg.a);
  334. SDL_RenderClear(app->renderer);
  335. nk_sdl_render(ctx, app->AA);
  336. nk_sdl_update_TextInput(ctx);
  337. /* show if TextInput is active for debug purpose. Feel free to remove this. */
  338. SDL_SetRenderDrawColor(app->renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  339. SDL_RenderDebugTextFormat(app->renderer, 10, 10, "TextInputActive? %s",
  340. SDL_TextInputActive(app->window) ? "Yes" : "No");
  341. SDL_RenderPresent(app->renderer);
  342. nk_input_begin(ctx);
  343. return SDL_APP_CONTINUE;
  344. }
  345. void
  346. SDL_AppQuit(void* appstate, SDL_AppResult result)
  347. {
  348. struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
  349. NK_UNUSED(result);
  350. if (app) {
  351. nk_sdl_shutdown(app->ctx);
  352. SDL_DestroyRenderer(app->renderer);
  353. SDL_DestroyWindow(app->window);
  354. SDL_free(app);
  355. }
  356. }