raylib-nuklear.h 37 KB

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