raylib-nuklear.h 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. /**********************************************************************************************
  2. *
  3. * raylib-nuklear - Nuklear for Raylib.
  4. *
  5. * FEATURES:
  6. * - Use the nuklear immediate-mode graphical user interface in raylib.
  7. *
  8. * DEPENDENCIES:
  9. * - raylib 4.0 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. #ifndef NK_INCLUDE_STANDARD_VARARGS
  39. #define NK_INCLUDE_STANDARD_VARARGS
  40. #endif
  41. #ifndef NK_INCLUDE_FIXED_TYPES
  42. #define NK_INCLUDE_FIXED_TYPES
  43. #endif // NK_INCLUDE_FIXED_TYPES
  44. #ifndef NK_BOOL
  45. #define NK_INCLUDE_STANDARD_BOOL
  46. #define NK_BOOL bool
  47. #endif // NK_BOOL
  48. #include "nuklear.h"
  49. #ifdef __cplusplus
  50. extern "C" {
  51. #endif
  52. NK_API struct nk_context* InitNuklear(int fontSize); // Initialize the Nuklear GUI context
  53. NK_API struct nk_context* InitNuklearEx(Font font, float fontSize); // Initialize the Nuklear GUI context, with a custom font
  54. NK_API void UpdateNuklear(struct nk_context * ctx); // Update the input state and internal components for Nuklear
  55. NK_API void DrawNuklear(struct nk_context * ctx); // Render the Nuklear GUI on the screen
  56. NK_API void UnloadNuklear(struct nk_context * ctx); // Deinitialize the Nuklear context
  57. NK_API struct nk_color ColorToNuklear(Color color); // Convert a raylib Color to a Nuklear color object
  58. NK_API struct nk_colorf ColorToNuklearF(Color color); // Convert a raylib Color to a Nuklear floating color
  59. NK_API struct Color ColorFromNuklear(struct nk_color color); // Convert a Nuklear color to a raylib Color
  60. NK_API struct Color ColorFromNuklearF(struct nk_colorf color); // Convert a Nuklear floating color to a raylib Color
  61. NK_API struct Rectangle RectangleFromNuklear(struct nk_rect rect); // Convert a Nuklear rectangle to a raylib Rectangle
  62. NK_API struct nk_rect RectangleToNuklear(Rectangle rect); // Convert a raylib Rectangle to a Nuklear Rectangle
  63. NK_API struct nk_image TextureToNuklear(Texture tex); // Convert a raylib Texture to A Nuklear image
  64. NK_API struct Texture TextureFromNuklear(struct nk_image img); // Convert a Nuklear image to a raylib Texture
  65. NK_API struct nk_image LoadNuklearImage(const char* path); // Load a Nuklear image
  66. NK_API void UnloadNuklearImage(struct nk_image img); // Unload a Nuklear image. And free its data
  67. NK_API void CleanupNuklearImage(struct nk_image img); // Frees the data stored by the Nuklear image
  68. #ifdef __cplusplus
  69. }
  70. #endif
  71. #endif // RAYLIB_NUKLEAR_H
  72. #ifdef RAYLIB_NUKLEAR_IMPLEMENTATION
  73. #ifndef RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  74. #define RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  75. #ifndef NK_ASSERT
  76. #define NK_ASSERT(condition) if (!(condition)) { TraceLog(LOG_WARNING, "NUKLEAR: Failed assert \"%s\" (%s:%i)", #condition, "nuklear.h", __LINE__); }
  77. #endif // NK_ASSERT
  78. // TODO: Replace NK_INCLUDE_DEFAULT_ALLOCATOR with MemAlloc() and MemFree()
  79. #ifndef NK_INCLUDE_DEFAULT_ALLOCATOR
  80. #define NK_INCLUDE_DEFAULT_ALLOCATOR
  81. #endif // NK_INCLUDE_DEFAULT_ALLOCATOR
  82. // Math
  83. #ifndef NK_COS
  84. #define NK_COS cosf
  85. #endif // NK_COS
  86. #ifndef NK_SIN
  87. #define NK_SIN sinf
  88. #endif // NK_COS
  89. #ifndef NK_INV_SQRT
  90. #define NK_INV_SQRT(value) (1.0f / sqrtf(value))
  91. #endif // NK_INV_SQRT
  92. #define NK_IMPLEMENTATION
  93. #define NK_KEYSTATE_BASED_INPUT
  94. #include "nuklear.h"
  95. #ifdef __cplusplus
  96. extern "C" {
  97. #endif
  98. #ifndef RAYLIB_NUKLEAR_DEFAULT_FONTSIZE
  99. /**
  100. * The default font size that is used when a font size is not provided.
  101. */
  102. #define RAYLIB_NUKLEAR_DEFAULT_FONTSIZE 10
  103. #endif // RAYLIB_NUKLEAR_DEFAULT_FONTSIZE
  104. #ifndef RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS
  105. /**
  106. * The amount of segments used when drawing an arc.
  107. *
  108. * @see NK_COMMAND_ARC_FILLED
  109. */
  110. #define RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS 20
  111. #endif // RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS
  112. /**
  113. * Nuklear callback; Get the width of the given text.
  114. *
  115. * @internal
  116. */
  117. NK_API float
  118. nk_raylib_font_get_text_width(nk_handle handle, float height, const char *text, int len)
  119. {
  120. NK_UNUSED(handle);
  121. if (len > 0) {
  122. // Grab the text with the cropped length so that it only measures the desired string length.
  123. const char* subtext = TextSubtext(text, 0, len);
  124. return (float)MeasureText(subtext, (int)height);
  125. }
  126. return 0;
  127. }
  128. /**
  129. * Nuklear callback; Get the width of the given text (userFont version)
  130. *
  131. * @internal
  132. */
  133. NK_API float
  134. nk_raylib_font_get_text_width_user_font(nk_handle handle, float height, const char *text, int len)
  135. {
  136. if (len > 0) {
  137. // Grab the text with the cropped length so that it only measures the desired string length.
  138. const char* subtext = TextSubtext(text, 0, len);
  139. // Spacing is determined by the font size divided by 10.
  140. return MeasureTextEx(*(Font*)handle.ptr, subtext, height, height / 10.0f).x;
  141. }
  142. return 0;
  143. }
  144. /**
  145. * Nuklear callback; Paste the current clipboard.
  146. *
  147. * @internal
  148. */
  149. NK_API void
  150. nk_raylib_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
  151. {
  152. const char *text = GetClipboardText();
  153. NK_UNUSED(usr);
  154. if (text != NULL) {
  155. nk_textedit_paste(edit, text, (int)TextLength(text));
  156. }
  157. }
  158. /**
  159. * Nuklear callback; Copy the given text.
  160. *
  161. * @internal
  162. */
  163. NK_API void
  164. nk_raylib_clipboard_copy(nk_handle usr, const char *text, int len)
  165. {
  166. NK_UNUSED(usr);
  167. NK_UNUSED(len);
  168. SetClipboardText(text);
  169. }
  170. /**
  171. * Initialize the Nuklear context for use with Raylib, with the given Nuklear user font.
  172. *
  173. * @param userFont The Nuklear user font to initialize the Nuklear context with.
  174. *
  175. * @internal
  176. */
  177. NK_API struct nk_context*
  178. InitNuklearContext(struct nk_user_font* userFont)
  179. {
  180. struct nk_context* ctx = (struct nk_context*)MemAlloc(sizeof(struct nk_context));
  181. // Clipboard
  182. ctx->clip.copy = nk_raylib_clipboard_copy;
  183. ctx->clip.paste = nk_raylib_clipboard_paste;
  184. ctx->clip.userdata = nk_handle_ptr(0);
  185. // Create the nuklear environment.
  186. if (nk_init_default(ctx, userFont) == 0) {
  187. TraceLog(LOG_ERROR, "NUKLEAR: Failed to initialize nuklear");
  188. return NULL;
  189. }
  190. TraceLog(LOG_INFO, "NUKLEAR: Initialized GUI");
  191. return ctx;
  192. }
  193. /**
  194. * Initialize the Nuklear context for use with Raylib.
  195. *
  196. * @param fontSize The size of the font to use for GUI text. Use 0 to use the default font size of 10.
  197. *
  198. * @return The nuklear context, or NULL on error.
  199. */
  200. NK_API struct nk_context*
  201. InitNuklear(int fontSize)
  202. {
  203. // User font.
  204. struct nk_user_font* userFont = (struct nk_user_font*)MemAlloc(sizeof(struct nk_user_font));
  205. // Use the default font size if desired.
  206. if (fontSize <= 0) {
  207. fontSize = RAYLIB_NUKLEAR_DEFAULT_FONTSIZE;
  208. }
  209. userFont->height = (float)fontSize;
  210. userFont->width = nk_raylib_font_get_text_width;
  211. userFont->userdata = nk_handle_ptr(0);
  212. // Nuklear context.
  213. return InitNuklearContext(userFont);
  214. }
  215. /**
  216. * Initialize the Nuklear context for use with Raylib, with a supplied custom font.
  217. *
  218. * @param font The custom raylib font to use with Nuklear.
  219. * @param fontSize The desired size of the font. Use 0 to set the default size of 10.
  220. *
  221. * @return The nuklear context, or NULL on error.
  222. */
  223. NK_API struct nk_context*
  224. InitNuklearEx(Font font, float fontSize)
  225. {
  226. // Copy the font to a new raylib font pointer.
  227. struct Font* newFont = (struct Font*)MemAlloc(sizeof(struct Font));
  228. // Use the default font size if desired.
  229. if (fontSize <= 0.0f) {
  230. fontSize = (float)RAYLIB_NUKLEAR_DEFAULT_FONTSIZE;
  231. }
  232. newFont->baseSize = font.baseSize;
  233. newFont->glyphCount = font.glyphCount;
  234. newFont->glyphPadding = font.glyphPadding;
  235. newFont->glyphs = font.glyphs;
  236. newFont->recs = font.recs;
  237. newFont->texture = font.texture;
  238. // Create the nuklear user font.
  239. struct nk_user_font* userFont = (struct nk_user_font*)MemAlloc(sizeof(struct nk_user_font));
  240. userFont->userdata = nk_handle_ptr(newFont);
  241. userFont->height = fontSize;
  242. userFont->width = nk_raylib_font_get_text_width_user_font;
  243. // Nuklear context.
  244. return InitNuklearContext(userFont);
  245. }
  246. /**
  247. * Convert the given Nuklear color to a raylib color.
  248. */
  249. NK_API Color
  250. ColorFromNuklear(struct nk_color color)
  251. {
  252. Color rc;
  253. rc.a = color.a;
  254. rc.r = color.r;
  255. rc.g = color.g;
  256. rc.b = color.b;
  257. return rc;
  258. }
  259. /**
  260. * Convert the given raylib color to a Nuklear color.
  261. */
  262. NK_API struct nk_color
  263. ColorToNuklear(Color color)
  264. {
  265. struct nk_color rc;
  266. rc.a = color.a;
  267. rc.r = color.r;
  268. rc.g = color.g;
  269. rc.b = color.b;
  270. return rc;
  271. }
  272. /**
  273. * Convert the given Nuklear float color to a raylib color.
  274. */
  275. NK_API Color
  276. ColorFromNuklearF(struct nk_colorf color)
  277. {
  278. return ColorFromNuklear(nk_rgba_cf(color));
  279. }
  280. /**
  281. * Convert the given raylib color to a raylib float color.
  282. */
  283. NK_API struct nk_colorf
  284. ColorToNuklearF(Color color)
  285. {
  286. return nk_color_cf(ColorToNuklear(color));
  287. }
  288. /**
  289. * Draw the given Nuklear context in raylib.
  290. *
  291. * @param ctx The nuklear context.
  292. */
  293. NK_API void
  294. DrawNuklear(struct nk_context * ctx)
  295. {
  296. const struct nk_command *cmd;
  297. nk_foreach(cmd, ctx) {
  298. switch (cmd->type) {
  299. case NK_COMMAND_NOP: {
  300. break;
  301. }
  302. case NK_COMMAND_SCISSOR: {
  303. // TODO(RobLoach): Verify if NK_COMMAND_SCISSOR works.
  304. const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
  305. BeginScissorMode(s->x, s->y, s->w, s->h);
  306. } break;
  307. case NK_COMMAND_LINE: {
  308. const struct nk_command_line *l = (const struct nk_command_line *)cmd;
  309. Color color = ColorFromNuklear(l->color);
  310. Vector2 startPos = {(float)l->begin.x, (float)l->begin.y};
  311. Vector2 endPos = {(float)l->end.x, (float)l->end.y};
  312. DrawLineEx(startPos, endPos, l->line_thickness, color);
  313. } break;
  314. case NK_COMMAND_CURVE: {
  315. const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
  316. Color color = ColorFromNuklear(q->color);
  317. Vector2 start = {(float)q->begin.x, (float)q->begin.y};
  318. // Vector2 controlPoint1 = (Vector2){q->ctrl[0].x, q->ctrl[0].y};
  319. // Vector2 controlPoint2 = (Vector2){q->ctrl[1].x, q->ctrl[1].y};
  320. Vector2 end = {(float)q->end.x, (float)q->end.y};
  321. // TODO: Encorporate segmented control point bezier curve?
  322. // DrawLineBezier(start, controlPoint1, (float)q->line_thickness, color);
  323. // DrawLineBezier(controlPoint1, controlPoint2, (float)q->line_thickness, color);
  324. // DrawLineBezier(controlPoint2, end, (float)q->line_thickness, color);
  325. DrawLineBezier(start, end, (float)q->line_thickness, color);
  326. } break;
  327. case NK_COMMAND_RECT: {
  328. const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
  329. Color color = ColorFromNuklear(r->color);
  330. Rectangle rect = {(float)r->x, (float)r->y, (float)r->w, (float)r->h};
  331. if (r->rounding > 0) {
  332. float roundness = (float)r->rounding * 4.0f / (rect.width + rect.height);
  333. DrawRectangleRoundedLines(rect, roundness, 1, r->line_thickness, color);
  334. }
  335. else {
  336. DrawRectangleLinesEx(rect, r->line_thickness, color);
  337. }
  338. } break;
  339. case NK_COMMAND_RECT_FILLED: {
  340. const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
  341. Color color = ColorFromNuklear(r->color);
  342. Rectangle rect = {(float)r->x, (float)r->y, (float)r->w, (float)r->h};
  343. if (r->rounding > 0) {
  344. float roundness = (float)r->rounding * 4.0f / (rect.width + rect.height);
  345. DrawRectangleRounded(rect, roundness, 1, color);
  346. }
  347. else {
  348. DrawRectangleRec(rect, color);
  349. }
  350. } break;
  351. case NK_COMMAND_RECT_MULTI_COLOR: {
  352. const struct nk_command_rect_multi_color* rectangle = (const struct nk_command_rect_multi_color *)cmd;
  353. Rectangle position = {(float)rectangle->x, (float)rectangle->y, (float)rectangle->w, (float)rectangle->h};
  354. Color left = ColorFromNuklear(rectangle->left);
  355. Color top = ColorFromNuklear(rectangle->top);
  356. Color bottom = ColorFromNuklear(rectangle->bottom);
  357. Color right = ColorFromNuklear(rectangle->right);
  358. DrawRectangleGradientEx(position, left, bottom, right, top);
  359. } break;
  360. case NK_COMMAND_CIRCLE: {
  361. const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
  362. Color color = ColorFromNuklear(c->color);
  363. DrawEllipseLines(c->x + c->w / 2, c->y + c->h / 2, c->w / 2, c->h / 2, color);
  364. } break;
  365. case NK_COMMAND_CIRCLE_FILLED: {
  366. const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
  367. Color color = ColorFromNuklear(c->color);
  368. DrawEllipse(c->x + c->w / 2, c->y + c->h / 2, c->w / 2, c->h / 2, color);
  369. } break;
  370. case NK_COMMAND_ARC: {
  371. const struct nk_command_arc *a = (const struct nk_command_arc*)cmd;
  372. Color color = ColorFromNuklear(a->color);
  373. Vector2 center = {(float)a->cx, (float)a->cy};
  374. DrawRingLines(center, 0, a->r, a->a[0] * RAD2DEG - 45, a->a[1] * RAD2DEG - 45, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, color);
  375. } break;
  376. case NK_COMMAND_ARC_FILLED: {
  377. const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled*)cmd;
  378. Color color = ColorFromNuklear(a->color);
  379. Vector2 center = {(float)a->cx, (float)a->cy};
  380. DrawRing(center, 0, a->r, a->a[0] * RAD2DEG - 45, a->a[1] * RAD2DEG - 45, RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS, color);
  381. } break;
  382. case NK_COMMAND_TRIANGLE: {
  383. const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;
  384. Color color = ColorFromNuklear(t->color);
  385. Vector2 point1 = {(float)t->b.x, (float)t->b.y};
  386. Vector2 point2 = {(float)t->a.x, (float)t->a.y};
  387. Vector2 point3 = {(float)t->c.x, (float)t->c.y};
  388. DrawTriangleLines(point1, point2, point3, color);
  389. } break;
  390. case NK_COMMAND_TRIANGLE_FILLED: {
  391. const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;
  392. Color color = ColorFromNuklear(t->color);
  393. Vector2 point1 = {(float)t->b.x, (float)t->b.y};
  394. Vector2 point2 = {(float)t->a.x, (float)t->a.y};
  395. Vector2 point3 = {(float)t->c.x, (float)t->c.y};
  396. DrawTriangle(point1, point2, point3, color);
  397. } break;
  398. case NK_COMMAND_POLYGON: {
  399. // TODO: Confirm Polygon
  400. const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
  401. Color color = ColorFromNuklear(p->color);
  402. Vector2* points = MemAlloc(p->point_count * (unsigned short)sizeof(Vector2));
  403. unsigned short i;
  404. for (i = 0; i < p->point_count; i++) {
  405. points[i].x = p->points[i].x;
  406. points[i].y = p->points[i].y;
  407. }
  408. DrawTriangleStrip(points, p->point_count, color);
  409. MemFree(points);
  410. } break;
  411. case NK_COMMAND_POLYGON_FILLED: {
  412. // TODO: Polygon filled expects counter clockwise order
  413. const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;
  414. Color color = ColorFromNuklear(p->color);
  415. Vector2* points = MemAlloc(p->point_count * (unsigned short)sizeof(Vector2));
  416. unsigned short i;
  417. for (i = 0; i < p->point_count; i++) {
  418. points[i].x = p->points[i].x;
  419. points[i].y = p->points[i].y;
  420. }
  421. DrawTriangleFan(points, p->point_count, color);
  422. MemFree(points);
  423. } break;
  424. case NK_COMMAND_POLYLINE: {
  425. // TODO: Polygon expects counter clockwise order
  426. const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
  427. Color color = ColorFromNuklear(p->color);
  428. Vector2* points = MemAlloc(p->point_count * (unsigned short)sizeof(Vector2));
  429. unsigned short i;
  430. for (i = 0; i < p->point_count; i++) {
  431. points[i].x = p->points[i].x;
  432. points[i].y = p->points[i].y;
  433. }
  434. DrawTriangleStrip(points, p->point_count, color);
  435. MemFree(points);
  436. } break;
  437. case NK_COMMAND_TEXT: {
  438. const struct nk_command_text *text = (const struct nk_command_text*)cmd;
  439. Color color = ColorFromNuklear(text->foreground);
  440. Color background = ColorFromNuklear(text->background);
  441. float fontSize = text->font->height;
  442. Font* font = (Font*)text->font->userdata.ptr;
  443. DrawRectangle(text->x, text->y, text->w, text->h, background);
  444. if (font != NULL) {
  445. Vector2 position = {(float)text->x, (float)text->y};
  446. DrawTextEx(*font, (const char*)text->string, position, fontSize, fontSize / 10.0f, color);
  447. }
  448. else {
  449. DrawText((const char*)text->string, text->x, text->y, (int)fontSize, color);
  450. }
  451. } break;
  452. case NK_COMMAND_IMAGE: {
  453. const struct nk_command_image *i = (const struct nk_command_image *)cmd;
  454. Texture texture = *(Texture*)i->img.handle.ptr;
  455. Rectangle source = {0, 0, (float)texture.width, (float)texture.height};
  456. Rectangle dest = {(float)i->x, (float)i->y, (float)i->w, (float)i->h};
  457. Vector2 origin = {0, 0};
  458. Color tint = ColorFromNuklear(i->col);
  459. DrawTexturePro(texture, source, dest, origin, 0, tint);
  460. } break;
  461. case NK_COMMAND_CUSTOM: {
  462. TraceLog(LOG_WARNING, "NUKLEAR: Unverified custom callback implementation NK_COMMAND_CUSTOM");
  463. const struct nk_command_custom *custom = (const struct nk_command_custom *)cmd;
  464. custom->callback(NULL, custom->x, custom->y, custom->w, custom->h, custom->callback_data);
  465. } break;
  466. default: {
  467. TraceLog(LOG_WARNING, "NUKLEAR: Missing implementation %i", cmd->type);
  468. } break;
  469. }
  470. }
  471. nk_clear(ctx);
  472. }
  473. /**
  474. * Update the Nuklear context for the keyboard input from raylib.
  475. *
  476. * @param ctx The nuklear context.
  477. *
  478. * @internal
  479. */
  480. NK_API void nk_raylib_input_keyboard(struct nk_context * ctx)
  481. {
  482. bool control = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
  483. bool shift = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
  484. nk_input_key(ctx, NK_KEY_SHIFT, shift);
  485. nk_input_key(ctx, NK_KEY_CTRL, control);
  486. nk_input_key(ctx, NK_KEY_DEL, IsKeyDown(KEY_DELETE));
  487. nk_input_key(ctx, NK_KEY_ENTER, IsKeyDown(KEY_ENTER) || IsKeyDown(KEY_KP_ENTER));
  488. nk_input_key(ctx, NK_KEY_TAB, IsKeyDown(KEY_TAB));
  489. nk_input_key(ctx, NK_KEY_BACKSPACE, IsKeyDown(KEY_BACKSPACE));
  490. nk_input_key(ctx, NK_KEY_COPY, IsKeyPressed(KEY_C) && control);
  491. nk_input_key(ctx, NK_KEY_CUT, IsKeyPressed(KEY_X) && control);
  492. nk_input_key(ctx, NK_KEY_PASTE, IsKeyPressed(KEY_V) && control);
  493. nk_input_key(ctx, NK_KEY_TEXT_LINE_START, IsKeyPressed(KEY_B) && control);
  494. nk_input_key(ctx, NK_KEY_TEXT_LINE_END, IsKeyPressed(KEY_E) && control);
  495. nk_input_key(ctx, NK_KEY_TEXT_UNDO, IsKeyDown(KEY_Z) && control);
  496. nk_input_key(ctx, NK_KEY_TEXT_REDO, IsKeyDown(KEY_R) && control);
  497. nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, IsKeyDown(KEY_A) && control);
  498. nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, IsKeyDown(KEY_LEFT) && control);
  499. nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, IsKeyDown(KEY_RIGHT) && control);
  500. nk_input_key(ctx, NK_KEY_LEFT, IsKeyDown(KEY_LEFT) && !control);
  501. nk_input_key(ctx, NK_KEY_RIGHT, IsKeyDown(KEY_RIGHT) && !control);
  502. //nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, IsKeyDown());
  503. //nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, IsKeyDown());
  504. //nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, IsKeyDown());
  505. nk_input_key(ctx, NK_KEY_UP, IsKeyDown(KEY_UP));
  506. nk_input_key(ctx, NK_KEY_DOWN, IsKeyDown(KEY_DOWN));
  507. nk_input_key(ctx, NK_KEY_TEXT_START, IsKeyDown(KEY_HOME));
  508. nk_input_key(ctx, NK_KEY_TEXT_END, IsKeyDown(KEY_END));
  509. nk_input_key(ctx, NK_KEY_SCROLL_START, IsKeyDown(KEY_HOME) && control);
  510. nk_input_key(ctx, NK_KEY_SCROLL_END, IsKeyDown(KEY_END) && control);
  511. nk_input_key(ctx, NK_KEY_SCROLL_DOWN, IsKeyDown(KEY_PAGE_DOWN));
  512. nk_input_key(ctx, NK_KEY_SCROLL_UP, IsKeyDown(KEY_PAGE_UP));
  513. // Keys
  514. if (IsKeyPressed(KEY_APOSTROPHE)) nk_input_unicode(ctx, shift ? 34 : (nk_rune)KEY_APOSTROPHE);
  515. if (IsKeyPressed(KEY_COMMA)) nk_input_unicode(ctx, shift ? 60 : (nk_rune)KEY_COMMA);
  516. if (IsKeyPressed(KEY_MINUS)) nk_input_unicode(ctx, shift ? 95 : (nk_rune)KEY_MINUS);
  517. if (IsKeyPressed(KEY_PERIOD)) nk_input_unicode(ctx, shift ? 62 : (nk_rune)KEY_PERIOD);
  518. if (IsKeyPressed(KEY_SLASH)) nk_input_unicode(ctx, shift ? 63 : (nk_rune)KEY_SLASH);
  519. if (IsKeyPressed(KEY_ZERO)) nk_input_unicode(ctx, shift ? 41 : (nk_rune)KEY_ZERO);
  520. if (IsKeyPressed(KEY_ONE)) nk_input_unicode(ctx, shift ? 33 : (nk_rune)KEY_ONE);
  521. if (IsKeyPressed(KEY_TWO)) nk_input_unicode(ctx, shift ? 64 : (nk_rune)KEY_TWO);
  522. if (IsKeyPressed(KEY_THREE)) nk_input_unicode(ctx, shift ? 35 : (nk_rune)KEY_THREE);
  523. if (IsKeyPressed(KEY_FOUR)) nk_input_unicode(ctx, shift ? 36 : (nk_rune)KEY_FOUR);
  524. if (IsKeyPressed(KEY_FIVE)) nk_input_unicode(ctx, shift ? 37 : (nk_rune)KEY_FIVE);
  525. if (IsKeyPressed(KEY_SIX)) nk_input_unicode(ctx, shift ? 94 : (nk_rune)KEY_SIX);
  526. if (IsKeyPressed(KEY_SEVEN)) nk_input_unicode(ctx, shift ? 38 : (nk_rune)KEY_SEVEN);
  527. if (IsKeyPressed(KEY_EIGHT)) nk_input_unicode(ctx, shift ? 42 : (nk_rune)KEY_EIGHT);
  528. if (IsKeyPressed(KEY_NINE)) nk_input_unicode(ctx, shift ? 40 : (nk_rune)KEY_NINE);
  529. if (IsKeyPressed(KEY_SEMICOLON)) nk_input_unicode(ctx, shift ? 41 : (nk_rune)KEY_SEMICOLON);
  530. if (IsKeyPressed(KEY_EQUAL)) nk_input_unicode(ctx, shift ? 43 : (nk_rune)KEY_EQUAL);
  531. if (IsKeyPressed(KEY_A)) nk_input_unicode(ctx, shift ? KEY_A : KEY_A + 32);
  532. if (IsKeyPressed(KEY_B)) nk_input_unicode(ctx, shift ? KEY_B : KEY_B + 32);
  533. if (IsKeyPressed(KEY_C)) nk_input_unicode(ctx, shift ? KEY_C : KEY_C + 32);
  534. if (IsKeyPressed(KEY_D)) nk_input_unicode(ctx, shift ? KEY_D : KEY_D + 32);
  535. if (IsKeyPressed(KEY_E)) nk_input_unicode(ctx, shift ? KEY_E : KEY_E + 32);
  536. if (IsKeyPressed(KEY_F)) nk_input_unicode(ctx, shift ? KEY_F : KEY_F + 32);
  537. if (IsKeyPressed(KEY_G)) nk_input_unicode(ctx, shift ? KEY_G : KEY_G + 32);
  538. if (IsKeyPressed(KEY_H)) nk_input_unicode(ctx, shift ? KEY_H : KEY_H + 32);
  539. if (IsKeyPressed(KEY_I)) nk_input_unicode(ctx, shift ? KEY_I : KEY_I + 32);
  540. if (IsKeyPressed(KEY_J)) nk_input_unicode(ctx, shift ? KEY_J : KEY_J + 32);
  541. if (IsKeyPressed(KEY_K)) nk_input_unicode(ctx, shift ? KEY_K : KEY_K + 32);
  542. if (IsKeyPressed(KEY_L)) nk_input_unicode(ctx, shift ? KEY_L : KEY_L + 32);
  543. if (IsKeyPressed(KEY_M)) nk_input_unicode(ctx, shift ? KEY_M : KEY_M + 32);
  544. if (IsKeyPressed(KEY_N)) nk_input_unicode(ctx, shift ? KEY_N : KEY_N + 32);
  545. if (IsKeyPressed(KEY_O)) nk_input_unicode(ctx, shift ? KEY_O : KEY_O + 32);
  546. if (IsKeyPressed(KEY_P)) nk_input_unicode(ctx, shift ? KEY_P : KEY_P + 32);
  547. if (IsKeyPressed(KEY_Q)) nk_input_unicode(ctx, shift ? KEY_Q : KEY_Q + 32);
  548. if (IsKeyPressed(KEY_R)) nk_input_unicode(ctx, shift ? KEY_R : KEY_R + 32);
  549. if (IsKeyPressed(KEY_S)) nk_input_unicode(ctx, shift ? KEY_S : KEY_S + 32);
  550. if (IsKeyPressed(KEY_T)) nk_input_unicode(ctx, shift ? KEY_T : KEY_T + 32);
  551. if (IsKeyPressed(KEY_U)) nk_input_unicode(ctx, shift ? KEY_U : KEY_U + 32);
  552. if (IsKeyPressed(KEY_V)) nk_input_unicode(ctx, shift ? KEY_V : KEY_V + 32);
  553. if (IsKeyPressed(KEY_W)) nk_input_unicode(ctx, shift ? KEY_W : KEY_W + 32);
  554. if (IsKeyPressed(KEY_X)) nk_input_unicode(ctx, shift ? KEY_X : KEY_X + 32);
  555. if (IsKeyPressed(KEY_Y)) nk_input_unicode(ctx, shift ? KEY_Y : KEY_Y + 32);
  556. if (IsKeyPressed(KEY_Z)) nk_input_unicode(ctx, shift ? KEY_Z : KEY_Z + 32);
  557. if (IsKeyPressed(KEY_LEFT_BRACKET)) nk_input_unicode(ctx, shift ? 123 : (nk_rune)KEY_LEFT_BRACKET);
  558. if (IsKeyPressed(KEY_BACKSLASH)) nk_input_unicode(ctx, shift ? 124 : (nk_rune)KEY_BACKSLASH);
  559. if (IsKeyPressed(KEY_RIGHT_BRACKET)) nk_input_unicode(ctx, shift ? 125 : (nk_rune)KEY_RIGHT_BRACKET);
  560. if (IsKeyPressed(KEY_GRAVE)) nk_input_unicode(ctx, shift ? 126 : (nk_rune)KEY_GRAVE);
  561. // Functions
  562. if (IsKeyPressed(KEY_SPACE)) nk_input_unicode(ctx, KEY_SPACE);
  563. if (IsKeyPressed(KEY_TAB)) nk_input_unicode(ctx, 9);
  564. // Keypad
  565. if (IsKeyPressed(KEY_KP_0)) nk_input_unicode(ctx, KEY_ZERO);
  566. if (IsKeyPressed(KEY_KP_1)) nk_input_unicode(ctx, KEY_ONE);
  567. if (IsKeyPressed(KEY_KP_2)) nk_input_unicode(ctx, KEY_TWO);
  568. if (IsKeyPressed(KEY_KP_3)) nk_input_unicode(ctx, KEY_THREE);
  569. if (IsKeyPressed(KEY_KP_4)) nk_input_unicode(ctx, KEY_FOUR);
  570. if (IsKeyPressed(KEY_KP_5)) nk_input_unicode(ctx, KEY_FIVE);
  571. if (IsKeyPressed(KEY_KP_6)) nk_input_unicode(ctx, KEY_SIX);
  572. if (IsKeyPressed(KEY_KP_7)) nk_input_unicode(ctx, KEY_SEVEN);
  573. if (IsKeyPressed(KEY_KP_8)) nk_input_unicode(ctx, KEY_EIGHT);
  574. if (IsKeyPressed(KEY_KP_9)) nk_input_unicode(ctx, KEY_NINE);
  575. if (IsKeyPressed(KEY_KP_DECIMAL)) nk_input_unicode(ctx, KEY_PERIOD);
  576. if (IsKeyPressed(KEY_KP_DIVIDE)) nk_input_unicode(ctx, KEY_SLASH);
  577. if (IsKeyPressed(KEY_KP_MULTIPLY)) nk_input_unicode(ctx, 48);
  578. if (IsKeyPressed(KEY_KP_SUBTRACT)) nk_input_unicode(ctx, 45);
  579. if (IsKeyPressed(KEY_KP_ADD)) nk_input_unicode(ctx, 43);
  580. }
  581. /**
  582. * Update the Nuklear context for the mouse input from raylib.
  583. *
  584. * @param ctx The nuklear context.
  585. *
  586. * @internal
  587. */
  588. NK_API void nk_raylib_input_mouse(struct nk_context * ctx)
  589. {
  590. nk_input_motion(ctx, GetMouseX(), GetMouseY());
  591. nk_input_button(ctx, NK_BUTTON_LEFT, GetMouseX(), GetMouseY(), IsMouseButtonDown(MOUSE_LEFT_BUTTON));
  592. nk_input_button(ctx, NK_BUTTON_RIGHT, GetMouseX(), GetMouseY(), IsMouseButtonDown(MOUSE_RIGHT_BUTTON));
  593. nk_input_button(ctx, NK_BUTTON_MIDDLE, GetMouseX(), GetMouseY(), IsMouseButtonDown(MOUSE_MIDDLE_BUTTON));
  594. // Mouse Wheel
  595. float mouseWheel = GetMouseWheelMove();
  596. if (mouseWheel != 0.0f) {
  597. struct nk_vec2 mouseWheelMove;
  598. mouseWheelMove.x = 0.0f;
  599. mouseWheelMove.y = mouseWheel;
  600. nk_input_scroll(ctx, mouseWheelMove);
  601. }
  602. }
  603. /**
  604. * Update the Nuklear context for raylib's state.
  605. *
  606. * @param ctx The nuklear context to act upon.
  607. */
  608. NK_API void
  609. UpdateNuklear(struct nk_context * ctx)
  610. {
  611. nk_input_begin(ctx);
  612. {
  613. nk_raylib_input_mouse(ctx);
  614. nk_raylib_input_keyboard(ctx);
  615. }
  616. nk_input_end(ctx);
  617. }
  618. /**
  619. * Unload the given Nuklear context, along with all internal raylib textures.
  620. *
  621. * @param ctx The nuklear context.
  622. */
  623. NK_API void
  624. UnloadNuklear(struct nk_context * ctx)
  625. {
  626. struct nk_user_font* userFont;
  627. // Skip unloading if it's not set.
  628. if (ctx == NULL) {
  629. return;
  630. }
  631. // Unload the font.
  632. userFont = (struct nk_user_font*)ctx->style.font;
  633. if (userFont != NULL) {
  634. // Clear the raylib Font object.
  635. void* fontPtr = userFont->userdata.ptr;
  636. if (fontPtr != NULL) {
  637. MemFree(fontPtr);
  638. }
  639. // Clear the user font.
  640. MemFree(userFont);
  641. ctx->style.font = NULL;
  642. }
  643. // Unload the nuklear context.
  644. nk_free(ctx);
  645. TraceLog(LOG_INFO, "NUKLEAR: Unloaded GUI");
  646. }
  647. /**
  648. * Convert the given Nuklear rectangle to a raylib Rectangle.
  649. */
  650. NK_API struct
  651. Rectangle RectangleFromNuklear(struct nk_rect rect)
  652. {
  653. Rectangle output;
  654. output.x = rect.x;
  655. output.y = rect.y;
  656. output.width = rect.w;
  657. output.height = rect.h;
  658. return output;
  659. }
  660. /**
  661. * Convert the given raylib Rectangle to a Nuklear rectangle.
  662. */
  663. NK_API struct
  664. nk_rect RectangleToNuklear(Rectangle rect)
  665. {
  666. return nk_rect(rect.x, rect.y, rect.width, rect.height);
  667. }
  668. /**
  669. * Convert the given raylib texture to a Nuklear image
  670. */
  671. NK_API struct nk_image TextureToNuklear(Texture tex)
  672. {
  673. // Declare the img to store data and allocate memory
  674. // For the texture
  675. struct nk_image img;
  676. Texture* stored_tex = (Texture*)MemAlloc(sizeof(Texture));
  677. // Copy the data from the texture given into the new texture
  678. stored_tex->id = tex.id;
  679. stored_tex->width = tex.width;
  680. stored_tex->height = tex.height;
  681. stored_tex->mipmaps = tex.mipmaps;
  682. stored_tex->format = tex.format;
  683. // Initialize the nk_image struct
  684. img.handle.ptr = stored_tex;
  685. img.w = (nk_ushort)stored_tex->width;
  686. img.h = (nk_ushort)stored_tex->height;
  687. return img;
  688. }
  689. /**
  690. * Convert the given Nuklear image to a raylib Texture
  691. */
  692. NK_API struct Texture TextureFromNuklear(struct nk_image img)
  693. {
  694. // Declare texture for storage
  695. // And get back the stored texture
  696. Texture tex;
  697. Texture* stored_tex = (Texture*)img.handle.ptr;
  698. // Copy the data from the stored texture to the texture
  699. tex.id = stored_tex->id;
  700. tex.width = stored_tex->width;
  701. tex.height = stored_tex->height;
  702. tex.mipmaps = stored_tex->mipmaps;
  703. tex.format = stored_tex->format;
  704. return tex;
  705. }
  706. /**
  707. * Load a Nuklear image directly
  708. *
  709. * @param path The path to the image
  710. */
  711. NK_API struct nk_image LoadNuklearImage(const char* path)
  712. {
  713. return TextureToNuklear(LoadTexture(path));
  714. }
  715. /**
  716. * Unload a loaded Nuklear image
  717. *
  718. * @param img The Nuklear image to unload
  719. */
  720. NK_API void UnloadNuklearImage(struct nk_image img)
  721. {
  722. Texture tex = TextureFromNuklear(img);
  723. UnloadTexture(tex);
  724. CleanupNuklearImage(img);
  725. }
  726. /**
  727. * Cleans up memory used by a Nuklear image
  728. * Does not unload the image.
  729. *
  730. * @param img The Nuklear image to cleanup
  731. */
  732. NK_API void CleanupNuklearImage(struct nk_image img)
  733. {
  734. free(img.handle.ptr);
  735. }
  736. #ifdef __cplusplus
  737. }
  738. #endif
  739. #endif // RAYLIB_NUKLEAR_IMPLEMENTATION_ONCE
  740. #endif // RAYLIB_NUKLEAR_IMPLEMENTATION