raylib-nuklear.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. /**********************************************************************************************
  2. *
  3. * raylib-nuklear v5.5.0 - Nuklear GUI for Raylib.
  4. *
  5. * FEATURES:
  6. * - Use the Nuklear immediate-mode graphical user interface in raylib.
  7. *
  8. * DEPENDENCIES:
  9. * - raylib 5.5+ https://www.raylib.com/
  10. * - Nuklear https://github.com/Immediate-Mode-UI/Nuklear
  11. *
  12. * LICENSE: zlib/libpng
  13. *
  14. * raylib-nuklear is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  15. * BSD-like license that allows static linking with closed source software:
  16. *
  17. * Copyright (c) 2020 Rob Loach (@RobLoach)
  18. *
  19. * This software is provided "as-is", without any express or implied warranty. In no event
  20. * will the authors be held liable for any damages arising from the use of this software.
  21. *
  22. * Permission is granted to anyone to use this software for any purpose, including commercial
  23. * applications, and to alter it and redistribute it freely, subject to the following restrictions:
  24. *
  25. * 1. The origin of this software must not be misrepresented; you must not claim that you
  26. * wrote the original software. If you use this software in a product, an acknowledgment
  27. * in the product documentation would be appreciated but is not required.
  28. *
  29. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
  30. * as being the original software.
  31. *
  32. * 3. This notice may not be removed or altered from any source distribution.
  33. *
  34. **********************************************************************************************/
  35. #ifndef RAYLIB_NUKLEAR_H
  36. #define RAYLIB_NUKLEAR_H
  37. #include "raylib.h"
  38. // Nuklear defines
  39. #define NK_INCLUDE_FIXED_TYPES
  40. #define NK_INCLUDE_STANDARD_VARARGS
  41. #define NK_INCLUDE_STANDARD_BOOL
  42. #define NK_INCLUDE_COMMAND_USERDATA
  43. #define NK_KEYSTATE_BASED_INPUT
  44. #ifndef NK_ASSERT
  45. #ifdef NDEBUG
  46. #define NK_ASSERT(condition) ((void)0)
  47. #else
  48. #define NK_ASSERT(condition) do { if (!(condition)) { TraceLog(LOG_ERROR, "NUKLEAR: Failed assert \"%s\" (%s:%i)", #condition, "nuklear.h", __LINE__); }} while (0)
  49. #endif // NDEBUG
  50. #endif // NK_ASSERT
  51. #include "nuklear.h"
  52. #ifdef __cplusplus
  53. extern "C" {
  54. #endif
  55. NK_API struct nk_context* InitNuklear(int fontSize); // Initialize the Nuklear GUI context using raylib's font
  56. NK_API struct nk_context* InitNuklearEx(Font font, float fontSize); // Initialize the Nuklear GUI context, with a custom font
  57. NK_API Font LoadFontFromNuklear(int fontSize); // Loads the default Nuklear font
  58. NK_API void UpdateNuklear(struct nk_context * ctx); // Update the input state and internal components for Nuklear
  59. NK_API void UpdateNuklearEx(struct nk_context * ctx, float deltaTime); // Update the input state and internal components for Nuklear, with a custom frame time
  60. NK_API void DrawNuklear(struct nk_context * ctx); // Render the Nuklear GUI on the screen
  61. NK_API void UnloadNuklear(struct nk_context * ctx); // Deinitialize the Nuklear context
  62. NK_API struct nk_color ColorToNuklear(Color color); // Convert a raylib Color to a Nuklear color object
  63. NK_API struct nk_colorf ColorToNuklearF(Color color); // Convert a raylib Color to a Nuklear floating color
  64. NK_API struct Color ColorFromNuklear(struct nk_color color); // Convert a Nuklear color to a raylib Color
  65. NK_API struct Color ColorFromNuklearF(struct nk_colorf color); // Convert a Nuklear floating color to a raylib Color
  66. NK_API struct Rectangle RectangleFromNuklear(struct nk_context * ctx, struct nk_rect rect); // Convert a Nuklear rectangle to a raylib Rectangle
  67. NK_API struct nk_rect RectangleToNuklear(struct nk_context * ctx, Rectangle rect); // Convert a raylib Rectangle to a Nuklear Rectangle
  68. NK_API struct nk_image TextureToNuklear(Texture tex); // Convert a raylib Texture to A Nuklear image
  69. NK_API struct Texture TextureFromNuklear(struct nk_image img); // Convert a Nuklear image to a raylib Texture
  70. NK_API struct nk_image LoadNuklearImage(const char* path); // Load a Nuklear image
  71. NK_API void UnloadNuklearImage(struct nk_image img); // Unload a Nuklear image. And free its data
  72. NK_API void CleanupNuklearImage(struct nk_image img); // Frees the data stored by the Nuklear image
  73. NK_API void SetNuklearScaling(struct nk_context * ctx, float scaling); // Sets the scaling for the given Nuklear context
  74. NK_API float GetNuklearScaling(struct nk_context * ctx); // Retrieves the scaling of the given Nuklear context
  75. // Internal Nuklear functions
  76. NK_API float nk_raylib_font_get_text_width(nk_handle handle, float height, const char *text, int len);
  77. NK_API float nk_raylib_font_get_text_width_user_font(nk_handle handle, float height, const char *text, int len);
  78. NK_API void nk_raylib_clipboard_paste(nk_handle usr, struct nk_text_edit *edit);
  79. NK_API void nk_raylib_clipboard_copy(nk_handle usr, const char *text, int len);
  80. NK_API void* nk_raylib_malloc(nk_handle unused, void *old, nk_size size);
  81. NK_API void nk_raylib_mfree(nk_handle unused, void *ptr);
  82. NK_API struct nk_context* InitNuklearContext(struct nk_user_font* userFont);
  83. NK_API void nk_raylib_input_keyboard(struct nk_context * ctx);
  84. NK_API void nk_raylib_input_mouse(struct nk_context * ctx);
  85. #ifdef __cplusplus
  86. }
  87. #endif
  88. #endif // RAYLIB_NUKLEAR_H
  89. #ifdef RAYLIB_NUKLEAR_IMPLEMENTATION
  90. #ifndef RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  91. #define RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  92. #include <stddef.h> // NULL
  93. #include <math.h> // cosf, sinf, sqrtf
  94. // Math
  95. #ifndef NK_COS
  96. #define NK_COS cosf
  97. #endif // NK_COS
  98. #ifndef NK_SIN
  99. #define NK_SIN sinf
  100. #endif // NK_SIN
  101. #ifndef NK_INV_SQRT
  102. #define NK_INV_SQRT(value) (1.0f / sqrtf(value))
  103. #endif // NK_INV_SQRT
  104. #define NK_IMPLEMENTATION
  105. #include "nuklear.h"
  106. #ifdef __cplusplus
  107. extern "C" {
  108. #endif
  109. #ifndef RAYLIB_NUKLEAR_DEFAULT_FONTSIZE
  110. /**
  111. * The default font size that is used when a font size is not provided.
  112. */
  113. #define RAYLIB_NUKLEAR_DEFAULT_FONTSIZE 13
  114. #endif // RAYLIB_NUKLEAR_DEFAULT_FONTSIZE
  115. #ifndef RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS
  116. /**
  117. * The amount of segments used when drawing an arc.
  118. *
  119. * @see NK_COMMAND_ARC_FILLED
  120. */
  121. #define RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS 20
  122. #endif // RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS
  123. #ifdef RAYLIB_NUKLEAR_INCLUDE_DEFAULT_FONT
  124. #include "raylib-nuklear-font.h"
  125. #endif
  126. /**
  127. * The user data that's leverages internally through Nuklear.
  128. */
  129. typedef struct NuklearUserData {
  130. float scaling; // The scaling of the Nuklear user interface.
  131. } NuklearUserData;
  132. /**
  133. * Nuklear callback; Get the width of the given text.
  134. *
  135. * @internal
  136. */
  137. NK_API float
  138. nk_raylib_font_get_text_width(nk_handle handle, float height, const char *text, int len)
  139. {
  140. NK_UNUSED(handle);
  141. if (len > 0) {
  142. // Grab the text with the cropped length so that it only measures the desired string length.
  143. const char* subtext = TextSubtext(text, 0, len);
  144. // Raylib only counts the spacing between characters, but Nuklear expects one spacing to be
  145. // counter for every character in the string:
  146. return (float)MeasureText(subtext, (int)height) + height / 10.0f;
  147. }
  148. return 0;
  149. }
  150. /**
  151. * Nuklear callback; Get the width of the given text (userFont version)
  152. *
  153. * @internal
  154. */
  155. NK_API float
  156. nk_raylib_font_get_text_width_user_font(nk_handle handle, float height, const char *text, int len)
  157. {
  158. if (len > 0) {
  159. // Grab the text with the cropped length so that it only measures the desired string length.
  160. const char* subtext = TextSubtext(text, 0, len);
  161. // Spacing is determined by the font size divided by 10.
  162. // Raylib only counts the spacing between characters, but Nuklear expects one spacing to be
  163. // counter for every character in the string:
  164. return MeasureTextEx(*(Font*)handle.ptr, subtext, height, height / 10.0f).x + height / 10.0f;
  165. }
  166. return 0;
  167. }
  168. /**
  169. * Nuklear callback; Paste the current clipboard.
  170. *
  171. * @internal
  172. */
  173. NK_API void
  174. nk_raylib_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
  175. {
  176. const char *text = GetClipboardText();
  177. NK_UNUSED(usr);
  178. if (text != NULL) {
  179. nk_textedit_paste(edit, text, (int)TextLength(text));
  180. }
  181. }
  182. /**
  183. * Nuklear callback; Copy the given text.
  184. *
  185. * @internal
  186. */
  187. NK_API void
  188. nk_raylib_clipboard_copy(nk_handle usr, const char *text, int len)
  189. {
  190. NK_UNUSED(usr);
  191. char* trimmedText = (char*)MemAlloc((unsigned int)(sizeof(char) * (size_t)(len + 1)));
  192. if(!trimmedText)
  193. return;
  194. nk_memcopy(trimmedText, text, (nk_size)len);
  195. trimmedText[len] = 0;
  196. SetClipboardText(trimmedText);
  197. MemFree(trimmedText);
  198. }
  199. /**
  200. * Nuklear callback; Allocate memory for Nuklear.
  201. *
  202. * @internal
  203. */
  204. NK_API void*
  205. nk_raylib_malloc(nk_handle unused, void *old, nk_size size)
  206. {
  207. NK_UNUSED(unused);
  208. NK_UNUSED(old);
  209. return MemAlloc((unsigned int)size);
  210. }
  211. /**
  212. * Nuklear callback; Free memory for Nuklear.
  213. */
  214. NK_API void
  215. nk_raylib_mfree(nk_handle unused, void *ptr)
  216. {
  217. NK_UNUSED(unused);
  218. MemFree(ptr);
  219. }
  220. /**
  221. * Initialize the Nuklear context for use with Raylib, with the given Nuklear user font.
  222. *
  223. * @param userFont The Nuklear user font to initialize the Nuklear context with.
  224. *
  225. * @internal
  226. */
  227. NK_API struct nk_context*
  228. InitNuklearContext(struct nk_user_font* userFont)
  229. {
  230. struct nk_context* ctx = (struct nk_context*)MemAlloc(sizeof(struct nk_context));
  231. if (ctx == NULL) {
  232. TraceLog(LOG_ERROR, "NUKLEAR: Failed to initialize nuklear memory");
  233. return NULL;
  234. }
  235. struct NuklearUserData* userData = (struct NuklearUserData*)MemAlloc(sizeof(struct NuklearUserData));
  236. if (userData == NULL) {
  237. TraceLog(LOG_ERROR, "NUKLEAR: Failed to initialize nuklear user data");
  238. MemFree(ctx);
  239. return NULL;
  240. }
  241. // Allocator
  242. struct nk_allocator alloc;
  243. alloc.userdata = nk_handle_ptr(0);
  244. alloc.alloc = nk_raylib_malloc;
  245. alloc.free = nk_raylib_mfree;
  246. // Initialize the context.
  247. if (!nk_init(ctx, &alloc, userFont)) {
  248. TraceLog(LOG_ERROR, "NUKLEAR: Failed to initialize nuklear");
  249. MemFree(ctx);
  250. MemFree(userData);
  251. return NULL;
  252. }
  253. // Clipboard
  254. ctx->clip.copy = nk_raylib_clipboard_copy;
  255. ctx->clip.paste = nk_raylib_clipboard_paste;
  256. ctx->clip.userdata = nk_handle_ptr(0);
  257. // Set the internal user data.
  258. userData->scaling = 1.0f;
  259. nk_handle userDataHandle;
  260. userDataHandle.id = 1;
  261. userDataHandle.ptr = (void*)userData;
  262. nk_set_user_data(ctx, userDataHandle);
  263. TraceLog(LOG_INFO, "NUKLEAR: Initialized GUI");
  264. return ctx;
  265. }
  266. /**
  267. * Initialize the Nuklear context for use with Raylib.
  268. *
  269. * @param fontSize The size of the font to use for GUI text. Use 0 to use the default font size of 10.
  270. *
  271. * @return The nuklear context, or NULL on error.
  272. */
  273. NK_API struct nk_context*
  274. InitNuklear(int fontSize)
  275. {
  276. // User font.
  277. struct nk_user_font* userFont = (struct nk_user_font*)MemAlloc(sizeof(struct nk_user_font));
  278. // Use the default font size if desired.
  279. if (fontSize <= 0) {
  280. fontSize = RAYLIB_NUKLEAR_DEFAULT_FONTSIZE;
  281. }
  282. userFont->height = (float)fontSize;
  283. userFont->width = nk_raylib_font_get_text_width;
  284. userFont->userdata = nk_handle_ptr(0);
  285. // Nuklear context.
  286. return InitNuklearContext(userFont);
  287. }
  288. /**
  289. * Initialize the Nuklear context for use with Raylib, with a supplied custom font.
  290. *
  291. * @param font The custom raylib font to use with Nuklear.
  292. * @param fontSize The desired size of the font. Use 0 to set the default size of 10.
  293. *
  294. * @return The nuklear context, or NULL on error.
  295. */
  296. NK_API struct nk_context*
  297. InitNuklearEx(Font font, float fontSize)
  298. {
  299. // Copy the font to a new raylib font pointer.
  300. struct Font* newFont = (struct Font*)MemAlloc(sizeof(struct Font));
  301. // Use the default font size if desired.
  302. if (fontSize <= 0.0f) {
  303. fontSize = (float)RAYLIB_NUKLEAR_DEFAULT_FONTSIZE;
  304. }
  305. newFont->baseSize = font.baseSize;
  306. newFont->glyphCount = font.glyphCount;
  307. newFont->glyphPadding = font.glyphPadding;
  308. newFont->glyphs = font.glyphs;
  309. newFont->recs = font.recs;
  310. newFont->texture = font.texture;
  311. // Create the nuklear user font.
  312. struct nk_user_font* userFont = (struct nk_user_font*)MemAlloc(sizeof(struct nk_user_font));
  313. userFont->userdata = nk_handle_ptr(newFont);
  314. userFont->height = fontSize;
  315. userFont->width = nk_raylib_font_get_text_width_user_font;
  316. // Nuklear context.
  317. return InitNuklearContext(userFont);
  318. }
  319. /**
  320. * Load the default Nuklear font. Requires `RAYLIB_NUKLEAR_INCLUDE_DEFAULT_FONT` to be defined.
  321. *
  322. * @param size The size of the font to load (optional). Provide 0 if you'd like to use the default size from Nuklear.
  323. *
  324. * @return The loaded font, or an empty font on error.
  325. *
  326. * @code
  327. * #define RAYLIB_NUKLEAR_INCLUDE_DEFAULT_FONT
  328. * #include "raylib-nuklear.h"
  329. * Font font = LoadFontFromNuklear(0);
  330. * @endcode
  331. */
  332. NK_API Font LoadFontFromNuklear(int size) {
  333. #ifndef RAYLIB_NUKLEAR_INCLUDE_DEFAULT_FONT
  334. (void)size;
  335. TraceLog(LOG_ERROR, "NUKLEAR: RAYLIB_NUKLEAR_INCLUDE_DEFAULT_FONT must be defined to use LoadFontFromNuklear()");
  336. return CLITERAL(Font) {0};
  337. #else
  338. if (size <= 0) {
  339. size = RAYLIB_NUKLEAR_DEFAULT_FONTSIZE;
  340. }
  341. #ifndef RAYLIB_NUKLEAR_DEFAULT_FONT_GLYPHS
  342. /**
  343. * The amount of glyphs to load for the default font.
  344. */
  345. #define RAYLIB_NUKLEAR_DEFAULT_FONT_GLYPHS 95
  346. #endif
  347. return LoadFontFromMemory(".ttf", RAYLIB_NUKLEAR_DEFAULT_FONT_NAME, RAYLIB_NUKLEAR_DEFAULT_FONT_SIZE, size, NULL, RAYLIB_NUKLEAR_DEFAULT_FONT_GLYPHS);
  348. #endif
  349. }
  350. /**
  351. * Convert the given Nuklear color to a raylib color.
  352. */
  353. NK_API Color
  354. ColorFromNuklear(struct nk_color color)
  355. {
  356. Color rc;
  357. rc.a = color.a;
  358. rc.r = color.r;
  359. rc.g = color.g;
  360. rc.b = color.b;
  361. return rc;
  362. }
  363. /**
  364. * Convert the given raylib color to a Nuklear color.
  365. */
  366. NK_API struct nk_color
  367. ColorToNuklear(Color color)
  368. {
  369. struct nk_color rc;
  370. rc.a = color.a;
  371. rc.r = color.r;
  372. rc.g = color.g;
  373. rc.b = color.b;
  374. return rc;
  375. }
  376. /**
  377. * Convert the given Nuklear float color to a raylib color.
  378. */
  379. NK_API Color
  380. ColorFromNuklearF(struct nk_colorf color)
  381. {
  382. return ColorFromNuklear(nk_rgba_cf(color));
  383. }
  384. /**
  385. * Convert the given raylib color to a raylib float color.
  386. */
  387. NK_API struct nk_colorf
  388. ColorToNuklearF(Color color)
  389. {
  390. return nk_color_cf(ColorToNuklear(color));
  391. }
  392. /**
  393. * Draw the given Nuklear context in raylib.
  394. *
  395. * @param ctx The nuklear context.
  396. */
  397. NK_API void
  398. DrawNuklear(struct nk_context * ctx)
  399. {
  400. // Protect against drawing when there's nothing to draw.
  401. if (ctx == NULL || nk__begin(ctx) == 0) {
  402. return;
  403. }
  404. const struct nk_command *cmd;
  405. const float scale = GetNuklearScaling(ctx);
  406. nk_foreach(cmd, ctx) {
  407. switch (cmd->type) {
  408. case NK_COMMAND_NOP: {
  409. break;
  410. }
  411. case NK_COMMAND_SCISSOR: {
  412. // TODO(RobLoach): Verify if NK_COMMAND_SCISSOR works.
  413. const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
  414. BeginScissorMode((int)(s->x * scale), (int)(s->y * scale), (int)(s->w * scale), (int)(s->h * scale));
  415. } break;
  416. case NK_COMMAND_LINE: {
  417. const struct nk_command_line *l = (const struct nk_command_line *)cmd;
  418. Color color = ColorFromNuklear(l->color);
  419. Vector2 startPos = CLITERAL(Vector2) {(float)l->begin.x * scale, (float)l->begin.y * scale};
  420. Vector2 endPos = CLITERAL(Vector2) {(float)l->end.x * scale, (float)l->end.y * scale};
  421. DrawLineEx(startPos, endPos, l->line_thickness * scale, color);
  422. } break;
  423. case NK_COMMAND_CURVE: {
  424. const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
  425. Color color = ColorFromNuklear(q->color);
  426. Vector2 begin = CLITERAL(Vector2) {(float)q->begin.x * scale, (float)q->begin.y * scale};
  427. Vector2 controlPoint1 = CLITERAL(Vector2) {(float)q->ctrl[0].x * scale, (float)q->ctrl[0].y * scale};
  428. Vector2 controlPoint2 = CLITERAL(Vector2) {(float)q->ctrl[1].x * scale, (float)q->ctrl[1].y * scale};
  429. Vector2 end = CLITERAL(Vector2) {(float)q->end.x * scale, (float)q->end.y * scale};
  430. DrawSplineSegmentBezierCubic(begin, controlPoint1, controlPoint2, end, (float)q->line_thickness * scale, color);
  431. } break;
  432. case NK_COMMAND_RECT: {
  433. const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
  434. Color color = ColorFromNuklear(r->color);
  435. Rectangle rect = CLITERAL(Rectangle) {(float)r->x * scale, (float)r->y * scale, (float)r->w * scale, (float)r->h * scale};
  436. float roundness = (rect.width > rect.height) ?
  437. ((2 * r->rounding * scale)/rect.height) : ((2 * r->rounding * scale)/rect.width);
  438. roundness = NK_CLAMP(0.0f, roundness, 1.0f);
  439. if (roundness > 0.0f) {
  440. // DrawRectangleRoundedLines doesn't work in the same way as DrawRectangleLinesEx and it draws
  441. // the outline outside the region defined by the rectangle. To compensate for that, shrink
  442. // the rectangle by the thickness plus 1 (due to inconsistencies from DrawRectangleRoundedLines):
  443. rect.x += ((float) r->line_thickness) * scale + 1.0f;
  444. rect.y += ((float) r->line_thickness) * scale + 1.0f;
  445. rect.width = NK_MAX(rect.width - (2 * ((float) r->line_thickness) * scale + 1.0f), 0.0f);
  446. rect.height = NK_MAX(rect.height - (2 * ((float) r->line_thickness) * scale + 1.0f), 0.0f);
  447. #if RAYLIB_VERSION_MAJOR >= 5 && RAYLIB_VERSION_MINOR == 0
  448. DrawRectangleRoundedLines(rect, roundness, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, (float)r->line_thickness * scale, color);
  449. #else
  450. DrawRectangleRoundedLinesEx(rect, roundness, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, (float)r->line_thickness * scale, color);
  451. #endif
  452. }
  453. else {
  454. DrawRectangleLinesEx(rect, r->line_thickness * scale, color);
  455. }
  456. } break;
  457. case NK_COMMAND_RECT_FILLED: {
  458. const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
  459. Color color = ColorFromNuklear(r->color);
  460. Rectangle rect = CLITERAL(Rectangle) {(float)r->x * scale, (float)r->y * scale, (float)r->w * scale, (float)r->h * scale};
  461. float roundness = (rect.width > rect.height) ?
  462. ((2 * r->rounding * scale)/rect.height) : ((2 * r->rounding * scale)/rect.width);
  463. roundness = NK_CLAMP(0.0f, roundness, 1.0f);
  464. if (roundness > 0.0f) {
  465. DrawRectangleRounded(rect, roundness, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, color);
  466. }
  467. else {
  468. DrawRectangleRec(rect, color);
  469. }
  470. } break;
  471. case NK_COMMAND_RECT_MULTI_COLOR: {
  472. const struct nk_command_rect_multi_color* rectangle = (const struct nk_command_rect_multi_color *)cmd;
  473. Rectangle position = {(float)rectangle->x * scale, (float)rectangle->y * scale, (float)rectangle->w * scale, (float)rectangle->h * scale};
  474. Color left = ColorFromNuklear(rectangle->left);
  475. Color top = ColorFromNuklear(rectangle->top);
  476. Color bottom = ColorFromNuklear(rectangle->bottom);
  477. Color right = ColorFromNuklear(rectangle->right);
  478. DrawRectangleGradientEx(position, left, bottom, right, top);
  479. } break;
  480. case NK_COMMAND_CIRCLE: {
  481. const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
  482. Color color = ColorFromNuklear(c->color);
  483. for (unsigned short i = 0; i < c->line_thickness; i++) {
  484. DrawEllipseLines((int)(c->x * scale + c->w * scale / 2.0f), (int)(c->y * scale + c->h * scale / 2.0f), c->w * scale / 2.0f - (float)i / 2.0f, c->h * scale / 2.0f - (float)i / 2.0f, color);
  485. }
  486. } break;
  487. case NK_COMMAND_CIRCLE_FILLED: {
  488. const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
  489. Color color = ColorFromNuklear(c->color);
  490. DrawEllipse((int)(c->x * scale + c->w * scale / 2.0f), (int)(c->y * scale + c->h * scale / 2.0f), (int)(c->w * scale / 2), (int)(c->h * scale / 2), color);
  491. } break;
  492. case NK_COMMAND_ARC: {
  493. const struct nk_command_arc *a = (const struct nk_command_arc*)cmd;
  494. Color color = ColorFromNuklear(a->color);
  495. Vector2 center = CLITERAL(Vector2) {(float)a->cx, (float)a->cy};
  496. DrawRingLines(center, 0, a->r * scale, a->a[0] * RAD2DEG, a->a[1] * RAD2DEG, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, color);
  497. } break;
  498. case NK_COMMAND_ARC_FILLED: {
  499. const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled*)cmd;
  500. Color color = ColorFromNuklear(a->color);
  501. Vector2 center = CLITERAL(Vector2) {(float)a->cx * scale, (float)a->cy * scale};
  502. DrawRing(center, 0, a->r * scale, a->a[0] * RAD2DEG, a->a[1] * RAD2DEG, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, color);
  503. } break;
  504. case NK_COMMAND_TRIANGLE: {
  505. const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;
  506. Color color = ColorFromNuklear(t->color);
  507. Vector2 point1 = CLITERAL(Vector2) {(float)t->b.x * scale, (float)t->b.y * scale};
  508. Vector2 point2 = CLITERAL(Vector2) {(float)t->a.x * scale, (float)t->a.y * scale};
  509. Vector2 point3 = CLITERAL(Vector2) {(float)t->c.x * scale, (float)t->c.y * scale};
  510. // DrawLineEx(point1, point2, t->line_thickness * scale, color);
  511. // DrawLineEx(point2, point3, t->line_thickness * scale, color);
  512. // DrawLineEx(point3, point1, t->line_thickness * scale, color);
  513. // TODO: Add line thickness to DrawTriangleLines(), maybe via a DrawTriangleLinesEx()?
  514. DrawTriangleLines(point1, point2, point3, color);
  515. } break;
  516. case NK_COMMAND_TRIANGLE_FILLED: {
  517. const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;
  518. Color color = ColorFromNuklear(t->color);
  519. Vector2 point1 = CLITERAL(Vector2) {(float)t->b.x * scale, (float)t->b.y * scale};
  520. Vector2 point2 = CLITERAL(Vector2) {(float)t->a.x * scale, (float)t->a.y * scale};
  521. Vector2 point3 = CLITERAL(Vector2) {(float)t->c.x * scale, (float)t->c.y * scale};
  522. DrawTriangle(point1, point2, point3, color);
  523. } break;
  524. case NK_COMMAND_POLYGON: {
  525. const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
  526. Color color = ColorFromNuklear(p->color);
  527. struct Vector2* points = (struct Vector2*)MemAlloc((unsigned int)((size_t)(p->point_count + 1) * sizeof(Vector2)));
  528. unsigned short i;
  529. for (i = 0; i < p->point_count; i++) {
  530. points[i].x = p->points[i].x * scale;
  531. points[i].y = p->points[i].y * scale;
  532. }
  533. points[p->point_count] = points[0];
  534. DrawLineStrip(points, p->point_count + 1, color);
  535. MemFree(points);
  536. } break;
  537. case NK_COMMAND_POLYGON_FILLED: {
  538. // TODO: Implement NK_COMMAND_POLYGON_FILLED
  539. const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;
  540. Color color = ColorFromNuklear(p->color);
  541. struct Vector2* points = (struct Vector2*)MemAlloc((unsigned int)((size_t)(p->point_count + 1) * sizeof(Vector2)));
  542. for (unsigned short i = 0; i < p->point_count; i++) {
  543. points[i].x = p->points[i].x * scale;
  544. points[i].y = p->points[i].y * scale;
  545. }
  546. points[p->point_count] = points[0];
  547. DrawLineStrip(points, p->point_count + 1, color);
  548. MemFree(points);
  549. } break;
  550. case NK_COMMAND_POLYLINE: {
  551. const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
  552. Color color = ColorFromNuklear(p->color);
  553. for (unsigned short i = 0; i < p->point_count - 1; i++) {
  554. Vector2 start = {(float)p->points[i].x * scale, (float)p->points[i].y * scale};
  555. Vector2 end = {(float)p->points[i + 1].x * scale, (float)p->points[i + 1].y * scale};
  556. DrawLineEx(start, end, p->line_thickness * scale, color);
  557. }
  558. } break;
  559. case NK_COMMAND_TEXT: {
  560. const struct nk_command_text *text = (const struct nk_command_text*)cmd;
  561. Color color = ColorFromNuklear(text->foreground);
  562. float fontSize = text->font->height * scale;
  563. Font* font = (Font*)text->font->userdata.ptr;
  564. if (font != NULL) {
  565. Vector2 position = {(float)text->x * scale, (float)text->y * scale};
  566. DrawTextEx(*font, (const char*)text->string, position, fontSize, fontSize / 10.0f, color);
  567. }
  568. else {
  569. DrawText((const char*)text->string, (int)(text->x * scale), (int)(text->y * scale), (int)fontSize, color);
  570. }
  571. } break;
  572. case NK_COMMAND_IMAGE: {
  573. const struct nk_command_image *i = (const struct nk_command_image *)cmd;
  574. Texture texture = *(Texture*)i->img.handle.ptr;
  575. Rectangle source = CLITERAL(Rectangle) {(float)i->img.region[0], (float)i->img.region[1], (float)i->img.region[2], (float)i->img.region[3]};
  576. Rectangle dest = CLITERAL(Rectangle) {(float)i->x * scale, (float)i->y * scale, (float)i->w * scale, (float)i->h * scale};
  577. Vector2 origin = CLITERAL(Vector2) {0, 0};
  578. Color tint = ColorFromNuklear(i->col);
  579. DrawTexturePro(texture, source, dest, origin, 0, tint);
  580. } break;
  581. case NK_COMMAND_CUSTOM: {
  582. TraceLog(LOG_WARNING, "NUKLEAR: Unverified custom callback implementation NK_COMMAND_CUSTOM");
  583. const struct nk_command_custom *custom = (const struct nk_command_custom *)cmd;
  584. custom->callback(NULL, (short)(custom->x * scale), (short)(custom->y * scale), (unsigned short)(custom->w * scale), (unsigned short)(custom->h * scale), custom->callback_data);
  585. } break;
  586. default: {
  587. TraceLog(LOG_WARNING, "NUKLEAR: Missing implementation %i", cmd->type);
  588. } break;
  589. }
  590. }
  591. nk_clear(ctx);
  592. }
  593. struct nk_raylib_input_keyboard_check {
  594. int key;
  595. int input_key;
  596. bool modifier;
  597. };
  598. /**
  599. * Update the Nuklear context for the keyboard input from raylib.
  600. *
  601. * @param ctx The nuklear context.
  602. *
  603. * @internal
  604. */
  605. NK_API void
  606. nk_raylib_input_keyboard(struct nk_context * ctx)
  607. {
  608. bool control = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
  609. bool command = IsKeyDown(KEY_LEFT_SUPER);
  610. bool shift = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
  611. #define NK_RAYLIB_INPUT_KEYBOARD_CHECK_NUM 16
  612. struct nk_raylib_input_keyboard_check checks[NK_RAYLIB_INPUT_KEYBOARD_CHECK_NUM] = {
  613. (struct nk_raylib_input_keyboard_check) {KEY_DELETE, NK_KEY_DEL, true},
  614. (struct nk_raylib_input_keyboard_check) {KEY_ENTER, NK_KEY_ENTER, true},
  615. (struct nk_raylib_input_keyboard_check) {KEY_BACKSPACE, NK_KEY_BACKSPACE, true},
  616. (struct nk_raylib_input_keyboard_check) {KEY_C, NK_KEY_COPY, (control || command)},
  617. (struct nk_raylib_input_keyboard_check) {KEY_V, NK_KEY_PASTE, (control || command)},
  618. (struct nk_raylib_input_keyboard_check) {KEY_B, NK_KEY_TEXT_LINE_START, (control || command)},
  619. (struct nk_raylib_input_keyboard_check) {KEY_E, NK_KEY_TEXT_LINE_END, (control || command)},
  620. (struct nk_raylib_input_keyboard_check) {KEY_Z, NK_KEY_TEXT_UNDO, (control || command)},
  621. (struct nk_raylib_input_keyboard_check) {KEY_R, NK_KEY_TEXT_REDO, (control || command)},
  622. (struct nk_raylib_input_keyboard_check) {KEY_A, NK_KEY_TEXT_SELECT_ALL, (control || command)},
  623. (struct nk_raylib_input_keyboard_check) {KEY_LEFT, NK_KEY_TEXT_WORD_LEFT, (control || command)},
  624. (struct nk_raylib_input_keyboard_check) {KEY_RIGHT, NK_KEY_TEXT_WORD_RIGHT, (control || command)},
  625. (struct nk_raylib_input_keyboard_check) {KEY_RIGHT, NK_KEY_RIGHT, true},
  626. (struct nk_raylib_input_keyboard_check) {KEY_LEFT, NK_KEY_LEFT, true},
  627. (struct nk_raylib_input_keyboard_check) {KEY_UP, NK_KEY_UP, true},
  628. (struct nk_raylib_input_keyboard_check) {KEY_DOWN, NK_KEY_DOWN, true}
  629. };
  630. bool checked = false;
  631. for (int i = 0; i < NK_RAYLIB_INPUT_KEYBOARD_CHECK_NUM; i++) {
  632. struct nk_raylib_input_keyboard_check check = checks[i];
  633. if (IsKeyDown(check.key) && check.modifier) {
  634. nk_input_key(ctx, (enum nk_keys)check.input_key, true);
  635. checked = true;
  636. } else {
  637. nk_input_key(ctx, (enum nk_keys)check.input_key, false);
  638. }
  639. }
  640. #undef NK_RAYLIB_INPUT_KEYBOARD_CHECK_NUM
  641. nk_input_key(ctx, NK_KEY_SHIFT, shift);
  642. if (checked) {
  643. return;
  644. }
  645. nk_input_key(ctx, NK_KEY_LEFT, IsKeyDown(KEY_LEFT));
  646. nk_input_key(ctx, NK_KEY_RIGHT, IsKeyDown(KEY_RIGHT));
  647. nk_input_key(ctx, NK_KEY_UP, IsKeyDown(KEY_UP));
  648. nk_input_key(ctx, NK_KEY_DOWN, IsKeyDown(KEY_DOWN));
  649. nk_input_key(ctx, NK_KEY_TEXT_START, IsKeyDown(KEY_HOME));
  650. nk_input_key(ctx, NK_KEY_TEXT_END, IsKeyDown(KEY_END));
  651. nk_input_key(ctx, NK_KEY_SCROLL_START, IsKeyDown(KEY_HOME) && control);
  652. nk_input_key(ctx, NK_KEY_SCROLL_END, IsKeyDown(KEY_END) && control);
  653. nk_input_key(ctx, NK_KEY_SCROLL_DOWN, IsKeyDown(KEY_PAGE_DOWN));
  654. nk_input_key(ctx, NK_KEY_SCROLL_UP, IsKeyDown(KEY_PAGE_UP));
  655. // Functions
  656. if (IsKeyPressed(KEY_TAB)) nk_input_unicode(ctx, 9);
  657. // Unicode
  658. int code;
  659. while ((code = GetCharPressed()) != 0)
  660. nk_input_unicode(ctx, (nk_rune)code);
  661. }
  662. /**
  663. * Update the Nuklear context for the mouse input from raylib.
  664. *
  665. * @param ctx The nuklear context.
  666. *
  667. * @internal
  668. */
  669. NK_API void
  670. nk_raylib_input_mouse(struct nk_context * ctx)
  671. {
  672. const float scale = GetNuklearScaling(ctx);
  673. const int mouseX = (int)((float)GetMouseX() / scale);
  674. const int mouseY = (int)((float)GetMouseY() / scale);
  675. nk_input_motion(ctx, mouseX, mouseY);
  676. nk_input_button(ctx, NK_BUTTON_LEFT, mouseX, mouseY, IsMouseButtonDown(MOUSE_LEFT_BUTTON));
  677. nk_input_button(ctx, NK_BUTTON_RIGHT, mouseX, mouseY, IsMouseButtonDown(MOUSE_RIGHT_BUTTON));
  678. nk_input_button(ctx, NK_BUTTON_MIDDLE, mouseX, mouseY, IsMouseButtonDown(MOUSE_MIDDLE_BUTTON));
  679. // Mouse Wheel
  680. float mouseWheel = GetMouseWheelMove();
  681. if (mouseWheel != 0.0f) {
  682. struct nk_vec2 mouseWheelMove;
  683. mouseWheelMove.x = 0.0f;
  684. mouseWheelMove.y = mouseWheel;
  685. nk_input_scroll(ctx, mouseWheelMove);
  686. }
  687. }
  688. /**
  689. * Update the Nuklear context for raylib's state.
  690. *
  691. * @param ctx The nuklear context to act upon.
  692. */
  693. NK_API void
  694. UpdateNuklear(struct nk_context * ctx)
  695. {
  696. UpdateNuklearEx(ctx, GetFrameTime());
  697. }
  698. /**
  699. * Update the Nuklear context for raylib's state.
  700. *
  701. * @param ctx The nuklear context to act upon.
  702. * @param deltaTime Time in seconds since last frame.
  703. */
  704. NK_API void
  705. UpdateNuklearEx(struct nk_context * ctx, float deltaTime)
  706. {
  707. // Update the time that has changed since last frame.
  708. ctx->delta_time_seconds = deltaTime;
  709. // Update the input state.
  710. nk_input_begin(ctx);
  711. {
  712. nk_raylib_input_mouse(ctx);
  713. nk_raylib_input_keyboard(ctx);
  714. }
  715. nk_input_end(ctx);
  716. }
  717. /**
  718. * Unload the given Nuklear context, along with all internal raylib textures.
  719. *
  720. * @param ctx The nuklear context.
  721. */
  722. NK_API void
  723. UnloadNuklear(struct nk_context * ctx)
  724. {
  725. struct nk_user_font* userFont;
  726. // Skip unloading if it's not set.
  727. if (ctx == NULL) {
  728. return;
  729. }
  730. // Unload the font.
  731. userFont = (struct nk_user_font*)ctx->style.font;
  732. if (userFont != NULL) {
  733. // Clear the raylib Font object.
  734. void* fontPtr = userFont->userdata.ptr;
  735. if (fontPtr != NULL) {
  736. MemFree(fontPtr);
  737. }
  738. // Clear the user font.
  739. MemFree(userFont);
  740. ctx->style.font = NULL;
  741. }
  742. // Unload the custom user data.
  743. if (ctx->userdata.ptr != NULL) {
  744. MemFree(ctx->userdata.ptr);
  745. }
  746. // Unload the nuklear context.
  747. nk_free(ctx);
  748. MemFree(ctx);
  749. TraceLog(LOG_INFO, "NUKLEAR: Unloaded GUI");
  750. }
  751. /**
  752. * Convert the given Nuklear rectangle to a raylib Rectangle.
  753. */
  754. NK_API struct
  755. Rectangle RectangleFromNuklear(struct nk_context* ctx, struct nk_rect rect)
  756. {
  757. float scaling = GetNuklearScaling(ctx);
  758. Rectangle output;
  759. output.x = rect.x * scaling;
  760. output.y = rect.y * scaling;
  761. output.width = rect.w * scaling;
  762. output.height = rect.h * scaling;
  763. return output;
  764. }
  765. /**
  766. * Convert the given raylib Rectangle to a Nuklear rectangle.
  767. */
  768. NK_API struct
  769. nk_rect RectangleToNuklear(struct nk_context* ctx, Rectangle rect)
  770. {
  771. float scaling = GetNuklearScaling(ctx);
  772. return nk_rect(rect.x / scaling, rect.y / scaling, rect.width / scaling, rect.height / scaling);
  773. }
  774. /**
  775. * Convert the given raylib texture to a Nuklear image
  776. */
  777. NK_API struct nk_image
  778. TextureToNuklear(Texture tex)
  779. {
  780. // Declare the img to store data and allocate memory
  781. // For the texture
  782. struct nk_image img;
  783. struct Texture* stored_tex = (struct Texture*)MemAlloc(sizeof(Texture));
  784. // Copy the data from the texture given into the new texture
  785. stored_tex->id = tex.id;
  786. stored_tex->width = tex.width;
  787. stored_tex->height = tex.height;
  788. stored_tex->mipmaps = tex.mipmaps;
  789. stored_tex->format = tex.format;
  790. // Initialize the nk_image struct
  791. img.handle.ptr = stored_tex;
  792. img.w = (nk_ushort)stored_tex->width;
  793. img.h = (nk_ushort)stored_tex->height;
  794. // Set the region so we can sub-select the image later.
  795. img.region[0] = (nk_ushort)0;
  796. img.region[1] = (nk_ushort)0;
  797. img.region[2] = img.w;
  798. img.region[3] = img.h;
  799. return img;
  800. }
  801. /**
  802. * Convert the given Nuklear image to a raylib Texture
  803. */
  804. NK_API struct Texture
  805. TextureFromNuklear(struct nk_image img)
  806. {
  807. // Declare texture for storage
  808. // And get back the stored texture
  809. Texture tex;
  810. Texture* stored_tex = (Texture*)img.handle.ptr;
  811. // Copy the data from the stored texture to the texture
  812. tex.id = stored_tex->id;
  813. tex.width = stored_tex->width;
  814. tex.height = stored_tex->height;
  815. tex.mipmaps = stored_tex->mipmaps;
  816. tex.format = stored_tex->format;
  817. return tex;
  818. }
  819. /**
  820. * Load a Nuklear image directly
  821. *
  822. * @param path The path to the image
  823. */
  824. NK_API struct nk_image
  825. LoadNuklearImage(const char* path)
  826. {
  827. return TextureToNuklear(LoadTexture(path));
  828. }
  829. /**
  830. * Unload a loaded Nuklear image
  831. *
  832. * @param img The Nuklear image to unload
  833. */
  834. NK_API void
  835. UnloadNuklearImage(struct nk_image img)
  836. {
  837. Texture tex = TextureFromNuklear(img);
  838. UnloadTexture(tex);
  839. CleanupNuklearImage(img);
  840. }
  841. /**
  842. * Cleans up memory used by a Nuklear image
  843. * Does not unload the image.
  844. *
  845. * @param img The Nuklear image to cleanup
  846. */
  847. NK_API void
  848. CleanupNuklearImage(struct nk_image img)
  849. {
  850. MemFree(img.handle.ptr);
  851. }
  852. /**
  853. * Sets the scaling of the given Nuklear context.
  854. *
  855. * @param ctx The nuklear context.
  856. * @param scaling How much scale to apply to the graphical user interface.
  857. */
  858. NK_API void
  859. SetNuklearScaling(struct nk_context * ctx, float scaling)
  860. {
  861. if (ctx == NULL) {
  862. return;
  863. }
  864. if (scaling <= 0.0f) {
  865. TraceLog(LOG_WARNING, "NUKLEAR: Cannot set scaling to be less than 0");
  866. return;
  867. }
  868. struct NuklearUserData* userData = (struct NuklearUserData*)ctx->userdata.ptr;
  869. if (userData != NULL) {
  870. userData->scaling = scaling;
  871. }
  872. }
  873. /**
  874. * Retrieves the scale value of the given Nuklear context.
  875. *
  876. * @return The scale value that had been set for the Nuklear context. 1.0f is the default scale value.
  877. */
  878. NK_API float
  879. GetNuklearScaling(struct nk_context * ctx)
  880. {
  881. if (ctx == NULL) {
  882. return 1.0f;
  883. }
  884. struct NuklearUserData* userData = (struct NuklearUserData*)ctx->userdata.ptr;
  885. if (userData != NULL) {
  886. return userData->scaling;
  887. }
  888. return 1.0f;
  889. }
  890. #ifdef __cplusplus
  891. }
  892. #endif
  893. #endif // RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  894. #endif // RAYLIB_NUKLEAR_IMPLEMENTATION